aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Combat/ThreatManager.cpp
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2018-08-27 19:08:17 +0200
committerShauren <shauren.trinity@gmail.com>2021-10-23 02:14:04 +0200
commit392a644dc8562ea54b9c185a2776fceb1006e2cd (patch)
treeeec4d04885e582c39f0b88ea1cf0d87b4bb1015a /src/server/game/Combat/ThreatManager.cpp
parent395f58d651c7c370522ead6ba9a3c684d91e3a66 (diff)
Core/Threat: Threat system adjustments:
* Online states are now re-evaluated before victim update instead of continuously. Closes #22226. Tagging #21501. * Victim update now happens every 1s as opposed to every server tick unless current target goes away. * Suppressed threat is no longer re-established until the victim gains additional threat (by hitting the target, for instance). * Assistance threat is now split between non-controlled units threatened by target, as opposed to all units threatened by target. (cherry picked from commit 5cea572a9ad524c6f28ff8519bee61d1ff4357d0)
Diffstat (limited to 'src/server/game/Combat/ThreatManager.cpp')
-rw-r--r--src/server/game/Combat/ThreatManager.cpp280
1 files changed, 164 insertions, 116 deletions
diff --git a/src/server/game/Combat/ThreatManager.cpp b/src/server/game/Combat/ThreatManager.cpp
index 8ac3828b8cb..6d5273ac91b 100644
--- a/src/server/game/Combat/ThreatManager.cpp
+++ b/src/server/game/Combat/ThreatManager.cpp
@@ -52,20 +52,23 @@ void ThreatReference::ScaleThreat(float factor)
HeapNotifyDecreased();
}
-void ThreatReference::UpdateOnlineState()
+void ThreatReference::UpdateOffline()
{
- OnlineState onlineState = SelectOnlineState();
- if (onlineState == _online)
+ bool const shouldBeOffline = ShouldBeOffline();
+ if (shouldBeOffline == IsOffline())
return;
- bool increase = (onlineState > _online);
- _online = onlineState;
- if (increase)
- HeapNotifyIncreased();
- else
- HeapNotifyDecreased();
- if (!IsAvailable())
- _owner->GetThreatManager().SendRemoveToClients(_victim);
+ if (shouldBeOffline)
+ {
+ _online = ONLINE_STATE_OFFLINE;
+ HeapNotifyDecreased();
+ _mgr.SendRemoveToClients(_victim);
+ }
+ else
+ {
+ _online = ShouldBeSuppressed() ? ONLINE_STATE_SUPPRESSED : ONLINE_STATE_ONLINE;
+ HeapNotifyIncreased();
+ }
}
/*static*/ bool ThreatReference::FlagsAllowFighting(Unit const* a, Unit const* b)
@@ -85,25 +88,24 @@ void ThreatReference::UpdateOnlineState()
return true;
}
-ThreatReference::OnlineState ThreatReference::SelectOnlineState()
+bool ThreatReference::ShouldBeOffline() const
{
- // first, check all offline conditions
- if (!_owner->CanSeeOrDetect(_victim)) // not in map/phase, or stealth/invis
- return ONLINE_STATE_OFFLINE;
- if (_victim->HasUnitState(UNIT_STATE_DIED)) // feign death
- return ONLINE_STATE_OFFLINE;
+ if (!_owner->CanSeeOrDetect(_victim))
+ return true;
+ if (!_owner->_IsTargetAcceptable(_victim) || !_owner->CanCreatureAttack(_victim))
+ return true;
if (!FlagsAllowFighting(_owner, _victim) || !FlagsAllowFighting(_victim, _owner))
- return ONLINE_STATE_OFFLINE;
- if (_owner->IsAIEnabled() && !_owner->GetAI()->CanAIAttack(_victim))
- return ONLINE_STATE_OFFLINE;
- // next, check suppression (immunity to chosen melee attack school)
+ return true;
+ return false;
+}
+
+bool ThreatReference::ShouldBeSuppressed() const
+{
if (_victim->IsImmunedToDamage(_owner->GetMeleeDamageSchoolMask()))
- return ONLINE_STATE_SUPPRESSED;
- // or any form of CC that will break on damage - disorient, polymorph, blind etc
+ return true;
if (_victim->HasBreakableByDamageCrowdControlAura())
- return ONLINE_STATE_SUPPRESSED;
- // no suppression - we're online
- return ONLINE_STATE_ONLINE;
+ return true;
+ return false;
}
void ThreatReference::UpdateTauntState(TauntState state)
@@ -123,9 +125,14 @@ void ThreatReference::UpdateTauntState(TauntState state)
HeapNotifyIncreased();
}
-void ThreatReference::ClearThreat(bool sendRemove)
+void ThreatReference::ClearThreat()
+{
+ _mgr.ClearThreat(this);
+}
+
+void ThreatReference::UnregisterAndFree()
{
- _owner->GetThreatManager().PurgeThreatListRef(_victim->GetGUID(), sendRemove);
+ _owner->GetThreatManager().PurgeThreatListRef(_victim->GetGUID());
_victim->GetThreatManager().PurgeThreatenedByMeRef(_owner->GetGUID());
delete this;
}
@@ -148,7 +155,7 @@ void ThreatReference::ClearThreat(bool sendRemove)
return true;
}
-ThreatManager::ThreatManager(Unit* owner) : _owner(owner), _ownerCanHaveThreatList(false), _ownerEngaged(false), _updateClientTimer(CLIENT_THREAT_UPDATE_INTERVAL), _currentVictimRef(nullptr), _fixateRef(nullptr)
+ThreatManager::ThreatManager(Unit* owner) : _owner(owner), _ownerCanHaveThreatList(false), _ownerEngaged(false), _updateTimer(THREAT_UPDATE_INTERVAL), _currentVictimRef(nullptr), _fixateRef(nullptr)
{
for (int8 i = 0; i < MAX_SPELL_SCHOOL; ++i)
_singleSchoolModifiers[i] = 1.0f;
@@ -170,18 +177,25 @@ void ThreatManager::Update(uint32 tdiff)
{
if (!CanHaveThreatList() || !IsEngaged())
return;
- if (_updateClientTimer <= tdiff)
+ if (_updateTimer <= tdiff)
{
- _updateClientTimer = CLIENT_THREAT_UPDATE_INTERVAL;
- SendThreatListToClients();
+ UpdateVictim();
+ _updateTimer = THREAT_UPDATE_INTERVAL;
}
else
- _updateClientTimer -= tdiff;
+ _updateTimer -= tdiff;
+}
+
+Unit* ThreatManager::GetCurrentVictim()
+{
+ if (!_currentVictimRef || _currentVictimRef->ShouldBeOffline())
+ UpdateVictim();
+ return const_cast<ThreatManager const*>(this)->GetCurrentVictim();
}
Unit* ThreatManager::GetCurrentVictim() const
{
- if (_currentVictimRef)
+ if (_currentVictimRef && !_currentVictimRef->ShouldBeOffline())
return _currentVictimRef->GetVictim();
return nullptr;
}
@@ -194,22 +208,6 @@ Unit* ThreatManager::GetAnyTarget() const
return nullptr;
}
-Unit* ThreatManager::SelectVictim()
-{
- if (_sortedThreatList.empty())
- return nullptr;
-
- ThreatReference const* newVictimRef = ReselectVictim();
- if (newVictimRef != _currentVictimRef)
- {
- if (newVictimRef)
- SendNewVictimToClients(newVictimRef);
-
- _currentVictimRef = newVictimRef;
- }
- return newVictimRef ? newVictimRef->GetVictim() : nullptr;
-}
-
bool ThreatManager::IsThreatListEmpty(bool includeOffline) const
{
if (includeOffline)
@@ -265,14 +263,11 @@ bool ThreatManager::IsThreateningTo(ObjectGuid const& who, bool includeOffline)
}
bool ThreatManager::IsThreateningTo(Unit const* who, bool includeOffline) const { return IsThreateningTo(who->GetGUID(), includeOffline); }
-void ThreatManager::UpdateOnlineStates(bool meThreateningOthers, bool othersThreateningMe)
+void ThreatManager::EvaluateSuppressed()
{
- if (othersThreateningMe)
- for (auto const& pair : _myThreatListEntries)
- pair.second->UpdateOnlineState();
- if (meThreateningOthers)
- for (auto const& pair : _threatenedByMe)
- pair.second->UpdateOnlineState();
+ for (auto const& pair : _threatenedByMe)
+ if (pair.second->IsOnline() && pair.second->ShouldBeSuppressed())
+ pair.second->_online = ThreatReference::ONLINE_STATE_SUPPRESSED;
}
static void SaveCreatureHomePositionIfNeed(Creature* c)
@@ -367,7 +362,15 @@ void ThreatManager::AddThreat(Unit* target, float amount, SpellInfo const* spell
auto it = _myThreatListEntries.find(target->GetGUID());
if (it != _myThreatListEntries.end())
{
- it->second->AddThreat(amount);
+ ThreatReference* const ref = it->second;
+
+ // causing threat causes SUPPRESSED threat states to stop being suppressed
+ if (ref->GetOnlineState() == ThreatReference::ONLINE_STATE_SUPPRESSED)
+ if (!ref->ShouldBeSuppressed())
+ ref->_online = ThreatReference::ONLINE_STATE_ONLINE;
+
+ if (ref->IsOnline())
+ ref->AddThreat(amount);
return;
}
@@ -377,10 +380,11 @@ void ThreatManager::AddThreat(Unit* target, float amount, SpellInfo const* spell
target->GetThreatManager().PutThreatenedByMeRef(_owner->GetGUID(), ref);
if (!_ownerEngaged)
{
+ Creature* cOwner = ASSERT_NOTNULL(_owner->ToCreature()); // if we got here the owner can have a threat list, and must be a creature!
_ownerEngaged = true;
- Creature* cOwner = _owner->ToCreature();
- ASSERT(cOwner); // if we got here the owner can have a threat list, and must be a creature!
+ UpdateVictim();
+
SaveCreatureHomePositionIfNeed(cOwner);
if (CreatureAI* ownerAI = cOwner->AI())
ownerAI->JustEngagedWith(target);
@@ -437,14 +441,22 @@ void ThreatManager::TauntUpdate()
void ThreatManager::ResetAllThreat()
{
for (auto const& pair : _myThreatListEntries)
- pair.second->SetThreat(0.0f);
+ pair.second->ScaleThreat(0.0f);
}
void ThreatManager::ClearThreat(Unit* target)
{
auto it = _myThreatListEntries.find(target->GetGUID());
if (it != _myThreatListEntries.end())
- it->second->ClearThreat();
+ ClearThreat(it->second);
+}
+
+void ThreatManager::ClearThreat(ThreatReference* ref)
+{
+ SendRemoveToClients(ref->_victim);
+ ref->UnregisterAndFree();
+ if (!_currentVictimRef)
+ UpdateVictim();
}
void ThreatManager::ClearAllThreat()
@@ -455,7 +467,7 @@ void ThreatManager::ClearAllThreat()
SendClearAllThreatToClients();
do
- _myThreatListEntries.begin()->second->ClearThreat(false);
+ _myThreatListEntries.begin()->second->UnregisterAndFree();
while (!_myThreatListEntries.empty());
}
@@ -481,8 +493,24 @@ Unit* ThreatManager::GetFixateTarget() const
return nullptr;
}
+void ThreatManager::UpdateVictim()
+{
+ ThreatReference const* const newVictim = ReselectVictim();
+ bool const newHighest = (newVictim != _currentVictimRef);
+
+ _currentVictimRef = newVictim;
+ SendThreatListToClients(newVictim && newHighest);
+
+}
+
ThreatReference const* ThreatManager::ReselectVictim()
{
+ if (_sortedThreatList.empty())
+ return nullptr;
+
+ for (auto const& pair : _myThreatListEntries)
+ pair.second->UpdateOffline();
+
// fixated target is always preferred
if (_fixateRef && _fixateRef->IsAvailable())
return _fixateRef;
@@ -526,7 +554,7 @@ ThreatReference const* ThreatManager::ReselectVictim()
++it;
}
// we should have found the old victim at some point in the loop above, so execution should never get to this point
- ASSERT(false && "Current victim not found in sorted threat list even though it has a reference - manager desync!");
+ ASSERT(false, "Current victim not found in sorted threat list even though it has a reference - manager desync!");
return nullptr;
}
@@ -596,46 +624,41 @@ ThreatReference const* ThreatManager::ReselectVictim()
return threat;
}
-void ThreatManager::SendClearAllThreatToClients() const
-{
- WorldPackets::Combat::ThreatClear threatClear;
- threatClear.UnitGUID = _owner->GetGUID();
- _owner->SendMessageToSet(threatClear.Write(), false);
-}
-
-void ThreatManager::SendThreatListToClients() const
-{
- WorldPackets::Combat::ThreatUpdate threatUpdate;
- threatUpdate.UnitGUID = _owner->GetGUID();
- threatUpdate.ThreatList.reserve(_sortedThreatList.size());
- for (ThreatReference const* ref : _sortedThreatList)
- {
- if (!ref->IsAvailable()) // @todo check if suppressed threat should get sent for bubble/iceblock/hop etc
- continue;
-
- WorldPackets::Combat::ThreatInfo threatInfo;
- threatInfo.UnitGUID = ref->GetVictim()->GetGUID();
- threatInfo.Threat = int64(ref->GetThreat() * 100);
- threatUpdate.ThreatList.push_back(threatInfo);
- }
- _owner->SendMessageToSet(threatUpdate.Write(), false);
-}
-
void ThreatManager::ForwardThreatForAssistingMe(Unit* assistant, float baseAmount, SpellInfo const* spell, bool ignoreModifiers)
{
if (spell && spell->HasAttribute(SPELL_ATTR1_NO_THREAT)) // shortcut, none of the calls would do anything
return;
if (_threatenedByMe.empty())
return;
- float const perTarget = baseAmount / _threatenedByMe.size(); // Threat is divided evenly among all targets (LibThreat sourced)
+
+ std::vector<Creature*> canBeThreatened, cannotBeThreatened;
for (auto const& pair : _threatenedByMe)
- pair.second->GetOwner()->GetThreatManager().AddThreat(assistant, perTarget, spell, ignoreModifiers);
+ {
+ Creature* owner = pair.second->GetOwner();
+ if (!owner->HasBreakableByDamageCrowdControlAura())
+ canBeThreatened.push_back(owner);
+ else
+ cannotBeThreatened.push_back(owner);
+ }
+
+ if (!canBeThreatened.empty()) // targets under CC cannot gain assist threat - split evenly among the rest
+ {
+ float const perTarget = baseAmount / canBeThreatened.size();
+ for (Creature* threatened : canBeThreatened)
+ threatened->GetThreatManager().AddThreat(assistant, perTarget, spell, ignoreModifiers);
+ }
+
+ for (Creature* threatened : cannotBeThreatened)
+ threatened->GetThreatManager().AddThreat(assistant, 0.0f, spell, true);
}
void ThreatManager::RemoveMeFromThreatLists()
{
while (!_threatenedByMe.empty())
- _threatenedByMe.begin()->second->ClearThreat();
+ {
+ auto& ref = _threatenedByMe.begin()->second;
+ ref->_mgr.ClearThreat(_owner);
+ }
}
void ThreatManager::UpdateMyTempModifiers()
@@ -644,11 +667,19 @@ void ThreatManager::UpdateMyTempModifiers()
for (AuraEffect const* eff : _owner->GetAuraEffectsByType(SPELL_AURA_MOD_TOTAL_THREAT))
mod += eff->GetAmount();
- for (auto const& pair : _threatenedByMe)
+ if (_threatenedByMe.empty())
+ return;
+
+ auto it = _threatenedByMe.begin();
+ bool const isIncrease = (it->second->_tempModifier < mod);
+ do
{
- pair.second->_tempModifier = mod;
- pair.second->HeapNotifyChanged();
- }
+ it->second->_tempModifier = mod;
+ if (isIncrease)
+ it->second->HeapNotifyIncreased();
+ else
+ it->second->HeapNotifyDecreased();
+ } while ((++it) != _threatenedByMe.end());
}
void ThreatManager::UpdateMySpellSchoolModifiers()
@@ -686,6 +717,13 @@ void ThreatManager::UnregisterRedirectThreat(uint32 spellId, ObjectGuid const& v
UpdateRedirectInfo();
}
+void ThreatManager::SendClearAllThreatToClients() const
+{
+ WorldPackets::Combat::ThreatClear threatClear;
+ threatClear.UnitGUID = _owner->GetGUID();
+ _owner->SendMessageToSet(threatClear.Write(), false);
+}
+
void ThreatManager::SendRemoveToClients(Unit const* victim) const
{
WorldPackets::Combat::ThreatRemove threatRemove;
@@ -694,23 +732,36 @@ void ThreatManager::SendRemoveToClients(Unit const* victim) const
_owner->SendMessageToSet(threatRemove.Write(), false);
}
-void ThreatManager::SendNewVictimToClients(ThreatReference const* victimRef) const
+void ThreatManager::SendThreatListToClients(bool newHighest) const
{
- WorldPackets::Combat::HighestThreatUpdate highestThreatUpdate;
- highestThreatUpdate.UnitGUID = _owner->GetGUID();
- highestThreatUpdate.HighestThreatGUID = victimRef->_victim->GetGUID();
- highestThreatUpdate.ThreatList.reserve(_sortedThreatList.size());
- for (ThreatReference const* ref : _sortedThreatList)
+ auto fillSharedPacketDataAndSend = [&](auto& packet)
{
- if (!ref->IsAvailable())
- continue;
+ packet.UnitGUID = _owner->GetGUID();
+ packet.ThreatList.reserve(_sortedThreatList.size());
+ for (ThreatReference const* ref : _sortedThreatList)
+ {
+ if (!ref->IsAvailable())
+ continue;
- WorldPackets::Combat::ThreatInfo threatInfo;
- threatInfo.UnitGUID = ref->GetVictim()->GetGUID();
- threatInfo.Threat = int64(ref->GetThreat() * 100);
- highestThreatUpdate.ThreatList.push_back(threatInfo);
+ WorldPackets::Combat::ThreatInfo threatInfo;
+ threatInfo.UnitGUID = ref->GetVictim()->GetGUID();
+ threatInfo.Threat = int64(ref->GetThreat() * 100);
+ packet.ThreatList.push_back(threatInfo);
+ }
+ _owner->SendMessageToSet(packet.Write(), false);
+ };
+
+ if (newHighest)
+ {
+ WorldPackets::Combat::HighestThreatUpdate highestThreatUpdate;
+ highestThreatUpdate.HighestThreatGUID = _currentVictimRef->GetVictim()->GetGUID();
+ fillSharedPacketDataAndSend(highestThreatUpdate);
+ }
+ else
+ {
+ WorldPackets::Combat::ThreatUpdate threatUpdate;
+ fillSharedPacketDataAndSend(threatUpdate);
}
- _owner->SendMessageToSet(highestThreatUpdate.Write(), false);
}
void ThreatManager::PutThreatListRef(ObjectGuid const& guid, ThreatReference* ref)
@@ -721,22 +772,19 @@ void ThreatManager::PutThreatListRef(ObjectGuid const& guid, ThreatReference* re
ref->_handle = _sortedThreatList.push(ref);
}
-void ThreatManager::PurgeThreatListRef(ObjectGuid const& guid, bool sendRemove)
+void ThreatManager::PurgeThreatListRef(ObjectGuid const& guid)
{
auto it = _myThreatListEntries.find(guid);
if (it == _myThreatListEntries.end())
return;
ThreatReference* ref = it->second;
_myThreatListEntries.erase(it);
+ _sortedThreatList.erase(ref->_handle);
- if (_currentVictimRef == ref)
- _currentVictimRef = nullptr;
if (_fixateRef == ref)
_fixateRef = nullptr;
-
- _sortedThreatList.erase(ref->_handle);
- if (sendRemove && ref->IsAvailable())
- SendRemoveToClients(ref->_victim);
+ if (_currentVictimRef == ref)
+ _currentVictimRef = nullptr;
}
void ThreatManager::PutThreatenedByMeRef(ObjectGuid const& guid, ThreatReference* ref)