From ea76c8e25082a9688e5d1fa00012d32a8d8ce463 Mon Sep 17 00:00:00 2001 From: Niam5 Date: Fri, 30 Aug 2024 19:36:10 -0700 Subject: [PATCH] Misc: Use new unique_trackable_ptr for various classes exposed to scripts (not actually used anywhere currently) Co-Authored-By: Shauren Co-Authored-By: Foe --- src/game/BattleGround/BattleGround.cpp | 2 - src/game/BattleGround/BattleGround.h | 6 +++ src/game/BattleGround/BattleGroundMgr.cpp | 24 +++++------ src/game/BattleGround/BattleGroundMgr.h | 5 ++- src/game/Chat/Level3.cpp | 6 +-- src/game/Entities/Object.cpp | 26 +++++++++++- src/game/Entities/Object.h | 24 ++++------- src/game/Entities/Player.cpp | 9 +--- src/game/Entities/Unit.cpp | 1 + src/game/Globals/ObjectMgr.cpp | 15 +++---- src/game/Globals/ObjectMgr.h | 5 ++- src/game/Groups/Group.cpp | 2 +- src/game/Groups/Group.h | 6 +++ src/game/Guilds/Guild.h | 6 +++ src/game/Guilds/GuildHandler.cpp | 4 -- src/game/Guilds/GuildMgr.cpp | 12 +++--- src/game/Guilds/GuildMgr.h | 3 +- src/game/Maps/Map.cpp | 6 ++- src/game/Maps/Map.h | 6 +++ src/game/Maps/MapManager.cpp | 51 +++++++++++------------ src/game/Maps/MapManager.h | 9 ++-- src/game/Quests/QuestDef.h | 5 +++ src/game/Spells/Spell.cpp | 36 +++++++++------- src/game/Spells/Spell.h | 36 +++++++++------- src/game/Spells/SpellAuras.cpp | 2 +- src/game/Spells/SpellAuras.h | 7 ++++ 26 files changed, 182 insertions(+), 132 deletions(-) diff --git a/src/game/BattleGround/BattleGround.cpp b/src/game/BattleGround/BattleGround.cpp index 90ba790107c..143e0a99145 100644 --- a/src/game/BattleGround/BattleGround.cpp +++ b/src/game/BattleGround/BattleGround.cpp @@ -259,8 +259,6 @@ BattleGround::~BattleGround() { // remove objects and creatures // (this is done automatically in mapmanager update, when the instance is reset after the reset time) - sBattleGroundMgr.RemoveBattleGround(GetInstanceId(), GetTypeId()); - // skip template bgs as they were never added to visible bg list BattleGroundBracketId bracketId = GetBracketId(); if (bracketId != BG_BRACKET_ID_TEMPLATE) diff --git a/src/game/BattleGround/BattleGround.h b/src/game/BattleGround/BattleGround.h index 5a59893dffb..cff92a739d8 100644 --- a/src/game/BattleGround/BattleGround.h +++ b/src/game/BattleGround/BattleGround.h @@ -617,6 +617,10 @@ class BattleGround uint32 GetPlayerSkinRefLootId() const { return m_playerSkinReflootId; } void SetPlayerSkinRefLootId(uint32 reflootId) { m_playerSkinReflootId = reflootId; } + + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(MaNGOS::unique_weak_ptr weakRef) { m_weakRef = std::move(weakRef); } + protected: // this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround void EndNow(); @@ -707,6 +711,8 @@ class BattleGround float m_startMaxDist; uint32 m_playerSkinReflootId; + + MaNGOS::unique_weak_ptr m_weakRef; }; // helper functions for world state list fill diff --git a/src/game/BattleGround/BattleGroundMgr.cpp b/src/game/BattleGround/BattleGroundMgr.cpp index a9376bd8d7d..911a8175f64 100644 --- a/src/game/BattleGround/BattleGroundMgr.cpp +++ b/src/game/BattleGround/BattleGroundMgr.cpp @@ -1276,14 +1276,7 @@ void BattleGroundMgr::DeleteAllBattleGrounds() { // will also delete template bgs: for (uint8 i = BATTLEGROUND_TYPE_NONE; i < MAX_BATTLEGROUND_TYPE_ID; ++i) - { - for (BattleGroundSet::iterator itr = m_battleGrounds[i].begin(); itr != m_battleGrounds[i].end();) - { - BattleGround* bg = itr->second; - ++itr; // step from invalidate iterator pos in result element remove in ~BattleGround call - delete bg; - } - } + m_battleGrounds[i].clear(); } /** @@ -1607,7 +1600,7 @@ BattleGround* BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 insta for (auto& itr : m_battleGrounds[bgTypeId]) { if (itr.second->GetClientInstanceId() == instanceId) - return itr.second; + return itr.second.get(); } return nullptr; @@ -1629,13 +1622,13 @@ BattleGround* BattleGroundMgr::GetBattleGround(uint32 instanceId, BattleGroundTy { itr = m_battleGrounds[i].find(instanceId); if (itr != m_battleGrounds[i].end()) - return itr->second; + return itr->second.get(); } return nullptr; } itr = m_battleGrounds[bgTypeId].find(instanceId); - return ((itr != m_battleGrounds[bgTypeId].end()) ? itr->second : nullptr); + return ((itr != m_battleGrounds[bgTypeId].end()) ? itr->second.get() : nullptr); } /** @@ -1646,7 +1639,7 @@ BattleGround* BattleGroundMgr::GetBattleGround(uint32 instanceId, BattleGroundTy BattleGround* BattleGroundMgr::GetBattleGroundTemplate(BattleGroundTypeId bgTypeId) { // map is sorted and we can be sure that lowest instance id has only BG template - return m_battleGrounds[bgTypeId].empty() ? nullptr : m_battleGrounds[bgTypeId].begin()->second; + return m_battleGrounds[bgTypeId].empty() ? nullptr : m_battleGrounds[bgTypeId].begin()->second.get(); } /** @@ -1824,6 +1817,13 @@ uint32 BattleGroundMgr::CreateBattleGround(BattleGroundTypeId bgTypeId, bool IsA return bgTypeId; } +void BattleGroundMgr::AddBattleGround(uint32 instanceId, BattleGroundTypeId bgTypeId, BattleGround* bg) +{ + MaNGOS::unique_trackable_ptr& ptr = m_battleGrounds[bgTypeId][instanceId]; + ptr.reset(bg); + bg->SetWeakPtr(ptr); +} + /** Method that loads battleground data from DB */ diff --git a/src/game/BattleGround/BattleGroundMgr.h b/src/game/BattleGround/BattleGroundMgr.h index f8c32c1bfdf..578d47d4e58 100644 --- a/src/game/BattleGround/BattleGroundMgr.h +++ b/src/game/BattleGround/BattleGroundMgr.h @@ -23,11 +23,12 @@ #include "Utilities/EventProcessor.h" #include "Globals/SharedDefines.h" #include "Server/DBCEnums.h" +#include "Util/UniqueTrackablePtr.h" #include "BattleGround.h" #include -typedef std::map BattleGroundSet; +typedef std::map> BattleGroundSet; // this container can't be deque, because deque doesn't like removing the last element - if you remove it, it invalidates next iterator and crash appears typedef std::list BgFreeSlotQueueType; @@ -228,7 +229,7 @@ class BattleGroundMgr uint32 CreateBattleGround(BattleGroundTypeId /*bgTypeId*/, bool /*isArena*/, uint32 /*minPlayersPerTeam*/, uint32 /*maxPlayersPerTeam*/, uint32 /*levelMin*/, uint32 /*levelMax*/, char const* /*battleGroundName*/, uint32 /*mapId*/, float /*team1StartLocX*/, float /*team1StartLocY*/, float /*team1StartLocZ*/, float /*team1StartLocO*/, float /*team2StartLocX*/, float /*team2StartLocY*/, float /*team2StartLocZ*/, float /*team2StartLocO*/, float /*startMaxDist*/, uint32 /*playerSkinReflootId*/); - void AddBattleGround(uint32 instanceId, BattleGroundTypeId bgTypeId, BattleGround* bg) { m_battleGrounds[bgTypeId][instanceId] = bg; }; + void AddBattleGround(uint32 instanceId, BattleGroundTypeId bgTypeId, BattleGround* bg);; void RemoveBattleGround(uint32 instanceId, BattleGroundTypeId bgTypeId) { m_battleGrounds[bgTypeId].erase(instanceId); } uint32 CreateClientVisibleInstanceId(BattleGroundTypeId /*bgTypeId*/, BattleGroundBracketId /*bracketId*/); diff --git a/src/game/Chat/Level3.cpp b/src/game/Chat/Level3.cpp index b4d56d0463d..cb4596377ab 100644 --- a/src/game/Chat/Level3.cpp +++ b/src/game/Chat/Level3.cpp @@ -2846,7 +2846,7 @@ bool ChatHandler::HandleLookupQuestCommand(char* args) ObjectMgr::QuestMap const& qTemplates = sObjectMgr.GetQuestTemplates(); for (const auto& qTemplate : qTemplates) { - Quest* qinfo = qTemplate.second; + Quest* qinfo = qTemplate.second.get(); std::string title; // "" for avoid repeating check default locale sObjectMgr.GetQuestLocaleStrings(qinfo->GetQuestId(), loc_idx, &title); @@ -3118,10 +3118,7 @@ bool ChatHandler::HandleGuildUninviteCommand(char* args) return false; if (targetGuild->DelMember(target_guid)) - { targetGuild->Disband(); - delete targetGuild; - } return true; } @@ -3186,7 +3183,6 @@ bool ChatHandler::HandleGuildDeleteCommand(char* args) return false; targetGuild->Disband(); - delete targetGuild; return true; } diff --git a/src/game/Entities/Object.cpp b/src/game/Entities/Object.cpp index 197e6ea7066..33c150b6503 100644 --- a/src/game/Entities/Object.cpp +++ b/src/game/Entities/Object.cpp @@ -45,7 +45,7 @@ #include "Spells/SpellMgr.h" #include "MotionGenerators/PathFinder.h" -Object::Object(): m_updateFlag(0), m_itsNewObject(false), m_dbGuid(0) +Object::Object(): m_updateFlag(0), m_itsNewObject(false), m_dbGuid(0), m_scriptRef(this, NoopObjectDeleter()) { m_objectTypeId = TYPEID_OBJECT; m_objectType = TYPEMASK_OBJECT; @@ -78,6 +78,30 @@ Object::~Object() delete m_loot; } +void Object::AddToWorld() +{ + if (m_inWorld) + return; + + m_inWorld = true; + + // synchronize values mirror with values array (changes will send in updatecreate opcode any way + ClearUpdateMask(false); // false - we can't have update data in update queue before adding to world + + // Set new ref when adding to world (except if we already have one - also set in constructor to allow scripts to work in initialization phase) + // Changing the ref when adding/removing from world prevents accessing players on different maps (possibly from another thread) + if (!m_scriptRef) + m_scriptRef.reset(this, NoopObjectDeleter()); +} + +void Object::RemoveFromWorld() +{ + // if we remove from world then sending changes not required + ClearUpdateMask(true); + m_inWorld = false; + m_scriptRef = nullptr; +} + void Object::_InitValues() { m_uint32Values = new uint32[ m_valuesCount ]; diff --git a/src/game/Entities/Object.h b/src/game/Entities/Object.h index 81336e54427..8661bbd96b6 100644 --- a/src/game/Entities/Object.h +++ b/src/game/Entities/Object.h @@ -33,6 +33,7 @@ #include "PlayerDefines.h" #include "Entities/ObjectVisibility.h" #include "Grids/Cell.h" +#include "Util/UniqueTrackablePtr.h" #include "Utilities/EventProcessor.h" #include @@ -378,22 +379,8 @@ class Object virtual ~Object(); const bool& IsInWorld() const { return m_inWorld; } - virtual void AddToWorld() - { - if (m_inWorld) - return; - - m_inWorld = true; - - // synchronize values mirror with values array (changes will send in updatecreate opcode any way - ClearUpdateMask(false); // false - we can't have update data in update queue before adding to world - } - virtual void RemoveFromWorld() - { - // if we remove from world then sending changes not required - ClearUpdateMask(true); - m_inWorld = false; - } + virtual void AddToWorld(); + virtual void RemoveFromWorld(); ObjectGuid const& GetObjectGuid() const { return GetGuidValue(OBJECT_FIELD_GUID); } uint32 GetGUIDLow() const { return GetObjectGuid().GetCounter(); } @@ -629,6 +616,8 @@ class Object inline bool IsGameObject() const { return GetTypeId() == TYPEID_GAMEOBJECT; } inline bool IsCorpse() const { return GetTypeId() == TYPEID_CORPSE; } + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + protected: Object(); @@ -672,6 +661,9 @@ class Object uint32 m_dbGuid; + struct NoopObjectDeleter { void operator()(Object*) const { /*noop - not managed*/ } }; + MaNGOS::unique_trackable_ptr m_scriptRef; + public: // for output helpfull error messages from ASSERTs bool PrintIndexError(uint32 index, bool set) const; diff --git a/src/game/Entities/Player.cpp b/src/game/Entities/Player.cpp index 5bfccea4409..1c22820ff09 100644 --- a/src/game/Entities/Player.cpp +++ b/src/game/Entities/Player.cpp @@ -4217,17 +4217,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe // remove from guild if (uint32 guildId = GetGuildIdFromDB(playerguid)) - { if (Guild* guild = sGuildMgr.GetGuildById(guildId)) - { if (guild->DelMember(playerguid)) - { guild->Disband(); - delete guild; - } - } - } - + // remove from arena teams LeaveAllArenaTeams(playerguid); diff --git a/src/game/Entities/Unit.cpp b/src/game/Entities/Unit.cpp index e063606c8f2..72f0bd24048 100644 --- a/src/game/Entities/Unit.cpp +++ b/src/game/Entities/Unit.cpp @@ -5674,6 +5674,7 @@ void Unit::RemoveAura(Aura* Aur, AuraRemoveMode mode) // Set remove mode Aur->SetRemoveMode(mode); + Aur->InvalidateScriptRef(); // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura // remove aura from list before to prevent deleting it before diff --git a/src/game/Globals/ObjectMgr.cpp b/src/game/Globals/ObjectMgr.cpp index a505daffaec..aab43927973 100644 --- a/src/game/Globals/ObjectMgr.cpp +++ b/src/game/Globals/ObjectMgr.cpp @@ -152,9 +152,6 @@ ObjectMgr::ObjectMgr() : ObjectMgr::~ObjectMgr() { - for (auto& mQuestTemplate : mQuestTemplates) - delete mQuestTemplate.second; - for (auto& i : petInfo) delete[] i.second; @@ -4505,9 +4502,6 @@ void ObjectMgr::LoadGroups() void ObjectMgr::LoadQuests() { // For reload case - for (QuestMap::const_iterator itr = mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr) - delete itr->second; - mQuestTemplates.clear(); m_ExclusiveQuestGroups.clear(); @@ -4569,7 +4563,8 @@ void ObjectMgr::LoadQuests() Field* fields = queryResult->Fetch(); Quest* newQuest = new Quest(fields); - mQuestTemplates[newQuest->GetQuestId()] = newQuest; + auto itr = mQuestTemplates.try_emplace(newQuest->GetQuestId(), newQuest).first; + newQuest->m_weakRef = itr->second; } while (queryResult->NextRow()); @@ -4579,7 +4574,7 @@ void ObjectMgr::LoadQuests() for (auto& mQuestTemplate : mQuestTemplates) { - Quest* qinfo = mQuestTemplate.second; + Quest* qinfo = mQuestTemplate.second.get(); // additional quest integrity checks (GO, creature_template and item_template must be loaded already) @@ -5158,7 +5153,7 @@ void ObjectMgr::LoadQuests() // Prevent any breadcrumb loops, and inform target quests of their breadcrumbs for (auto& mQuestTemplate : mQuestTemplates) { - Quest* qinfo = mQuestTemplate.second; + Quest* qinfo = mQuestTemplate.second.get(); uint32 qid = qinfo->GetQuestId(); uint32 breadcrumbForQuestId = qinfo->BreadcrumbForQuestId; std::set questSet; @@ -5839,7 +5834,7 @@ void ObjectMgr::LoadConditions() for (auto& mQuestTemplate : mQuestTemplates) // needs to be checked after loading conditions { - Quest* qinfo = mQuestTemplate.second; + Quest* qinfo = mQuestTemplate.second.get(); if (qinfo->RequiredCondition) { diff --git a/src/game/Globals/ObjectMgr.h b/src/game/Globals/ObjectMgr.h index 240feb3956c..df944a7d72e 100644 --- a/src/game/Globals/ObjectMgr.h +++ b/src/game/Globals/ObjectMgr.h @@ -35,6 +35,7 @@ #include "Entities/ObjectGuid.h" #include "Globals/Conditions.h" #include "Maps/SpawnGroupDefines.h" +#include "Util/UniqueTrackablePtr.h" #include #include @@ -470,7 +471,7 @@ class ObjectMgr typedef std::unordered_map ArenaTeamMap; - typedef std::unordered_map QuestMap; + typedef std::unordered_map> QuestMap; typedef std::unordered_map AreaTriggerMap; @@ -541,7 +542,7 @@ class ObjectMgr Quest const* GetQuestTemplate(uint32 quest_id) const { QuestMap::const_iterator itr = mQuestTemplates.find(quest_id); - return itr != mQuestTemplates.end() ? itr->second : nullptr; + return itr != mQuestTemplates.end() ? itr->second.get() : nullptr; } QuestMap const& GetQuestTemplates() const { return mQuestTemplates; } diff --git a/src/game/Groups/Group.cpp b/src/game/Groups/Group.cpp index 7f1abe6317f..7d0449908bd 100644 --- a/src/game/Groups/Group.cpp +++ b/src/game/Groups/Group.cpp @@ -67,7 +67,7 @@ GroupMemberStatus GetGroupMemberStatus(const Player* member = nullptr) Group::Group() : m_Id(0), m_leaderLastOnline(0), m_groupFlags(GROUP_FLAG_NORMAL), m_difficulty(REGULAR_DIFFICULTY), m_bgGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), - m_subGroupsCounts(nullptr) + m_subGroupsCounts(nullptr), m_scriptRef(this, NoopGroupDeleter()) { } diff --git a/src/game/Groups/Group.h b/src/game/Groups/Group.h index 5d7705d8787..f83cb3fcb2b 100644 --- a/src/game/Groups/Group.h +++ b/src/game/Groups/Group.h @@ -26,6 +26,7 @@ #include "BattleGround/BattleGround.h" #include "Server/DBCEnums.h" #include "Globals/SharedDefines.h" +#include "Util/UniqueTrackablePtr.h" class WorldSession; class Map; @@ -277,6 +278,8 @@ class Group ObjectGuid GetTargetIcon(int index) { return m_targetIcons[index]; } + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + protected: bool _addMember(ObjectGuid guid, const char* name, bool isAssistant = false); bool _addMember(ObjectGuid guid, const char* name, bool isAssistant, uint8 group); @@ -365,5 +368,8 @@ class Group ObjectGuid m_currentLooterGuid; BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; uint8* m_subGroupsCounts; + + struct NoopGroupDeleter { void operator()(Group*) const { /*noop - not managed*/ } }; + MaNGOS::unique_trackable_ptr m_scriptRef; }; #endif diff --git a/src/game/Guilds/Guild.h b/src/game/Guilds/Guild.h index 6dee83d8773..50949adffa2 100644 --- a/src/game/Guilds/Guild.h +++ b/src/game/Guilds/Guild.h @@ -26,6 +26,7 @@ #include "Entities/Item.h" #include "Globals/ObjectAccessor.h" #include "Globals/SharedDefines.h" +#include "Util/UniqueTrackablePtr.h" class Item; @@ -443,6 +444,9 @@ class Guild void LogBankEvent(uint8 EventType, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount = 0, uint8 DestTabId = 0); bool AddGBankItemToDB(uint32 GuildId, uint32 BankTab, uint32 BankTabSlot, uint32 GUIDLow, uint32 Entry) const; + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(MaNGOS::unique_weak_ptr weakRef) { m_weakRef = std::move(weakRef); } + protected: void AddRank(const std::string& name_, uint32 rights, uint32 money); @@ -481,6 +485,8 @@ class Guild uint64 m_GuildBankMoney; + MaNGOS::unique_weak_ptr m_weakRef; + private: void UpdateAccountsNumber() { m_accountsNumber = 0;}// mark for lazy calculation at request in GetAccountsNumber diff --git a/src/game/Guilds/GuildHandler.cpp b/src/game/Guilds/GuildHandler.cpp index e09d1307b35..153b2a5f687 100644 --- a/src/game/Guilds/GuildHandler.cpp +++ b/src/game/Guilds/GuildHandler.cpp @@ -183,7 +183,6 @@ void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) if (guild->DelMember(slot->guid)) { guild->Disband(); - delete guild; return; } @@ -401,7 +400,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) if (_player->GetObjectGuid() == guild->GetLeaderGuid()) { guild->Disband(); - delete guild; return; } @@ -410,7 +408,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) if (guild->DelMember(_player->GetObjectGuid())) { guild->Disband(); - delete guild; return; } @@ -438,7 +435,6 @@ void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) } guild->Disband(); - delete guild; DEBUG_LOG("WORLD: Guild Successfully Disbanded"); } diff --git a/src/game/Guilds/GuildMgr.cpp b/src/game/Guilds/GuildMgr.cpp index 2206415989d..27ae06f46e5 100644 --- a/src/game/Guilds/GuildMgr.cpp +++ b/src/game/Guilds/GuildMgr.cpp @@ -33,13 +33,13 @@ GuildMgr::GuildMgr() GuildMgr::~GuildMgr() { - for (auto& itr : m_GuildMap) - delete itr.second; } void GuildMgr::AddGuild(Guild* guild) { - m_GuildMap[guild->GetId()] = guild; + MaNGOS::unique_trackable_ptr& ptr = m_GuildMap[guild->GetId()]; + ptr.reset(guild); + guild->SetWeakPtr(ptr); } void GuildMgr::RemoveGuild(uint32 guildId) @@ -51,7 +51,7 @@ Guild* GuildMgr::GetGuildById(uint32 guildId) const { GuildMap::const_iterator itr = m_GuildMap.find(guildId); if (itr != m_GuildMap.end()) - return itr->second; + return itr->second.get(); return nullptr; } @@ -60,7 +60,7 @@ Guild* GuildMgr::GetGuildByName(std::string const& name) const { for (const auto& itr : m_GuildMap) if (itr.second->GetName() == name) - return itr.second; + return itr.second.get(); return nullptr; } @@ -69,7 +69,7 @@ Guild* GuildMgr::GetGuildByLeader(ObjectGuid const& guid) const { for (const auto& itr : m_GuildMap) if (itr.second->GetLeaderGuid() == guid) - return itr.second; + return itr.second.get(); return nullptr; } diff --git a/src/game/Guilds/GuildMgr.h b/src/game/Guilds/GuildMgr.h index 0aed958d6ce..de5f993a7ee 100644 --- a/src/game/Guilds/GuildMgr.h +++ b/src/game/Guilds/GuildMgr.h @@ -20,13 +20,14 @@ #define _GUILDMGR_H #include "Common.h" +#include "Util/UniqueTrackablePtr.h" class Guild; class ObjectGuid; class GuildMgr { - typedef std::unordered_map GuildMap; + typedef std::unordered_map> GuildMap; GuildMap m_GuildMap; public: diff --git a/src/game/Maps/Map.cpp b/src/game/Maps/Map.cpp index 00ba9ec2725..c80906edb4a 100644 --- a/src/game/Maps/Map.cpp +++ b/src/game/Maps/Map.cpp @@ -39,6 +39,7 @@ #include "Chat/Chat.h" #include "Weather/Weather.h" #include "AI/ScriptDevAI/ScriptDevAIMgr.h" +#include "BattleGround/BattleGroundMgr.h" #ifdef BUILD_METRICS #include "Metric/Metric.h" @@ -2149,7 +2150,10 @@ void BattleGroundMap::Update(const uint32& diff) // ]] // BattleGround Template instance cannot be updated, because it would be deleted if (!m_bg->GetInvitedCount(HORDE) && !m_bg->GetInvitedCount(ALLIANCE)) - delete m_bg; + { + sBattleGroundMgr.RemoveBattleGround(GetInstanceId(), m_bg->GetTypeId()); + m_bg = nullptr; + } } else m_bg->Update(diff); diff --git a/src/game/Maps/Map.h b/src/game/Maps/Map.h index dce640727d2..f8b296ba67c 100644 --- a/src/game/Maps/Map.h +++ b/src/game/Maps/Map.h @@ -38,6 +38,7 @@ #include "Globals/GraveyardManager.h" #include "Maps/SpawnManager.h" #include "Maps/MapDataContainer.h" +#include "Util/UniqueTrackablePtr.h" #include "World/WorldStateVariableManager.h" #include @@ -215,6 +216,10 @@ class Map : public GridRefManager bool CreatureRespawnRelocation(Creature* c); // used only in CreatureRelocation and ObjectGridUnloader uint32 GetInstanceId() const { return i_InstanceId; } + + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(MaNGOS::unique_weak_ptr weakRef) { m_weakRef = std::move(weakRef); } + virtual bool CanEnter(Player* player); const char* GetMapName() const; @@ -467,6 +472,7 @@ class Map : public GridRefManager uint8 i_spawnMode; uint32 i_id; uint32 i_InstanceId; + MaNGOS::unique_weak_ptr m_weakRef; uint32 m_unloadTimer; float m_VisibleDistance; MapPersistentState* m_persistentState; diff --git a/src/game/Maps/MapManager.cpp b/src/game/Maps/MapManager.cpp index d6c561ed266..b90f49ecaa6 100644 --- a/src/game/Maps/MapManager.cpp +++ b/src/game/Maps/MapManager.cpp @@ -41,8 +41,7 @@ MapManager::MapManager() MapManager::~MapManager() { - for (auto& i_map : i_maps) - delete i_map.second; + i_maps.clear(); DeleteStateMachine(); } @@ -97,7 +96,9 @@ void MapManager::CreateContinents() { Map* m = new WorldMap(id, i_gridCleanUpDelay, 0); // add map into container - i_maps[MapID(id)] = m; + MaNGOS::unique_trackable_ptr& ptr = i_maps[MapID(id)]; + ptr.reset(m); + m->SetWeakPtr(ptr); // non-instanceable maps always expected have saved state futures.push_back(std::async(std::launch::async, std::bind(&Map::Initialize, m, true))); @@ -134,7 +135,9 @@ Map* MapManager::CreateMap(uint32 id, const WorldObject* obj) std::lock_guard lock(m_lock); m = new WorldMap(id, i_gridCleanUpDelay, instanceId); // add map into container - i_maps[MapID(id, instanceId)] = m; + MaNGOS::unique_trackable_ptr& ptr = i_maps[MapID(id, instanceId)]; + ptr.reset(m); + m->SetWeakPtr(ptr); // non-instanceable maps always expected have saved state m->Initialize(); @@ -167,7 +170,7 @@ Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const return nullptr; } - return iter->second; + return iter->second.get(); } void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId) @@ -177,13 +180,11 @@ void MapManager::DeleteInstance(uint32 mapid, uint32 instanceId) MapMapType::iterator iter = i_maps.find(MapID(mapid, instanceId)); if (iter != i_maps.end()) { - Map* pMap = iter->second; - if (pMap->Instanceable()) + if (iter->second->Instanceable()) { - i_maps.erase(iter); + auto node = i_maps.extract(iter); - pMap->UnloadAll(true); - delete pMap; + node.mapped()->UnloadAll(true); } } } @@ -209,14 +210,12 @@ void MapManager::Update(uint32 diff) MapMapType::iterator iter = i_maps.begin(); while (iter != i_maps.end()) { - Map* pMap = iter->second; // check if map can be unloaded - if (pMap->CanUnload((uint32)i_timer.GetCurrent())) + if (iter->second->CanUnload((uint32)i_timer.GetCurrent())) { - pMap->UnloadAll(true); - delete pMap; + auto node = i_maps.extract(iter++); - i_maps.erase(iter++); + node.mapped()->UnloadAll(true); } else ++iter; @@ -253,11 +252,7 @@ void MapManager::UnloadAll() for (auto& i_map : i_maps) i_map.second->UnloadAll(true); - while (!i_maps.empty()) - { - delete i_maps.begin()->second; - i_maps.erase(i_maps.begin()); - } + i_maps.clear(); if (m_updater.activated()) m_updater.deactivate(); @@ -283,7 +278,7 @@ uint32 MapManager::GetNumInstances() uint32 ret = 0; for (auto& i_map : i_maps) { - Map* map = i_map.second; + Map* map = i_map.second.get(); if (!map->IsDungeon()) continue; ret += 1; } @@ -296,7 +291,7 @@ uint32 MapManager::GetNumPlayersInInstances() uint32 ret = 0; for (auto& i_map : i_maps) { - Map* map = i_map.second; + Map* map = i_map.second.get(); if (!map->IsDungeon()) continue; ret += map->GetPlayers().getSize(); } @@ -342,7 +337,9 @@ Map* MapManager::CreateInstance(uint32 id, Player* player) // add a new map object into the registry if (pNewMap) { - i_maps[MapID(id, NewInstanceId)] = pNewMap; + MaNGOS::unique_trackable_ptr& ptr = i_maps[MapID(id, NewInstanceId)]; + ptr.reset(pNewMap); + pNewMap->SetWeakPtr(ptr); map = pNewMap; } @@ -393,7 +390,9 @@ BattleGroundMap* MapManager::CreateBattleGroundMap(uint32 id, uint32 InstanceId, bg->SetBgMap(map); // add map into map container - i_maps[MapID(id, InstanceId)] = map; + MaNGOS::unique_trackable_ptr& ptr = i_maps[MapID(id, InstanceId)]; + ptr.reset(map); + map->SetWeakPtr(ptr); // BGs/Arenas not have saved instance data map->Initialize(false); @@ -406,11 +405,11 @@ void MapManager::DoForAllMapsWithMapId(uint32 mapId, std::function w MapMapType::const_iterator start = i_maps.lower_bound(MapID(mapId, 0)); MapMapType::const_iterator end = i_maps.lower_bound(MapID(mapId + 1, 0)); for (MapMapType::const_iterator itr = start; itr != end; ++itr) - worker(itr->second); + worker(itr->second.get()); } void MapManager::DoForAllMaps(const std::function& worker) { for (MapMapType::const_iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) - worker(itr->second); + worker(itr->second.get()); } diff --git a/src/game/Maps/MapManager.h b/src/game/Maps/MapManager.h index 5b91268a7c5..04f5b157152 100644 --- a/src/game/Maps/MapManager.h +++ b/src/game/Maps/MapManager.h @@ -26,6 +26,7 @@ #include "Maps/Map.h" #include "Grids/GridStates.h" #include "Maps/MapUpdater.h" +#include "Util/UniqueTrackablePtr.h" #include @@ -61,7 +62,7 @@ class MapManager : public MaNGOS::Singleton::Lock Guard; public: - typedef std::map MapMapType; + typedef std::map > MapMapType; void CreateContinents(); Map* CreateMap(uint32, const WorldObject* obj); @@ -154,7 +155,7 @@ class MapManager : public MaNGOS::Singleton void DoForAllMapsWithMapId(uint32 mapId, Do& _do); @@ -198,7 +199,7 @@ inline void MapManager::DoForAllMapsWithMapId(uint32 mapId, Do& _do) MapMapType::const_iterator start = i_maps.lower_bound(MapID(mapId, 0)); MapMapType::const_iterator end = i_maps.lower_bound(MapID(mapId + 1, 0)); for (MapMapType::const_iterator itr = start; itr != end; ++itr) - _do(itr->second); + _do(itr->second.get()); } template @@ -206,7 +207,7 @@ inline WorldObject* MapManager::SearchOnAllLoadedMap(Check& check) { for (auto& mapItr : i_maps) { - WorldObject* result = check(mapItr.second); + WorldObject* result = check(mapItr.second.get()); if (result) return result; } diff --git a/src/game/Quests/QuestDef.h b/src/game/Quests/QuestDef.h index 2c0bcc8f6eb..4d55beb5007 100644 --- a/src/game/Quests/QuestDef.h +++ b/src/game/Quests/QuestDef.h @@ -21,6 +21,7 @@ #include "Platform/Define.h" #include "Database/DatabaseEnv.h" +#include "Util/UniqueTrackablePtr.h" #include @@ -289,6 +290,8 @@ class Quest uint32 GetRewChoiceItemsCount() const { return m_rewchoiceitemscount; } uint32 GetRewItemsCount() const { return m_rewitemscount; } + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_weakRef; } + typedef std::vector PrevQuests; PrevQuests prevQuests; typedef std::vector PrevChainQuests; @@ -361,6 +364,8 @@ class Quest uint32 CompleteEmoteDelay; uint32 QuestStartScript; uint32 QuestCompleteScript; + + MaNGOS::unique_weak_ptr m_weakRef; }; enum QuestUpdateState diff --git a/src/game/Spells/Spell.cpp b/src/game/Spells/Spell.cpp index 07c8504121b..cd833376e2b 100644 --- a/src/game/Spells/Spell.cpp +++ b/src/game/Spells/Spell.cpp @@ -382,7 +382,7 @@ void SpellLog::SendToSet() Spell::Spell(WorldObject* caster, SpellEntry const* info, uint32 triggeredFlags, ObjectGuid originalCasterGUID, SpellEntry const* triggeredBy) : m_partialApplicationMask(0), m_spellScript(SpellScriptMgr::GetSpellScript(info->Id)), m_auraScript(SpellScriptMgr::GetAuraScript(info->Id)), m_effectSkipMask(0), - m_spellLog(this), m_param1(0), m_param2(0), m_trueCaster(caster) + m_spellEvent(nullptr), m_spellLog(this), m_param1(0), m_param2(0), m_trueCaster(caster) { MANGOS_ASSERT(caster != nullptr && info != nullptr); MANGOS_ASSERT(info == sSpellTemplate.LookupEntry(info->Id) && "`info` must be pointer to sSpellTemplate element"); @@ -3105,8 +3105,8 @@ SpellCastResult Spell::SpellStart(SpellCastTargets const* targets, Aura* trigger m_triggeredByAuraSpell = triggeredByAura->GetSpellProto(); // create and add update event for this spell - SpellEvent* Event = new SpellEvent(this); - m_trueCaster->m_events.AddEvent(Event, m_trueCaster->m_events.CalculateTime(1)); + m_spellEvent = new SpellEvent(this); + m_trueCaster->m_events.AddEvent(m_spellEvent, m_trueCaster->m_events.CalculateTime(1)); if (m_trueCaster->IsUnit()) // gameobjects dont have a sense of already casting a spell { @@ -7497,25 +7497,24 @@ bool Spell::HaveTargetsForEffect(SpellEffectIndex effect) const SpellEvent::SpellEvent(Spell* spell) : BasicEvent() { - m_Spell = spell; + m_Spell.reset(spell, [](Spell* toDelete) + { + if (toDelete->IsDeletable() || World::IsStopped()) + { + delete toDelete; + } + else + { + sLog.outError("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", + (toDelete->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), toDelete->GetCaster()->GetGUIDLow(), toDelete->m_spellInfo->Id); + } + }); } SpellEvent::~SpellEvent() { if (m_Spell->getState() != SPELL_STATE_FINISHED) m_Spell->cancel(); - - if (m_Spell->IsDeletable() || World::IsStopped()) - { - delete m_Spell; - } - else - { - sLog.outError("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", - (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUIDLow(), m_Spell->m_spellInfo->Id); - sLog.outCustomLog("~SpellEvent: %s %u tried to delete non-deletable spell %u. Was not deleted, causes memory leak.", - (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUIDLow(), m_Spell->m_spellInfo->Id); - } } bool SpellEvent::Execute(uint64 e_time, uint32 p_time) @@ -8820,3 +8819,8 @@ SpellModRAII::~SpellModRAII() m_modOwner->SetSpellModSpell(nullptr); } } + +MaNGOS::unique_weak_ptr Spell::GetWeakPtr() const +{ + return m_spellEvent->GetSpellWeakPtr(); +} \ No newline at end of file diff --git a/src/game/Spells/Spell.h b/src/game/Spells/Spell.h index 517ee02efca..501b6ed94a8 100644 --- a/src/game/Spells/Spell.h +++ b/src/game/Spells/Spell.h @@ -28,6 +28,7 @@ #include "Entities/Player.h" #include "Server/SQLStorages.h" #include "Spells/SpellEffectDefines.h" +#include "Util/UniqueTrackablePtr.h" class WorldSession; class WorldPacket; @@ -343,6 +344,23 @@ class SpellCastArgs Position m_destination; }; +class SpellEvent : public BasicEvent +{ +public: + SpellEvent(Spell* spell); + virtual ~SpellEvent(); + + virtual bool Execute(uint64 e_time, uint32 p_time) override; + virtual void Abort(uint64 e_time) override; + virtual bool IsDeletable() const override; + + Spell* GetSpell() const { return m_Spell.get(); } + MaNGOS::unique_weak_ptr GetSpellWeakPtr() const { return m_Spell; } + +protected: + MaNGOS::unique_trackable_ptr m_Spell; +}; + class Spell { friend struct MaNGOS::SpellNotifierPlayer; @@ -812,6 +830,8 @@ class Spell void SetIgnoreRoot(bool state) { m_ignoreRoot = state; } void SetDamageDoneModifier(float mod, SpellEffectIndex effIdx); void SetUsableWhileStunned(bool state) { m_usableWhileStunned = state; } + + MaNGOS::unique_weak_ptr GetWeakPtr() const; protected: void SendLoot(ObjectGuid guid, LootType loottype, LockType lockType); bool IgnoreItemRequirements() const; // some item use spells have unexpected reagent data @@ -984,6 +1004,8 @@ class Spell // and in same time need aura data and after aura deleting. SpellEntry const* m_triggeredByAuraSpell; + SpellEvent* m_spellEvent; + // needed to store all log for this spell SpellLog m_spellLog; @@ -1213,18 +1235,4 @@ namespace MaNGOS typedef void(Spell::*pEffect)(SpellEffectIndex eff_idx); -class SpellEvent : public BasicEvent -{ - public: - SpellEvent(Spell* spell); - virtual ~SpellEvent(); - - virtual bool Execute(uint64 e_time, uint32 p_time) override; - virtual void Abort(uint64 e_time) override; - virtual bool IsDeletable() const override; - - Spell* GetSpell() const { return m_Spell; } - protected: - Spell* m_Spell; -}; #endif diff --git a/src/game/Spells/SpellAuras.cpp b/src/game/Spells/SpellAuras.cpp index 892ae684c2f..24ff27b4748 100644 --- a/src/game/Spells/SpellAuras.cpp +++ b/src/game/Spells/SpellAuras.cpp @@ -329,7 +329,7 @@ Aura::Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 const* curr m_spellmod(nullptr), m_periodicTimer(0), m_periodicTick(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_effIndex(eff), m_positive(false), m_isPeriodic(false), m_isAreaAura(false), m_isPersistent(false), m_magnetUsed(false), m_spellAuraHolder(holder), - m_scriptValue(0), m_storage(nullptr), m_affectOverriden(false) + m_scriptValue(0), m_storage(nullptr), m_scriptRef(this, NoopAuraDeleter()), m_affectOverriden(false) { MANGOS_ASSERT(target); MANGOS_ASSERT(spellproto && spellproto == sSpellTemplate.LookupEntry(spellproto->Id) && "`info` must be pointer to sSpellTemplate element"); diff --git a/src/game/Spells/SpellAuras.h b/src/game/Spells/SpellAuras.h index 0da892526ce..75dfb777a4e 100644 --- a/src/game/Spells/SpellAuras.h +++ b/src/game/Spells/SpellAuras.h @@ -22,6 +22,7 @@ #include "Server/DBCEnums.h" #include "Entities/ObjectGuid.h" #include "Spells/Scripts/SpellScript.h" +#include "Util/UniqueTrackablePtr.h" /** * Used to modify what an Aura does to a player/npc. @@ -552,6 +553,9 @@ class Aura void ForcePeriodicity(uint32 periodicTime); void SetAffectOverriden() { m_affectOverriden = true; } // spell script must implement condition + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + void InvalidateScriptRef() { m_scriptRef = nullptr; } + protected: Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32 const* currentDamage, int32 const* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster = nullptr, Item* castItem = nullptr); @@ -592,6 +596,9 @@ class Aura uint64 m_scriptValue; // persistent value for spell script state ScriptStorage* m_storage; bool m_affectOverriden; + + struct NoopAuraDeleter { void operator()(Aura*) const { /*noop - not managed*/ } }; + MaNGOS::unique_trackable_ptr m_scriptRef; private: void ReapplyAffectedPassiveAuras(Unit* target, bool owner_mode); };