From 98206ec20115c996d796974cf6bc02e90246e55a Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 22 Feb 2022 18:37:01 -0500 Subject: [PATCH] Fixes aura infinite loop Port From (https://github.com/TrinityCore/TrinityCore/commit/9cb01a79046fce3f76835bb68bf66e4f3079e4bc) --- Source/Game/Entities/Unit/Unit.Spells.cs | 43 +++++++++++++++++++--- Source/Game/Spells/Auras/Aura.cs | 5 +++ Source/Game/Spells/Auras/AuraEffect.cs | 45 ++++++++++++++---------- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index d9cd122f5..6115ac5a6 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -24,6 +24,7 @@ using Game.Spells; using System; using System.Collections.Generic; using System.Linq; +using System.Text; namespace Game.Entities { @@ -3345,12 +3346,44 @@ namespace Game.Entities { // this may be a dead loop if some events on aura remove will continiously apply aura on remove // we want to have all auras removed, so use your brain when linking events - while (!m_appliedAuras.Empty()) - _UnapplyAura(m_appliedAuras.FirstOrDefault(), AuraRemoveMode.Default); + for (int counter = 0; !m_appliedAuras.Empty() || !m_ownedAuras.Empty(); counter++) + { + foreach (var aurAppIter in GetAppliedAuras()) + _UnapplyAura(aurAppIter, AuraRemoveMode.Default); - while (!m_ownedAuras.Empty()) - RemoveOwnedAura(m_ownedAuras.FirstOrDefault()); + foreach (var aurIter in GetOwnedAuras()) + RemoveOwnedAura(aurIter); + + const int maxIteration = 50; + // give this loop a few tries, if there are still auras then log as much information as possible + if (counter >= maxIteration) + { + StringBuilder sstr = new(); + sstr.AppendLine($"Unit::RemoveAllAuras() iterated {maxIteration} times already but there are still {m_appliedAuras.Count} m_appliedAuras and {m_ownedAuras.Count} m_ownedAuras. Details:"); + sstr.AppendLine(GetDebugInfo()); + + if (!m_appliedAuras.Empty()) + { + sstr.AppendLine("m_appliedAuras:"); + + foreach (var auraAppPair in GetAppliedAuras()) + sstr.AppendLine(auraAppPair.Value.GetDebugInfo()); + } + + if (!m_ownedAuras.Empty()) + { + sstr.AppendLine("m_ownedAuras:"); + + foreach (var auraPair in GetOwnedAuras()) + sstr.AppendLine(auraPair.Value.GetDebugInfo()); + } + + Log.outError(LogFilter.Unit, sstr.ToString()); + break; + } + } } + public void RemoveArenaAuras() { // in join, remove positive buffs, on end, remove negative @@ -3364,6 +3397,7 @@ namespace Game.Entities aura.GetSpellInfo().HasAttribute(SpellAttr5.RemoveEnteringArena); // special marker, always remove }); } + public void RemoveAllAurasExceptType(AuraType type) { foreach (var pair in GetAppliedAuras()) @@ -3385,6 +3419,7 @@ namespace Game.Entities RemoveOwnedAura(pair, AuraRemoveMode.Default); } } + public void RemoveAllAurasExceptType(AuraType type1, AuraType type2) { foreach (var pair in GetAppliedAuras()) diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index fd4af826b..0b2a4b7a5 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -299,6 +299,11 @@ namespace Game.Spells _target.SendMessageToSet(update, true); } + public string GetDebugInfo() + { + return $"Base: {(GetBase() != null ? GetBase().GetDebugInfo() : "NULL")}\nTarget: {(GetTarget() != null ? GetTarget().GetDebugInfo() : "NULL")}"; + } + public Unit GetTarget() { return _target; } public Aura GetBase() { return _base; } diff --git a/Source/Game/Spells/Auras/AuraEffect.cs b/Source/Game/Spells/Auras/AuraEffect.cs index 645946444..16a567c0c 100644 --- a/Source/Game/Spells/Auras/AuraEffect.cs +++ b/Source/Game/Spells/Auras/AuraEffect.cs @@ -924,8 +924,9 @@ namespace Game.Spells target.m_invisibilityDetect.AddValue(type, -GetAmount()); } - // call functions which may have additional effects after chainging state of unit - target.UpdateObjectVisibility(); + // call functions which may have additional effects after changing state of unit + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.ModInvisibility)] @@ -978,13 +979,15 @@ namespace Game.Spells target.m_invisibility.AddValue(type, -GetAmount()); } - // call functions which may have additional effects after chainging state of unit + // call functions which may have additional effects after changing state of unit if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real)) { // drop flag at invisibiliy in bg target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); } - target.UpdateObjectVisibility(); + + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.ModStealthDetect)] @@ -1009,8 +1012,9 @@ namespace Game.Spells target.m_stealthDetect.AddValue(type, -GetAmount()); } - // call functions which may have additional effects after chainging state of unit - target.UpdateObjectVisibility(); + // call functions which may have additional effects after changing state of unit + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.ModStealth)] @@ -1046,13 +1050,15 @@ namespace Game.Spells } } - // call functions which may have additional effects after chainging state of unit + // call functions which may have additional effects after changing state of unit if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real)) { // drop flag at stealth in bg target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis); } - target.UpdateObjectVisibility(); + + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.ModStealthLevel)] @@ -1069,8 +1075,9 @@ namespace Game.Spells else target.m_stealth.AddValue(type, -GetAmount()); - // call functions which may have additional effects after chainging state of unit - target.UpdateObjectVisibility(); + // call functions which may have additional effects after changing state of unit + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.DetectAmore)] @@ -1133,7 +1140,7 @@ namespace Game.Spells } // die at aura end else if (target.IsAlive()) - // call functions which may have additional effects after chainging state of unit + // call functions which may have additional effects after changing state of unit target.SetDeathState(DeathState.JustDied); } @@ -1709,7 +1716,7 @@ namespace Game.Spells else target.RemoveUnitFlag(UnitFlags.NonAttackable2); - // call functions which may have additional effects after chainging state of unit + // call functions which may have additional effects after changing state of unit if (apply && mode.HasAnyFlag(AuraEffectHandleModes.Real)) { if (target.GetMap().IsDungeon()) @@ -1810,7 +1817,7 @@ namespace Game.Spells { target.AddUnitFlag(UnitFlags.Silenced); - // call functions which may have additional effects after chainging state of unit + // call functions which may have additional effects after changing state of unit // Stop cast only spells vs PreventionType & SPELL_PREVENTION_TYPE_SILENCE for (var i = CurrentSpellTypes.Melee; i < CurrentSpellTypes.Max; ++i) { @@ -1889,7 +1896,7 @@ namespace Game.Spells { target.AddUnitFlag2(UnitFlags2.NoActions); - // call functions which may have additional effects after chainging state of unit + // call functions which may have additional effects after changing state of unit // Stop cast only spells vs PreventionType & SPELL_PREVENTION_TYPE_SILENCE for (var i = CurrentSpellTypes.Melee; i < CurrentSpellTypes.Max; ++i) { @@ -1969,8 +1976,9 @@ namespace Game.Spells target.RemoveDynamicFlag(UnitDynFlags.TrackUnit); } - // call functions which may have additional effects after chainging state of unit - target.UpdateObjectVisibility(); + // call functions which may have additional effects after changing state of unit + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.Untrackable)] @@ -4769,8 +4777,9 @@ namespace Game.Spells target.m_invisibilityDetect.DelFlag(InvisibilityType.Drunk); } - // call functions which may have additional effects after chainging state of unit - target.UpdateObjectVisibility(); + // call functions which may have additional effects after changing state of unit + if (target.IsInWorld) + target.UpdateObjectVisibility(); } [AuraEffectHandler(AuraType.OverrideSpells)]