diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-03-13 18:51:29 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-03-14 00:14:16 +0100 |
commit | a79b42bf681e211997923dbc6c191aae187aded6 (patch) | |
tree | dc52e4651fe17d4e6ce3437490d07313113432aa | |
parent | 7850107a42e7709f6e92f542860160b8c1432c94 (diff) |
Core/Misc: Use our new unique_trackable_ptr for various classes exposed to scripts (not actually used anywhere currently)
(cherry picked from commit 4779fa5048642b57a0f69de7ab56b9d563c1cbc4)
34 files changed, 218 insertions, 161 deletions
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index a06c87d2eeb..938ac559b4c 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -145,7 +145,6 @@ Battleground::~Battleground() for (uint32 i = 0; i < size; ++i) DelObject(i); - sBattlegroundMgr->RemoveBattleground(GetTypeID(), GetInstanceID()); // unload map if (m_Map) { diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 4671ba22780..76c98c3f6c2 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -23,6 +23,7 @@ #include "ObjectGuid.h" #include "Position.h" #include "SharedDefines.h" +#include "UniqueTrackablePtr.h" #include <deque> #include <map> @@ -496,6 +497,9 @@ class TC_GAME_API Battleground // because BattleGrounds with different types and same level range has different m_BracketId uint8 GetUniqueBracketId() const; + Trinity::unique_weak_ptr<Battleground> GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(Trinity::unique_weak_ptr<Battleground> 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(); @@ -626,5 +630,7 @@ class TC_GAME_API Battleground Position StartPosition[PVP_TEAMS_COUNT]; float m_StartMaxDist; uint32 ScriptId; + + Trinity::unique_weak_ptr<Battleground> m_weakRef; }; #endif diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index b59831ff05d..1b3d2f0c851 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -69,18 +69,6 @@ BattlegroundMgr::~BattlegroundMgr() void BattlegroundMgr::DeleteAllBattlegrounds() { - for (BattlegroundDataContainer::iterator itr1 = bgDataStore.begin(); itr1 != bgDataStore.end(); ++itr1) - { - BattlegroundData& data = itr1->second; - - while (!data.m_Battlegrounds.empty()) - delete data.m_Battlegrounds.begin()->second; - data.m_Battlegrounds.clear(); - - while (!data.BGFreeSlotQueue.empty()) - delete data.BGFreeSlotQueue.front(); - } - bgDataStore.clear(); } @@ -104,18 +92,19 @@ void BattlegroundMgr::Update(uint32 diff) for (BattlegroundContainer::iterator itr = ++itrDelete; itr != bgs.end();) { itrDelete = itr++; - Battleground* bg = itrDelete->second; + Battleground* bg = itrDelete->second.get(); bg->Update(m_UpdateTimer); if (bg->ToBeDeleted()) { - itrDelete->second = nullptr; - bgs.erase(itrDelete); BattlegroundClientIdsContainer& clients = itr1->second.m_ClientBattlegroundIds[bg->GetBracketId()]; if (!clients.empty()) clients.erase(bg->GetClientInstanceID()); - delete bg; + // move out unique_ptr to delete after erasing + Trinity::unique_trackable_ptr<Battleground> bgPtr = std::move(itrDelete->second); + + bgs.erase(itrDelete); } } } @@ -274,7 +263,7 @@ Battleground* BattlegroundMgr::GetBattlegroundThroughClientInstance(uint32 insta for (BattlegroundContainer::const_iterator itr = it->second.m_Battlegrounds.begin(); itr != it->second.m_Battlegrounds.end(); ++itr) { if (itr->second->GetClientInstanceID() == instanceId) - return itr->second; + return itr->second.get(); } return nullptr; @@ -305,7 +294,7 @@ Battleground* BattlegroundMgr::GetBattleground(uint32 instanceId, BattlegroundTy BattlegroundContainer const& bgs = it->second.m_Battlegrounds; BattlegroundContainer::const_iterator itr = bgs.find(instanceId); if (itr != bgs.end()) - return itr->second; + return itr->second.get(); } return nullptr; @@ -319,7 +308,7 @@ Battleground* BattlegroundMgr::GetBattlegroundTemplate(BattlegroundTypeId bgType BattlegroundContainer const& bgs = itr->second.m_Battlegrounds; //map is sorted and we can be sure that lowest instance id has only BG template - return bgs.empty() ? nullptr : bgs.begin()->second; + return bgs.empty() ? nullptr : bgs.begin()->second.get(); } uint32 BattlegroundMgr::CreateClientVisibleInstanceId(BattlegroundTypeId bgTypeId, BattlegroundBracketId bracket_id) @@ -1015,10 +1004,9 @@ void BattlegroundMgr::RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uin void BattlegroundMgr::AddBattleground(Battleground* bg) { if (bg) - bgDataStore[bg->GetTypeID()].m_Battlegrounds[bg->GetInstanceID()] = bg; -} - -void BattlegroundMgr::RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId) -{ - bgDataStore[bgTypeId].m_Battlegrounds.erase(instanceId); + { + Trinity::unique_trackable_ptr<Battleground>& ptr = bgDataStore[bg->GetTypeID()].m_Battlegrounds[bg->GetInstanceID()]; + ptr.reset(bg); + bg->SetWeakPtr(ptr); + } } diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 7335abe190d..939d3ef87b1 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -22,11 +22,12 @@ #include "DBCEnums.h" #include "Battleground.h" #include "BattlegroundQueue.h" +#include "UniqueTrackablePtr.h" #include <unordered_map> struct BattlemasterListEntry; -typedef std::map<uint32, Battleground*> BattlegroundContainer; +typedef std::map<uint32, Trinity::unique_trackable_ptr<Battleground>> BattlegroundContainer; typedef std::set<uint32> BattlegroundClientIdsContainer; typedef std::unordered_map<uint32, BattlegroundTypeId> BattleMastersMap; @@ -68,6 +69,11 @@ class TC_GAME_API BattlegroundMgr ~BattlegroundMgr(); public: + BattlegroundMgr(BattlegroundMgr const& right) = delete; + BattlegroundMgr(BattlegroundMgr&& right) = delete; + BattlegroundMgr& operator=(BattlegroundMgr const& right) = delete; + BattlegroundMgr& operator=(BattlegroundMgr&& right) = delete; + static BattlegroundMgr* instance(); void Update(uint32 diff); @@ -87,7 +93,6 @@ class TC_GAME_API BattlegroundMgr Battleground* CreateNewBattleground(BattlegroundTypeId bgTypeId, PvPDifficultyEntry const* bracketEntry, uint8 arenaType, bool isRated); void AddBattleground(Battleground* bg); - void RemoveBattleground(BattlegroundTypeId bgTypeId, uint32 instanceId); void AddToBGFreeSlotQueue(BattlegroundTypeId bgTypeId, Battleground* bg); void RemoveFromBGFreeSlotQueue(BattlegroundTypeId bgTypeId, uint32 instanceId); BGFreeSlotQueueContainer& GetBGFreeSlotQueueStore(BattlegroundTypeId bgTypeId); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 416df2cce7b..9765ef91434 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -61,7 +61,7 @@ constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max MAX_VISIBILITY_DISTANCE }; -Object::Object() +Object::Object() : m_scriptRef(this, NoopObjectDeleter()) { m_objectTypeId = TYPEID_OBJECT; m_objectType = TYPEMASK_OBJECT; @@ -151,6 +151,11 @@ void Object::AddToWorld() // synchronize values mirror with values array (changes will send in updatecreate opcode any way ASSERT(!m_objectUpdated); ClearUpdateMask(false); + + // 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() @@ -162,6 +167,8 @@ void Object::RemoveFromWorld() // if we remove from world then sending changes not required ClearUpdateMask(true); + + m_scriptRef = nullptr; } void Object::BuildMovementUpdateBlock(UpdateData* data, uint32 flags) const diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 3a72759bb74..abf3bd3bf98 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -29,6 +29,7 @@ #include "Position.h" #include "SharedDefines.h" #include "SpellDefines.h" +#include "UniqueTrackablePtr.h" #include "UpdateFields.h" #include "UpdateMask.h" #include <list> @@ -200,6 +201,8 @@ class TC_GAME_API Object virtual std::string GetDebugInfo() const; + Trinity::unique_weak_ptr<Object> GetWeakPtr() const { return m_scriptRef; } + protected: Object(); @@ -243,8 +246,12 @@ class TC_GAME_API Object PackedGuid m_PackGUID; + struct NoopObjectDeleter { void operator()(Object*) const { /*noop - not managed*/ } }; + Trinity::unique_trackable_ptr<Object> m_scriptRef; + // for output helpfull error messages from asserts bool PrintIndexError(uint32 index, bool set) const; + Object(Object const& right) = delete; Object(Object&& right) = delete; Object& operator=(Object const& right) = delete; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ef84452914b..b4c0139c766 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4018,7 +4018,7 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); if (ObjectGuid::LowType guildId = sCharacterCache->GetCharacterGuildIdByGuid(playerguid)) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) - guild->DeleteMember(trans, playerguid, false, false, true); + guild->DeleteMember(trans, playerguid, false, false); // close player ticket if any GmTicket* ticket = sTicketMgr->GetTicketByPlayer(playerguid); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d31025c40ce..71ca198c61e 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -4177,8 +4177,8 @@ void Unit::RemoveAllAuras() { sstr << "m_ownedAuras:" << "\n"; - for (std::pair<uint32 const, Aura*>& auraPair : m_ownedAuras) - sstr << auraPair.second->GetDebugInfo() << "\n"; + for (auto const& [spellId, aura] : m_ownedAuras) + sstr << aura->GetDebugInfo() << "\n"; } TC_LOG_ERROR("entities.unit", "{}", sstr.str()); @@ -9638,6 +9638,12 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup) if (IsInWorld()) RemoveFromWorld(); + else + { + // cleanup that must happen even if not in world + if (IsVehicle()) + RemoveVehicleKit(); + } ASSERT(GetGUID()); @@ -11810,7 +11816,7 @@ bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry) if (!vehInfo) return false; - m_vehicleKit = new Vehicle(this, vehInfo, creatureEntry); + m_vehicleKit = Trinity::make_unique_trackable<Vehicle>(this, vehInfo, creatureEntry); m_updateFlag |= UPDATEFLAG_VEHICLE; m_unitTypeMask |= UNIT_MASK_VEHICLE; return true; @@ -11822,8 +11828,6 @@ void Unit::RemoveVehicleKit() return; m_vehicleKit->Uninstall(); - delete m_vehicleKit; - m_vehicleKit = nullptr; m_updateFlag &= ~UPDATEFLAG_VEHICLE; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index c39eb4328bc..970d55a274a 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1730,7 +1730,8 @@ class TC_GAME_API Unit : public WorldObject ObjectGuid LastCharmerGUID; bool CreateVehicleKit(uint32 id, uint32 creatureEntry); void RemoveVehicleKit(); - Vehicle* GetVehicleKit() const { return m_vehicleKit; } + Vehicle* GetVehicleKit() const { return m_vehicleKit.get(); } + Trinity::unique_weak_ptr<Vehicle> GetVehicleKitWeakPtr() const { return m_vehicleKit; } Vehicle* GetVehicle() const { return m_vehicle; } void SetVehicle(Vehicle* vehicle) { m_vehicle = vehicle; } bool IsOnVehicle(Unit const* vehicle) const; @@ -1892,7 +1893,7 @@ class TC_GAME_API Unit : public WorldObject uint32 m_regenTimer; Vehicle* m_vehicle; - Vehicle* m_vehicleKit; + Trinity::unique_trackable_ptr<Vehicle> m_vehicleKit; uint32 m_unitTypeMask; LiquidTypeEntry const* _lastLiquid; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index c94ea836f06..4011703c7c2 100755 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -989,3 +989,8 @@ std::string Vehicle::GetDebugInfo() const return sstr.str(); } + +Trinity::unique_weak_ptr<Vehicle> Vehicle::GetWeakPtr() const +{ + return _me->GetVehicleKitWeakPtr(); +} diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h index b9cc63bc744..d59c440bfdf 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.h +++ b/src/server/game/Entities/Vehicle/Vehicle.h @@ -20,8 +20,9 @@ #include "ObjectDefines.h" #include "Object.h" -#include "VehicleDefines.h" +#include "UniqueTrackablePtr.h" #include "Unit.h" +#include "VehicleDefines.h" #include <list> struct VehicleEntry; @@ -30,14 +31,10 @@ class VehicleJoinEvent; class TC_GAME_API Vehicle : public TransportBase { - protected: - friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry); + public: Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry); - - friend void Unit::RemoveVehicleKit(); ~Vehicle(); - public: void Install(); void Uninstall(); void Reset(bool evading = false); @@ -73,6 +70,8 @@ class TC_GAME_API Vehicle : public TransportBase std::string GetDebugInfo() const; + Trinity::unique_weak_ptr<Vehicle> GetWeakPtr() const; + protected: friend class VehicleJoinEvent; uint32 UsableSeatNum; ///< Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 67bf9047c82..3aea616d607 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -4759,7 +4759,8 @@ void ObjectMgr::LoadQuests() Field* fields = result->Fetch(); uint32 questId = fields[0].GetUInt32(); - _questTemplates.emplace(std::piecewise_construct, std::forward_as_tuple(questId), std::forward_as_tuple(fields)); + auto itr = _questTemplates.emplace(std::piecewise_construct, std::forward_as_tuple(questId), std::forward_as_tuple(new Quest(fields))).first; + itr->second->_weakRef = itr->second; } while (result->NextRow()); std::unordered_map<uint32, uint32> usedMailTemplates; @@ -4808,7 +4809,7 @@ void ObjectMgr::LoadQuests() auto itr = _questTemplates.find(questId); if (itr != _questTemplates.end()) - (itr->second.*loader.LoaderFunction)(fields); + (itr->second.get()->*loader.LoaderFunction)(fields); else TC_LOG_ERROR("server.loading", "Table `{}` has data for quest {} but such quest does not exist", loader.TableName, questId); } while (result->NextRow()); @@ -4822,7 +4823,7 @@ void ObjectMgr::LoadQuests() if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) continue; - Quest* qinfo = &questPair.second; + Quest* qinfo = questPair.second.get(); // additional quest integrity checks (GO, creature_template and item_template must be loaded already) @@ -5329,7 +5330,7 @@ void ObjectMgr::LoadQuests() auto prevQuestItr = _questTemplates.find(prevQuestId); if (prevQuestItr == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest {} has PrevQuestId {}, but no such quest", qinfo->GetQuestId(), qinfo->_prevQuestId); - else if (prevQuestItr->second._breadcrumbForQuestId) + else if (prevQuestItr->second->_breadcrumbForQuestId) TC_LOG_ERROR("sql.sql", "Quest {} should not be unlocked by breadcrumb quest {}", qinfo->_id, prevQuestId); else if (qinfo->_prevQuestId > 0) qinfo->DependentPreviousQuests.push_back(prevQuestId); @@ -5341,7 +5342,7 @@ void ObjectMgr::LoadQuests() if (nextQuestItr == _questTemplates.end()) TC_LOG_ERROR("sql.sql", "Quest {} has NextQuestId {}, but no such quest", qinfo->GetQuestId(), qinfo->_nextQuestId); else - nextQuestItr->second.DependentPreviousQuests.push_back(qinfo->GetQuestId()); + nextQuestItr->second->DependentPreviousQuests.push_back(qinfo->GetQuestId()); } if (uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId)) @@ -5390,7 +5391,7 @@ void ObjectMgr::LoadQuests() if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, questPair.first, nullptr)) continue; - Quest* qinfo = &questPair.second; + Quest* qinfo = questPair.second.get(); uint32 qid = qinfo->GetQuestId(); uint32 breadcrumbForQuestId = std::abs(qinfo->_breadcrumbForQuestId); std::set<uint32> questSet; @@ -6934,7 +6935,8 @@ uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt Quest const* ObjectMgr::GetQuestTemplate(uint32 quest_id) const { - return Trinity::Containers::MapGetValuePtr(_questTemplates, quest_id); + auto itr = _questTemplates.find(quest_id); + return itr != _questTemplates.end() ? itr->second.get() : nullptr; } void ObjectMgr::LoadGraveyardZones() @@ -10475,7 +10477,7 @@ void ObjectMgr::InitializeQueriesData(QueryDataGroup mask) // Initialize Query Data for quests if (mask & QUERY_DATA_QUESTS) for (auto& questTemplatePair : _questTemplates) - pool.PostWork([quest = &questTemplatePair.second]() { quest->InitializeQueryData(); }); + pool.PostWork([quest = questTemplatePair.second.get()]() { quest->InitializeQueryData(); }); // Initialize Quest POI data if (mask & QUERY_DATA_POIS) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 6eb39767842..cdd1981ada0 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -34,6 +34,7 @@ #include "SharedDefines.h" #include "Trainer.h" #include "VehicleDefines.h" +#include "UniqueTrackablePtr.h" #include <iterator> #include <map> #include <unordered_map> @@ -945,7 +946,7 @@ class TC_GAME_API ObjectMgr static ObjectMgr* instance(); - typedef std::unordered_map<uint32, Quest> QuestContainer; + typedef std::unordered_map<uint32, Trinity::unique_trackable_ptr<Quest>> QuestContainer; typedef std::unordered_map<uint32, AreaTrigger> AreaTriggerContainer; diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 3a8ba730fa7..e3b870cba51 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -62,7 +62,8 @@ Loot* Roll::getLoot() Group::Group() : m_leaderGuid(), m_leaderName(""), m_groupType(GROUPTYPE_NORMAL), m_dungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL), m_raidDifficulty(RAID_DIFFICULTY_10MAN_NORMAL), m_bgGroup(nullptr), m_bfGroup(nullptr), m_lootMethod(FREE_FOR_ALL), m_lootThreshold(ITEM_QUALITY_UNCOMMON), m_looterGuid(), -m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), m_isLeaderOffline(false) +m_masterLooterGuid(), m_subGroupsCounts(nullptr), m_guid(), m_counter(0), m_maxEnchantingLevel(0), m_dbStoreId(0), m_isLeaderOffline(false), + m_scriptRef(this, NoopGroupDeleter()) { for (uint8 i = 0; i < TARGET_ICONS_COUNT; ++i) m_targetIcons[i].Clear(); diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index 402264f19ef..f03a2fc44fa 100644 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -24,6 +24,7 @@ #include "Loot.h" #include "SharedDefines.h" #include "Timer.h" +#include "UniqueTrackablePtr.h" #include <map> class Battlefield; @@ -338,6 +339,8 @@ class TC_GAME_API Group // FG: evil hacks void BroadcastGroupUpdate(void); + Trinity::unique_weak_ptr<Group> GetWeakPtr() const { return m_scriptRef; } + protected: bool _setMembersGroup(ObjectGuid guid, uint8 group); void _homebindIfInstance(Player* player); @@ -373,5 +376,8 @@ class TC_GAME_API Group uint32 m_dbStoreId; // Represents the ID used in database (Can be reused by other groups if group was disbanded) bool m_isLeaderOffline; TimeTracker m_leaderOfflineTimer; + + struct NoopGroupDeleter { void operator()(Group*) const { /*noop - not managed*/ } }; + Trinity::unique_trackable_ptr<Group> m_scriptRef; }; #endif diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 568194d1f04..18fed0e33c6 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -1532,7 +1532,8 @@ void Guild::HandleAcceptMember(WorldSession* session) void Guild::HandleLeaveMember(WorldSession* session) { Player* player = session->GetPlayer(); - bool disband = false; + + sCalendarMgr->RemovePlayerGuildEventsAndSignups(player->GetGUID(), GetId()); // If leader is leaving if (_IsLeader(player)) @@ -1544,7 +1545,6 @@ void Guild::HandleLeaveMember(WorldSession* session) { // Guild is disbanded if leader leaves. Disband(); - disband = true; } } else @@ -1557,11 +1557,6 @@ void Guild::HandleLeaveMember(WorldSession* session) SendCommandResult(session, GUILD_COMMAND_QUIT, ERR_GUILD_COMMAND_SUCCESS, m_name); } - - sCalendarMgr->RemovePlayerGuildEventsAndSignups(player->GetGUID(), GetId()); - - if (disband) - delete this; } void Guild::HandleRemoveMember(WorldSession* session, std::string_view name) @@ -1786,7 +1781,6 @@ void Guild::HandleDisband(WorldSession* session) { Disband(); TC_LOG_DEBUG("guild", "Guild Successfully Disbanded"); - delete this; } } @@ -2110,13 +2104,8 @@ bool Guild::Validate() if (!pLeader) { CharacterDatabaseTransaction dummy(nullptr); - DeleteMember(dummy, m_leaderGuid); - // If no more members left, disband guild - if (m_members.empty()) - { - Disband(); + if (DeleteMember(dummy, m_leaderGuid)) return false; - } } else if (!pLeader->IsRank(GR_GUILDMASTER)) _SetLeaderGUID(*pLeader); @@ -2276,7 +2265,7 @@ bool Guild::AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 return true; } -void Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding, bool isKicked, bool canDeleteGuild) +bool Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding, bool isKicked) { ObjectGuid::LowType lowguid = guid.GetCounter(); Player* player = ObjectAccessor::FindConnectedPlayer(guid); @@ -2298,9 +2287,7 @@ void Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bo if (!newLeader) { Disband(); - if (canDeleteGuild) - delete this; - return; + return true; } _SetLeaderGUID(*newLeader); @@ -2333,6 +2320,14 @@ void Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bo _DeleteMemberFromDB(trans, lowguid); if (!isDisbanding) _UpdateAccountsNumber(); + + if (m_members.empty()) + { + Disband(); + return true; + } + + return false; } bool Guild::ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 newRank) diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index ba11f5fb470..45e75a985e3 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -22,6 +22,7 @@ #include "ObjectGuid.h" #include "Optional.h" #include "SharedDefines.h" +#include "UniqueTrackablePtr.h" #include <set> #include <unordered_map> #include <unordered_set> @@ -714,7 +715,7 @@ class TC_GAME_API Guild // Members // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. bool AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 rankId = GUILD_RANK_NONE); - void DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false, bool canDeleteGuild = false); + bool DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding = false, bool isKicked = false); bool ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 newRank); uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const; @@ -727,6 +728,9 @@ class TC_GAME_API Guild void ResetTimes(); + Trinity::unique_weak_ptr<Guild> GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(Trinity::unique_weak_ptr<Guild> weakRef) { m_weakRef = std::move(weakRef); } + protected: ObjectGuid::LowType m_id; std::string m_name; @@ -747,6 +751,8 @@ class TC_GAME_API Guild LogHolder<EventLogEntry> m_eventLog; std::array<LogHolder<BankEventLogEntry>, GUILD_BANK_MAX_TABS + 1> m_bankEventLog = {}; + Trinity::unique_weak_ptr<Guild> m_weakRef; + private: inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } inline RankInfo const* GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : nullptr; } diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 21f58962514..bf804ecb9cb 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -26,15 +26,13 @@ GuildMgr::GuildMgr() : NextGuildId(1) { } -GuildMgr::~GuildMgr() -{ - for (GuildContainer::iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) - delete itr->second; -} +GuildMgr::~GuildMgr() = default; void GuildMgr::AddGuild(Guild* guild) { - GuildStore[guild->GetId()] = guild; + Trinity::unique_trackable_ptr<Guild>& ptr = GuildStore[guild->GetId()]; + ptr.reset(guild); + guild->SetWeakPtr(ptr); } void GuildMgr::RemoveGuild(ObjectGuid::LowType guildId) @@ -57,16 +55,16 @@ Guild* GuildMgr::GetGuildById(ObjectGuid::LowType guildId) const { GuildContainer::const_iterator itr = GuildStore.find(guildId); if (itr != GuildStore.end()) - return itr->second; + return itr->second.get(); return nullptr; } Guild* GuildMgr::GetGuildByName(std::string_view guildName) const { - for (auto [id, guild] : GuildStore) + for (auto const& [id, guild] : GuildStore) if (StringEqualI(guild->GetName(), guildName)) - return guild; + return guild.get(); return nullptr; } @@ -89,7 +87,7 @@ Guild* GuildMgr::GetGuildByLeader(ObjectGuid guid) const { for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) if (itr->second->GetLeaderGUID() == guid) - return itr->second; + return itr->second.get(); return nullptr; } @@ -387,10 +385,10 @@ void GuildMgr::LoadGuilds() for (GuildContainer::iterator itr = GuildStore.begin(); itr != GuildStore.end();) { - Guild* guild = itr->second; + Guild* guild = itr->second.get(); ++itr; - if (guild && !guild->Validate()) - delete guild; + if (guild) + guild->Validate(); } TC_LOG_INFO("server.loading", ">> Validated data of loaded guilds in {} ms", GetMSTimeDiffToNow(oldMSTime)); @@ -400,7 +398,7 @@ void GuildMgr::LoadGuilds() void GuildMgr::ResetTimes() { for (GuildContainer::const_iterator itr = GuildStore.begin(); itr != GuildStore.end(); ++itr) - if (Guild* guild = itr->second) + if (Guild* guild = itr->second.get()) guild->ResetTimes(); CharacterDatabase.DirectExecute("TRUNCATE guild_member_withdraw"); diff --git a/src/server/game/Guilds/GuildMgr.h b/src/server/game/Guilds/GuildMgr.h index 00d2136623a..8a48ae32b2c 100644 --- a/src/server/game/Guilds/GuildMgr.h +++ b/src/server/game/Guilds/GuildMgr.h @@ -20,6 +20,7 @@ #include "Define.h" #include "ObjectGuid.h" +#include "UniqueTrackablePtr.h" #include <unordered_map> #include <vector> @@ -50,7 +51,7 @@ public: void ResetTimes(); protected: - typedef std::unordered_map<ObjectGuid::LowType, Guild*> GuildContainer; + typedef std::unordered_map<ObjectGuid::LowType, Trinity::unique_trackable_ptr<Guild>> GuildContainer; ObjectGuid::LowType NextGuildId; GuildContainer GuildStore; }; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 7e972ce874e..1678a942926 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1877,7 +1877,7 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact { // Reset guild if (Guild* guild = sGuildMgr->GetGuildById(characterInfo->GuildId)) - guild->DeleteMember(trans, factionChangeInfo->Guid, false, false, true); + guild->DeleteMember(trans, factionChangeInfo->Guid, false, false); Player::LeaveAllArenaTeams(factionChangeInfo->Guid); } @@ -1992,14 +1992,14 @@ void WorldSession::HandleCharFactionOrRaceChangeCallback(std::shared_ptr<Charact // Disable all old-faction specific quests { ObjectMgr::QuestContainer const& questTemplates = sObjectMgr->GetQuestTemplates(); - for (auto const& questTemplatePair : questTemplates) + for (auto const& [questId, quest] : questTemplates) { uint32 newRaceMask = (newTeam == ALLIANCE) ? RACEMASK_ALLIANCE : RACEMASK_HORDE; - if (questTemplatePair.second.GetAllowableRaces() && !(questTemplatePair.second.GetAllowableRaces() & newRaceMask)) + if (quest->GetAllowableRaces() && !(quest->GetAllowableRaces() & newRaceMask)) { stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_QUESTSTATUS_REWARDED_ACTIVE_BY_QUEST); stmt->setUInt32(0, lowGuid); - stmt->setUInt32(1, questTemplatePair.first); + stmt->setUInt32(1, questId); trans->Append(stmt); } } diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index cfd11dcfb78..90914ba6218 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -689,17 +689,12 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b } // note: this isn't fast but it's meant to be executed very rarely - Map const* map = sMapMgr->CreateBaseMap(mapid); // _not_ include difficulty - MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps(); - MapInstanced::InstancedMaps::iterator mitr; + Map* baseMap = sMapMgr->CreateBaseMap(mapid); // _not_ include difficulty uint32 timeLeft; - for (mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr) + for (auto& [_, map] : baseMap->ToMapInstanced()->GetInstancedMaps()) { - Map* map2 = mitr->second; - if (!map2->IsDungeon()) - continue; - + InstanceMap* instanceMap = map->ToInstanceMap(); if (warn) { if (now >= resetTime) @@ -707,10 +702,10 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, b else timeLeft = uint32(resetTime - now); - ((InstanceMap*)map2)->SendResetWarnings(timeLeft); + instanceMap->SendResetWarnings(timeLeft); } else - ((InstanceMap*)map2)->Reset(INSTANCE_RESET_GLOBAL); + instanceMap->Reset(INSTANCE_RESET_GLOBAL); } /// @todo delete creature/gameobject respawn times even if the maps are not loaded diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index dadd8cc14de..e51e50cbf7e 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -32,6 +32,7 @@ #include "SpawnData.h" #include "Timer.h" #include "Transaction.h" +#include "UniqueTrackablePtr.h" #include <bitset> #include <list> #include <memory> @@ -429,6 +430,9 @@ class TC_GAME_API Map : public GridRefManager<NGridType> uint32 GetInstanceId() const { return i_InstanceId; } uint8 GetSpawnMode() const { return (i_spawnMode); } + Trinity::unique_weak_ptr<Map> GetWeakPtr() const { return m_weakRef; } + void SetWeakPtr(Trinity::unique_weak_ptr<Map> weakRef) { m_weakRef = std::move(weakRef); } + enum EnterState { CAN_ENTER = 0, @@ -710,6 +714,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> MapEntry const* i_mapEntry; uint8 i_spawnMode; uint32 i_InstanceId; + Trinity::unique_weak_ptr<Map> m_weakRef; uint32 m_unloadTimer; float m_VisibleDistance; DynamicMapTree _dynamicTree; diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index 141f1808ebe..ccd2d962152 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -97,10 +97,6 @@ void MapInstanced::UnloadAll() for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) i->second->UnloadAll(); - // Delete the maps only after everything is unloaded to prevent crashes - for (InstancedMaps::iterator i = m_InstancedMaps.begin(); i != m_InstancedMaps.end(); ++i) - delete i->second; - m_InstancedMaps.clear(); // Unload own grids (just dummy(placeholder) grids, neccesary to unload GridMaps!) @@ -237,7 +233,9 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, if (sWorld->getBoolConfig(CONFIG_INSTANCEMAP_LOAD_GRIDS)) map->LoadAllCells(); - m_InstancedMaps[InstanceId] = map; + Trinity::unique_trackable_ptr<Map>& ptr = m_InstancedMaps[InstanceId]; + ptr.reset(map); + map->SetWeakPtr(ptr); return map; } @@ -262,7 +260,9 @@ BattlegroundMap* MapInstanced::CreateBattleground(uint32 InstanceId, Battlegroun map->SetBG(bg); bg->SetBgMap(map); - m_InstancedMaps[InstanceId] = map; + Trinity::unique_trackable_ptr<Map>& ptr = m_InstancedMaps[InstanceId]; + ptr.reset(map); + map->SetWeakPtr(ptr); return map; } @@ -292,7 +292,6 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr) sMapMgr->FreeInstanceId(itr->second->GetInstanceId()); // erase map - delete itr->second; m_InstancedMaps.erase(itr++); return true; diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index d60abbc25d1..2d26f559bad 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -18,15 +18,16 @@ #ifndef TRINITY_MAP_INSTANCED_H #define TRINITY_MAP_INSTANCED_H -#include "Map.h" -#include "InstanceSaveMgr.h" #include "DBCEnums.h" +#include "InstanceSaveMgr.h" +#include "Map.h" +#include "UniqueTrackablePtr.h" class TC_GAME_API MapInstanced : public Map { friend class MapManager; public: - typedef std::unordered_map< uint32, Map*> InstancedMaps; + typedef std::unordered_map<uint32, Trinity::unique_trackable_ptr<Map>> InstancedMaps; MapInstanced(uint32 id, time_t expiry); ~MapInstanced() { } @@ -42,7 +43,7 @@ class TC_GAME_API MapInstanced : public Map Map* FindInstanceMap(uint32 instanceId) const { InstancedMaps::const_iterator i = m_InstancedMaps.find(instanceId); - return(i == m_InstancedMaps.end() ? nullptr : i->second); + return(i == m_InstancedMaps.end() ? nullptr : i->second.get()); } bool DestroyInstance(InstancedMaps::iterator &itr); diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 1d17f6caa98..d340a85e4df 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -33,6 +33,7 @@ #include "Player.h" #include "WorldSession.h" #include "Opcodes.h" +#include <numeric> MapManager::MapManager() : _nextInstanceId(0), _scheduledScripts(0) @@ -85,7 +86,9 @@ Map* MapManager::CreateBaseMap(uint32 id) map->LoadCorpseData(); } - i_maps[id] = map; + Trinity::unique_trackable_ptr<Map>& ptr = i_maps[id]; + ptr.reset(map); + map->SetWeakPtr(ptr); } ASSERT(map); @@ -255,12 +258,12 @@ bool MapManager::IsValidMAP(uint32 mapid, bool startUp) void MapManager::UnloadAll() { - for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end();) - { + // first unload maps + for (auto iter = i_maps.begin(); iter != i_maps.end(); ++iter) iter->second->UnloadAll(); - delete iter->second; - i_maps.erase(iter++); - } + + // then delete them + i_maps.clear(); if (m_updater.activated()) m_updater.deactivate(); @@ -273,14 +276,12 @@ uint32 MapManager::GetNumInstances() std::lock_guard<std::mutex> lock(_mapsLock); uint32 ret = 0; - for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + for (auto const& [_, map] : i_maps) { - Map* map = itr->second; - if (!map->Instanceable()) + MapInstanced* mapInstanced = map->ToMapInstanced(); + if (!mapInstanced) continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced*)map)->GetInstancedMaps(); - for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if (mitr->second->IsDungeon()) ret++; + ret += mapInstanced->GetInstancedMaps().size(); } return ret; } @@ -290,15 +291,13 @@ uint32 MapManager::GetNumPlayersInInstances() std::lock_guard<std::mutex> lock(_mapsLock); uint32 ret = 0; - for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + for (auto& [_, map] : i_maps) { - Map* map = itr->second; - if (!map->Instanceable()) + MapInstanced* mapInstanced = map->ToMapInstanced(); + if (!mapInstanced) continue; - MapInstanced::InstancedMaps &maps = ((MapInstanced*)map)->GetInstancedMaps(); - for (MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) - if (mitr->second->IsDungeon()) - ret += ((InstanceMap*)mitr->second)->GetPlayers().getSize(); + MapInstanced::InstancedMaps& maps = mapInstanced->GetInstancedMaps(); + ret += std::accumulate(maps.begin(), maps.end(), 0u, [](uint32 total, MapInstanced::InstancedMaps::value_type const& value) { return total + value.second->GetPlayers().getSize(); }); } return ret; } diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 2323e31ab9a..5754415ba73 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -23,6 +23,7 @@ #include "MapInstanced.h" #include "GridStates.h" #include "MapUpdater.h" +#include "UniqueTrackablePtr.h" #include <boost/dynamic_bitset.hpp> class Transport; @@ -140,7 +141,7 @@ class TC_GAME_API MapManager bool IsScriptScheduled() const { return _scheduledScripts > 0; } private: - typedef std::unordered_map<uint32, Map*> MapMapType; + typedef std::unordered_map<uint32, Trinity::unique_trackable_ptr<Map>> MapMapType; typedef boost::dynamic_bitset<size_t> InstanceIds; MapManager(); @@ -149,7 +150,7 @@ class TC_GAME_API MapManager Map* FindBaseMap(uint32 mapId) const { MapMapType::const_iterator iter = i_maps.find(mapId); - return (iter == i_maps.end() ? nullptr : iter->second); + return (iter == i_maps.end() ? nullptr : iter->second.get()); } MapManager(MapManager const&) = delete; @@ -175,12 +176,12 @@ void MapManager::DoForAllMaps(Worker&& worker) for (auto& mapPair : i_maps) { - Map* map = mapPair.second; + Map* map = mapPair.second.get(); if (MapInstanced* mapInstanced = map->ToMapInstanced()) { MapInstanced::InstancedMaps& instances = mapInstanced->GetInstancedMaps(); for (auto& instancePair : instances) - worker(instancePair.second); + worker(instancePair.second.get()); } else worker(map); @@ -195,12 +196,12 @@ inline void MapManager::DoForAllMapsWithMapId(uint32 mapId, Worker&& worker) auto itr = i_maps.find(mapId); if (itr != i_maps.end()) { - Map* map = itr->second; + Map* map = itr->second.get(); if (MapInstanced* mapInstanced = map->ToMapInstanced()) { MapInstanced::InstancedMaps& instances = mapInstanced->GetInstancedMaps(); for (auto& p : instances) - worker(p.second); + worker(p.second.get()); } else worker(map); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index a8d3fa98661..6e9a0be33df 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -22,6 +22,7 @@ #include "DatabaseEnvFwd.h" #include "DBCEnums.h" #include "SharedDefines.h" +#include "UniqueTrackablePtr.h" #include "WorldPacket.h" #include <vector> @@ -332,6 +333,8 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player, bool sendHiddenRewards = false) const; + Trinity::unique_weak_ptr<Quest> GetWeakPtr() const { return _weakRef; } + std::vector<uint32> DependentPreviousQuests; std::vector<uint32> DependentBreadcrumbQuests; WorldPacket QueryData[TOTAL_LOCALES]; @@ -408,6 +411,8 @@ class TC_GAME_API Quest // Helpers static uint32 RoundXPValue(uint32 xp); + + Trinity::unique_weak_ptr<Quest> _weakRef; }; struct QuestStatusData diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 2543219d436..c987893f2bd 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -428,7 +428,7 @@ m_castItemGuid(createInfo.CastItemGUID), m_applyTime(GameTime::GetGameTime()), m_owner(createInfo._owner), m_timeCla(0), m_updateTargetMapInterval(0), _casterInfo(), m_procCharges(0), m_stackAmount(1), m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), -m_procCooldown(TimePoint::min()) +m_procCooldown(TimePoint::min()), m_scriptRef(this, NoopAuraDeleter()) { if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) m_timeCla = 1 * IN_MILLISECONDS; @@ -618,6 +618,8 @@ void Aura::_Remove(AuraRemoveMode removeMode) m_dropEvent->ScheduleAbort(); m_dropEvent = nullptr; } + + m_scriptRef = nullptr; } void Aura::UpdateTargetMap(Unit* caster, bool apply) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 126f11141b3..f392ad6fb2f 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -20,6 +20,7 @@ #include "SpellAuraDefines.h" #include "SpellInfo.h" +#include "UniqueTrackablePtr.h" class SpellInfo; struct SpellModifier; @@ -269,6 +270,14 @@ class TC_GAME_API Aura virtual std::string GetDebugInfo() const; + Trinity::unique_weak_ptr<Aura> GetWeakPtr() const { return m_scriptRef; } + + Aura(Aura const&) = delete; + Aura(Aura&&) = delete; + + Aura& operator=(Aura const&) = delete; + Aura& operator=(Aura&&) = delete; + private: AuraScript* GetScriptByName(std::string const& scriptName) const; void _DeleteRemovedApplications(); @@ -302,6 +311,9 @@ class TC_GAME_API Aura private: std::vector<AuraApplication*> _removedApplications; + + struct NoopAuraDeleter { void operator()(Aura*) const { /*noop - not managed*/ } }; + Trinity::unique_trackable_ptr<Aura> m_scriptRef; }; class TC_GAME_API UnitAura : public Aura diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 13731b2679a..22b2b3a4c18 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -55,6 +55,7 @@ #include "Unit.h" #include "UpdateData.h" #include "UpdateMask.h" +#include "UniqueTrackablePtr.h" #include "Util.h" #include "Vehicle.h" #include "VMapFactory.h" @@ -487,16 +488,20 @@ SpellValue::SpellValue(SpellInfo const* proto) class TC_GAME_API SpellEvent : public BasicEvent { - public: - SpellEvent(Spell* spell); - ~SpellEvent(); +public: + explicit SpellEvent(Spell* spell); + ~SpellEvent(); + + bool Execute(uint64 e_time, uint32 p_time) override; + void Abort(uint64 e_time) override; + bool IsDeletable() const override; + Spell const* GetSpell() const { return m_Spell.get(); } + Trinity::unique_weak_ptr<Spell> GetSpellWeakPtr() const { return m_Spell; } - bool Execute(uint64 e_time, uint32 p_time) override; - void Abort(uint64 e_time) override; - bool IsDeletable() const override; + std::string GetDebugInfo() const { return m_Spell->GetDebugInfo(); } - protected: - Spell* m_Spell; +protected: + Trinity::unique_trackable_ptr<Spell> m_Spell; }; Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID) : @@ -7430,9 +7435,8 @@ Unit* Spell::GetUnitCasterForEffectHandlers() const return m_originalCaster ? m_originalCaster : m_caster->ToUnit(); } -SpellEvent::SpellEvent(Spell* spell) : BasicEvent() +SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell) { - m_Spell = spell; } SpellEvent::~SpellEvent() @@ -7440,11 +7444,7 @@ SpellEvent::~SpellEvent() if (m_Spell->getState() != SPELL_STATE_FINISHED) m_Spell->cancel(); - if (m_Spell->IsDeletable()) - { - delete m_Spell; - } - else + if (!m_Spell->IsDeletable()) { TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.", (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id); @@ -8177,6 +8177,11 @@ std::string Spell::GetDebugInfo() const return sstr.str(); } +Trinity::unique_weak_ptr<Spell> Spell::GetWeakPtr() const +{ + return _spellEvent->GetSpellWeakPtr(); +} + void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount) { for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 3359bf6d730..8dbcdd9ad7d 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -24,6 +24,7 @@ #include "Position.h" #include "SharedDefines.h" #include "SpellDefines.h" +#include "UniqueTrackablePtr.h" #include <memory> namespace WorldPackets @@ -458,6 +459,9 @@ class TC_GAME_API Spell Spell** m_selfContainer; // pointer to our spell container (if applicable) std::string GetDebugInfo() const; + + Trinity::unique_weak_ptr<Spell> GetWeakPtr() const; + void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount); protected: diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 73255185c67..bd3403fa40e 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -141,8 +141,6 @@ public: return false; targetGuild->Disband(); - delete targetGuild; - return true; } @@ -190,7 +188,7 @@ public: return false; CharacterDatabaseTransaction trans(nullptr); - targetGuild->DeleteMember(trans, targetGuid, false, true, true); + targetGuild->DeleteMember(trans, targetGuid, false, true); return true; } diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 57fe66a981f..2da6946a2e3 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -140,8 +140,8 @@ public: Player* player = handler->GetPlayer(); for (auto const& [id, quest] : sObjectMgr->GetQuestTemplates()) { - if (quest.GetRequiredClasses() && player->SatisfyQuestClass(&quest, false)) - player->LearnQuestRewardedSpells(&quest); + if (quest->GetRequiredClasses() && player->SatisfyQuestClass(quest.get(), false)) + player->LearnQuestRewardedSpells(quest.get()); } return true; } diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index b14bc9661c9..dfdbdc39586 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -710,7 +710,7 @@ public: } if (handler->GetSession()) - handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second.GetQuestLevel(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second->GetQuestLevel(), title.c_str(), statusStr); else handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, questTemplatePair.first, title.c_str(), statusStr); @@ -722,7 +722,7 @@ public: } } - std::string const& title = questTemplatePair.second.GetTitle(); + std::string const& title = questTemplatePair.second->GetTitle(); if (title.empty()) continue; @@ -755,7 +755,7 @@ public: } if (handler->GetSession()) - handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second.GetQuestLevel(), title.c_str(), statusStr); + handler->PSendSysMessage(LANG_QUEST_LIST_CHAT, questTemplatePair.first, questTemplatePair.first, questTemplatePair.second->GetQuestLevel(), title.c_str(), statusStr); else handler->PSendSysMessage(LANG_QUEST_LIST_CONSOLE, questTemplatePair.first, title.c_str(), statusStr); |