diff --git a/src/framework/Utilities/EventProcessor.cpp b/src/framework/Utilities/EventProcessor.cpp index 65de7c1aa..2bcf6a46a 100644 --- a/src/framework/Utilities/EventProcessor.cpp +++ b/src/framework/Utilities/EventProcessor.cpp @@ -26,7 +26,7 @@ EventProcessor::EventProcessor() EventProcessor::~EventProcessor() { - KillAllEvents(); + KillAllEvents(true); } void EventProcessor::Update(uint32 p_time) @@ -58,21 +58,31 @@ void EventProcessor::Update(uint32 p_time) } } -void EventProcessor::KillAllEvents() +void EventProcessor::KillAllEvents(bool force) { // prevent event insertions m_aborting = true; // first, abort all existing events - for (EventList::iterator i = m_events.begin(); i != m_events.end(); ++i) + for (EventList::iterator i = m_events.begin(); i != m_events.end();) { - i->second->to_Abort = true; - i->second->Abort(m_time); - delete i->second; + EventList::iterator i_old = i; + ++i; + + i_old->second->to_Abort = true; + i_old->second->Abort(m_time); + if(force || i_old->second->IsDeletable()) + { + delete i_old->second; + + if(!force) // need per-element cleanup + m_events.erase (i_old); + } } - // clear event list - m_events.clear(); + // fast clear event list (in force case) + if(force) + m_events.clear(); } void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime) diff --git a/src/framework/Utilities/EventProcessor.h b/src/framework/Utilities/EventProcessor.h index 5d83c02a2..350db5bb5 100644 --- a/src/framework/Utilities/EventProcessor.h +++ b/src/framework/Utilities/EventProcessor.h @@ -38,6 +38,8 @@ class BasicEvent // e_time is execution time, p_time is update interval virtual bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) { return true; } + virtual bool IsDeletable() const { return true; } // this event can be safely deleted + virtual void Abort(uint64 /*e_time*/) {} // this method executes when the event is aborted bool to_Abort; // set by externals when the event is aborted, aborted events don't execute @@ -57,7 +59,7 @@ class EventProcessor ~EventProcessor(); void Update(uint32 p_time); - void KillAllEvents(); + void KillAllEvents(bool force); void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true); uint64 CalculateTime(uint64 t_offset); protected: diff --git a/src/game/Map.cpp b/src/game/Map.cpp index fad5200f2..7518cf170 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -1355,6 +1355,9 @@ void Map::RemoveAllObjectsInRemoveList() Remove((GameObject*)obj,true); break; case TYPEID_UNIT: + // in case triggred sequence some spell can continue casting after prev CleanupsBeforeDelete call + // make sure that like sources auras/etc removed before destructor start + ((Creature*)obj)->CleanupsBeforeDelete (); Remove((Creature*)obj,true); break; default: diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 982d5b02a..a18a8cd3a 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -268,7 +268,8 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi m_caster = Caster; m_selfContainer = NULL; m_triggeringContainer = triggeringContainer; - m_deletable = true; + m_referencedFromCurrentSpell = false; + m_executedCurrently = false; m_delayAtDamageCount = 0; m_applyMultiplierMask = 0; @@ -2019,6 +2020,8 @@ void Spell::cancel() void Spell::cast(bool skipCheck) { + SetExecutedCurrently(true); + uint8 castResult = 0; // update pointers base at GUIDs to prevent access to non-existed already object @@ -2028,6 +2031,7 @@ void Spell::cast(bool skipCheck) if(!m_targets.getUnitTarget() && m_targets.getUnitTargetGUID() && m_targets.getUnitTargetGUID() != m_caster->GetGUID()) { cancel(); + SetExecutedCurrently(false); return; } @@ -2039,6 +2043,7 @@ void Spell::cast(bool skipCheck) { SendCastResult(castResult); finish(false); + SetExecutedCurrently(false); return; } @@ -2050,6 +2055,7 @@ void Spell::cast(bool skipCheck) { SendCastResult(castResult); finish(false); + SetExecutedCurrently(false); return; } } @@ -2082,7 +2088,10 @@ void Spell::cast(bool skipCheck) FillTargetMap(); if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap + { + SetExecutedCurrently(false); return; + } SendCastResult(castResult); SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... @@ -2114,6 +2123,8 @@ void Spell::cast(bool skipCheck) // Immediate spell, no big deal handle_immediate(); } + + SetExecutedCurrently(false); } void Spell::handle_immediate() @@ -5063,3 +5074,8 @@ void SpellEvent::Abort(uint64 /*e_time*/) if (m_Spell->getState() != SPELL_STATE_FINISHED) m_Spell->cancel(); } + +bool SpellEvent::IsDeletable() const +{ + return m_Spell->IsDeletable(); +} diff --git a/src/game/Spell.h b/src/game/Spell.h index 093a91570..aa32c326a 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -380,8 +380,9 @@ class Spell bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } bool IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && IsRangedSpell() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } - bool IsDeletable() const { return m_deletable; } - void SetDeletable(bool deletable) { m_deletable = deletable; } + bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; } + void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; } + void SetExecutedCurrently(bool yes) { m_executedCurrently = yes; } uint64 GetDelayStart() const { return m_delayStart; } void SetDelayStart(uint64 m_time) { m_delayStart = m_time; } uint64 GetDelayMoment() const { return m_delayMoment; } @@ -433,7 +434,8 @@ class Spell bool m_immediateHandled; // were immediate actions handled? (used by delayed spells only) // These vars are used in both delayed spell system and modified immediate spell system - bool m_deletable; // is the spell pending deletion or must be updated till permitted to delete? + bool m_referencedFromCurrentSpell; // mark as references to prevent deleted and access by dead pointers + bool m_executedCurrently; // mark as executed to prevent deleted and access by dead pointers bool m_needSpellLog; // need to send spell log? uint8 m_applyMultiplierMask; // by effect: damage multiplier needed? float m_damageMultipliers[3]; // by effect: damage multiplier @@ -695,6 +697,7 @@ class SpellEvent : public BasicEvent virtual bool Execute(uint64 e_time, uint32 p_time); virtual void Abort(uint64 e_time); + virtual bool IsDeletable() const; protected: Spell* m_Spell; }; diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 2f29cfc46..31354130f 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3470,7 +3470,7 @@ void Aura::HandleAuraModSilence(bool apply, bool Real) if ( state == SPELL_STATE_PREPARING || state == SPELL_STATE_CASTING ) { currentSpell->cancel(); - currentSpell->SetDeletable(true); + currentSpell->SetReferencedFromCurrent(false); m_target->m_currentSpells[i] = NULL; } } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 7e68980b9..46f5a15aa 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -233,9 +233,11 @@ Unit::~Unit() // set current spells as deletable for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) { - // spell may be safely deleted now - if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true); - m_currentSpells[i] = NULL; + if (m_currentSpells[i]) + { + m_currentSpells[i]->SetReferencedFromCurrent(false); + m_currentSpells[i] = NULL; + } } RemoveAllGameObjects(); @@ -3145,7 +3147,7 @@ void Unit::_UpdateSpells( uint32 time ) { if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED) { - m_currentSpells[i]->SetDeletable(true); // spell may be safely deleted now + m_currentSpells[i]->SetReferencedFromCurrent(false); m_currentSpells[i] = NULL; // remove pointer } } @@ -3258,7 +3260,6 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell ) uint32 CSpellType = pSpell->GetCurrentContainer(); - pSpell->SetDeletable(false); // spell will not be deleted until gone from current pointers if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self // break same type spell if it is not delayed @@ -3315,10 +3316,11 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell ) // current spell (if it is still here) may be safely deleted now if (m_currentSpells[CSpellType]) - m_currentSpells[CSpellType]->SetDeletable(true); + m_currentSpells[CSpellType]->SetReferencedFromCurrent(false); // set new current spell m_currentSpells[CSpellType] = pSpell; + pSpell->SetReferencedFromCurrent(true); } void Unit::InterruptSpell(uint32 spellType, bool withDelayed) @@ -3336,7 +3338,7 @@ void Unit::InterruptSpell(uint32 spellType, bool withDelayed) if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED) m_currentSpells[spellType]->cancel(); - m_currentSpells[spellType]->SetDeletable(true); + m_currentSpells[spellType]->SetReferencedFromCurrent(false); m_currentSpells[spellType] = NULL; } } @@ -3372,7 +3374,7 @@ void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) && (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) m_currentSpells[CURRENT_GENERIC_SPELL]->cancel(); - m_currentSpells[CURRENT_GENERIC_SPELL]->SetDeletable(true); + m_currentSpells[CURRENT_GENERIC_SPELL]->SetReferencedFromCurrent(false); m_currentSpells[CURRENT_GENERIC_SPELL] = NULL; } @@ -3386,7 +3388,7 @@ void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) && (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) ) m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel(); - m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetDeletable(true); + m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->SetReferencedFromCurrent(false); m_currentSpells[CURRENT_AUTOREPEAT_SPELL] = NULL; } @@ -3395,7 +3397,7 @@ void Unit::InterruptNonMeleeSpells(bool withDelayed, uint32 spell_id) { if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED) m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); - m_currentSpells[CURRENT_CHANNELED_SPELL]->SetDeletable(true); + m_currentSpells[CURRENT_CHANNELED_SPELL]->SetReferencedFromCurrent(false); m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; } } @@ -9791,7 +9793,7 @@ void Unit::CleanupsBeforeDelete() if(m_uint32Values) // only for fully created object { InterruptNonMeleeSpells(true); - m_Events.KillAllEvents(); + m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted ans will deleated at call in Map::RemoveAllObjectsInRemoveList CombatStop(); ClearComboPointHolders(); DeleteThreatList();