diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f032f9bff8d..6b59704a078 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 797583196cf..af00fe21efd 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; } - } - if(!restart) - { - // done - scAuras.push_back(holder); - break; + ++itr; } + + // 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 4fda849f3dc..a04a3a9e12c 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 4982631239d..39d6e5c6670 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__