From 8bdd5b6e2c127322f9a8bba18b58cacb72506229 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:58:38 -0700 Subject: [PATCH 1/4] Address quickbuilds being unbuildable Address an issue where quickbuilds would become unbuildable. The main issue lied within serializing parent/child info too often for some reason / serializing it when the info wasnt dirty. Only serializing this info when it is actually dirty and has changed has addressed the issue and allows quickbuilds to never break. --- dGame/Entity.cpp | 7 +++++-- dGame/Entity.h | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 132a0eb7..960439bf 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -79,6 +79,7 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity) m_Components = {}; m_DieCallbacks = {}; m_PhantomCollisionCallbacks = {}; + m_IsParentChildDirty = true; m_Settings = info.settings; m_NetworkSettings = info.networkSettings; @@ -974,8 +975,9 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke } else outBitStream->Write0(); //No GM Level } - outBitStream->Write((m_ParentEntity != nullptr || m_ChildEntities.size() > 0)); - if (m_ParentEntity || m_ChildEntities.size() > 0) { + outBitStream->Write((m_ParentEntity != nullptr || m_ChildEntities.size() > 0) && (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION)); + if ((m_ParentEntity != nullptr || m_ChildEntities.size() > 0) && (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION)) { + m_IsParentChildDirty = false; outBitStream->Write(m_ParentEntity != nullptr); if (m_ParentEntity) { outBitStream->Write(m_ParentEntity->GetObjectID()); @@ -1661,6 +1663,7 @@ void Entity::RegisterCoinDrop(uint64_t count) { } void Entity::AddChild(Entity* child) { + m_IsParentChildDirty = true; m_ChildEntities.push_back(child); } diff --git a/dGame/Entity.h b/dGame/Entity.h index cef7b97f..f2bc4237 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -322,6 +322,8 @@ protected: int8_t m_Observers = 0; + bool m_IsParentChildDirty = true; + /* * Collision */ From 7dfcd22a2eec9bf91998146b827faa765d5ca629 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:59:30 -0700 Subject: [PATCH 2/4] Properly place build activator The build activator as a result of the previous changes was spawning at the wrong position. This commit pulls the activators position from the settings (should they exist) and sets them accordingly. --- dGame/dComponents/RebuildComponent.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index abee5e16..538fdeed 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -22,6 +22,16 @@ RebuildComponent::RebuildComponent(Entity* entity) : Component(entity) { { m_Precondition = new PreconditionExpression(GeneralUtils::UTF16ToWTF8(checkPreconditions)); } + + auto positionAsVector = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rebuild_activators"), 31); + if (positionAsVector.size() == 3) { + m_ActivatorPosition.x = std::stof(positionAsVector[0]); + m_ActivatorPosition.y = std::stof(positionAsVector[1]); + m_ActivatorPosition.z = std::stof(positionAsVector[2]); + } else { + m_ActivatorPosition = m_Parent->GetPosition(); + } + SpawnActivator(); } RebuildComponent::~RebuildComponent() { From 09c459a083640ed42262837fd490fbd87803806b Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 15 Jun 2022 23:04:03 -0700 Subject: [PATCH 3/4] Added comment --- dGame/Entity.cpp | 2 ++ dGame/dComponents/RebuildComponent.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 960439bf..79512737 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -975,6 +975,8 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke } else outBitStream->Write0(); //No GM Level } + + // Only serialize parent / child info should the info be dirty (changed) or if this is the construction of the entity. outBitStream->Write((m_ParentEntity != nullptr || m_ChildEntities.size() > 0) && (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION)); if ((m_ParentEntity != nullptr || m_ChildEntities.size() > 0) && (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION)) { m_IsParentChildDirty = false; diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index 538fdeed..25b7eb1b 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -23,6 +23,8 @@ RebuildComponent::RebuildComponent(Entity* entity) : Component(entity) { m_Precondition = new PreconditionExpression(GeneralUtils::UTF16ToWTF8(checkPreconditions)); } + // Should a setting that has the build activator position exist, fetch that setting here and parse it for position. + // It is assumed that the user who sets this setting uses the correct character delimiter (character 31) auto positionAsVector = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rebuild_activators"), 31); if (positionAsVector.size() == 3) { m_ActivatorPosition.x = std::stof(positionAsVector[0]); From 4a39221dd0446c8507eb873b8fff7784797a4b46 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Thu, 16 Jun 2022 08:38:38 -0700 Subject: [PATCH 4/4] Address reviews Changed the activator position parsing to have TryParse so that we dont throw an exception trying to load the position. Should the loading of the activator position fail the game will default to the position of the entity. change delimiter value to hex Updated the character delimiter used for rebuild_activator settings to use hex Remove extra parsing of activator position in Entity.cpp we were parsing the activator position but when doing so where we were, this was after we had ended up spawning the activator since that is now in the constructor of the rebuild component. The extra parsing has been removed. Simplify dirty parent/child info Simplify the if condition for parent child info. This info only needs to be written should it be changed (dirty) or if the packet being sent is a construction, meaning that a requesting player needs all base data and needs to know what parents/children an entity has at that time. get rid of extra parenthesis Left over extra parenthesis were around these conditions on accident --- dGame/Entity.cpp | 17 ++--------------- dGame/dComponents/RebuildComponent.cpp | 14 ++++++++------ 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 79512737..16b2f0af 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -562,19 +562,6 @@ void Entity::Initialize() comp->SetPostImaginationCost(rebCompData[0].post_imagination_cost); comp->SetTimeBeforeSmash(rebCompData[0].time_before_smash); - const auto rebuildActivatorValue = GetVarAsString(u"rebuild_activators"); - - if (!rebuildActivatorValue.empty()) { - std::vector split = GeneralUtils::SplitString(rebuildActivatorValue, 0x1f); - NiPoint3 pos; - - pos.x = std::stof(split[0]); - pos.y = std::stof(split[1]); - pos.z = std::stof(split[2]); - - comp->SetActivatorPosition(pos); - } - const auto rebuildResetTime = GetVar(u"rebuild_reset_time"); if (rebuildResetTime != 0.0f) { @@ -977,8 +964,8 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke } // Only serialize parent / child info should the info be dirty (changed) or if this is the construction of the entity. - outBitStream->Write((m_ParentEntity != nullptr || m_ChildEntities.size() > 0) && (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION)); - if ((m_ParentEntity != nullptr || m_ChildEntities.size() > 0) && (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION)) { + outBitStream->Write(m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION); + if (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION) { m_IsParentChildDirty = false; outBitStream->Write(m_ParentEntity != nullptr); if (m_ParentEntity) { diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index 25b7eb1b..5e313a7a 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -24,15 +24,17 @@ RebuildComponent::RebuildComponent(Entity* entity) : Component(entity) { } // Should a setting that has the build activator position exist, fetch that setting here and parse it for position. - // It is assumed that the user who sets this setting uses the correct character delimiter (character 31) - auto positionAsVector = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rebuild_activators"), 31); - if (positionAsVector.size() == 3) { - m_ActivatorPosition.x = std::stof(positionAsVector[0]); - m_ActivatorPosition.y = std::stof(positionAsVector[1]); - m_ActivatorPosition.z = std::stof(positionAsVector[2]); + // It is assumed that the user who sets this setting uses the correct character delimiter (character 31 or in hex 0x1F) + auto positionAsVector = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rebuild_activators"), 0x1F); + if (positionAsVector.size() == 3 && + GeneralUtils::TryParse(positionAsVector[0], m_ActivatorPosition.x) && + GeneralUtils::TryParse(positionAsVector[1], m_ActivatorPosition.y) && + GeneralUtils::TryParse(positionAsVector[2], m_ActivatorPosition.z)) { } else { + Game::logger->Log("RebuildComponent", "Failed to find activator position for lot %i. Defaulting to parents position.\n", m_Parent->GetLOT()); m_ActivatorPosition = m_Parent->GetPosition(); } + SpawnActivator(); }