Core/Spells: Fully prevent infinite proc loops and add logging to detect most spells that could possibly trigger this behavior at startup
Port From (https://github.com/TrinityCore/TrinityCore/commit/29eac37a16df2ec14cba89f4d6e28f54ca1a4e25)
This commit is contained in:
@@ -84,6 +84,7 @@ namespace Game.Spells
|
||||
m_castId = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, m_caster.GetMapId(), m_spellInfo.Id, m_caster.GetMap().GenerateLowGuid(HighGuid.Cast));
|
||||
m_originalCastId = originalCastId;
|
||||
m_SpellVisual.SpellXSpellVisualID = caster.GetCastSpellXSpellVisualId(m_spellInfo);
|
||||
m_procChainLength = caster.IsUnit() ? caster.ToUnit().GetProcChainLength() : 0;
|
||||
|
||||
//Auto Shot & Shoot (wand)
|
||||
m_autoRepeat = m_spellInfo.IsAutoRepeatRangedSpell();
|
||||
@@ -7991,6 +7992,8 @@ namespace Game.Spells
|
||||
public bool IsProcDisabled() { return _triggeredCastFlags.HasAnyFlag(TriggerCastFlags.DisallowProcEvents); }
|
||||
public bool IsChannelActive() { return m_caster.IsUnit() && m_caster.ToUnit().GetChannelSpellId() != 0; }
|
||||
|
||||
public int GetProcChainLength() { return m_procChainLength; }
|
||||
|
||||
public bool IsDeletable()
|
||||
{
|
||||
return !m_referencedFromCurrentSpell && !m_executedCurrently;
|
||||
@@ -8161,6 +8164,7 @@ namespace Game.Spells
|
||||
// we can't store original aura link to prevent access to deleted auras
|
||||
// and in same time need aura data and after aura deleting.
|
||||
public SpellInfo m_triggeredByAuraSpell;
|
||||
int m_procChainLength;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -1518,6 +1518,7 @@ namespace Game.Entities
|
||||
procEntry.SpellPhaseMask = ProcFlagsSpellPhase.Hit;
|
||||
procEntry.HitMask = ProcFlagsHit.None; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
|
||||
|
||||
bool triggersSpell = false;
|
||||
foreach (var spellEffectInfo in spellInfo.GetEffects())
|
||||
{
|
||||
if (!spellEffectInfo.IsAura())
|
||||
@@ -1543,6 +1544,10 @@ namespace Game.Entities
|
||||
if (spellEffectInfo.CalcValue() <= -100)
|
||||
procEntry.HitMask = ProcFlagsHit.Miss;
|
||||
break;
|
||||
case AuraType.ProcTriggerSpell:
|
||||
case AuraType.ProcTriggerSpellWithValue:
|
||||
triggersSpell = spellEffectInfo.TriggerSpell != 0;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
@@ -1561,6 +1566,20 @@ namespace Game.Entities
|
||||
procEntry.Cooldown = spellInfo.ProcCooldown;
|
||||
procEntry.Charges = spellInfo.ProcCharges;
|
||||
|
||||
if (spellInfo.HasAttribute(SpellAttr3.CanProcFromProcs) && !procEntry.SpellFamilyMask
|
||||
&& procEntry.Chance >= 100
|
||||
&& spellInfo.ProcBasePPM <= 0.0f
|
||||
&& procEntry.Cooldown <= 0
|
||||
&& procEntry.Charges <= 0
|
||||
&& procEntry.ProcFlags.HasFlag(ProcFlags.DealMeleeAbility | ProcFlags.DealRangedAttack | ProcFlags.DealRangedAbility | ProcFlags.DealHelpfulAbility
|
||||
| ProcFlags.DealHarmfulAbility | ProcFlags.DealHelpfulSpell | ProcFlags.DealHarmfulSpell | ProcFlags.DealHarmfulPeriodic | ProcFlags.DealHelpfulPeriodic)
|
||||
&& triggersSpell)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Spell Id {spellInfo.Id} has SPELL_ATTR3_CAN_PROC_FROM_PROCS attribute and no restriction on what spells can cause it to proc and no cooldown. " +
|
||||
"This spell can cause infinite proc loops. Proc data for this spell was not generated, data in `spell_proc` table is required for it to function!");
|
||||
continue;
|
||||
}
|
||||
|
||||
mSpellProcMap[(spellInfo.Id, spellInfo.Difficulty)] = procEntry;
|
||||
++count;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user