From 0028ca1128917fc374f02a1b45d1a1959b2d5312 Mon Sep 17 00:00:00 2001 From: Niam5 Date: Sat, 17 Aug 2024 22:27:43 -0700 Subject: [PATCH] Misc: Use new unique_trackable_ptr for various classes exposed to scripts (not actually used anywhere currently) Co-Authored-By: Shauren --- src/game/BattleGround/BattleGround.cpp | 4 --- src/game/BattleGround/BattleGround.h | 7 +++- src/game/BattleGround/BattleGroundMgr.cpp | 17 ++++++--- src/game/BattleGround/BattleGroundMgr.h | 5 +-- src/game/Chat/Level3.cpp | 6 +--- src/game/Entities/Object.cpp | 28 +++++++++++++-- src/game/Entities/Object.h | 24 +++++-------- src/game/Entities/Player.cpp | 7 ---- src/game/Entities/Unit.cpp | 7 ++-- src/game/Entities/Unit.h | 5 +-- src/game/Entities/Vehicle.cpp | 6 ++++ src/game/Entities/Vehicle.h | 2 ++ src/game/Globals/ObjectMgr.cpp | 11 ++---- 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/LuaEngine | 2 +- src/game/Maps/Map.cpp | 1 + src/game/Maps/Map.h | 6 ++++ src/game/Maps/MapManager.cpp | 43 +++++++++++------------ src/game/Maps/MapManager.h | 7 ++-- src/game/Quests/QuestDef.h | 5 +++ src/game/Spells/Spell.cpp | 30 +++++++++------- src/game/Spells/Spell.h | 34 +++++++++++------- src/game/Spells/SpellAuras.cpp | 2 +- src/game/Spells/SpellAuras.h | 8 +++++ 30 files changed, 183 insertions(+), 122 deletions(-) diff --git a/src/game/BattleGround/BattleGround.cpp b/src/game/BattleGround/BattleGround.cpp index a5ec1273a7..3a1bf90fac 100644 --- a/src/game/BattleGround/BattleGround.cpp +++ b/src/game/BattleGround/BattleGround.cpp @@ -240,10 +240,6 @@ BattleGround::BattleGround(): m_BuffChange(false), m_ArenaBuffSpawned(false), m_ 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 615cd4b7f8..cdc2f93cff 100644 --- a/src/game/BattleGround/BattleGround.h +++ b/src/game/BattleGround/BattleGround.h @@ -398,7 +398,7 @@ class BattleGround /* Map pointers */ void SetBgMap(BattleGroundMap* map) { m_Map = map; } - BattleGroundMap* GetBgMap() + BattleGroundMap* GetBgMap() const { MANGOS_ASSERT(m_Map); return m_Map; @@ -560,6 +560,9 @@ class BattleGround // door-events are automaticly added - but _ALL_ other must be in this vector std::map m_ActiveEvents; + 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(); @@ -641,6 +644,8 @@ class BattleGround float m_TeamStartLocZ[PVP_TEAM_COUNT]; float m_TeamStartLocO[PVP_TEAM_COUNT]; float m_startMaxDist; + + 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 d5f07feff8..079c35eab0 100644 --- a/src/game/BattleGround/BattleGroundMgr.cpp +++ b/src/game/BattleGround/BattleGroundMgr.cpp @@ -1149,7 +1149,7 @@ void BattleGroundMgr::DeleteAllBattleGrounds() { for (BattleGroundSet::iterator itr = m_BattleGrounds[i].begin(); itr != m_BattleGrounds[i].end();) { - BattleGround* bg = itr->second; + BattleGround* bg = itr->second.get(); ++itr; // step from invalidate iterator pos in result element remove in ~BattleGround call delete bg; } @@ -1672,7 +1672,7 @@ BattleGround* BattleGroundMgr::GetBattleGroundThroughClientInstance(uint32 insta for (BattleGroundSet::iterator itr = m_BattleGrounds[bgTypeId].begin(); itr != m_BattleGrounds[bgTypeId].end(); ++itr) { if (itr->second->GetClientInstanceID() == instanceId) - return itr->second; + return itr->second.get(); } return nullptr; } @@ -1687,18 +1687,18 @@ 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); } 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(); } uint32 BattleGroundMgr::CreateClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracket_id) @@ -1858,6 +1858,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); +} + void BattleGroundMgr::CreateInitialBattleGrounds() { uint32 count = 0; diff --git a/src/game/BattleGround/BattleGroundMgr.h b/src/game/BattleGround/BattleGroundMgr.h index 4cd6b3ac84..bda324c16c 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; @@ -209,7 +210,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); - 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 bracket_id); void DeleteClientVisibleInstanceId(BattleGroundTypeId bgTypeId, BattleGroundBracketId bracket_id, uint32 clientInstanceID) diff --git a/src/game/Chat/Level3.cpp b/src/game/Chat/Level3.cpp index 0d78689a69..072ca605d3 100644 --- a/src/game/Chat/Level3.cpp +++ b/src/game/Chat/Level3.cpp @@ -3646,7 +3646,7 @@ bool ChatHandler::HandleLookupQuestCommand(char* args) ObjectMgr::QuestMap const& qTemplates = sObjectMgr.GetQuestTemplates(); for (ObjectMgr::QuestMap::const_iterator iter = qTemplates.begin(); iter != qTemplates.end(); ++iter) { - Quest* qinfo = iter->second; + Quest* qinfo = iter->second.get(); std::string title; // "" for avoid repeating check default locale sObjectMgr.GetQuestLocaleStrings(qinfo->GetQuestId(), loc_idx, &title); @@ -3918,10 +3918,7 @@ bool ChatHandler::HandleGuildUninviteCommand(char* args) return false; if (targetGuild->DelMember(target_guid)) - { targetGuild->Disband(); - delete targetGuild; - } return true; } @@ -3975,7 +3972,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 c39963ffdc..41794d016f 100644 --- a/src/game/Entities/Object.cpp +++ b/src/game/Entities/Object.cpp @@ -47,7 +47,7 @@ #include "LuaEngine/ElunaEventMgr.h" #endif -Object::Object(): m_updateFlag(0) +Object::Object(): m_updateFlag(0), m_scriptRef(this, NoopObjectDeleter()) { m_objectTypeId = TYPEID_OBJECT; m_objectType = TYPEMASK_OBJECT; @@ -57,7 +57,7 @@ Object::Object(): m_updateFlag(0) m_inWorld = false; m_objectUpdated = false; - loot = nullptr; + loot = nullptr; } Object::~Object() @@ -80,6 +80,30 @@ Object::~Object() delete 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 38bfd934e9..c4bc43cc91 100644 --- a/src/game/Entities/Object.h +++ b/src/game/Entities/Object.h @@ -27,6 +27,7 @@ #include "Entities/EntitiesMgr.h" #include "Globals/SharedDefines.h" #include "Camera.h" +#include "Util/UniqueTrackablePtr.h" #include "Util/Util.h" #ifdef BUILD_ELUNA #include "LuaEngine/LuaValue.h" @@ -315,22 +316,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(); } @@ -566,6 +553,8 @@ class Object Loot* loot; + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + protected: Object(); @@ -607,6 +596,9 @@ class Object Object(const Object&); // prevent generation copy constructor Object& operator=(Object const&); // prevent generation assigment operator + 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 257173f9e4..c76637c04f 100644 --- a/src/game/Entities/Player.cpp +++ b/src/game/Entities/Player.cpp @@ -4496,16 +4496,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 ec9dbb67c2..72df363cd0 100644 --- a/src/game/Entities/Unit.cpp +++ b/src/game/Entities/Unit.cpp @@ -641,7 +641,6 @@ Unit::~Unit() delete m_combatData; delete m_charmInfo; - delete m_vehicleInfo; delete movespline; // those should be already removed at "RemoveFromWorld()" call @@ -5941,6 +5940,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 @@ -12943,19 +12943,18 @@ void Unit::OnRelocated() */ void Unit::SetVehicleId(uint32 entry, uint32 overwriteNpcEntry) { - 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 c63957342f..db04938337 100644 --- a/src/game/Entities/Unit.h +++ b/src/game/Entities/Unit.h @@ -1644,7 +1644,8 @@ class Unit : public WorldObject void Unmount(bool from_aura = false); MountCapabilityEntry const* GetMountCapability(uint32 mountType) const; - 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; @@ -2540,7 +2541,7 @@ class Unit : public WorldObject bool m_canParry; bool m_canBlock; - VehicleInfo* m_vehicleInfo; + MaNGOS::unique_trackable_ptr m_vehicleInfo; void DisableSpline(); bool m_isCreatureLinkingTrigger; bool m_isSpawningLinked; diff --git a/src/game/Entities/Vehicle.cpp b/src/game/Entities/Vehicle.cpp index 6322576787..c42df2d2bd 100644 --- a/src/game/Entities/Vehicle.cpp +++ b/src/game/Entities/Vehicle.cpp @@ -624,4 +624,10 @@ void VehicleInfo::RemoveSeatMods(Unit* passenger, uint32 seatFlags) } } +MaNGOS::unique_weak_ptr VehicleInfo::GetWeakPtr() const +{ + Unit* pVehicle = (Unit*)m_owner; + return pVehicle->GetVehicleInfoWeakPtr(); +} + /*! @} */ diff --git a/src/game/Entities/Vehicle.h b/src/game/Entities/Vehicle.h index 27123b90cd..32cf748600 100644 --- a/src/game/Entities/Vehicle.h +++ b/src/game/Entities/Vehicle.h @@ -79,6 +79,8 @@ class VehicleInfo : public TransportBase void RemoveAccessoriesFromMap(); ///< Unsummones accessory in case of far-teleport or death + MaNGOS::unique_weak_ptr GetWeakPtr() const; + private: // Internal use to calculate the boarding position void CalculateBoardingPositionOf(float gx, float gy, float gz, float go, float& lx, float& ly, float& lz, float& lo) const; diff --git a/src/game/Globals/ObjectMgr.cpp b/src/game/Globals/ObjectMgr.cpp index 1647269444..761b2d2a6a 100644 --- a/src/game/Globals/ObjectMgr.cpp +++ b/src/game/Globals/ObjectMgr.cpp @@ -163,9 +163,6 @@ ObjectMgr::ObjectMgr() : ObjectMgr::~ObjectMgr() { - for (QuestMap::iterator i = mQuestTemplates.begin(); i != mQuestTemplates.end(); ++i) - delete i->second; - for (PetLevelInfoMap::iterator i = petInfo.begin(); i != petInfo.end(); ++i) delete[] i->second; @@ -3734,9 +3731,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(); @@ -3813,7 +3807,8 @@ void ObjectMgr::LoadQuests() Field* fields = result->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 (result->NextRow()); @@ -3825,7 +3820,7 @@ void ObjectMgr::LoadQuests() for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); ++iter) { - Quest* qinfo = iter->second; + Quest* qinfo = iter->second.get(); // additional quest integrity checks (GO, creature_template and item_template must be loaded already) diff --git a/src/game/Globals/ObjectMgr.h b/src/game/Globals/ObjectMgr.h index ee93310be1..5cc489835d 100644 --- a/src/game/Globals/ObjectMgr.h +++ b/src/game/Globals/ObjectMgr.h @@ -33,6 +33,7 @@ #include "Maps/MapPersistentStateMgr.h" #include "Globals/ObjectAccessor.h" #include "Entities/ObjectGuid.h" +#include "Util/UniqueTrackablePtr.h" #include #include @@ -545,7 +546,7 @@ class ObjectMgr typedef std::unordered_map ArenaTeamMap; - typedef std::unordered_map QuestMap; + typedef std::unordered_map> QuestMap; typedef std::unordered_map AreaTriggerMap; @@ -604,7 +605,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 316b7e99cd..4e4021ec82 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_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(REGULAR_DIFFICULTY), m_raidDifficulty(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 22a2dec866..51eb70b2f1 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" struct ItemPrototype; @@ -310,6 +311,8 @@ class Group InstanceGroupBind* GetBoundInstance(Map* aMap, Difficulty difficulty); BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } + 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); @@ -400,5 +403,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 feecc0e8be..3142fdc20b 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; @@ -492,6 +493,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); + 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); @@ -530,6 +534,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 e7d83bb84c..9df98a93ca 100644 --- a/src/game/Guilds/GuildHandler.cpp +++ b/src/game/Guilds/GuildHandler.cpp @@ -252,7 +252,6 @@ void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) if (guild->DelMember(slot->guid)) { guild->Disband(); - delete guild; return; } @@ -615,7 +614,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) if (_player->GetObjectGuid() == guild->GetLeaderGuid()) { guild->Disband(); - delete guild; return; } @@ -624,7 +622,6 @@ void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) if (guild->DelMember(_player->GetObjectGuid())) { guild->Disband(); - delete guild; return; } @@ -659,7 +656,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 57696d1cf3..463bcf3cf1 100644 --- a/src/game/Guilds/GuildMgr.cpp +++ b/src/game/Guilds/GuildMgr.cpp @@ -33,13 +33,13 @@ GuildMgr::GuildMgr() GuildMgr::~GuildMgr() { - for (GuildMap::iterator itr = m_GuildMap.begin(); itr != m_GuildMap.end(); ++itr) - 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) @@ -59,7 +59,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; } @@ -76,7 +76,7 @@ Guild* GuildMgr::GetGuildByName(std::string const& name) const { for (GuildMap::const_iterator itr = m_GuildMap.begin(); itr != m_GuildMap.end(); ++itr) if (itr->second->GetName() == name) - return itr->second; + return itr->second.get(); return nullptr; } @@ -85,7 +85,7 @@ Guild* GuildMgr::GetGuildByLeader(ObjectGuid const& guid) const { for (GuildMap::const_iterator itr = m_GuildMap.begin(); itr != m_GuildMap.end(); ++itr) 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 151583fc27..262ee02dec 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/LuaEngine b/src/game/LuaEngine index f34e8987df..5ca638f99f 160000 --- a/src/game/LuaEngine +++ b/src/game/LuaEngine @@ -1 +1 @@ -Subproject commit f34e8987df9648fdc7c28867f970df54b7ee3e18 +Subproject commit 5ca638f99fcd4a9f2cc94b42d0443ffa010618d0 diff --git a/src/game/Maps/Map.cpp b/src/game/Maps/Map.cpp index 9ff3246087..50d665db43 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 "Grids/ObjectGridLoader.h" +#include "Util/UniqueTrackablePtr.h" #ifdef BUILD_ELUNA #include "LuaEngine/LuaEngine.h" diff --git a/src/game/Maps/Map.h b/src/game/Maps/Map.h index fd96d8f1c9..d056fdd09b 100644 --- a/src/game/Maps/Map.h +++ b/src/game/Maps/Map.h @@ -33,6 +33,7 @@ #include "MapRefManager.h" #include "DBScripts/ScriptMgr.h" #include "Entities/CreatureLinkingMgr.h" +#include "Util/UniqueTrackablePtr.h" #include "Vmap/DynamicTree.h" #ifdef BUILD_ELUNA @@ -177,6 +178,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; @@ -370,6 +375,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 af30fe3f02..4378b79612 100644 --- a/src/game/Maps/MapManager.cpp +++ b/src/game/Maps/MapManager.cpp @@ -43,8 +43,7 @@ MapManager::MapManager() MapManager::~MapManager() { - for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter) - delete iter->second; + i_maps.clear(); for (TransportSet::iterator i = m_Transports.begin(); i != m_Transports.end(); ++i) delete *i; @@ -116,7 +115,9 @@ Map* MapManager::CreateMap(uint32 id, const WorldObject* obj) { m = new WorldMap(id, i_gridCleanUpDelay); // 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 m->CreateInstanceData(true); @@ -149,7 +150,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) @@ -159,13 +160,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); } } } @@ -189,14 +188,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; @@ -233,11 +230,7 @@ void MapManager::UnloadAll() for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end(); ++iter) iter->second->UnloadAll(true); - while (!i_maps.empty()) - { - delete i_maps.begin()->second; - i_maps.erase(i_maps.begin()); - } + i_maps.clear(); TerrainManager::Instance().UnloadAll(); } @@ -247,7 +240,7 @@ uint32 MapManager::GetNumInstances() uint32 ret = 0; for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) { - Map* map = itr->second; + Map* map = itr->second.get(); if (!map->IsDungeon()) continue; ret += 1; } @@ -259,7 +252,7 @@ uint32 MapManager::GetNumPlayersInInstances() uint32 ret = 0; for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) { - Map* map = itr->second; + Map* map = itr->second.get(); if (!map->IsDungeon()) continue; ret += map->GetPlayers().getSize(); } @@ -305,7 +298,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; } @@ -355,7 +350,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->CreateInstanceData(false); diff --git a/src/game/Maps/MapManager.h b/src/game/Maps/MapManager.h index 2a397a078f..5a53d9b01d 100644 --- a/src/game/Maps/MapManager.h +++ b/src/game/Maps/MapManager.h @@ -24,6 +24,7 @@ #include "Policies/Singleton.h" #include "Maps/Map.h" #include "Grids/GridStates.h" +#include "Util/UniqueTrackablePtr.h" class Transport; class BattleGround; @@ -56,7 +57,7 @@ class MapManager : public MaNGOS::Singleton::Lock Guard; public: - typedef std::map MapMapType; + typedef std::map > MapMapType; Map* CreateMap(uint32, const WorldObject* obj); Map* CreateBgMap(uint32 mapid, BattleGround* bg); @@ -137,7 +138,7 @@ class MapManager : public MaNGOS::Singleton worker) { for (MapMapType::const_iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) - worker(itr->second); + worker(itr->second.get()); } private: @@ -172,7 +173,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()); } #define sMapMgr MapManager::Instance() diff --git a/src/game/Quests/QuestDef.h b/src/game/Quests/QuestDef.h index c3cf693cb7..6ab8bedfeb 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 @@ -326,6 +327,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; @@ -409,6 +412,8 @@ class Quest uint32 QuestCompleteScript; uint32 SoundAcceptId; uint32 SoundTurnInId; + + MaNGOS::unique_weak_ptr m_weakRef; }; enum QuestUpdateState diff --git a/src/game/Spells/Spell.cpp b/src/game/Spells/Spell.cpp index 7707d8e6e5..c2e1c915b8 100644 --- a/src/game/Spells/Spell.cpp +++ b/src/game/Spells/Spell.cpp @@ -425,7 +425,7 @@ void SpellLog::SendToSet() // *********** Spell::Spell(Unit* caster, SpellEntry const* info, uint32 triggeredFlags, ObjectGuid originalCasterGUID, SpellEntry const* triggeredBy) : - m_spellLog(this) + m_spellEvent(nullptr), m_spellLog(this) { MANGOS_ASSERT(caster != nullptr && info != nullptr); MANGOS_ASSERT(info == sSpellTemplate.LookupEntry(info->Id) && "`info` must be pointer to sSpellTemplate element"); @@ -7900,23 +7900,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()) - { - 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) @@ -8417,3 +8418,8 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r break; } } + +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 35af547ee5..ac84eee678 100644 --- a/src/game/Spells/Spell.h +++ b/src/game/Spells/Spell.h @@ -27,6 +27,7 @@ #include "Entities/Unit.h" #include "Entities/Player.h" #include "Server/SQLStorages.h" +#include "Util/UniqueTrackablePtr.h" class WorldSession; class WorldPacket; @@ -303,6 +304,23 @@ class SpellLog uint32 m_currentEffect; }; +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; @@ -581,6 +599,8 @@ class Spell typedef std::list UnitList; + 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 @@ -755,6 +775,8 @@ class Spell // and in same time need aura data and after aura deleting. SpellEntry const* m_triggeredByAuraSpell; + SpellEvent* m_spellEvent; + private: // NPC Summonings struct CreaturePosition @@ -997,16 +1019,4 @@ namespace MaNGOS typedef void(Spell::*pEffect)(SpellEffectEntry const* spellEffect); -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; - protected: - Spell* m_Spell; -}; #endif diff --git a/src/game/Spells/SpellAuras.cpp b/src/game/Spells/SpellAuras.cpp index e52f273c70..9427e3d7c9 100644 --- a/src/game/Spells/SpellAuras.cpp +++ b/src/game/Spells/SpellAuras.cpp @@ -435,7 +435,7 @@ static AuraType const frozenAuraTypes[] = { SPELL_AURA_MOD_ROOT, SPELL_AURA_MOD_ Aura::Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster, Item* castItem) : 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_spellAuraHolder(holder) + m_isPersistent(false), m_spellAuraHolder(holder), m_scriptRef(this, NoopAuraDeleter()) { 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 f9b9f8620d..d51fe44f4e 100644 --- a/src/game/Spells/SpellAuras.h +++ b/src/game/Spells/SpellAuras.h @@ -21,6 +21,7 @@ #include "Spells/SpellAuraDefines.h" #include "Server/DBCEnums.h" #include "Entities/ObjectGuid.h" +#include "Util/UniqueTrackablePtr.h" /** * Used to modify what an Aura does to a player/npc. @@ -487,6 +488,10 @@ class Aura bool IsLastAuraOnHolder(); bool HasMechanic(uint32 mechanic) const; + + MaNGOS::unique_weak_ptr GetWeakPtr() const { return m_scriptRef; } + void InvalidateScriptRef() { m_scriptRef = nullptr; } + protected: Aura(SpellEntry const* spellproto, SpellEffectIndex eff, int32* currentBasePoints, SpellAuraHolder* holder, Unit* target, Unit* caster = nullptr, Item* castItem = nullptr); @@ -519,6 +524,9 @@ class Aura bool m_isPersistent: 1; SpellAuraHolder* const m_spellAuraHolder; + + struct NoopAuraDeleter { void operator()(Aura*) const { /*noop - not managed*/ } }; + MaNGOS::unique_trackable_ptr m_scriptRef; private: void ReapplyAffectedPassiveAuras(Unit* target, bool owner_mode); };