From 77e549c0f417b8dc4e6cbe8ab98aa3f3ab93fb97 Mon Sep 17 00:00:00 2001 From: Shauren Date: Thu, 9 Apr 2026 16:35:42 +0200 Subject: [PATCH] Core/Spells: Fixed crashes happening when aura remove or proc script despawns a creature that is already despawning --- src/server/game/Spells/Spell.cpp | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index d73bcdc3e2..d411f5938e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3617,10 +3617,19 @@ void Spell::cancel() SendCastResult(SPELL_FAILED_INTERRUPTED); break; case SPELL_STATE_CHANNELING: - for (TargetInfo const& targetInfo : m_UniqueTargetInfo) - if (targetInfo.MissCondition == SPELL_MISS_NONE) - if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID)) - unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL); + { + // Mark current spell as not deletable to protect against scripts attempting to despawn the caster twice (aura removal) + // while current spell is being cancelled by despawn + bool executed = m_executedCurrently; + SetExecutedCurrently(true); + + for (TargetInfo const& targetInfo : m_UniqueTargetInfo) + if (targetInfo.MissCondition == SPELL_MISS_NONE) + if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID)) + unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL); + + SetExecutedCurrently(executed); + } SendChannelUpdate(0, SPELL_FAILED_INTERRUPTED); SendInterrupted(0); @@ -4370,7 +4379,16 @@ void Spell::finish(SpellCastResult result) if (Creature* creatureCaster = unitCaster->ToCreature()) creatureCaster->ReleaseSpellFocus(this); - Unit::ProcSkillsAndAuras(unitCaster, nullptr, PROC_FLAG_CAST_ENDED, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, this, nullptr, nullptr); + { + // Mark current spell as not deletable to protect against scripts attempting to despawn the caster twice + // while current spell is already being finished by despawn + bool executed = m_executedCurrently; + SetExecutedCurrently(true); + + Unit::ProcSkillsAndAuras(unitCaster, nullptr, PROC_FLAG_CAST_ENDED, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, this, nullptr, nullptr); + + SetExecutedCurrently(executed); + } if (IsEmpowerSpell()) {