From 28ce8ac54d00a36dfd53e086792b62e8a4f46d92 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 8 Apr 2024 13:13:49 -0700 Subject: [PATCH] remove usage of xmldoc as a ptr (#1538) resolves a memory leak in BrickDatabase, adds stability to character save doc. Tested that saving manually via force-save, logout and /crash all saved my position and my removed banana as expected. The doc was always deleted on character destruction and on any updates, so this is just a semantic change (and now we no longer have new'd tinyxml2::documents on the heap) --- dGame/Character.cpp | 52 +++++++------------ dGame/Character.h | 4 +- dGame/Entity.cpp | 5 +- dGame/Entity.h | 2 +- dGame/dComponents/BuffComponent.cpp | 12 ++--- dGame/dComponents/BuffComponent.h | 4 +- dGame/dComponents/CharacterComponent.cpp | 14 ++--- dGame/dComponents/CharacterComponent.h | 4 +- dGame/dComponents/Component.cpp | 4 +- dGame/dComponents/Component.h | 4 +- .../ControllablePhysicsComponent.cpp | 8 +-- .../ControllablePhysicsComponent.h | 4 +- dGame/dComponents/DestroyableComponent.cpp | 8 +-- dGame/dComponents/DestroyableComponent.h | 4 +- dGame/dComponents/InventoryComponent.cpp | 35 +++++++------ dGame/dComponents/InventoryComponent.h | 10 ++-- .../dComponents/LevelProgressionComponent.cpp | 8 +-- dGame/dComponents/LevelProgressionComponent.h | 4 +- dGame/dComponents/MissionComponent.cpp | 28 +++++----- dGame/dComponents/MissionComponent.h | 4 +- dGame/dMission/Mission.cpp | 38 +++++++------- dGame/dMission/Mission.h | 4 +- dGame/dUtilities/BrickDatabase.cpp | 9 ++-- 23 files changed, 125 insertions(+), 144 deletions(-) diff --git a/dGame/Character.cpp b/dGame/Character.cpp index eab7583f..59a67462 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -27,12 +27,9 @@ Character::Character(uint32_t id, User* parentUser) { m_ID = id; m_ParentUser = parentUser; m_OurEntity = nullptr; - m_Doc = nullptr; } Character::~Character() { - if (m_Doc) delete m_Doc; - m_Doc = nullptr; m_OurEntity = nullptr; m_ParentUser = nullptr; } @@ -55,8 +52,6 @@ void Character::UpdateInfoFromDatabase() { m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused. m_ZoneCloneID = 0; - m_Doc = nullptr; - //Quickly and dirtly parse the xmlData to get the info we need: DoQuickXMLDataParse(); @@ -70,18 +65,13 @@ void Character::UpdateInfoFromDatabase() { } void Character::UpdateFromDatabase() { - if (m_Doc) delete m_Doc; UpdateInfoFromDatabase(); } void Character::DoQuickXMLDataParse() { if (m_XMLData.size() == 0) return; - delete m_Doc; - m_Doc = new tinyxml2::XMLDocument(); - if (!m_Doc) return; - - if (m_Doc->Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) { + if (m_Doc.Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) { LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID); } else { LOG("Failed to load xmlData!"); @@ -89,7 +79,7 @@ void Character::DoQuickXMLDataParse() { return; } - tinyxml2::XMLElement* mf = m_Doc->FirstChildElement("obj")->FirstChildElement("mf"); + tinyxml2::XMLElement* mf = m_Doc.FirstChildElement("obj")->FirstChildElement("mf"); if (!mf) { LOG("Failed to find mf tag!"); return; @@ -108,7 +98,7 @@ void Character::DoQuickXMLDataParse() { mf->QueryAttribute("ess", &m_Eyes); mf->QueryAttribute("ms", &m_Mouth); - tinyxml2::XMLElement* inv = m_Doc->FirstChildElement("obj")->FirstChildElement("inv"); + tinyxml2::XMLElement* inv = m_Doc.FirstChildElement("obj")->FirstChildElement("inv"); if (!inv) { LOG("Char has no inv!"); return; @@ -141,7 +131,7 @@ void Character::DoQuickXMLDataParse() { } - tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); + tinyxml2::XMLElement* character = m_Doc.FirstChildElement("obj")->FirstChildElement("char"); if (character) { character->QueryAttribute("cc", &m_Coins); int32_t gm_level = 0; @@ -205,7 +195,7 @@ void Character::DoQuickXMLDataParse() { character->QueryAttribute("lzrw", &m_OriginalRotation.w); } - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag"); if (flags) { auto* currentChild = flags->FirstChildElement(); while (currentChild) { @@ -239,12 +229,10 @@ void Character::SetBuildMode(bool buildMode) { } void Character::SaveXMLToDatabase() { - if (!m_Doc) return; - //For metrics, we'll record the time it took to save: auto start = std::chrono::system_clock::now(); - tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); + tinyxml2::XMLElement* character = m_Doc.FirstChildElement("obj")->FirstChildElement("char"); if (character) { character->SetAttribute("gm", static_cast(m_GMLevel)); character->SetAttribute("cc", m_Coins); @@ -266,11 +254,11 @@ void Character::SaveXMLToDatabase() { } auto emotes = character->FirstChildElement("ue"); - if (!emotes) emotes = m_Doc->NewElement("ue"); + if (!emotes) emotes = m_Doc.NewElement("ue"); emotes->DeleteChildren(); for (int emoteID : m_UnlockedEmotes) { - auto emote = m_Doc->NewElement("e"); + auto emote = m_Doc.NewElement("e"); emote->SetAttribute("id", emoteID); emotes->LinkEndChild(emote); @@ -280,15 +268,15 @@ void Character::SaveXMLToDatabase() { } //Export our flags: - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag"); if (!flags) { - flags = m_Doc->NewElement("flag"); //Create a flags tag if we don't have one - m_Doc->FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time + flags = m_Doc.NewElement("flag"); //Create a flags tag if we don't have one + m_Doc.FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time } flags->DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes for (std::pair flag : m_PlayerFlags) { - auto* f = m_Doc->NewElement("f"); + auto* f = m_Doc.NewElement("f"); f->SetAttribute("id", flag.first); //Because of the joy that is tinyxml2, it doesn't offer a function to set a uint64 as an attribute. @@ -301,7 +289,7 @@ void Character::SaveXMLToDatabase() { // Prevents the news feed from showing up on world transfers if (GetPlayerFlag(ePlayerFlag::IS_NEWS_SCREEN_VISIBLE)) { - auto* s = m_Doc->NewElement("s"); + auto* s = m_Doc.NewElement("s"); s->SetAttribute("si", ePlayerFlag::IS_NEWS_SCREEN_VISIBLE); flags->LinkEndChild(s); } @@ -326,7 +314,7 @@ void Character::SaveXMLToDatabase() { void Character::SetIsNewLogin() { // If we dont have a flag element, then we cannot have a s element as a child of flag. - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag"); if (!flags) return; auto* currentChild = flags->FirstChildElement(); @@ -344,7 +332,7 @@ void Character::SetIsNewLogin() { void Character::WriteToDatabase() { //Dump our xml into m_XMLData: tinyxml2::XMLPrinter printer(0, true, 0); - m_Doc->Print(&printer); + m_Doc.Print(&printer); //Finally, save to db: Database::Get()->UpdateCharacterXml(m_ID, printer.CStr()); @@ -421,15 +409,15 @@ void Character::SetRetroactiveFlags() { void Character::SaveXmlRespawnCheckpoints() { //Export our respawn points: - auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); + auto* points = m_Doc.FirstChildElement("obj")->FirstChildElement("res"); if (!points) { - points = m_Doc->NewElement("res"); - m_Doc->FirstChildElement("obj")->LinkEndChild(points); + points = m_Doc.NewElement("res"); + m_Doc.FirstChildElement("obj")->LinkEndChild(points); } points->DeleteChildren(); for (const auto& point : m_WorldRespawnCheckpoints) { - auto* r = m_Doc->NewElement("r"); + auto* r = m_Doc.NewElement("r"); r->SetAttribute("w", point.first); r->SetAttribute("x", point.second.x); @@ -443,7 +431,7 @@ void Character::SaveXmlRespawnCheckpoints() { void Character::LoadXmlRespawnCheckpoints() { m_WorldRespawnCheckpoints.clear(); - auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); + auto* points = m_Doc.FirstChildElement("obj")->FirstChildElement("res"); if (!points) { return; } diff --git a/dGame/Character.h b/dGame/Character.h index b994fb61..77f286f0 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -37,7 +37,7 @@ public: void LoadXmlRespawnCheckpoints(); const std::string& GetXMLData() const { return m_XMLData; } - tinyxml2::XMLDocument* GetXMLDoc() const { return m_Doc; } + const tinyxml2::XMLDocument& GetXMLDoc() const { return m_Doc; } /** * Out of abundance of safety and clarity of what this saves, this is its own function. @@ -623,7 +623,7 @@ private: /** * The character XML belonging to this character */ - tinyxml2::XMLDocument* m_Doc; + tinyxml2::XMLDocument m_Doc; /** * Title of an announcement this character made (reserved for GMs) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 97e86758..00ad8471 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -476,8 +476,7 @@ void Entity::Initialize() { } if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) { - auto* xmlDoc = m_Character ? m_Character->GetXMLDoc() : nullptr; - AddComponent(xmlDoc); + AddComponent(); } // if this component exists, then we initialize it. it's value is always 0 if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) { @@ -1244,7 +1243,7 @@ void Entity::WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType outBitStream.Write0(); } -void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) { +void Entity::UpdateXMLDoc(tinyxml2::XMLDocument& doc) { //This function should only ever be called from within Character, meaning doc should always exist when this is called. //Naturally, we don't include any non-player components in this update function. diff --git a/dGame/Entity.h b/dGame/Entity.h index 740d7c92..ffdcb713 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -174,7 +174,7 @@ public: void WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType); void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType); - void UpdateXMLDoc(tinyxml2::XMLDocument* doc); + void UpdateXMLDoc(tinyxml2::XMLDocument& doc); void Update(float deltaTime); // Events diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index 8b76e423..44c88ccb 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -326,9 +326,9 @@ Entity* BuffComponent::GetParent() const { return m_Parent; } -void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { +void BuffComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { // Load buffs - auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); + auto* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); // Make sure we have a clean buff element. auto* buffElement = dest->FirstChildElement("buff"); @@ -386,15 +386,15 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { } } -void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) { +void BuffComponent::UpdateXml(tinyxml2::XMLDocument& doc) { // Save buffs - auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); + auto* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); // Make sure we have a clean buff element. auto* buffElement = dest->FirstChildElement("buff"); if (buffElement == nullptr) { - buffElement = doc->NewElement("buff"); + buffElement = doc.NewElement("buff"); dest->LinkEndChild(buffElement); } else { @@ -402,7 +402,7 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) { } for (const auto& [id, buff] : m_Buffs) { - auto* buffEntry = doc->NewElement("b"); + auto* buffEntry = doc.NewElement("b"); // TODO: change this if to if (buff.cancelOnZone || buff.cancelOnLogout) handling at some point. No current way to differentiate between zone transfer and logout. if (buff.cancelOnZone) continue; diff --git a/dGame/dComponents/BuffComponent.h b/dGame/dComponents/BuffComponent.h index df3c6a78..507e53a0 100644 --- a/dGame/dComponents/BuffComponent.h +++ b/dGame/dComponents/BuffComponent.h @@ -57,9 +57,9 @@ public: Entity* GetParent() const; - void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 3eafd924..d706af9c 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -186,9 +186,9 @@ void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) { m_GMLevel = gmlevel; } -void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { +void CharacterComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); + auto* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag while loading XML!"); return; @@ -299,8 +299,8 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { } } -void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* minifig = doc->FirstChildElement("obj")->FirstChildElement("mf"); +void CharacterComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* minifig = doc.FirstChildElement("obj")->FirstChildElement("mf"); if (!minifig) { LOG("Failed to find mf tag while updating XML!"); return; @@ -320,7 +320,7 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { // done with minifig - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); + tinyxml2::XMLElement* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag while updating XML!"); return; @@ -338,11 +338,11 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { // Set the zone statistics of the form ... auto zoneStatistics = character->FirstChildElement("zs"); - if (!zoneStatistics) zoneStatistics = doc->NewElement("zs"); + if (!zoneStatistics) zoneStatistics = doc.NewElement("zs"); zoneStatistics->DeleteChildren(); for (auto pair : m_ZoneStatistics) { - auto zoneStatistic = doc->NewElement("s"); + auto zoneStatistic = doc.NewElement("s"); zoneStatistic->SetAttribute("map", pair.first); zoneStatistic->SetAttribute("ac", pair.second.m_AchievementsCollected); diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index aa5c2e29..7e63b0bd 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -70,8 +70,8 @@ public: CharacterComponent(Entity* parent, Character* character, const SystemAddress& systemAddress); ~CharacterComponent() override; - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; diff --git a/dGame/dComponents/Component.cpp b/dGame/dComponents/Component.cpp index 705c44a7..8f38fb61 100644 --- a/dGame/dComponents/Component.cpp +++ b/dGame/dComponents/Component.cpp @@ -21,11 +21,11 @@ void Component::OnUse(Entity* originator) { } -void Component::UpdateXml(tinyxml2::XMLDocument* doc) { +void Component::UpdateXml(tinyxml2::XMLDocument& doc) { } -void Component::LoadFromXml(tinyxml2::XMLDocument* doc) { +void Component::LoadFromXml(const tinyxml2::XMLDocument& doc) { } diff --git a/dGame/dComponents/Component.h b/dGame/dComponents/Component.h index 062924f7..160565fb 100644 --- a/dGame/dComponents/Component.h +++ b/dGame/dComponents/Component.h @@ -34,13 +34,13 @@ public: * Save data from this componennt to character XML * @param doc the document to write data to */ - virtual void UpdateXml(tinyxml2::XMLDocument* doc); + virtual void UpdateXml(tinyxml2::XMLDocument& doc); /** * Load base data for this component from character XML * @param doc the document to read data from */ - virtual void LoadFromXml(tinyxml2::XMLDocument* doc); + virtual void LoadFromXml(const tinyxml2::XMLDocument& doc); virtual void Serialize(RakNet::BitStream& outBitStream, bool isConstruction); diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index dccbe915..18e4b19d 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -158,8 +158,8 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo } } -void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); +void ControllablePhysicsComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag!"); return; @@ -178,8 +178,8 @@ void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { m_DirtyPosition = true; } -void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); +void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag while updating XML!"); return; diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index 8834128a..6309b8fc 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -28,8 +28,8 @@ public: 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; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Sets the position of this entity, also ensures this update is serialized next tick. diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 1b9b3285..476235f9 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -185,8 +185,8 @@ void DestroyableComponent::Update(float deltaTime) { m_DamageCooldownTimer -= deltaTime; } -void DestroyableComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); +void DestroyableComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); if (!dest) { LOG("Failed to find dest tag!"); return; @@ -207,8 +207,8 @@ void DestroyableComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { m_DirtyHealth = true; } -void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); +void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); if (!dest) { LOG("Failed to find dest tag!"); return; diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index 85a4f941..56f30103 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -26,8 +26,8 @@ public: 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; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Initializes the component using a different LOT diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 161d7b91..8af7fb34 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -38,7 +38,7 @@ #include "CDObjectSkillsTable.h" #include "CDSkillBehaviorTable.h" -InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { +InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; this->m_Pushed = {}; @@ -48,7 +48,8 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do const auto lot = parent->GetLOT(); if (lot == 1) { - LoadXml(document); + auto* character = m_Parent->GetCharacter(); + if (character) LoadXml(character->GetXMLDoc()); CheckProxyIntegrity(); @@ -472,10 +473,10 @@ bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& return true; } -void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { +void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) { LoadPetXml(document); - auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); + auto* inventoryElement = document.FirstChildElement("obj")->FirstChildElement("inv"); if (inventoryElement == nullptr) { LOG("Failed to find 'inv' xml element!"); @@ -594,10 +595,10 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { } } -void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { +void InventoryComponent::UpdateXml(tinyxml2::XMLDocument& document) { UpdatePetXml(document); - auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); + auto* inventoryElement = document.FirstChildElement("obj")->FirstChildElement("inv"); if (inventoryElement == nullptr) { LOG("Failed to find 'inv' xml element!"); @@ -631,7 +632,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { bags->DeleteChildren(); for (const auto* inventory : inventoriesToSave) { - auto* bag = document->NewElement("b"); + auto* bag = document.NewElement("b"); bag->SetAttribute("t", inventory->GetType()); bag->SetAttribute("m", static_cast(inventory->GetSize())); @@ -654,14 +655,14 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { continue; } - auto* bagElement = document->NewElement("in"); + auto* bagElement = document.NewElement("in"); bagElement->SetAttribute("t", inventory->GetType()); for (const auto& pair : inventory->GetItems()) { auto* item = pair.second; - auto* itemElement = document->NewElement("i"); + auto* itemElement = document.NewElement("i"); itemElement->SetAttribute("l", item->GetLot()); itemElement->SetAttribute("id", item->GetId()); @@ -680,7 +681,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { continue; } - auto* extraInfo = document->NewElement("x"); + auto* extraInfo = document.NewElement("x"); extraInfo->SetAttribute("ma", data->GetString(false).c_str()); @@ -1542,8 +1543,8 @@ void InventoryComponent::PurgeProxies(Item* item) { } } -void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { - auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); +void InventoryComponent::LoadPetXml(const tinyxml2::XMLDocument& document) { + auto* petInventoryElement = document.FirstChildElement("obj")->FirstChildElement("pet"); if (petInventoryElement == nullptr) { m_Pets.clear(); @@ -1574,19 +1575,19 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { } } -void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) { - auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); +void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument& document) { + auto* petInventoryElement = document.FirstChildElement("obj")->FirstChildElement("pet"); if (petInventoryElement == nullptr) { - petInventoryElement = document->NewElement("pet"); + petInventoryElement = document.NewElement("pet"); - document->FirstChildElement("obj")->LinkEndChild(petInventoryElement); + document.FirstChildElement("obj")->LinkEndChild(petInventoryElement); } petInventoryElement->DeleteChildren(); for (const auto& pet : m_Pets) { - auto* petElement = document->NewElement("p"); + auto* petElement = document.NewElement("p"); petElement->SetAttribute("id", pet.first); petElement->SetAttribute("l", pet.second.lot); diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 8f58a523..a1eb14d1 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -38,12 +38,12 @@ enum class eItemType : int32_t; class InventoryComponent final : public Component { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; - explicit InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document = nullptr); + InventoryComponent(Entity* parent); void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - void LoadXml(tinyxml2::XMLDocument* document); - void UpdateXml(tinyxml2::XMLDocument* document) override; + void LoadXml(const tinyxml2::XMLDocument& document); + void UpdateXml(tinyxml2::XMLDocument& document) override; /** * Returns an inventory of the specified type, if it exists @@ -470,13 +470,13 @@ private: * Saves all the pet information stored in inventory items to the database * @param document the xml doc to save to */ - void LoadPetXml(tinyxml2::XMLDocument* document); + void LoadPetXml(const tinyxml2::XMLDocument& document); /** * Loads all the pet information from an xml doc into items * @param document the xml doc to load from */ - void UpdatePetXml(tinyxml2::XMLDocument* document); + void UpdatePetXml(tinyxml2::XMLDocument& document); }; #endif diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index 2d3d5144..a6801a40 100644 --- a/dGame/dComponents/LevelProgressionComponent.cpp +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -13,8 +13,8 @@ LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component m_CharacterVersion = eCharacterVersion::LIVE; } -void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); +void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* level = doc.FirstChildElement("obj")->FirstChildElement("lvl"); if (!level) { LOG("Failed to find lvl tag while updating XML!"); return; @@ -24,8 +24,8 @@ void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { level->SetAttribute("cv", static_cast(m_CharacterVersion)); } -void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); +void LevelProgressionComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* level = doc.FirstChildElement("obj")->FirstChildElement("lvl"); if (!level) { LOG("Failed to find lvl tag while loading XML!"); return; diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index a27039f3..e9981ab6 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -27,13 +27,13 @@ public: * Save data from this componennt to character XML * @param doc the document to write data to */ - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Load base data for this component from character XML * @param doc the document to read data from */ - void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; /** * Gets the current level of the entity diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index 151fcf2f..1eb02e57 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -504,10 +504,8 @@ bool MissionComponent::RequiresItem(const LOT lot) { } -void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; - - auto* mis = doc->FirstChildElement("obj")->FirstChildElement("mis"); +void MissionComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* mis = doc.FirstChildElement("obj")->FirstChildElement("mis"); if (mis == nullptr) return; @@ -523,7 +521,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { auto* mission = new Mission(this, missionId); - mission->LoadFromXml(doneM); + mission->LoadFromXml(*doneM); doneM = doneM->NextSiblingElement(); @@ -540,7 +538,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { auto* mission = new Mission(this, missionId); - mission->LoadFromXml(currentM); + mission->LoadFromXml(*currentM); if (currentM->QueryAttribute("o", &missionOrder) == tinyxml2::XML_SUCCESS && mission->IsMission()) { mission->SetUniqueMissionOrderID(missionOrder); @@ -554,25 +552,23 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { } -void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; - +void MissionComponent::UpdateXml(tinyxml2::XMLDocument& doc) { auto shouldInsertMis = false; - auto* obj = doc->FirstChildElement("obj"); + auto* obj = doc.FirstChildElement("obj"); auto* mis = obj->FirstChildElement("mis"); if (mis == nullptr) { - mis = doc->NewElement("mis"); + mis = doc.NewElement("mis"); shouldInsertMis = true; } mis->DeleteChildren(); - auto* done = doc->NewElement("done"); - auto* cur = doc->NewElement("cur"); + auto* done = doc.NewElement("done"); + auto* cur = doc.NewElement("cur"); for (const auto& pair : m_Missions) { auto* mission = pair.second; @@ -580,10 +576,10 @@ void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { if (mission) { const auto complete = mission->IsComplete(); - auto* m = doc->NewElement("m"); + auto* m = doc.NewElement("m"); if (complete) { - mission->UpdateXml(m); + mission->UpdateXml(*m); done->LinkEndChild(m); @@ -591,7 +587,7 @@ void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { } if (mission->IsMission()) m->SetAttribute("o", mission->GetUniqueMissionOrderID()); - mission->UpdateXml(m); + mission->UpdateXml(*m); cur->LinkEndChild(m); } diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index 866f1650..a01794f0 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -31,8 +31,8 @@ public: explicit MissionComponent(Entity* parent); ~MissionComponent() override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Returns all the missions for this entity, mapped by mission ID diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 4ed80bf3..c2ed2a42 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -65,24 +65,24 @@ Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { } } -void Mission::LoadFromXml(tinyxml2::XMLElement* element) { +void Mission::LoadFromXml(const tinyxml2::XMLElement& element) { // Start custom XML - if (element->Attribute("state") != nullptr) { - m_State = static_cast(std::stoul(element->Attribute("state"))); + if (element.Attribute("state") != nullptr) { + m_State = static_cast(std::stoul(element.Attribute("state"))); } // End custom XML - if (element->Attribute("cct") != nullptr) { - m_Completions = std::stoul(element->Attribute("cct")); + if (element.Attribute("cct") != nullptr) { + m_Completions = std::stoul(element.Attribute("cct")); - m_Timestamp = std::stoul(element->Attribute("cts")); + m_Timestamp = std::stoul(element.Attribute("cts")); if (IsComplete()) { return; } } - auto* task = element->FirstChildElement(); + auto* task = element.FirstChildElement(); auto index = 0U; @@ -132,19 +132,19 @@ void Mission::LoadFromXml(tinyxml2::XMLElement* element) { } } -void Mission::UpdateXml(tinyxml2::XMLElement* element) { +void Mission::UpdateXml(tinyxml2::XMLElement& element) { // Start custom XML - element->SetAttribute("state", static_cast(m_State)); + element.SetAttribute("state", static_cast(m_State)); // End custom XML - element->DeleteChildren(); + element.DeleteChildren(); - element->SetAttribute("id", static_cast(info.id)); + element.SetAttribute("id", static_cast(info.id)); if (m_Completions > 0) { - element->SetAttribute("cct", static_cast(m_Completions)); + element.SetAttribute("cct", static_cast(m_Completions)); - element->SetAttribute("cts", static_cast(m_Timestamp)); + element.SetAttribute("cts", static_cast(m_Timestamp)); if (IsComplete()) { return; @@ -155,27 +155,27 @@ void Mission::UpdateXml(tinyxml2::XMLElement* element) { if (task->GetType() == eMissionTaskType::COLLECTION || task->GetType() == eMissionTaskType::VISIT_PROPERTY) { - auto* child = element->GetDocument()->NewElement("sv"); + auto* child = element.GetDocument()->NewElement("sv"); child->SetAttribute("v", static_cast(task->GetProgress())); - element->LinkEndChild(child); + element.LinkEndChild(child); for (auto unique : task->GetUnique()) { - auto* uniqueElement = element->GetDocument()->NewElement("sv"); + auto* uniqueElement = element.GetDocument()->NewElement("sv"); uniqueElement->SetAttribute("v", static_cast(unique)); - element->LinkEndChild(uniqueElement); + element.LinkEndChild(uniqueElement); } break; } - auto* child = element->GetDocument()->NewElement("sv"); + auto* child = element.GetDocument()->NewElement("sv"); child->SetAttribute("v", static_cast(task->GetProgress())); - element->LinkEndChild(child); + element.LinkEndChild(child); } } diff --git a/dGame/dMission/Mission.h b/dGame/dMission/Mission.h index d8c104e8..74b8d352 100644 --- a/dGame/dMission/Mission.h +++ b/dGame/dMission/Mission.h @@ -28,8 +28,8 @@ public: Mission(MissionComponent* missionComponent, uint32_t missionId); ~Mission(); - void LoadFromXml(tinyxml2::XMLElement* element); - void UpdateXml(tinyxml2::XMLElement* element); + void LoadFromXml(const tinyxml2::XMLElement& element); + void UpdateXml(tinyxml2::XMLElement& element); /** * Returns the ID of this mission diff --git a/dGame/dUtilities/BrickDatabase.cpp b/dGame/dUtilities/BrickDatabase.cpp index 7b447b84..61a7341d 100644 --- a/dGame/dUtilities/BrickDatabase.cpp +++ b/dGame/dUtilities/BrickDatabase.cpp @@ -29,15 +29,14 @@ const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) { return emptyCache; } - auto* doc = new tinyxml2::XMLDocument(); - if (doc->Parse(data.str().c_str(), data.str().size()) != 0) { - delete doc; + tinyxml2::XMLDocument doc; + if (doc.Parse(data.str().c_str(), data.str().size()) != 0) { return emptyCache; } BrickList parts; - auto* lxfml = doc->FirstChildElement("LXFML"); + auto* lxfml = doc.FirstChildElement("LXFML"); auto* bricks = lxfml->FirstChildElement("Bricks"); std::string searchTerm = "Brick"; @@ -86,7 +85,5 @@ const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) { m_Cache[lxfmlPath] = parts; - delete doc; - return m_Cache[lxfmlPath]; }