From 8694a2ae24ea0570f5f8f8fcc747958f14ae05ef Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 23 Dec 2021 20:00:45 -0500 Subject: [PATCH] Core/Entities: Kick engagement logic upstairs to Unit (from ThreatManager), since all Units with AI need it (not just those with threat list). Port From (https://github.com/TrinityCore/TrinityCore/commit/35e55f10899712435102764671241b94a2026599) --- Source/Game/Chat/Commands/DebugCommands.cs | 8 ++-- Source/Game/Combat/CombatManager.cs | 4 ++ Source/Game/Combat/ThreatManager.cs | 45 +++++++--------------- Source/Game/Entities/Creature/Creature.cs | 20 ++++++++-- Source/Game/Entities/Unit/Unit.Combat.cs | 11 ++++-- Source/Game/Entities/Unit/Unit.Fields.cs | 3 ++ 6 files changed, 49 insertions(+), 42 deletions(-) diff --git a/Source/Game/Chat/Commands/DebugCommands.cs b/Source/Game/Chat/Commands/DebugCommands.cs index a36651bb7..a5dea619b 100644 --- a/Source/Game/Chat/Commands/DebugCommands.cs +++ b/Source/Game/Chat/Commands/DebugCommands.cs @@ -934,7 +934,7 @@ namespace Game.Chat { if (!mgr.IsThreatListEmpty(true)) { - if (mgr.IsEngaged()) + if (target.IsEngaged()) handler.SendSysMessage($"Threat list of {target.GetName()} ({target.GetGUID()}, SpawnID {(target.IsCreature() ? target.ToCreature().GetSpawnId() : 0)}):"); else handler.SendSysMessage($"{target.GetName()} ({target.GetGUID()}, SpawnID {(target.IsCreature() ? target.ToCreature().GetSpawnId() : 0)}) is not engaged, but still has a threat list? Well, here it is:"); @@ -948,13 +948,15 @@ namespace Game.Chat } handler.SendSysMessage("End of threat list."); } - else if (!mgr.IsEngaged()) + else if (!target.IsEngaged()) handler.SendSysMessage($"{target.GetName()} ({target.GetGUID()}, SpawnID {(target.IsCreature() ? target.ToCreature().GetSpawnId() : 0)}) is not currently engaged."); else handler.SendSysMessage($"{target.GetName()} ({target.GetGUID()}, SpawnID {(target.IsCreature() ? target.ToCreature().GetSpawnId() : 0)}) seems to be engaged, but does not have a threat list??"); } + else if (target.IsEngaged()) + handler.SendSysMessage($"{target.GetName()} ({target.GetGUID()}) is currently engaged. (This unit cannot have a threat list.)"); else - handler.SendSysMessage($"{target.GetName()} ({target.GetGUID()}) cannot have a threat list."); + handler.SendSysMessage($"{target.GetName()} ({target.GetGUID()}) is not currently engaged. (This unit cannot have a threat list.)"); return true; } diff --git a/Source/Game/Combat/CombatManager.cs b/Source/Game/Combat/CombatManager.cs index 710f306ab..b4990b1dc 100644 --- a/Source/Game/Combat/CombatManager.cs +++ b/Source/Game/Combat/CombatManager.cs @@ -277,11 +277,15 @@ namespace Game.Combat { _owner.AddUnitFlag(UnitFlags.InCombat); _owner.AtEnterCombat(); + if (!_owner.CanHaveThreatList() && !_owner.IsEngaged()) + _owner.AtEngage(GetAnyTarget()); } else { _owner.RemoveUnitFlag(UnitFlags.InCombat); _owner.AtExitCombat(); + if (_owner.IsEngaged() && !(_owner.IsCreature() && _owner.ToCreature().IsAIEnabled())) + _owner.AtDisengage(); } Unit master = _owner.GetCharmerOrOwner(); diff --git a/Source/Game/Combat/ThreatManager.cs b/Source/Game/Combat/ThreatManager.cs index 070330e75..381876c50 100644 --- a/Source/Game/Combat/ThreatManager.cs +++ b/Source/Game/Combat/ThreatManager.cs @@ -32,7 +32,6 @@ namespace Game.Combat public Unit _owner; bool _ownerCanHaveThreatList; - bool _ownerEngaged; public bool NeedClientUpdate; uint _updateTimer; @@ -82,7 +81,7 @@ namespace Game.Combat public void Update(uint tdiff) { - if (!CanHaveThreatList() || !IsEngaged()) + if (!CanHaveThreatList() || IsThreatListEmpty()) return; if (_updateTimer <= tdiff) @@ -192,13 +191,6 @@ namespace Game.Combat } } - static void SaveCreatureHomePositionIfNeed(Creature c) - { - MovementGeneratorType movetype = c.GetMotionMaster().GetCurrentMovementGeneratorType(); - if (movetype == MovementGeneratorType.Waypoint || movetype == MovementGeneratorType.Point || (c.IsAIEnabled() && c.GetAI().IsEscorted())) - c.SetHomePosition(c.GetPosition()); - } - public void AddThreat(Unit target, float amount, SpellInfo spell = null, bool ignoreModifiers = false, bool ignoreRedirects = false) { // step 1: we can shortcut if the spell has one of the NO_THREAT attrs set - nothing will happen @@ -317,20 +309,10 @@ namespace Game.Combat if (newRefe.IsOnline()) // ...and if the ref is online it also gets the threat it should have newRefe.AddThreat(amount); - if (!_ownerEngaged) + if (!_owner.IsEngaged()) { - Creature cOwner = _owner.ToCreature(); // if we got here the owner can have a threat list, and must be a creature! - _ownerEngaged = true; - + _owner.AtEngage(target); UpdateVictim(); - SaveCreatureHomePositionIfNeed(cOwner); - CreatureAI ownerAI = cOwner.GetAI(); - if (ownerAI != null) - ownerAI.JustEngagedWith(target); - - CreatureGroup formation = cOwner.GetFormation(); - if (formation != null) - formation.MemberEngagingTarget(cOwner, target); } } @@ -407,14 +389,17 @@ namespace Game.Combat public void ClearAllThreat() { - _ownerEngaged = false; - if (_myThreatListEntries.Empty()) - return; - - SendClearAllThreatToClients(); - do - _myThreatListEntries.First().Value.UnregisterAndFree(); - while (!_myThreatListEntries.Empty()); + if (!_myThreatListEntries.Empty()) + { + SendClearAllThreatToClients(); + do + _myThreatListEntries.FirstOrDefault().Value.UnregisterAndFree(); + while (!_myThreatListEntries.Empty()); + } + // note: i don't really like having this here + // (maybe engage flag should be in creature ai? it's inherently an AI property...) + if (_owner.IsEngaged()) + _owner.AtDisengage(); } public void FixateTarget(Unit target) @@ -783,8 +768,6 @@ namespace Game.Combat // identical to ThreatManager::CanHaveThreatList(GetOwner()) public bool CanHaveThreatList() { return _ownerCanHaveThreatList; } - public bool IsEngaged() { return _ownerEngaged; } - public int GetThreatListSize() { return _sortedThreatList.Count; } // fastest of the three threat list getters - gets the threat list in "arbitrary" order diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 2d9f9cb3d..73a802fe8 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -1042,9 +1042,9 @@ namespace Game.Entities && !GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoXpAtKill); } - public override void AtEnterCombat() + public override void AtEngage(Unit target) { - base.AtEnterCombat(); + base.AtEngage(target); if (!GetCreatureTemplate().TypeFlags.HasAnyFlag(CreatureTypeFlags.MountedCombatAllowed)) Dismount(); @@ -1055,11 +1055,23 @@ namespace Game.Entities UpdateSpeed(UnitMoveType.Swim); UpdateSpeed(UnitMoveType.Flight); } + + MovementGeneratorType movetype = GetMotionMaster().GetCurrentMovementGeneratorType(); + if (movetype == MovementGeneratorType.Waypoint || movetype == MovementGeneratorType.Point || (IsAIEnabled() && GetAI().IsEscorted())) + SetHomePosition(GetPosition()); + + CreatureAI ai = GetAI(); + if (ai != null) + ai.JustEngagedWith(target); + + CreatureGroup formation = GetFormation(); + if (formation != null) + formation.MemberEngagingTarget(this, target); } - public override void AtExitCombat() + public override void AtDisengage() { - base.AtExitCombat(); + base.AtDisengage(); ClearUnitState(UnitState.AttackPlayer); if (HasDynamicFlag(UnitDynFlags.Tapped)) diff --git a/Source/Game/Entities/Unit/Unit.Combat.cs b/Source/Game/Entities/Unit/Unit.Combat.cs index 289b06ecb..31e915e5d 100644 --- a/Source/Game/Entities/Unit/Unit.Combat.cs +++ b/Source/Game/Entities/Unit/Unit.Combat.cs @@ -57,6 +57,9 @@ namespace Game.Entities RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeavingCombat); } + public virtual void AtEngage(Unit target) { m_isEngaged = true; } + public virtual void AtDisengage() { m_isEngaged = false; } + public void CombatStop(bool includingCast = false, bool mutualPvP = true) { if (includingCast && IsNonMeleeSpellCast(false)) @@ -144,10 +147,10 @@ namespace Game.Entities public bool CanHaveThreatList() { return m_threatManager.CanHaveThreatList(); } - // For NPCs with threat list: Whether there are any enemies on our threat list - // For other units: Whether we're in combat - // This value is different from IsInCombat when a projectile spell is midair (combat on launch - threat+aggro on impact) - public bool IsEngaged() { return CanHaveThreatList() ? m_threatManager.IsEngaged() : IsInCombat(); } + // This value can be different from IsInCombat: + // - when a projectile spell is midair against a creature (combat on launch - threat+aggro on impact) + // - when the creature has no targets left, but the AI has not yet ceased engaged logic + public bool IsEngaged() { return m_isEngaged; } public bool IsEngagedBy(Unit who) { return CanHaveThreatList() ? IsThreatenedBy(who) : IsInCombatWith(who); } diff --git a/Source/Game/Entities/Unit/Unit.Fields.cs b/Source/Game/Entities/Unit/Unit.Fields.cs index f48b8cd62..fe90511a9 100644 --- a/Source/Game/Entities/Unit/Unit.Fields.cs +++ b/Source/Game/Entities/Unit/Unit.Fields.cs @@ -54,6 +54,9 @@ namespace Game.Entities internal float[] m_modAttackSpeedPct = new float[(int)WeaponAttackType.Max]; protected uint[] m_attackTimer = new uint[(int)WeaponAttackType.Max]; + // Threat+combat management + bool m_isEngaged; + CombatManager m_combatManager; ThreatManager m_threatManager;