diff --git a/src/game/BattleGround/BattleGround.cpp b/src/game/BattleGround/BattleGround.cpp index 226ab0a6215..e4dc7011c5b 100644 --- a/src/game/BattleGround/BattleGround.cpp +++ b/src/game/BattleGround/BattleGround.cpp @@ -290,7 +290,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(); diff --git a/src/game/BattleGround/BattleGround.h b/src/game/BattleGround/BattleGround.h index 051b7aed116..e5591414867 100644 --- a/src/game/BattleGround/BattleGround.h +++ b/src/game/BattleGround/BattleGround.h @@ -673,6 +673,10 @@ class BattleGround void SetPlayerSkinRefLootId(uint32 reflootId) { m_playerSkinReflootId = reflootId; } virtual void AlterTeleportLocation(Player* player, ObjectGuid& transportGuid, float& x, float& y, float& z, float& ori) {} + + 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(); @@ -765,6 +769,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 bc9dec8bcc6..3290864a6b2 100644 --- a/src/game/BattleGround/BattleGroundMgr.cpp +++ b/src/game/BattleGround/BattleGroundMgr.cpp @@ -1285,14 +1285,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(); } /** @@ -1637,7 +1630,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; @@ -1659,13 +1652,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); } /** @@ -1676,7 +1669,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(); } /** @@ -1893,6 +1886,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 54507ca9775..5f5ee75ff25 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; @@ -215,7 +216,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 68adc39cbaa..443393d0042 100644 --- a/src/game/Chat/Level3.cpp +++ b/src/game/Chat/Level3.cpp @@ -3259,7 +3259,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); @@ -3531,10 +3531,7 @@ bool ChatHandler::HandleGuildUninviteCommand(char* args) return false; if (targetGuild->DelMember(target_guid)) - { targetGuild->Disband(); - delete targetGuild; - } return true; } @@ -3599,7 +3596,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 1887d45200d..f20aecfe267 100644 --- a/src/game/Entities/Object.cpp +++ b/src/game/Entities/Object.cpp @@ -48,7 +48,7 @@ #include "MotionGenerators/PathFinder.h" #include "Movement/MoveSpline.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; @@ -81,6 +81,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 5e9ad587fb2..abfac0a7980 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 @@ -389,22 +390,9 @@ class Object virtual ~Object(); const bool& IsInWorld() const { return m_inWorld; } - virtual void AddToWorld() - { - if (m_inWorld) - return; - - m_inWorld = true; + virtual void AddToWorld(); - // 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 RemoveFromWorld(); ObjectGuid const& GetObjectGuid() const { return GetGuidValue(OBJECT_FIELD_GUID); } uint32 GetGUIDLow() const { return GetObjectGuid().GetCounter(); } @@ -683,6 +671,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 c81da6bdec0..c10aca18edf 100644 --- a/src/game/Entities/Player.cpp +++ b/src/game/Entities/Player.cpp @@ -4513,16 +4513,9 @@ 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 9f98197db22..015778193e1 100644 --- a/src/game/Entities/Unit.cpp +++ b/src/game/Entities/Unit.cpp @@ -397,7 +397,6 @@ Unit::~Unit() delete m_combatData; delete m_charmInfo; - delete m_vehicleInfo; delete movespline; // those should be already removed at "RemoveFromWorld()" call @@ -6173,6 +6172,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 @@ -12351,19 +12351,18 @@ void Unit::SetVehicleId(uint32 entry, uint32 overwriteNpcEntry) if (m_vehicleInfo && entry == m_vehicleInfo->GetVehicleEntry()->m_ID) return; - delete m_vehicleInfo; + m_vehicleInfo = nullptr; if (entry) { VehicleEntry const* ventry = sVehicleStore.LookupEntry(entry); MANGOS_ASSERT(ventry != nullptr); - m_vehicleInfo = new VehicleInfo(this, ventry, overwriteNpcEntry); + m_vehicleInfo.reset(new VehicleInfo(this, ventry, overwriteNpcEntry)); m_updateFlag |= UPDATEFLAG_VEHICLE; } else { - m_vehicleInfo = nullptr; m_updateFlag &= ~UPDATEFLAG_VEHICLE; } diff --git a/src/game/Entities/Unit.h b/src/game/Entities/Unit.h index 09023011dc7..789af8862fa 100644 --- a/src/game/Entities/Unit.h +++ b/src/game/Entities/Unit.h @@ -1538,7 +1538,8 @@ class Unit : public WorldObject virtual bool Mount(uint32 displayid, const Aura* aura = nullptr); virtual bool Unmount(const Aura* aura = nullptr); - VehicleInfo* GetVehicleInfo() const { return m_vehicleInfo; } + VehicleInfo* GetVehicleInfo() const { return m_vehicleInfo.get(); } + MaNGOS::unique_weak_ptr GetVehicleInfoWeakPtr() const { return m_vehicleInfo; } bool IsVehicle() const { return m_vehicleInfo != nullptr; } void SetVehicleId(uint32 entry, uint32 overwriteNpcEntry); Unit const* FindRootVehicle(const Unit* whichVehicle = nullptr) const; @@ -2732,7 +2733,7 @@ class Unit : public WorldObject bool m_canDualWield = false; - VehicleInfo* m_vehicleInfo; + MaNGOS::unique_trackable_ptr m_vehicleInfo; void DisableSpline(); void EndSpline(); bool m_isCreatureLinkingTrigger; diff --git a/src/game/Globals/ObjectMgr.cpp b/src/game/Globals/ObjectMgr.cpp index 13e70e73fc5..f8a8a440730 100644 --- a/src/game/Globals/ObjectMgr.cpp +++ b/src/game/Globals/ObjectMgr.cpp @@ -172,9 +172,6 @@ ObjectMgr::ObjectMgr() : ObjectMgr::~ObjectMgr() { - for (auto& mQuestTemplate : mQuestTemplates) - delete mQuestTemplate.second; - for (auto& i : petInfo) delete[] i.second; @@ -4871,9 +4868,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(); @@ -4943,7 +4937,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()); @@ -4953,7 +4948,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) @@ -5533,7 +5528,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; @@ -6036,7 +6031,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 7c25c9a1f53..a00a45f8e89 100644 --- a/src/game/Globals/ObjectMgr.h +++ b/src/game/Globals/ObjectMgr.h @@ -36,6 +36,7 @@ #include "Globals/Conditions.h" #include "Maps/SpawnGroupDefines.h" #include "Entities/Vehicle.h" +#include "Util/UniqueTrackablePtr.h" #include #include @@ -516,7 +517,7 @@ class ObjectMgr typedef std::unordered_map ArenaTeamMap; - typedef std::unordered_map QuestMap; + typedef std::unordered_map> QuestMap; typedef std::unordered_map AreaTriggerMap; @@ -584,7 +585,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 17627a1d34e..23ed85ab31e 100644 --- a/src/game/Groups/Group.cpp +++ b/src/game/Groups/Group.cpp @@ -70,7 +70,7 @@ GroupMemberStatus GetGroupMemberStatus(const Player* member = nullptr) Group::Group() : m_Id(0), m_leaderLastOnline(0), m_groupFlags(GROUP_FLAG_NORMAL), m_dungeonDifficulty(REGULAR_DIFFICULTY), m_raidDifficulty(REGULAR_DIFFICULTY), m_bgGroup(nullptr), m_bfGroup(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 0df7994a141..a74321a414e 100644 --- a/src/game/Groups/Group.h +++ b/src/game/Groups/Group.h @@ -28,6 +28,7 @@ #include "Server/DBCEnums.h" #include "Globals/SharedDefines.h" #include "LFG/LFG.h" +#include "Util/UniqueTrackablePtr.h" struct ItemPrototype; @@ -298,6 +299,8 @@ class Group LFGData& GetLfgData() { return m_lfgData; } + 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); @@ -392,5 +395,8 @@ class Group uint8* m_subGroupsCounts; LFGData m_lfgData; + + 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 d3ed37440c4..1b5193f5814 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; @@ -446,6 +447,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); @@ -482,6 +486,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 ddf5535f969..08bc5e272d5 100644 --- a/src/game/Guilds/GuildHandler.cpp +++ b/src/game/Guilds/GuildHandler.cpp @@ -184,7 +184,6 @@ void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) if (guild->DelMember(slot->guid)) { guild->Disband(); - delete guild; return; } @@ -402,7 +401,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) if (_player->GetObjectGuid() == guild->GetLeaderGuid()) { guild->Disband(); - delete guild; return; } @@ -411,7 +409,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) if (guild->DelMember(_player->GetObjectGuid())) { guild->Disband(); - delete guild; return; } @@ -439,7 +436,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 1777196c3dc..dd24ae0f98a 100644 --- a/src/game/Maps/Map.cpp +++ b/src/game/Maps/Map.cpp @@ -43,6 +43,7 @@ #include "Grids/ObjectGridLoader.h" #include "Vmap/GameObjectModel.h" #include "LFG/LFGMgr.h" +#include "BattleGround/BattleGroundMgr.h" #ifdef BUILD_METRICS #include "Metric/Metric.h" @@ -2124,7 +2125,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 01a14aeb935..04f2c68b5eb 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 @@ -214,6 +215,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; @@ -479,6 +484,7 @@ class Map : public GridRefManager uint8 i_spawnMode; uint32 i_id; uint32 i_InstanceId; + MaNGOS::unique_weak_ptr m_weakRef; uint32 m_unloadTimer; uint32 m_clientUpdateTimer; float m_VisibleDistance; diff --git a/src/game/Maps/MapManager.cpp b/src/game/Maps/MapManager.cpp index f3a82278485..5550120b4e9 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(); } @@ -96,7 +95,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))); @@ -135,7 +136,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(); @@ -168,7 +171,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) @@ -178,13 +181,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); } } } @@ -210,14 +211,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; @@ -254,11 +253,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(); @@ -273,7 +268,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; } @@ -286,7 +281,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(); } @@ -337,7 +332,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; } @@ -390,7 +387,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); @@ -403,11 +402,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 ab71f2783b4..4ed0fcb3191 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); @@ -153,7 +154,7 @@ class MapManager : public MaNGOS::Singleton void DoForAllMapsWithMapId(uint32 mapId, Do& _do); @@ -196,7 +197,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 @@ -204,7 +205,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 1e6234d063b..829078244b9 100644 --- a/src/game/Quests/QuestDef.h +++ b/src/game/Quests/QuestDef.h @@ -22,6 +22,7 @@ #include "Platform/Define.h" #include "Database/DatabaseEnv.h" #include "Server/DBCEnums.h" +#include "Util/UniqueTrackablePtr.h" #include @@ -319,6 +320,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; @@ -396,6 +399,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 1b5f4cf0dac..bf255bf5a0d 100644 --- a/src/game/Spells/Spell.cpp +++ b/src/game/Spells/Spell.cpp @@ -8486,23 +8486,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); - } } bool SpellEvent::Execute(uint64 e_time, uint32 p_time) diff --git a/src/game/Spells/Spell.h b/src/game/Spells/Spell.h index 9738e1f9851..a2558119179 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; @@ -327,9 +328,9 @@ class SpellEvent : public BasicEvent virtual void Abort(uint64 e_time) override; virtual bool IsDeletable() const override; - Spell* GetSpell() const { return m_Spell; } + Spell* GetSpell() const { return m_Spell.get(); } protected: - Spell* m_Spell; + MaNGOS::unique_trackable_ptr m_Spell; }; class SpellModRAII diff --git a/src/game/Spells/SpellAuras.cpp b/src/game/Spells/SpellAuras.cpp index 404c71bce20..39fc2484ef5 100755 --- a/src/game/Spells/SpellAuras.cpp +++ b/src/game/Spells/SpellAuras.cpp @@ -385,7 +385,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 17636283b8e..3809e779acd 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. @@ -569,6 +570,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); @@ -610,6 +614,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); };