diff options
-rw-r--r-- | src/server/game/Combat/ThreatManager.h | 26 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_debug.cpp | 79 |
2 files changed, 66 insertions, 39 deletions
diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h index 14ee60aea77..09717ff66fb 100644 --- a/src/server/game/Combat/ThreatManager.h +++ b/src/server/game/Combat/ThreatManager.h @@ -69,8 +69,9 @@ class SpellInfo; * The current (= last selected) victim can be accessed using GetCurrentVictim. SelectVictim selects a (potentially new) victim. * * Beyond that, ThreatManager has a variety of helpers and notifiers, which are documented inline below. * * * - * SPECIAL NOTE: Please be aware that any heap iterator may be invalidated if you modify a ThreatReference. The heap holds const pointers for a reason. * - * If you need to modify multiple ThreatReference objects, then use GetModifiableThreatList(), which is safe to modify! * + * SPECIAL NOTE: Please be aware that any iterator may be invalidated if you modify a ThreatReference. The heap holds const pointers for a reason, but * + * that doesn't mean you're scot free. A variety of actions (casting spells, teleporting units, and so forth) can cause changes to * + * the threat list. Use with care - or default to GetModifiableThreatList(), which inherently copies entries. * \********************************************************************************************************************************************************/ class ThreatReference; @@ -85,6 +86,7 @@ class TC_GAME_API ThreatManager { public: typedef boost::heap::fibonacci_heap<ThreatReference const*, boost::heap::compare<CompareThreatLessThan>> threat_list_heap; + class ThreatListIterator; static const uint32 CLIENT_THREAT_UPDATE_INTERVAL = 1000u; static bool CanHaveThreatList(Unit const* who); @@ -121,11 +123,13 @@ class TC_GAME_API ThreatManager float GetThreat(Unit const* who, bool includeOffline = false) const; size_t GetThreatListSize() const { return _sortedThreatList.size(); } // fastest of the three threat list getters - gets the threat list in "arbitrary" order - Trinity::IteratorPair<threat_list_heap::const_iterator> GetUnsortedThreatList() const { return { _sortedThreatList.begin(), _sortedThreatList.end() }; } + // iterators will invalidate on adding/removing entries from the threat list; slightly less finicky than GetSorted. + Trinity::IteratorPair<ThreatListIterator> GetUnsortedThreatList() const { return { _myThreatListEntries.begin(), _myThreatListEntries.end() }; } // slightly slower than GetUnsorted, but, well...sorted - only use it if you need the sorted property, of course + // this iterator pair will invalidate on any modification (even indirect) of the threat list; spell casts and similar can all induce this! // note: current tank is NOT guaranteed to be the first entry in this list - check GetCurrentVictim separately if you want that! Trinity::IteratorPair<threat_list_heap::ordered_iterator> GetSortedThreatList() const { return { _sortedThreatList.ordered_begin(), _sortedThreatList.ordered_end() }; } - // slowest of the three threat list getters (by far), but lets you modify the threat references + // slowest of the three threat list getters (by far), but lets you modify the threat references - this is also sorted std::vector<ThreatReference*> GetModifiableThreatList() const; // does any unit have a threat list entry with victim == this.owner? @@ -217,6 +221,20 @@ class TC_GAME_API ThreatManager ThreatManager(ThreatManager const&) = delete; ThreatManager& operator=(ThreatManager const&) = delete; + class ThreatListIterator + { + private: + decltype(_myThreatListEntries)::const_iterator _it; + + public: + ThreatReference const* operator*() const { return _it->second; } + ThreatReference const* operator->() const { return _it->second; } + ThreatListIterator& operator++() { ++_it; return *this; } + bool operator==(ThreatListIterator const& o) const { return _it == o._it; } + bool operator!=(ThreatListIterator const& o) const { return _it != o._it; } + ThreatListIterator(decltype(_it) it) : _it(it) {} + }; + friend class ThreatReference; friend struct CompareThreatLessThan; friend class debug_commandscript; diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index e1ca92ce670..67490c05f7d 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -555,8 +555,8 @@ public: if (!target) return false; - handler->PSendSysMessage("Loot recipient for creature %s (%s, DB GUID %s) is %s", - target->GetName().c_str(), target->GetGUID().ToString().c_str(), std::to_string(target->GetSpawnId()).c_str(), + handler->PSendSysMessage("Loot recipient for creature %s (%s, SpawnID " UI64FMTD ") is %s", + target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetSpawnId(), target->hasLootRecipient() ? (target->GetLootRecipient() ? target->GetLootRecipient()->GetName().c_str() : "offline") : "no loot recipient"); return true; } @@ -874,50 +874,59 @@ public: for (auto const& pair : threatenedByMe) { Unit* unit = pair.second->GetOwner(); - handler->PSendSysMessage(" %u. %s (%s, SpawnID %u) - threat %f", ++count, unit->GetName().c_str(), unit->GetGUID().ToString().c_str(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, pair.second->GetThreat()); + handler->PSendSysMessage(" %u. %s (%s, SpawnID " UI64FMTD ") - threat %f", ++count, unit->GetName().c_str(), unit->GetGUID().ToString().c_str(), unit->GetTypeId() == TYPEID_UNIT ? unit->ToCreature()->GetSpawnId() : 0, pair.second->GetThreat()); } handler->SendSysMessage("End of threatened-by-me list."); } - if (!mgr.CanHaveThreatList()) - handler->PSendSysMessage("%s (%s) cannot have a threat list.", target->GetName().c_str(), target->GetGUID().ToString().c_str()); - else if (mgr.IsEngaged()) + if (mgr.CanHaveThreatList()) { - count = 0; - handler->PSendSysMessage("Threat list of %s (%s, SpawnID %u)", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); - for (ThreatReference const* ref : mgr.GetSortedThreatList()) + if (!mgr.IsThreatListEmpty(true)) { - Unit* unit = ref->GetVictim(); - char const* onlineStr; - switch (ref->GetOnlineState()) - { - case ThreatReference::ONLINE_STATE_SUPPRESSED: - onlineStr = " [SUPPRESSED]"; - break; - case ThreatReference::ONLINE_STATE_OFFLINE: - onlineStr = " [OFFLINE]"; - break; - default: - onlineStr = ""; - } - char const* tauntStr; - switch (ref->GetTauntState()) + if (mgr.IsEngaged()) + handler->PSendSysMessage("Threat list of %s (%s, SpawnID " UI64FMTD "):", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); + else + handler->PSendSysMessage("%s (%s, SpawnID " UI64FMTD ") is not engaged, but still has a threat list? Well, here it is:", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); + + count = 0; + for (ThreatReference const* ref : mgr.GetSortedThreatList()) { - case ThreatReference::TAUNT_STATE_TAUNT: - tauntStr = " [TAUNT]"; - break; - case ThreatReference::TAUNT_STATE_DETAUNT: - tauntStr = " [DETAUNT]"; - break; - default: - tauntStr = ""; + Unit* unit = ref->GetVictim(); + char const* onlineStr; + switch (ref->GetOnlineState()) + { + case ThreatReference::ONLINE_STATE_SUPPRESSED: + onlineStr = " [SUPPRESSED]"; + break; + case ThreatReference::ONLINE_STATE_OFFLINE: + onlineStr = " [OFFLINE]"; + break; + default: + onlineStr = ""; + } + char const* tauntStr; + switch (ref->GetTauntState()) + { + case ThreatReference::TAUNT_STATE_TAUNT: + tauntStr = " [TAUNT]"; + break; + case ThreatReference::TAUNT_STATE_DETAUNT: + tauntStr = " [DETAUNT]"; + break; + default: + tauntStr = ""; + } + handler->PSendSysMessage(" %u. %s (%s) - threat %f%s%s", ++count, unit->GetName().c_str(), unit->GetGUID().ToString().c_str(), ref->GetThreat(), tauntStr, onlineStr); } - handler->PSendSysMessage(" %u. %s (%s) - threat %f%s%s", ++count, unit->GetName().c_str(), unit->GetGUID().ToString().c_str(), ref->GetThreat(), tauntStr, onlineStr); + handler->SendSysMessage("End of threat list."); } - handler->SendSysMessage("End of threat list."); + else if (!mgr.IsEngaged()) + handler->PSendSysMessage("%s (%s, SpawnID " UI64FMTD ") is not currently engaged.", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); + else + handler->PSendSysMessage("%s (%s, SpawnID " UI64FMTD ") seems to be engaged, but does not have a threat list??", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); } else - handler->PSendSysMessage("%s (%s, SpawnID %u) is not currently engaged.", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->GetTypeId() == TYPEID_UNIT ? target->ToCreature()->GetSpawnId() : 0); + handler->PSendSysMessage("%s (%s) cannot have a threat list.", target->GetName().c_str(), target->GetGUID().ToString().c_str()); return true; } |