aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/Combat/ThreatManager.h26
-rw-r--r--src/server/scripts/Commands/cs_debug.cpp79
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;
}