Instead mark spell as delatable mark it as executed and referenced from Unit current spells array and not deleted spell in like cases.

This is solve crashs if spell deleted at caster die in result triggered spells casting chain from currently executed spell.
This commit is contained in:
VladimirMangos 2008-11-03 01:09:18 +03:00
parent 322b201c4d
commit ed7390dede
7 changed files with 61 additions and 25 deletions

View file

@ -26,7 +26,7 @@ EventProcessor::EventProcessor()
EventProcessor::~EventProcessor() EventProcessor::~EventProcessor()
{ {
KillAllEvents(); KillAllEvents(true);
} }
void EventProcessor::Update(uint32 p_time) 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 // prevent event insertions
m_aborting = true; m_aborting = true;
// first, abort all existing events // 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; EventList::iterator i_old = i;
i->second->Abort(m_time); ++i;
delete i->second;
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 // fast clear event list (in force case)
m_events.clear(); if(force)
m_events.clear();
} }
void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime) void EventProcessor::AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime)

View file

@ -38,6 +38,8 @@ class BasicEvent
// e_time is execution time, p_time is update interval // e_time is execution time, p_time is update interval
virtual bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) { return true; } 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 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 bool to_Abort; // set by externals when the event is aborted, aborted events don't execute
@ -57,7 +59,7 @@ class EventProcessor
~EventProcessor(); ~EventProcessor();
void Update(uint32 p_time); void Update(uint32 p_time);
void KillAllEvents(); void KillAllEvents(bool force);
void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true); void AddEvent(BasicEvent* Event, uint64 e_time, bool set_addtime = true);
uint64 CalculateTime(uint64 t_offset); uint64 CalculateTime(uint64 t_offset);
protected: protected:

View file

@ -1355,6 +1355,9 @@ void Map::RemoveAllObjectsInRemoveList()
Remove((GameObject*)obj,true); Remove((GameObject*)obj,true);
break; break;
case TYPEID_UNIT: 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); Remove((Creature*)obj,true);
break; break;
default: default:

View file

@ -268,7 +268,8 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_caster = Caster; m_caster = Caster;
m_selfContainer = NULL; m_selfContainer = NULL;
m_triggeringContainer = triggeringContainer; m_triggeringContainer = triggeringContainer;
m_deletable = true; m_referencedFromCurrentSpell = false;
m_executedCurrently = false;
m_delayAtDamageCount = 0; m_delayAtDamageCount = 0;
m_applyMultiplierMask = 0; m_applyMultiplierMask = 0;
@ -2019,6 +2020,8 @@ void Spell::cancel()
void Spell::cast(bool skipCheck) void Spell::cast(bool skipCheck)
{ {
SetExecutedCurrently(true);
uint8 castResult = 0; uint8 castResult = 0;
// update pointers base at GUIDs to prevent access to non-existed already object // 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()) if(!m_targets.getUnitTarget() && m_targets.getUnitTargetGUID() && m_targets.getUnitTargetGUID() != m_caster->GetGUID())
{ {
cancel(); cancel();
SetExecutedCurrently(false);
return; return;
} }
@ -2039,6 +2043,7 @@ void Spell::cast(bool skipCheck)
{ {
SendCastResult(castResult); SendCastResult(castResult);
finish(false); finish(false);
SetExecutedCurrently(false);
return; return;
} }
@ -2050,6 +2055,7 @@ void Spell::cast(bool skipCheck)
{ {
SendCastResult(castResult); SendCastResult(castResult);
finish(false); finish(false);
SetExecutedCurrently(false);
return; return;
} }
} }
@ -2082,7 +2088,10 @@ void Spell::cast(bool skipCheck)
FillTargetMap(); FillTargetMap();
if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap
{
SetExecutedCurrently(false);
return; return;
}
SendCastResult(castResult); SendCastResult(castResult);
SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... 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 // Immediate spell, no big deal
handle_immediate(); handle_immediate();
} }
SetExecutedCurrently(false);
} }
void Spell::handle_immediate() void Spell::handle_immediate()
@ -5063,3 +5074,8 @@ void SpellEvent::Abort(uint64 /*e_time*/)
if (m_Spell->getState() != SPELL_STATE_FINISHED) if (m_Spell->getState() != SPELL_STATE_FINISHED)
m_Spell->cancel(); m_Spell->cancel();
} }
bool SpellEvent::IsDeletable() const
{
return m_Spell->IsDeletable();
}

View file

@ -380,8 +380,9 @@ class Spell
bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); } 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 IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && IsRangedSpell() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); }
bool IsDeletable() const { return m_deletable; } bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
void SetDeletable(bool deletable) { m_deletable = deletable; } void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
void SetExecutedCurrently(bool yes) { m_executedCurrently = yes; }
uint64 GetDelayStart() const { return m_delayStart; } uint64 GetDelayStart() const { return m_delayStart; }
void SetDelayStart(uint64 m_time) { m_delayStart = m_time; } void SetDelayStart(uint64 m_time) { m_delayStart = m_time; }
uint64 GetDelayMoment() const { return m_delayMoment; } uint64 GetDelayMoment() const { return m_delayMoment; }
@ -433,7 +434,8 @@ class Spell
bool m_immediateHandled; // were immediate actions handled? (used by delayed spells only) 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 // 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? bool m_needSpellLog; // need to send spell log?
uint8 m_applyMultiplierMask; // by effect: damage multiplier needed? uint8 m_applyMultiplierMask; // by effect: damage multiplier needed?
float m_damageMultipliers[3]; // by effect: damage multiplier 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 bool Execute(uint64 e_time, uint32 p_time);
virtual void Abort(uint64 e_time); virtual void Abort(uint64 e_time);
virtual bool IsDeletable() const;
protected: protected:
Spell* m_Spell; Spell* m_Spell;
}; };

View file

@ -3470,7 +3470,7 @@ void Aura::HandleAuraModSilence(bool apply, bool Real)
if ( state == SPELL_STATE_PREPARING || state == SPELL_STATE_CASTING ) if ( state == SPELL_STATE_PREPARING || state == SPELL_STATE_CASTING )
{ {
currentSpell->cancel(); currentSpell->cancel();
currentSpell->SetDeletable(true); currentSpell->SetReferencedFromCurrent(false);
m_target->m_currentSpells[i] = NULL; m_target->m_currentSpells[i] = NULL;
} }
} }

View file

@ -233,9 +233,11 @@ Unit::~Unit()
// set current spells as deletable // set current spells as deletable
for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++) for (uint32 i = 0; i < CURRENT_MAX_SPELL; i++)
{ {
// spell may be safely deleted now if (m_currentSpells[i])
if (m_currentSpells[i]) m_currentSpells[i]->SetDeletable(true); {
m_currentSpells[i] = NULL; m_currentSpells[i]->SetReferencedFromCurrent(false);
m_currentSpells[i] = NULL;
}
} }
RemoveAllGameObjects(); RemoveAllGameObjects();
@ -3145,7 +3147,7 @@ void Unit::_UpdateSpells( uint32 time )
{ {
if (m_currentSpells[i] && m_currentSpells[i]->getState() == SPELL_STATE_FINISHED) 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 m_currentSpells[i] = NULL; // remove pointer
} }
} }
@ -3258,7 +3260,6 @@ void Unit::SetCurrentCastedSpell( Spell * pSpell )
uint32 CSpellType = pSpell->GetCurrentContainer(); 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 if (pSpell == m_currentSpells[CSpellType]) return; // avoid breaking self
// break same type spell if it is not delayed // 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 // current spell (if it is still here) may be safely deleted now
if (m_currentSpells[CSpellType]) if (m_currentSpells[CSpellType])
m_currentSpells[CSpellType]->SetDeletable(true); m_currentSpells[CSpellType]->SetReferencedFromCurrent(false);
// set new current spell // set new current spell
m_currentSpells[CSpellType] = pSpell; m_currentSpells[CSpellType] = pSpell;
pSpell->SetReferencedFromCurrent(true);
} }
void Unit::InterruptSpell(uint32 spellType, bool withDelayed) 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) if (m_currentSpells[spellType]->getState() != SPELL_STATE_FINISHED)
m_currentSpells[spellType]->cancel(); m_currentSpells[spellType]->cancel();
m_currentSpells[spellType]->SetDeletable(true); m_currentSpells[spellType]->SetReferencedFromCurrent(false);
m_currentSpells[spellType] = NULL; 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) && if ( (m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_FINISHED) &&
(withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) ) (withDelayed || m_currentSpells[CURRENT_GENERIC_SPELL]->getState() != SPELL_STATE_DELAYED) )
m_currentSpells[CURRENT_GENERIC_SPELL]->cancel(); 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; 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) && if ( (m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_FINISHED) &&
(withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) ) (withDelayed || m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->getState() != SPELL_STATE_DELAYED) )
m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->cancel(); 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; 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) if (m_currentSpells[CURRENT_CHANNELED_SPELL]->getState() != SPELL_STATE_FINISHED)
m_currentSpells[CURRENT_CHANNELED_SPELL]->cancel(); 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; m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
} }
} }
@ -9791,7 +9793,7 @@ void Unit::CleanupsBeforeDelete()
if(m_uint32Values) // only for fully created object if(m_uint32Values) // only for fully created object
{ {
InterruptNonMeleeSpells(true); 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(); CombatStop();
ClearComboPointHolders(); ClearComboPointHolders();
DeleteThreatList(); DeleteThreatList();