From dfc9966d3b2aa00e654833c703cb8e74567eb538 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 5 Sep 2010 07:22:08 +0400 Subject: [PATCH] [10445] Re-implement in more safe way single cast spell targets system. It also fix case when target can unexpected lost single target aura at phase switch in case when target still visible in new phase (pet for example) --- src/game/SpellAuras.cpp | 10 +--- src/game/Unit.cpp | 101 +++++++++++++++++++++++---------------- src/game/Unit.h | 8 ++-- src/shared/revision_nr.h | 2 +- 4 files changed, 68 insertions(+), 53 deletions(-) diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f032f9bff..6b59704a0 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -8886,14 +8886,8 @@ void SpellAuraHolder::UnregisterSingleCastHolder() if (IsSingleTarget()) { if(Unit* caster = GetCaster()) - { - caster->GetSingleCastSpellAuraHolders().remove(this); - } - else - { - sLog.outError("Couldn't find the caster of the single target aura (SpellId %u), may crash later!", GetId()); - MANGOS_ASSERT(false); - } + caster->GetSingleCastSpellTargets().erase(GetSpellProto()); + m_isSingleTarget = false; } } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 797583196..af00fe21e 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -3945,39 +3945,34 @@ bool Unit::AddSpellAuraHolder(SpellAuraHolder *holder) } // update single target auras list (before aura add to aura list, to prevent unexpected remove recently added aura) - if (holder->IsSingleTarget() && holder->GetTarget()) + if (holder->IsSingleTarget()) { - // caster pointer can be deleted in time aura remove, find it by guid at each iteration - for(;;) + if (Unit* caster = holder->GetCaster()) // caster not in world { - Unit* caster = holder->GetCaster(); - if(!caster) // caster deleted and not required adding scAura - break; - - bool restart = false; - SpellAuraHolderList& scAuras = caster->GetSingleCastSpellAuraHolders(); - for(SpellAuraHolderList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr) + SingleCastSpellTargetMap& scTargets = caster->GetSingleCastSpellTargets(); + for(SingleCastSpellTargetMap::const_iterator itr = scTargets.begin(); itr != scTargets.end();) { - if( (*itr)->GetTarget() != holder->GetTarget() && - IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) ) + SpellEntry const* itr_spellEntry = itr->first; + ObjectGuid itr_targetGuid = itr->second; + + if (itr_targetGuid != GetObjectGuid() && + IsSingleTargetSpells(itr_spellEntry, aurSpellInfo)) { - if ((*itr)->IsInUse()) - { - sLog.outError("Holder (Spell %u) is in process but attempt removed at aura (Spell %u) adding, need add stack rule for IsSingleTargetSpell", (*itr)->GetId(), holder->GetId()); - continue; - } - (*itr)->GetTarget()->RemoveSpellAuraHolder((*itr)); - restart = true; - break; + scTargets.erase(itr); // remove for caster in any case + + // remove from target if target found + if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) + itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id); + + itr = scTargets.begin(); // list can be chnaged at remove aura + continue; } + + ++itr; } - if(!restart) - { - // done - scAuras.push_back(holder); - break; - } + // register spell holder single target + scTargets[aurSpellInfo] = GetObjectGuid(); } } @@ -4493,12 +4488,13 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase) // single target auras from other casters for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end(); ) { - if (iter->second->GetCasterGUID()!=GetGUID() && IsSingleTargetSpell(iter->second->GetSpellProto())) + if (iter->second->GetCasterGUID() != GetGUID() && iter->second->IsSingleTarget()) { if(!newPhase) { RemoveSpellAuraHolder(iter->second); iter = m_spellAuraHolders.begin(); + continue; } else { @@ -4507,29 +4503,52 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase) { RemoveSpellAuraHolder(iter->second); iter = m_spellAuraHolders.begin(); + continue; } - else - ++iter; } } - else - ++iter; + + ++iter; } - // single cast!! // single target auras at other targets - SpellAuraHolderList& scAuras = GetSingleCastSpellAuraHolders(); - for (SpellAuraHolderList::iterator iter = scAuras.begin(); iter != scAuras.end(); ) + SingleCastSpellTargetMap& scTargets = GetSingleCastSpellTargets(); + for (SingleCastSpellTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end(); ) { - SpellAuraHolder* holder = *iter; - if (holder->GetTarget() != this && !holder->GetTarget()->InSamePhase(newPhase)) + SpellEntry const* itr_spellEntry = itr->first; + ObjectGuid itr_targetGuid = itr->second; + + if (itr_targetGuid != GetObjectGuid()) { - scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveSpellAuraHolder - holder->GetTarget()->RemoveSpellAuraHolder(holder); - iter = scAuras.begin(); + if(!newPhase) + { + scTargets.erase(itr); // remove for caster in any case + + // remove from target if target found + if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid)) + itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id); + + itr = scTargets.begin(); // list can be changed at remove aura + continue; + } + else + { + Unit* itr_target = GetMap()->GetUnit(itr_targetGuid); + if(!itr_target || !itr_target->InSamePhase(newPhase)) + { + scTargets.erase(itr); // remove for caster in any case + + // remove from target if target found + if (itr_target) + itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id); + + itr = scTargets.begin(); // list can be changed at remove aura + continue; + } + } } - else - ++iter; + + ++itr; } } diff --git a/src/game/Unit.h b/src/game/Unit.h index 4fda849f3..a04a3a9e1 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1115,6 +1115,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject typedef std::list Diminishing; typedef std::set ComboPointHolderSet; typedef std::map VisibleAuraMap; + typedef std::map SingleCastSpellTargetMap; + virtual ~Unit ( ); @@ -1658,8 +1660,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; bool isInvisibleForAlive() const; - SpellAuraHolderList & GetSingleCastSpellAuraHolders() { return m_scSpellAuraHolders; } - SpellAuraHolderList const& GetSingleCastSpellAuraHolders() const { return m_scSpellAuraHolders; } + SingleCastSpellTargetMap & GetSingleCastSpellTargets() { return m_singleCastSpellTargets; } + SingleCastSpellTargetMap const& GetSingleCastSpellTargets() const { return m_singleCastSpellTargets; } SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; // Threat related methods @@ -1908,7 +1910,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject AuraList m_deletedAuras; // auras removed while in ApplyModifier and waiting deleted SpellAuraHolderList m_deletedHolders; - SpellAuraHolderList m_scSpellAuraHolders; // casted by unit single per-caster auras + SingleCastSpellTargetMap m_singleCastSpellTargets; // casted by unit single per-caster auras typedef std::list DynObjectGUIDs; DynObjectGUIDs m_dynObjGUIDs; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 498263123..39d6e5c66 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10444" + #define REVISION_NR "10445" #endif // __REVISION_NR_H__