diff options
author | Treeston <treeston.mmoc@gmail.com> | 2018-08-27 19:08:17 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-10-23 02:14:04 +0200 |
commit | 392a644dc8562ea54b9c185a2776fceb1006e2cd (patch) | |
tree | eec4d04885e582c39f0b88ea1cf0d87b4bb1015a /src/server/game/Combat/ThreatManager.cpp | |
parent | 395f58d651c7c370522ead6ba9a3c684d91e3a66 (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.cpp | 280 |
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) |