From 92c90bf77771911e751a7a7d8882e3a3fd8fb5fe Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 2 Jan 2022 19:49:21 -0500 Subject: [PATCH] Core/Unit: Spell focusing now no longer nonsensical. HasSpellFocus always const. Error logs for various stuff. Port From (https://github.com/TrinityCore/TrinityCore/commit/14c38a1c529e634b068a67b3e7475ddcf599086b) --- Source/Game/AI/CoreAI/CreatureAI.cs | 4 +- .../Game/Entities/Creature/Creature.Fields.cs | 14 +- Source/Game/Entities/Creature/Creature.cs | 133 ++++++++---------- Source/Game/Entities/Unit/Unit.Spells.cs | 4 +- Source/Game/Handlers/PetHandler.cs | 4 +- Source/Game/Spells/Spell.cs | 8 +- 6 files changed, 76 insertions(+), 91 deletions(-) diff --git a/Source/Game/AI/CoreAI/CreatureAI.cs b/Source/Game/AI/CoreAI/CreatureAI.cs index c3e2fd181..d1adee1da 100644 --- a/Source/Game/AI/CoreAI/CreatureAI.cs +++ b/Source/Game/AI/CoreAI/CreatureAI.cs @@ -254,7 +254,7 @@ namespace Game.AI { Unit victim = me.SelectVictim(); if (victim != null) - if (!me.HandleSpellFocus(null, true) && victim != me.GetVictim()) + if (!me.HasSpellFocus() && victim != me.GetVictim()) AttackStart(victim); return me.GetVictim() != null; @@ -313,7 +313,7 @@ namespace Game.AI me.ResetPlayerDamageReq(); me.SetLastDamagedTime(0); me.SetCannotReachTarget(false); - me.DoNotReacquireTarget(); + me.DoNotReacquireSpellFocusTarget(); EngagementOver(); return true; diff --git a/Source/Game/Entities/Creature/Creature.Fields.cs b/Source/Game/Entities/Creature/Creature.Fields.cs index 8840b42b7..324689f20 100644 --- a/Source/Game/Entities/Creature/Creature.Fields.cs +++ b/Source/Game/Entities/Creature/Creature.Fields.cs @@ -27,11 +27,7 @@ namespace Game.Entities CreatureTemplate m_creatureInfo; CreatureData m_creatureData; - Spell _focusSpell; // Locks the target during spell cast for proper facing - uint _spellFocusDelay; - bool _shouldReacquireSpellFocusTarget; - ObjectGuid _suppressedSpellFocusTarget; // Stores the creature's "real" target while casting - float _suppressedSpellFocusOrientation; // Stores the creature's "real" orientation while casting + SpellFocusInfo _spellFocusInfo; long _lastDamagedTime; // Part of Evade mechanics MultiMap m_textRepeat = new(); @@ -104,4 +100,12 @@ namespace Game.Entities Active, // in move list Inactive // in move list but should not move } + + struct SpellFocusInfo + { + public Spell spell; + public uint delay; // ms until the creature's target should snap back (0 = no snapback scheduled) + public ObjectGuid target; // the creature's "real" target while casting + public float orientation; // the creature's "real" orientation while casting + } } diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 37f177ffb..695f9a002 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -532,23 +532,12 @@ namespace Game.Entities GetThreatManager().Update(diff); - if (_shouldReacquireSpellFocusTarget && !HandleSpellFocus(null, true)) + if (_spellFocusInfo.delay != 0) { - SetTarget(_suppressedSpellFocusTarget); - - if (!HasUnitFlag2(UnitFlags2.DisableTurn)) - { - if (!_suppressedSpellFocusTarget.IsEmpty()) - { - WorldObject objTarget = Global.ObjAccessor.GetWorldObject(this, _suppressedSpellFocusTarget); - if (objTarget) - SetFacingToObject(objTarget); - } - else - SetFacingTo(_suppressedSpellFocusOrientation); - } - - _shouldReacquireSpellFocusTarget = false; + if (_spellFocusInfo.delay <= diff) + ReacquireSpellFocusTarget(); + else + _spellFocusInfo.delay -= 0; } // periodic check to see if the creature has passed an evade boundary @@ -932,7 +921,7 @@ namespace Game.Entities if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target)) { - if (!HandleSpellFocus(null, true)) + if (!HasSpellFocus()) SetInFront(target); return target; } @@ -1121,7 +1110,7 @@ namespace Game.Entities return true; } - if (HasSpellFocusTarget()) + if (HasSpellFocus()) return true; if (HasUnitState(UnitState.Casting)) @@ -1820,8 +1809,8 @@ namespace Game.Entities SaveRespawnTime(); ReleaseSpellFocus(null, false); // remove spellcast focus - DoNotReacquireTarget(); // cancel delayed re-target - SetTarget(ObjectGuid.Empty); // drop target - dead mobs shouldn't ever target things + DoNotReacquireSpellFocusTarget(); // cancel delayed re-target + SetTarget(ObjectGuid.Empty); // drop target - dead mobs shouldn't ever target things SetNpcFlags(NPCFlags.None); SetNpcFlags2(NPCFlags2.None); @@ -2919,16 +2908,16 @@ namespace Game.Entities public override void SetTarget(ObjectGuid guid) { - if (HandleSpellFocus(null, true)) - _suppressedSpellFocusTarget = guid; + if (HasSpellFocus()) + _spellFocusInfo.target = guid; else SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Target), guid); } - public void SetSpellFocusTarget(Spell focusSpell, WorldObject target) + public void SetSpellFocus(Spell focusSpell, WorldObject target) { // already focused - if (_focusSpell != null) + if (_spellFocusInfo.spell != null) return; // Prevent dead/feigning death creatures from setting a focus target, so they won't turn @@ -2953,14 +2942,17 @@ namespace Game.Entities return; // store pre-cast values for target and orientation (used to later restore) - if (!HandleSpellFocus(null, true)) + if (_spellFocusInfo.delay == 0) { // only overwrite these fields if we aren't transitioning from one spell focus to another - _suppressedSpellFocusTarget = GetTarget(); - _suppressedSpellFocusOrientation = GetOrientation(); + _spellFocusInfo.target = GetTarget(); + _spellFocusInfo.orientation = GetOrientation(); } + else // don't automatically reacquire target for the previous spellcast + _spellFocusInfo.delay = 0; - _focusSpell = focusSpell; + _spellFocusInfo.spell = focusSpell; + bool noTurnDuringCast = spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast); // set target, then force send update packet to players if it changed to provide appropriate facing ObjectGuid newTarget = target ? target.GetGUID() : ObjectGuid.Empty; if (GetTarget() != newTarget) @@ -2970,7 +2962,7 @@ namespace Game.Entities // here we determine if the (relatively expensive) forced update is worth it, or whether we can afford to wait until the scheduled update tick // only require instant update for spells that actually have a visual if (spellInfo.GetSpellVisual() != 0 && (focusSpell.GetCastTime() == 0 || // if the spell is instant cast - spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast))) // client gets confused if we attempt to turn at the regularly scheduled update packet + noTurnDuringCast)) // client gets confused if we attempt to turn at the regularly scheduled update packet { List playersNearby = GetPlayerListInGrid(GetVisibilityRange()); foreach (Player player in playersNearby) @@ -2982,8 +2974,6 @@ namespace Game.Entities } } - bool noTurnDuringCast = spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast); - if (!HasUnitFlag2(UnitFlags2.DisableTurn)) { // Face the target - we need to do this before the unit state is modified for no-turn spells @@ -3001,75 +2991,68 @@ namespace Game.Entities AddUnitState(UnitState.Focusing); } - public override bool HandleSpellFocus(Spell focusSpell = null, bool withDelay = false) + public override bool HasSpellFocus(Spell focusSpell = null) { if (!IsAlive()) // dead creatures cannot focus { - ReleaseSpellFocus(null, false); + if (_spellFocusInfo.spell != null || _spellFocusInfo.delay != 0) + Log.outWarn(LogFilter.Unit, $"Creature '{GetName()}' (entry {GetEntry()}) has spell focus (spell id {(_spellFocusInfo.spell != null ? _spellFocusInfo.spell.GetSpellInfo().Id : 0)}, delay {_spellFocusInfo.delay}ms) despite being dead."); + return false; } - if (focusSpell && (focusSpell != _focusSpell)) - return false; - - if (!_focusSpell) - { - if (!withDelay || _spellFocusDelay == 0) - return false; - if (Time.GetMSTimeDiffToNow(_spellFocusDelay) > 1000) // @todo figure out if we can get rid of this magic number somehow - { - _spellFocusDelay = 0; // save checks in the future - return false; - } - } - - return true; + if (focusSpell) + return focusSpell == _spellFocusInfo.spell; + else + return _spellFocusInfo.spell != null || _spellFocusInfo.delay != 0; } public void ReleaseSpellFocus(Spell focusSpell = null, bool withDelay = true) { - if (_focusSpell == null) + if (!_spellFocusInfo.spell) return; // focused to something else - if (focusSpell && focusSpell != _focusSpell) + if (focusSpell && focusSpell != _spellFocusInfo.spell) return; - if (IsPet() && !HasUnitFlag2(UnitFlags2.DisableTurn))// player pets do not use delay system + if (_spellFocusInfo.spell.GetSpellInfo().HasAttribute(SpellAttr5.DontTurnDuringCast)) + ClearUnitState(UnitState.Focusing); + + if (IsPet()) // player pets do not use delay system { - SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.Target), _suppressedSpellFocusTarget); - if (!_suppressedSpellFocusTarget.IsEmpty()) + if (!HasUnitFlag2(UnitFlags2.DisableTurn)) + ReacquireSpellFocusTarget(); + } + else // don't allow re-target right away to prevent visual bugs + _spellFocusInfo.delay = withDelay ? 1000 : 1u; + + _spellFocusInfo.spell = null; + } + + void ReacquireSpellFocusTarget() + { + if (!HasSpellFocus()) + return; + + SetTarget(_spellFocusInfo.target); + + if (!HasUnitFlag2(UnitFlags2.DisableTurn)) + { + if (!_spellFocusInfo.target.IsEmpty()) { - WorldObject objTarget = Global.ObjAccessor.GetWorldObject(this, _suppressedSpellFocusTarget); + WorldObject objTarget = Global.ObjAccessor.GetWorldObject(this, _spellFocusInfo.target); if (objTarget) SetFacingToObject(objTarget, false); } else - SetFacingTo(_suppressedSpellFocusOrientation, false); + SetFacingTo(_spellFocusInfo.orientation, false); } - else - // tell the creature that it should reacquire its actual target after the delay expires (this is handled in ::Update) - // player pets don't need to do this, as they automatically reacquire their target on focus release - MustReacquireTarget(); - if (_focusSpell.GetSpellInfo().HasAttribute(SpellAttr5.DontTurnDuringCast)) - ClearUnitState(UnitState.Focusing); - - _focusSpell = null; - _spellFocusDelay = (!IsPet() && withDelay) ? GameTime.GetGameTimeMS() : 0; // don't allow re-target right away to prevent visual bugs + _spellFocusInfo.delay = 0; } - public override bool HasSpellFocusTarget() { return IsAlive() && (_focusSpell != null || _spellFocusDelay != 0); } - - public void MustReacquireTarget() { _shouldReacquireSpellFocusTarget = true; } // flags the Creature for forced (client displayed) target reacquisition in the next Update call - - public void DoNotReacquireTarget() - { - _shouldReacquireSpellFocusTarget = false; - _suppressedSpellFocusTarget = ObjectGuid.Empty; - SetTarget(ObjectGuid.Empty); - _suppressedSpellFocusOrientation = 0.0f; - } + public void DoNotReacquireSpellFocusTarget() { _spellFocusInfo.delay = 0; } public ulong GetSpawnId() { return m_spawnId; } diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index d2cf4d942..154c01065 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1041,9 +1041,7 @@ namespace Game.Entities return 0; } - public virtual bool HandleSpellFocus(Spell focusSpell = null, bool withDelay = false) { return false; } - - public virtual bool HasSpellFocusTarget() { return false; } + public virtual bool HasSpellFocus(Spell focusSpell = null) { return false; } /// /// Check if our current channel spell has attribute SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING diff --git a/Source/Game/Handlers/PetHandler.cs b/Source/Game/Handlers/PetHandler.cs index dbb77221c..c905989c6 100644 --- a/Source/Game/Handlers/PetHandler.cs +++ b/Source/Game/Handlers/PetHandler.cs @@ -327,7 +327,7 @@ namespace Game Unit unit_target2 = spell.m_targets.GetUnitTarget(); if (unit_target) { - if (!pet.HandleSpellFocus()) + if (!pet.HasSpellFocus()) pet.SetInFront(unit_target); Player player = unit_target.ToPlayer(); if (player) @@ -335,7 +335,7 @@ namespace Game } else if (unit_target2) { - if (!pet.HandleSpellFocus()) + if (!pet.HasSpellFocus()) pet.SetInFront(unit_target2); Player player = unit_target2.ToPlayer(); if (player) diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 1bfa86229..1dfa88b66 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2343,9 +2343,9 @@ namespace Game.Spells if (!(m_spellInfo.IsNextMeleeSwingSpell() || IsAutoRepeat())) { if (m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget()) - m_caster.ToCreature().SetSpellFocusTarget(this, m_targets.GetObjectTarget()); + m_caster.ToCreature().SetSpellFocus(this, m_targets.GetObjectTarget()); else if (m_spellInfo.HasAttribute(SpellAttr5.DontTurnDuringCast)) - m_caster.ToCreature().SetSpellFocusTarget(this, null); + m_caster.ToCreature().SetSpellFocus(this, null); } } @@ -3998,8 +3998,8 @@ namespace Game.Spells { Creature creatureCaster = unitCaster.ToCreature(); if (creatureCaster != null) - if (!creatureCaster.HandleSpellFocus(this)) - creatureCaster.SetSpellFocusTarget(this, Global.ObjAccessor.GetWorldObject(creatureCaster, target.TargetGUID)); + if (!creatureCaster.HasSpellFocus()) + creatureCaster.SetSpellFocus(this, Global.ObjAccessor.GetWorldObject(creatureCaster, target.TargetGUID)); } } }