[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)
This commit is contained in:
VladimirMangos 2010-09-05 07:22:08 +04:00
parent 6e6936c321
commit dfc9966d3b
4 changed files with 68 additions and 53 deletions

View file

@ -8886,14 +8886,8 @@ void SpellAuraHolder::UnregisterSingleCastHolder()
if (IsSingleTarget()) if (IsSingleTarget())
{ {
if(Unit* caster = GetCaster()) if(Unit* caster = GetCaster())
{ caster->GetSingleCastSpellTargets().erase(GetSpellProto());
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);
}
m_isSingleTarget = false; m_isSingleTarget = false;
} }
} }

View file

@ -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) // 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 if (Unit* caster = holder->GetCaster()) // caster not in world
for(;;)
{ {
Unit* caster = holder->GetCaster(); SingleCastSpellTargetMap& scTargets = caster->GetSingleCastSpellTargets();
if(!caster) // caster deleted and not required adding scAura for(SingleCastSpellTargetMap::const_iterator itr = scTargets.begin(); itr != scTargets.end();)
break;
bool restart = false;
SpellAuraHolderList& scAuras = caster->GetSingleCastSpellAuraHolders();
for(SpellAuraHolderList::const_iterator itr = scAuras.begin(); itr != scAuras.end(); ++itr)
{ {
if( (*itr)->GetTarget() != holder->GetTarget() && SpellEntry const* itr_spellEntry = itr->first;
IsSingleTargetSpells((*itr)->GetSpellProto(),aurSpellInfo) ) ObjectGuid itr_targetGuid = itr->second;
if (itr_targetGuid != GetObjectGuid() &&
IsSingleTargetSpells(itr_spellEntry, aurSpellInfo))
{ {
if ((*itr)->IsInUse()) scTargets.erase(itr); // remove for caster in any case
{
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()); // remove from target if target found
continue; if (Unit* itr_target = GetMap()->GetUnit(itr_targetGuid))
} itr_target->RemoveAurasDueToSpell(itr_spellEntry->Id);
(*itr)->GetTarget()->RemoveSpellAuraHolder((*itr));
restart = true; itr = scTargets.begin(); // list can be chnaged at remove aura
break; continue;
} }
++itr;
} }
if(!restart) // register spell holder single target
{ scTargets[aurSpellInfo] = GetObjectGuid();
// done
scAuras.push_back(holder);
break;
}
} }
} }
@ -4493,12 +4488,13 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
// single target auras from other casters // single target auras from other casters
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end(); ) 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) if(!newPhase)
{ {
RemoveSpellAuraHolder(iter->second); RemoveSpellAuraHolder(iter->second);
iter = m_spellAuraHolders.begin(); iter = m_spellAuraHolders.begin();
continue;
} }
else else
{ {
@ -4507,29 +4503,52 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase)
{ {
RemoveSpellAuraHolder(iter->second); RemoveSpellAuraHolder(iter->second);
iter = m_spellAuraHolders.begin(); iter = m_spellAuraHolders.begin();
continue;
} }
else
++iter;
} }
} }
else
++iter; ++iter;
} }
// single cast!!
// single target auras at other targets // single target auras at other targets
SpellAuraHolderList& scAuras = GetSingleCastSpellAuraHolders(); SingleCastSpellTargetMap& scTargets = GetSingleCastSpellTargets();
for (SpellAuraHolderList::iterator iter = scAuras.begin(); iter != scAuras.end(); ) for (SingleCastSpellTargetMap::iterator itr = scTargets.begin(); itr != scTargets.end(); )
{ {
SpellAuraHolder* holder = *iter; SpellEntry const* itr_spellEntry = itr->first;
if (holder->GetTarget() != this && !holder->GetTarget()->InSamePhase(newPhase)) ObjectGuid itr_targetGuid = itr->second;
if (itr_targetGuid != GetObjectGuid())
{ {
scAuras.erase(iter); // explicitly remove, instead waiting remove in RemoveSpellAuraHolder if(!newPhase)
holder->GetTarget()->RemoveSpellAuraHolder(holder); {
iter = scAuras.begin(); 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;
} }
} }

View file

@ -1115,6 +1115,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
typedef std::list<DiminishingReturn> Diminishing; typedef std::list<DiminishingReturn> Diminishing;
typedef std::set<uint32> ComboPointHolderSet; typedef std::set<uint32> ComboPointHolderSet;
typedef std::map<uint8, uint32> VisibleAuraMap; typedef std::map<uint8, uint32> VisibleAuraMap;
typedef std::map<SpellEntry const*, ObjectGuid> SingleCastSpellTargetMap;
virtual ~Unit ( ); virtual ~Unit ( );
@ -1658,8 +1660,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0;
bool isInvisibleForAlive() const; bool isInvisibleForAlive() const;
SpellAuraHolderList & GetSingleCastSpellAuraHolders() { return m_scSpellAuraHolders; } SingleCastSpellTargetMap & GetSingleCastSpellTargets() { return m_singleCastSpellTargets; }
SpellAuraHolderList const& GetSingleCastSpellAuraHolders() const { return m_scSpellAuraHolders; } SingleCastSpellTargetMap const& GetSingleCastSpellTargets() const { return m_singleCastSpellTargets; }
SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY];
// Threat related methods // 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 AuraList m_deletedAuras; // auras removed while in ApplyModifier and waiting deleted
SpellAuraHolderList m_deletedHolders; 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<uint64> DynObjectGUIDs; typedef std::list<uint64> DynObjectGUIDs;
DynObjectGUIDs m_dynObjGUIDs; DynObjectGUIDs m_dynObjGUIDs;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "10444" #define REVISION_NR "10445"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__