Compare commits

..

1 Commits

Author SHA1 Message Date
David Markowitz
bc0a7f4259 Script: Fix incorrect kill method 2023-11-01 19:58:48 -07:00
20 changed files with 188 additions and 366 deletions

View File

@@ -224,44 +224,6 @@ sudo setcap 'cap_net_bind_service=+ep' AuthServer
```
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
### Linux Service
If you are running this on a linux based system, it will use your terminal to run the program interactively, preventing you using it for other tasks and requiring it to be open to run the server.
_Note: You could use screen or tmux instead for virtual terminals_
To run the server non-interactively, we can use a systemctl service by copying the following file:
```shell
cp ./systemd.example /etc/systemd/system/darkflame.service
```
Make sure to edit the file in `/etc/systemd/system/darkflame.service` and change the:
- `User` and `Group` to the user that runs the darkflame server.
- `ExecPath` to the full file path of the server executable.
To register, enable and start the service use the following commands:
- Reload the systemd manager configuration to make it aware of the new service file:
```shell
systemctl daemon-reload
```
- Start the service:
```shell
systemctl start darkflame.service
```
- Enable OR disable the service to start on boot using:
```shell
systemctl enable darkflame.service
systemctl disable darkflame.service
```
- Verify that the service is running without errors:
```shell
systemctl status darkflame.service
```
- You can also restart, stop, or check the logs of the service using journalctl
```shell
systemctl restart darkflame.service
systemctl stop darkflame.service
journalctl -xeu darkflame.service
```
### First admin user
Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
@@ -323,7 +285,6 @@ Below are known good SHA256 checksums of the client:
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
You must also make absolutely sure your LEGO Universe client is not in a Windows OneDrive. DLU is not and will not support a client being stored in a OneDrive, so ensure you have moved the client outside of that location.
### Darkflame Universe Client
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.

View File

@@ -144,7 +144,7 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
listOfBadSegments.emplace_back(position, originalSegment.length());
}
position += originalSegment.length() + 1;
position += segment.length() + 1;
}
return listOfBadSegments;

View File

@@ -15,9 +15,7 @@ enum class eCharacterVersion : uint32_t {
// Fixes vault size value
VAULT_SIZE,
// Fixes speed base value in level component
SPEED_BASE,
// Fixes explore missions that were corruped
UP_TO_DATE // Will become EXPLORE
UP_TO_DATE, // will become SPEED_BASE
};
#endif //!__ECHARACTERVERSION__H__

View File

@@ -3,8 +3,6 @@
#include "Game.h"
#include "Logger.h"
#include "EntityManager.h"
#include "dZoneManager.h"
#include "WorldConfig.h"
#include "DestroyableComponent.h"
#include "BehaviorContext.h"
#include "eBasicAttackSuccessTypes.h"
@@ -15,15 +13,8 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) {
PlayFx(u"onhit", entity->GetObjectID()); //This damage animation doesn't seem to play consistently
PlayFx(u"onhit", entity->GetObjectID());
destroyableComponent->Damage(this->m_MaxDamage, context->originator, context->skillID);
//Handle player damage cooldown
if (entity->IsPlayer() && !this->m_DontApplyImmune) {
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
destroyableComponent->SetDamageCooldownTimer(immunityTime);
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
}
}
this->m_OnSuccess->Handle(context, bitStream, branch);
@@ -81,7 +72,6 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
}
if (isImmune) {
LOG_DEBUG("Target targetEntity %llu is immune!", branch.target);
this->m_OnFailImmune->Handle(context, bitStream, branch);
return;
}
@@ -188,15 +178,11 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
return;
}
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
LOG_DEBUG("Damage cooldown timer currently %f s", destroyableComponent->GetDamageCooldownTimer());
const bool isImmune = (destroyableComponent->IsImmune()) || (destroyableComponent->IsCooldownImmune());
const bool isImmune = destroyableComponent->IsImmune();
bitStream->Write(isImmune);
if (isImmune) {
LOG_DEBUG("Target targetEntity %llu is immune!", branch.target);
this->m_OnFailImmune->Calculate(context, bitStream, branch);
return;
}
@@ -217,12 +203,6 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
bitStream->Write(isSuccess);
//Handle player damage cooldown
if (isSuccess && targetEntity->IsPlayer() && !this->m_DontApplyImmune) {
destroyableComponent->SetDamageCooldownTimer(immunityTime);
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
}
eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE;
if (isSuccess) {
if (healthDamageDealt >= 1) {
@@ -256,8 +236,6 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
}
void BasicAttackBehavior::Load() {
this->m_DontApplyImmune = GetBoolean("dont_apply_immune");
this->m_MinDamage = GetInt("min damage");
if (this->m_MinDamage == 0) this->m_MinDamage = 1;

View File

@@ -10,14 +10,14 @@ public:
/**
* @brief Reads a 16bit short from the bitStream and when the actual behavior handling finishes with all of its branches, the bitStream
* is then offset to after the allocated bits for this stream.
*
*
*/
void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch);
/**
* @brief Handles a client initialized Basic Attack Behavior cast to be deserialized and verified on the server.
*
* @param context The Skill's Behavior context. All behaviors in the same tree share the same context
*
* @param context The Skill's Behavior context. All behaviors in the same tree share the same context
* @param bitStream The bitStream to deserialize. BitStreams will always check their bounds before reading in a behavior
* and will fail gracefully if an overread is detected.
* @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down.
@@ -27,13 +27,13 @@ public:
/**
* @brief Writes a 16bit short to the bitStream and when the actual behavior calculation finishes with all of its branches, the number
* of bits used is then written to where the 16bit short initially was.
*
*
*/
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
/**
* @brief Calculates a server initialized Basic Attack Behavior cast to be serialized to the client
*
*
* @param context The Skill's Behavior context. All behaviors in the same tree share the same context
* @param bitStream The bitStream to serialize to.
* @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down.
@@ -44,12 +44,10 @@ public:
* @brief Loads this Behaviors parameters from the database. For this behavior specifically:
* max and min damage will always be the same. If min is less than max, they are both set to max.
* If an action is not in the database, then no action is taken for that result.
*
*
*/
void Load() override;
private:
bool m_DontApplyImmune;
uint32_t m_MinDamage;
uint32_t m_MaxDamage;

View File

@@ -73,8 +73,6 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_ImmuneToQuickbuildInterruptCount = 0;
m_ImmuneToPullToPointCount = 0;
m_DeathBehavior = -1;
m_DamageCooldownTimer = 0.0f;
}
DestroyableComponent::~DestroyableComponent() {
@@ -181,10 +179,6 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
}
}
void DestroyableComponent::Update(float deltaTime) {
m_DamageCooldownTimer -= deltaTime;
}
void DestroyableComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest");
if (!dest) {
@@ -415,7 +409,7 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore
}
bool DestroyableComponent::IsEnemy(const Entity* other) const {
if (m_Parent->IsPlayer() && other->IsPlayer()) {
if (m_Parent->IsPlayer() && other->IsPlayer()){
auto* thisCharacterComponent = m_Parent->GetComponent<CharacterComponent>();
if (!thisCharacterComponent) return false;
auto* otherCharacterComponent = other->GetComponent<CharacterComponent>();
@@ -470,10 +464,6 @@ bool DestroyableComponent::IsImmune() const {
return m_IsGMImmune || m_ImmuneToBasicAttackCount > 0;
}
bool DestroyableComponent::IsCooldownImmune() const {
return m_DamageCooldownTimer > 0.0f;
}
bool DestroyableComponent::IsKnockbackImmune() const {
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
auto* inventoryComponent = m_Parent->GetComponent<InventoryComponent>();
@@ -556,8 +546,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
return;
}
if (IsImmune() || IsCooldownImmune()) {
LOG_DEBUG("Target targetEntity %llu is immune!", m_Parent->GetObjectID()); //Immune is succesfully proc'd
if (IsImmune()) {
return;
}
@@ -645,9 +634,9 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
}
//check if hardcore mode is enabled
if (Game::entityManager->GetHardcoreMode()) {
if (Game::entityManager->GetHardcoreMode()) {
DoHardcoreModeDrops(source);
}
}
Smash(source, eKillType::VIOLENT, u"", skillID);
}
@@ -807,16 +796,16 @@ void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
}
void DestroyableComponent::SetStatusImmunity(
const eStateChangeType state,
const bool bImmuneToBasicAttack,
const bool bImmuneToDamageOverTime,
const bool bImmuneToKnockback,
const bool bImmuneToInterrupt,
const bool bImmuneToSpeed,
const bool bImmuneToImaginationGain,
const bool bImmuneToImaginationLoss,
const bool bImmuneToQuickbuildInterrupt,
const bool bImmuneToPullToPoint) {
const eStateChangeType state,
const bool bImmuneToBasicAttack,
const bool bImmuneToDamageOverTime,
const bool bImmuneToKnockback,
const bool bImmuneToInterrupt,
const bool bImmuneToSpeed,
const bool bImmuneToImaginationGain,
const bool bImmuneToImaginationLoss,
const bool bImmuneToQuickbuildInterrupt,
const bool bImmuneToPullToPoint) {
if (state == eStateChangeType::POP) {
if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1;
@@ -829,7 +818,7 @@ void DestroyableComponent::SetStatusImmunity(
if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1;
if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1;
} else if (state == eStateChangeType::PUSH) {
} else if (state == eStateChangeType::PUSH){
if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1;
if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1;
if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1;
@@ -956,7 +945,7 @@ void DestroyableComponent::AddOnHitCallback(const std::function<void(Entity*)>&
m_OnHitCallbacks.push_back(callback);
}
void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) {
void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){
//check if this is a player:
if (m_Parent->IsPlayer()) {
//remove hardcore_lose_uscore_on_death_percent from the player's uscore:
@@ -974,9 +963,9 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) {
if (inventory) {
//get the items inventory:
auto items = inventory->GetInventory(eInventoryType::ITEMS);
if (items) {
if (items){
auto itemMap = items->GetItems();
if (!itemMap.empty()) {
if (!itemMap.empty()){
for (const auto& item : itemMap) {
//drop the item:
if (!item.second) continue;

View File

@@ -24,7 +24,6 @@ public:
DestroyableComponent(Entity* parentEntity);
~DestroyableComponent() override;
void Update(float deltaTime) override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
void LoadFromXml(tinyxml2::XMLDocument* doc) override;
void UpdateXml(tinyxml2::XMLDocument* doc) override;
@@ -167,11 +166,6 @@ public:
*/
bool IsImmune() const;
/**
* @return whether this entity is currently immune to attacks due to a damage cooldown period
*/
bool IsCooldownImmune() const;
/**
* Sets if this entity has GM immunity, making it not killable
* @param value the GM immunity of this entity
@@ -412,23 +406,18 @@ public:
);
// Getters for status immunities
const bool GetImmuneToBasicAttack() { return m_ImmuneToBasicAttackCount > 0; };
const bool GetImmuneToDamageOverTime() { return m_ImmuneToDamageOverTimeCount > 0; };
const bool GetImmuneToKnockback() { return m_ImmuneToKnockbackCount > 0; };
const bool GetImmuneToInterrupt() { return m_ImmuneToInterruptCount > 0; };
const bool GetImmuneToSpeed() { return m_ImmuneToSpeedCount > 0; };
const bool GetImmuneToImaginationGain() { return m_ImmuneToImaginationGainCount > 0; };
const bool GetImmuneToImaginationLoss() { return m_ImmuneToImaginationLossCount > 0; };
const bool GetImmuneToQuickbuildInterrupt() { return m_ImmuneToQuickbuildInterruptCount > 0; };
const bool GetImmuneToPullToPoint() { return m_ImmuneToPullToPointCount > 0; };
const bool GetImmuneToBasicAttack() {return m_ImmuneToBasicAttackCount > 0;};
const bool GetImmuneToDamageOverTime() {return m_ImmuneToDamageOverTimeCount > 0;};
const bool GetImmuneToKnockback() {return m_ImmuneToKnockbackCount > 0;};
const bool GetImmuneToInterrupt() {return m_ImmuneToInterruptCount > 0;};
const bool GetImmuneToSpeed() {return m_ImmuneToSpeedCount > 0;};
const bool GetImmuneToImaginationGain() {return m_ImmuneToImaginationGainCount > 0;};
const bool GetImmuneToImaginationLoss() {return m_ImmuneToImaginationLossCount > 0;};
const bool GetImmuneToQuickbuildInterrupt() {return m_ImmuneToQuickbuildInterruptCount > 0;};
const bool GetImmuneToPullToPoint() {return m_ImmuneToPullToPointCount > 0;};
// Damage cooldown setters/getters
void SetDamageCooldownTimer(float value) { m_DamageCooldownTimer = value; }
float GetDamageCooldownTimer() { return m_DamageCooldownTimer; }
// Death behavior setters/getters
void SetDeathBehavior(int32_t value) { m_DeathBehavior = value; }
int32_t GetDeathBehavior() const { return m_DeathBehavior; }
void SetDeathBehavior(int32_t value) { m_DeathBehavior = value; }
/**
* Utility to reset all stats to the default stats based on items and completed missions
@@ -616,11 +605,6 @@ private:
* Death behavior type. If 0, the client plays a death animation as opposed to a smash animation.
*/
int32_t m_DeathBehavior;
/**
* Damage immunity cooldown timer. Set to a value that then counts down to create a damage cooldown for players
*/
float m_DamageCooldownTimer;
};
#endif // DESTROYABLECOMPONENT_H

View File

@@ -620,7 +620,3 @@ bool MissionComponent::HasCollectible(int32_t collectibleID) {
bool MissionComponent::HasMission(uint32_t missionId) {
return GetMission(missionId) != nullptr;
}
void FixExplorerMissions() {
}

View File

@@ -170,9 +170,6 @@ public:
*/
bool HasMission(uint32_t missionId);
void FixExplorerMissions();
private:
/**
* All the missions owned by this entity, mapped by mission ID

View File

@@ -29,7 +29,6 @@
#include "RenderComponent.h"
#include "eObjectBits.h"
#include "eGameMasterLevel.h"
#include "eMissionState.h"
std::unordered_map<LOT, PetComponent::PetPuzzleData> PetComponent::buildCache{};
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
@@ -440,15 +439,9 @@ void PetComponent::Update(float deltaTime) {
}
}
auto* missionComponent = owner->GetComponent<MissionComponent>();
if (!missionComponent) return;
// Determine if the "Lost Tags" mission has been completed and digging has been unlocked
const bool digUnlocked = missionComponent->GetMissionState(842) == eMissionState::COMPLETE;
Entity* closestTresure = PetDigServer::GetClosestTresure(position);
if (closestTresure != nullptr && digUnlocked) {
if (closestTresure != nullptr) {
// Skeleton Dragon Pat special case for bone digging
if (closestTresure->GetLOT() == 12192 && m_Parent->GetLOT() != 13067) {
goto skipTresure;

View File

@@ -2523,9 +2523,15 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent
inStream->Read(sd0Size);
std::shared_ptr<char[]> sd0Data(new char[sd0Size]);
if (sd0Data == nullptr) return;
if (sd0Data == nullptr) {
return;
}
inStream->ReadAlignedBytes(reinterpret_cast<unsigned char*>(sd0Data.get()), sd0Size);
for (uint32_t i = 0; i < sd0Size; ++i) {
uint8_t c;
inStream->Read(c);
sd0Data[i] = c;
}
uint32_t timeTaken;
inStream->Read(timeTaken);
@@ -2559,156 +2565,165 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent
//We runs this in async because the http library here is blocking, meaning it'll halt the thread.
//But we don't want the server to go unresponsive, because then the client would disconnect.
auto returnVal = std::async(std::launch::async, [&]() {
//We need to get a new ID for our model first:
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t newID) {
LWOOBJID newIDL = newID;
GeneralUtils::SetBit(newIDL, eObjectBits::CHARACTER);
GeneralUtils::SetBit(newIDL, eObjectBits::PERSISTENT);
//We need to get a new ID for our model first:
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t newID) {
LWOOBJID newIDL = newID;
GeneralUtils::SetBit(newIDL, eObjectBits::CHARACTER);
GeneralUtils::SetBit(newIDL, eObjectBits::PERSISTENT);
uint32_t blueprintIDSmall = ObjectIDManager::Instance()->GenerateRandomObjectID();
LWOOBJID blueprintID = blueprintIDSmall;
GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER);
GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT);
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t blueprintIDSmall) {
blueprintIDSmall = ObjectIDManager::Instance()->GenerateRandomObjectID();
LWOOBJID blueprintID = blueprintIDSmall;
GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER);
GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT);
//We need to get the propertyID: (stolen from Wincent's propertyManagementComp)
const auto& worldId = Game::zoneManager->GetZone()->GetZoneID();
//We need to get the propertyID: (stolen from Wincent's propertyManagementComp)
const auto& worldId = Game::zoneManager->GetZone()->GetZoneID();
const auto zoneId = worldId.GetMapID();
const auto cloneId = worldId.GetCloneID();
const auto zoneId = worldId.GetMapID();
const auto cloneId = worldId.GetCloneID();
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT id FROM PropertyTemplate WHERE mapID = ?;");
query.bind(1, (int)zoneId);
auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT id FROM PropertyTemplate WHERE mapID = ?;");
query.bind(1, (int)zoneId);
auto result = query.execQuery();
auto result = query.execQuery();
if (result.eof() || result.fieldIsNull(0)) return;
if (result.eof() || result.fieldIsNull(0)) return;
int templateId = result.getIntField(0);
int templateId = result.getIntField(0);
auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;");
result.finalize();
propertyLookup->setInt(1, templateId);
propertyLookup->setInt64(2, cloneId);
auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;");
auto* propertyEntry = propertyLookup->executeQuery();
uint64_t propertyId = 0;
propertyLookup->setInt(1, templateId);
propertyLookup->setInt64(2, cloneId);
if (propertyEntry->next()) {
propertyId = propertyEntry->getUInt64(1);
}
auto* propertyEntry = propertyLookup->executeQuery();
uint64_t propertyId = 0;
delete propertyEntry;
delete propertyLookup;
if (propertyEntry->next()) {
propertyId = propertyEntry->getUInt64(1);
}
//Insert into ugc:
auto ugcs = Database::CreatePreppedStmt("INSERT INTO `ugc`(`id`, `account_id`, `character_id`, `is_optimized`, `lxfml`, `bake_ao`, `filename`) VALUES (?,?,?,?,?,?,?)");
ugcs->setUInt(1, blueprintIDSmall);
ugcs->setInt(2, entity->GetParentUser()->GetAccountID());
ugcs->setInt(3, entity->GetCharacter()->GetID());
ugcs->setInt(4, 0);
delete propertyEntry;
delete propertyLookup;
//whacky stream biz
std::string s(sd0Data.get(), sd0Size);
std::istringstream iss(s);
//Insert into ugc:
auto ugcs = Database::CreatePreppedStmt("INSERT INTO `ugc`(`id`, `account_id`, `character_id`, `is_optimized`, `lxfml`, `bake_ao`, `filename`) VALUES (?,?,?,?,?,?,?)");
ugcs->setUInt(1, blueprintIDSmall);
ugcs->setInt(2, entity->GetParentUser()->GetAccountID());
ugcs->setInt(3, entity->GetCharacter()->GetID());
ugcs->setInt(4, 0);
ugcs->setBlob(5, &iss);
ugcs->setBoolean(6, false);
ugcs->setString(7, "weedeater.lxfml");
ugcs->execute();
delete ugcs;
//whacky stream biz
std::string s(sd0Data.get(), sd0Size);
std::istringstream iss(s);
std::istream& stream = iss;
//Insert into the db as a BBB model:
auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
stmt->setUInt64(1, newIDL);
stmt->setUInt64(2, propertyId);
stmt->setUInt(3, blueprintIDSmall);
stmt->setUInt(4, 14); // 14 is the lot the BBB models use
stmt->setDouble(5, 0.0f); // x
stmt->setDouble(6, 0.0f); // y
stmt->setDouble(7, 0.0f); // z
stmt->setDouble(8, 0.0f); // rx
stmt->setDouble(9, 0.0f); // ry
stmt->setDouble(10, 0.0f); // rz
stmt->setDouble(11, 0.0f); // rw
stmt->setString(12, "Objects_14_name"); // Model name. TODO make this customizable
stmt->setString(13, ""); // Model description. TODO implement this.
stmt->setDouble(14, 0); // behavior 1. TODO implement this.
stmt->setDouble(15, 0); // behavior 2. TODO implement this.
stmt->setDouble(16, 0); // behavior 3. TODO implement this.
stmt->setDouble(17, 0); // behavior 4. TODO implement this.
stmt->setDouble(18, 0); // behavior 5. TODO implement this.
stmt->execute();
delete stmt;
ugcs->setBlob(5, &iss);
ugcs->setBoolean(6, false);
ugcs->setString(7, "weedeater.lxfml");
ugcs->execute();
delete ugcs;
/*
Commented out until UGC server would be updated to use a sd0 file instead of lxfml stream.
(or you uncomment the lxfml decomp stuff above)
*/
//Insert into the db as a BBB model:
auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
stmt->setUInt64(1, newIDL);
stmt->setUInt64(2, propertyId);
stmt->setUInt(3, blueprintIDSmall);
stmt->setUInt(4, 14); // 14 is the lot the BBB models use
stmt->setDouble(5, 0.0f); // x
stmt->setDouble(6, 0.0f); // y
stmt->setDouble(7, 0.0f); // z
stmt->setDouble(8, 0.0f); // rx
stmt->setDouble(9, 0.0f); // ry
stmt->setDouble(10, 0.0f); // rz
stmt->setDouble(11, 0.0f); // rw
stmt->setString(12, "Objects_14_name"); // Model name. TODO make this customizable
stmt->setString(13, ""); // Model description. TODO implement this.
stmt->setDouble(14, 0); // behavior 1. TODO implement this.
stmt->setDouble(15, 0); // behavior 2. TODO implement this.
stmt->setDouble(16, 0); // behavior 3. TODO implement this.
stmt->setDouble(17, 0); // behavior 4. TODO implement this.
stmt->setDouble(18, 0); // behavior 5. TODO implement this.
stmt->execute();
delete stmt;
////Send off to UGC for processing, if enabled:
//if (Game::config->GetValue("ugc_remote") == "1") {
// std::string ugcIP = Game::config->GetValue("ugc_ip");
// int ugcPort = std::stoi(Game::config->GetValue("ugc_port"));
/*
Commented out until UGC server would be updated to use a sd0 file instead of lxfml stream.
(or you uncomment the lxfml decomp stuff above)
*/
// httplib::Client cli(ugcIP, ugcPort); //connect to UGC HTTP server using our config above ^
////Send off to UGC for processing, if enabled:
//if (Game::config->GetValue("ugc_remote") == "1") {
// std::string ugcIP = Game::config->GetValue("ugc_ip");
// int ugcPort = std::stoi(Game::config->GetValue("ugc_port"));
// //Send out a request:
// std::string request = "/3dservices/UGCC150/150" + std::to_string(blueprintID) + ".lxfml";
// cli.Put(request.c_str(), lxfml.c_str(), "text/lxfml");
// httplib::Client cli(ugcIP, ugcPort); //connect to UGC HTTP server using our config above ^
// //When the "put" above returns, it means that the UGC HTTP server is done processing our model &
// //the nif, hkx and checksum files are ready to be downloaded from cache.
//}
// //Send out a request:
// std::string request = "/3dservices/UGCC150/150" + std::to_string(blueprintID) + ".lxfml";
// cli.Put(request.c_str(), lxfml.c_str(), "text/lxfml");
//Tell the client their model is saved: (this causes us to actually pop out of our current state):
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE);
bitStream.Write(localId);
bitStream.Write(eBlueprintSaveResponseType::EverythingWorked);
bitStream.Write<uint32_t>(1);
bitStream.Write(blueprintID);
// //When the "put" above returns, it means that the UGC HTTP server is done processing our model &
// //the nif, hkx and checksum files are ready to be downloaded from cache.
//}
bitStream.Write<uint32_t>(sd0Size);
//Tell the client their model is saved: (this causes us to actually pop out of our current state):
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE);
bitStream.Write(localId);
bitStream.Write(eBlueprintSaveResponseType::EverythingWorked);
bitStream.Write<uint32_t>(1);
bitStream.Write(blueprintID);
bitStream.WriteAlignedBytes(reinterpret_cast<unsigned char*>(sd0Data.get()), sd0Size);
bitStream.Write<uint32_t>(sd0Size);
SEND_PACKET;
for (size_t i = 0; i < sd0Size; ++i) {
bitStream.Write(sd0Data[i]);
}
//Now we have to construct this object:
SEND_PACKET;
EntityInfo info;
info.lot = 14;
info.pos = {};
info.rot = {};
info.spawner = nullptr;
info.spawnerID = entity->GetObjectID();
info.spawnerNodeID = 0;
//Now we have to construct this object:
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", blueprintID);
LDFBaseData* componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
LDFBaseData* modelType = new LDFData<int>(u"modelType", 2);
LDFBaseData* propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", newIDL);
EntityInfo info;
info.lot = 14;
info.pos = {};
info.rot = {};
info.spawner = nullptr;
info.spawnerID = entity->GetObjectID();
info.spawnerNodeID = 0;
info.settings.push_back(ldfBlueprintID);
info.settings.push_back(componentWhitelist);
info.settings.push_back(modelType);
info.settings.push_back(propertyObjectID);
info.settings.push_back(userModelID);
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", blueprintID);
LDFBaseData* componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
LDFBaseData* modelType = new LDFData<int>(u"modelType", 2);
LDFBaseData* propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", newIDL);
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
if (newEntity) {
Game::entityManager->ConstructEntity(newEntity);
info.settings.push_back(ldfBlueprintID);
info.settings.push_back(componentWhitelist);
info.settings.push_back(modelType);
info.settings.push_back(propertyObjectID);
info.settings.push_back(userModelID);
//Make sure the propMgmt doesn't delete our model after the server dies
//Trying to do this after the entity is constructed. Shouldn't really change anything but
//there was an issue with builds not appearing since it was placed above ConstructEntity.
PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), newIDL);
}
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
if (newEntity) {
Game::entityManager->ConstructEntity(newEntity);
});
//Make sure the propMgmt doesn't delete our model after the server dies
//Trying to do this after the entity is constructed. Shouldn't really change anything but
//there was an issue with builds not appearing since it was placed above ConstructEntity.
PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), newIDL);
}
});
});
});
}
void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
@@ -5610,18 +5625,10 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity*
std::vector<LDFBaseData*> config;
config.push_back(moduleAssembly);
LWOOBJID newIdBig;
// Make sure a subkey isnt already in use. Persistent Ids do not make sense here since this only needs to be unique for
// this character. Because of that, we just generate a random id and check for a collision.
do {
newIdBig = ObjectIDManager::Instance()->GenerateRandomObjectID();
GeneralUtils::SetBit(newIdBig, eObjectBits::CHARACTER);
} while (inv->FindItemBySubKey(newIdBig));
if (count == 3) {
inv->AddItem(6416, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config, LWOOBJID_EMPTY, true, false, newIdBig);
inv->AddItem(6416, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config);
} else if (count == 7) {
inv->AddItem(8092, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config, LWOOBJID_EMPTY, true, false, newIdBig);
inv->AddItem(8092, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config);
}
auto* missionComponent = character->GetComponent<MissionComponent>();

View File

@@ -29,7 +29,7 @@ void ReportCheat(User* user, const SystemAddress& sysAddr, const char* messageIf
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
"INSERT INTO player_cheat_detections (account_id, name, violation_msg, violation_system_address) VALUES (?, ?, ?, ?)")
);
user ? stmt->setInt(1, user->GetAccountID()) : stmt->setNull(1, sql::DataType::INTEGER);
stmt->setInt(1, user ? user->GetAccountID() : 0);
stmt->setString(2, user ? user->GetUsername().c_str() : "User is null.");
constexpr int32_t bufSize = 4096;

View File

@@ -247,7 +247,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
}
if (chatCommand == "credits" || chatCommand == "info") {
const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()) : VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string());
const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()) : VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string());
{
AMFArrayValue args;
@@ -1490,24 +1490,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
//Testing basic attack immunity
if (chatCommand == "attackimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
int32_t state = false;
if (!GeneralUtils::TryParse(args[0], state)) {
ChatPackets::SendSystemMessage(sysAddr, u"Invalid state.");
return;
}
if (destroyableComponent != nullptr) {
destroyableComponent->SetIsImmune(state);
}
return;
}
if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
auto* buffComponent = entity->GetComponent<BuffComponent>();
@@ -1861,7 +1843,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "castskill" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
auto* skillComponent = entity->GetComponent<SkillComponent>();
if (skillComponent) {
if (skillComponent){
uint32_t skillId;
if (!GeneralUtils::TryParse(args[0], skillId)) {
@@ -1878,7 +1860,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
uint32_t skillId;
int slot;
auto* inventoryComponent = entity->GetComponent<InventoryComponent>();
if (inventoryComponent) {
if (inventoryComponent){
if (!GeneralUtils::TryParse(args[0], slot)) {
ChatPackets::SendSystemMessage(sysAddr, u"Error getting slot.");
return;
@@ -1887,7 +1869,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill.");
return;
} else {
if (inventoryComponent->SetSkill(slot, skillId)) ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot successfully");
if(inventoryComponent->SetSkill(slot, skillId)) ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot successfully");
else ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot failed");
}
}
@@ -1896,7 +1878,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "setfaction" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent) {
if (destroyableComponent){
int32_t faction;
if (!GeneralUtils::TryParse(args[0], faction)) {
@@ -1911,7 +1893,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "addfaction" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent) {
if (destroyableComponent){
int32_t faction;
if (!GeneralUtils::TryParse(args[0], faction)) {
@@ -1926,7 +1908,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
if (chatCommand == "getfactions" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent) {
if (destroyableComponent){
ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:");
for (const auto entry : destroyableComponent->GetFactionIDs()) {
ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry)));

View File

@@ -154,7 +154,7 @@ int main(int argc, char** argv) {
Game::assetManager = new AssetManager(clientPath);
} catch (std::runtime_error& ex) {
LOG("Got an error while setting up assets: %s", ex.what());
LOG("Is the provided client_location in Windows Onedrive? If so, remove it from Onedrive.");
return EXIT_FAILURE;
}

View File

@@ -1,7 +1,6 @@
#include "NtCombatChallengeExplodingDummy.h"
#include "EntityManager.h"
#include "SkillComponent.h"
#include "DestroyableComponent.h"
void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) {
const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID");
@@ -16,17 +15,6 @@ void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) {
}
void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {
auto* destroyableComponent = self->GetComponent<DestroyableComponent>();
auto numTimesHit = self->GetVar<int32_t>(u"numTimesHit");
if (destroyableComponent && numTimesHit == 0) {
self->SetVar<int32_t>(u"numTimesHit", 1);
destroyableComponent->SetHealth(destroyableComponent->GetHealth() / 2);
return;
} else if (numTimesHit == 2) {
return;
}
self->SetVar<int32_t>(u"numTimesHit", 2);
const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID");
auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID);
@@ -40,6 +28,5 @@ void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* at
if (skillComponent != nullptr) {
skillComponent->CalculateBehavior(1338, 30875, attacker->GetObjectID());
}
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16.0f);
self->Smash(attacker->GetObjectID());
self->Kill(attacker);
}

View File

@@ -74,7 +74,6 @@
#include "ZCompression.h"
#include "EntityManager.h"
#include "CheatDetection.h"
#include "MissionComponent.h"
namespace Game {
Logger* logger = nullptr;
@@ -926,7 +925,7 @@ void HandlePacket(Packet* packet) {
//We need to delete the entity first, otherwise the char list could delete it while it exists in the world!
if (Game::server->GetZoneID() != 0) {
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
if (!user || !user->GetLastUsedChar()) return;
if (!user) return;
Game::entityManager->DestroyEntity(user->GetLastUsedChar()->GetEntity());
}
@@ -1058,9 +1057,6 @@ void HandlePacket(Packet* packet) {
auto* levelComponent = player->GetComponent<LevelProgressionComponent>();
if (!levelComponent) return;
auto* missionComponent = player->GetComponent<MissionComponent>();
if (!missionComponent) return;
auto version = levelComponent->GetCharacterVersion();
switch(version) {
case eCharacterVersion::RELEASE:
@@ -1074,14 +1070,9 @@ void HandlePacket(Packet* packet) {
player->RetroactiveVaultSize();
levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE);
case eCharacterVersion::VAULT_SIZE:
LOG("Updating Speedbase");
LOG("Updaing Speedbase");
levelComponent->SetRetroactiveBaseSpeed();
levelComponent->SetCharacterVersion(eCharacterVersion::SPEED_BASE);
case eCharacterVersion::SPEED_BASE:
LOG("Fixing Explorer missions");
missionComponent->FixExplorerMissions();
// Commented out so it runs every time for testing
// levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE);
levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE);
case eCharacterVersion::UP_TO_DATE:
break;
}

View File

@@ -25,7 +25,6 @@
|ban|`/ban <username>`|Bans a user from the server.|4|
|approveproperty|`/approveproperty`|Approves the property the player is currently visiting.|5|
|mute|`/mute <username> (days) (hours)`|Mute player for the given amount of time. If no time is given, the mute is indefinite.|6|
|attackimmune|`/attackimmune <value>`|Sets the character's immunity to basic attacks state, where value can be one of "1", to make yourself immune to basic attack damage, or "0" to undo.|8|
|gmimmune|`/gmimmunve <value>`|Sets the character's GMImmune state, where value can be one of "1", to make yourself immune to damage, or "0" to undo.|8|
|gminvis|`/gminvis`|Toggles invisibility for the character, though it's currently a bit buggy. Requires nonzero GM Level for the character, but the account must have a GM level of 8.|8|
|setname|`/setname <name>`|Sets a temporary name for your player. The name resets when you log out.|8|

Binary file not shown.

View File

@@ -1,19 +0,0 @@
[Unit]
# Description of the service.
Description=Darkflame LEGO Universe Server
# Wait for network to start first before starting this service.
After=network.target
[Service]
Type=simple
# Services should have their own, dedicated, user account.
# The specific user that our service will run as, you can find your current user by issuing `id -un`
User=darkflame
# The specific group that our service will run as, you can find your current primary group by issuing `id -gn`
Group=darkflame
# Full Path to the darkflame server process
ExecStart=/PATH/TO/DarkflameServer/build/MasterServer
[Install]
# Define the behavior if the service is enabled or disabled to automatically started at boot.
WantedBy=multi-user.target

View File

@@ -536,22 +536,3 @@ TEST_F(DestroyableTest, DestroyableComponentImmunityTest) {
}
/**
* Test the Damage cooldown timer of DestroyableComponent
*/
TEST_F(DestroyableTest, DestroyableComponentDamageCooldownTest) {
// Test the damage immune timer state (anything above 0.0f)
destroyableComponent->SetDamageCooldownTimer(1.0f);
EXPECT_FLOAT_EQ(destroyableComponent->GetDamageCooldownTimer(), 1.0f);
ASSERT_TRUE(destroyableComponent->IsCooldownImmune());
// Test that the Update() function correctly decrements the damage cooldown timer
destroyableComponent->Update(0.5f);
EXPECT_FLOAT_EQ(destroyableComponent->GetDamageCooldownTimer(), 0.5f);
ASSERT_TRUE(destroyableComponent->IsCooldownImmune());
// Test the non damage immune timer state (anything below or equal to 0.0f)
destroyableComponent->SetDamageCooldownTimer(0.0f);
EXPECT_FLOAT_EQ(destroyableComponent->GetDamageCooldownTimer(), 0.0f);
ASSERT_FALSE(destroyableComponent->IsCooldownImmune());
}