Skip to content

Commit

Permalink
[10445] Re-implement in more safe way single cast spell targets system.
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
VladimirMangos committed Sep 5, 2010
1 parent 4afad5a commit 81022d5
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 53 deletions.
10 changes: 2 additions & 8 deletions src/game/SpellAuras.cpp
Expand Up @@ -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;
}
}
101 changes: 60 additions & 41 deletions src/game/Unit.cpp
Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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
{
Expand All @@ -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;
}

}
Expand Down
8 changes: 5 additions & 3 deletions src/game/Unit.h
Expand Up @@ -1115,6 +1115,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
typedef std::list<DiminishingReturn> Diminishing;
typedef std::set<uint32> ComboPointHolderSet;
typedef std::map<uint8, uint32> VisibleAuraMap;
typedef std::map<SpellEntry const*, ObjectGuid> SingleCastSpellTargetMap;


virtual ~Unit ( );

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<uint64> DynObjectGUIDs;
DynObjectGUIDs m_dynObjGUIDs;
Expand Down
2 changes: 1 addition & 1 deletion 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__

1 comment on commit 81022d5

@SeTM
Copy link

@SeTM SeTM commented on 81022d5 Sep 5, 2010

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

../../../src/game/Unit.cpp: In member function ‘bool Unit::AddSpellAuraHolder(SpellAuraHolder_)’:
../../../src/game/Unit.cpp:4099: ошибка: нет подходящей функции для вызова ‘std::map<const SpellEntry_, ObjectGuid, std::less<const SpellEntry*>, std::allocator<std::pair<const SpellEntry* const, ObjectGuid> > >::erase(std::_Rb_tree_const_iterator<std::pair<const SpellEntry* const, ObjectGuid> >&)’
/usr/lib/gcc/x86_64-redhat-linux/4.4.4/../../../../include/c++/4.4.4/bits/stl_map.h:566: замечание: претенденты: void std::map<_Key, _Tp, _Compare, _Alloc>::erase(typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::pair<const _Key, _Tp> >::other>::iterator) [with Key = const SpellEntry, _Tp = ObjectGuid, _Compare = std::less, _Alloc = std::allocator<std::pair<const SpellEntry* const, ObjectGuid> >]

Please sign in to comment.