*Add m_duringRemoveFromWorld lock to prevent adding single target auras during or after remove from world process.

--HG--
branch : trunk
This commit is contained in:
QAston
2010-08-03 06:11:03 +02:00
parent 14827321bf
commit c5a9d3b463
5 changed files with 73 additions and 42 deletions
+31 -34
View File
@@ -185,6 +185,7 @@ Unit::Unit()
m_reactiveTimer[i] = 0; m_reactiveTimer[i] = 0;
m_cleanupDone = false; m_cleanupDone = false;
m_duringRemoveFromWorld = false;
} }
Unit::~Unit() Unit::~Unit()
@@ -206,6 +207,7 @@ Unit::~Unit()
delete m_charmInfo; delete m_charmInfo;
delete m_vehicleKit; delete m_vehicleKit;
ASSERT(!m_duringRemoveFromWorld);
ASSERT(!m_attacking); ASSERT(!m_attacking);
ASSERT(m_attackers.empty()); ASSERT(m_attackers.empty());
ASSERT(m_sharedVision.empty()); ASSERT(m_sharedVision.empty());
@@ -3635,6 +3637,7 @@ void Unit::_AddAura(UnitAura * aura, Unit * caster)
aura->SetIsSingleTarget(caster && IsSingleTargetSpell(aura->GetSpellProto())); aura->SetIsSingleTarget(caster && IsSingleTargetSpell(aura->GetSpellProto()));
if (aura->IsSingleTarget()) if (aura->IsSingleTarget())
{ {
ASSERT(IsInWorld() && !IsDuringRemoveFromWorld());
// register single target aura // register single target aura
caster->GetSingleCastAuras().push_back(aura); caster->GetSingleCastAuras().push_back(aura);
// remove other single target auras // remove other single target auras
@@ -4216,10 +4219,10 @@ void Unit::RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit
newAura = Aura::TryCreate(aura->GetSpellProto(), effMask, stealer, NULL, &baseDamage[0], NULL, aura->GetCasterGUID()); newAura = Aura::TryCreate(aura->GetSpellProto(), effMask, stealer, NULL, &baseDamage[0], NULL, aura->GetCasterGUID());
if (!newAura) if (!newAura)
return; return;
newAura->SetLoadedState(dur, dur, stealCharge ? 1 : aura->GetCharges(), aura->GetStackAmount(), recalculateMask, &damage[0]);
// strange but intended behaviour: Stolen single target auras won't be treated as single targeted // strange but intended behaviour: Stolen single target auras won't be treated as single targeted
if (newAura->IsSingleTarget()) if (newAura->IsSingleTarget())
newAura->UnregisterSingleTarget(); newAura->UnregisterSingleTarget();
newAura->SetLoadedState(dur, dur, stealCharge ? 1 : aura->GetCharges(), aura->GetStackAmount(), recalculateMask, &damage[0]);
newAura->ApplyForTargets(); newAura->ApplyForTargets();
} }
return; return;
@@ -4386,43 +4389,35 @@ void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemo
void Unit::RemoveAreaAurasDueToLeaveWorld() void Unit::RemoveAreaAurasDueToLeaveWorld()
{ {
bool cleanRun; // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later
do for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
{ {
cleanRun = true; Aura * aura = iter->second;
// make sure that all area auras not applied on self are removed - prevent access to deleted pointer later ++iter;
for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) Aura::ApplicationMap const & appMap = aura->GetApplicationMap();
for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();)
{ {
Aura * aura = iter->second; AuraApplication * aurApp = itr->second;
++iter; ++itr;
Aura::ApplicationMap const & appMap = aura->GetApplicationMap(); Unit * target = aurApp->GetTarget();
for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();) if (target == this)
{ continue;
AuraApplication * aurApp = itr->second; target->RemoveAura(aurApp);
++itr; // things linked on aura remove may apply new area aura - so start from the beginning
Unit * target = aurApp->GetTarget(); iter = m_ownedAuras.begin();
if (target == this)
continue;
target->RemoveAura(aurApp);
cleanRun = false;
// things linked on aura remove may apply new area aura - so start from the beginning
iter = m_ownedAuras.begin();
}
}
// remove area auras owned by others
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
if (iter->second->GetBase()->GetOwner() != this)
{
RemoveAura(iter);
cleanRun = false;
}
else
++iter;
} }
} }
while (!cleanRun);
// remove area auras owned by others
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
if (iter->second->GetBase()->GetOwner() != this)
{
RemoveAura(iter);
}
else
++iter;
}
} }
void Unit::RemoveAllAuras() void Unit::RemoveAllAuras()
@@ -13369,6 +13364,7 @@ void Unit::RemoveFromWorld()
if (IsInWorld()) if (IsInWorld())
{ {
m_duringRemoveFromWorld = true;
if (IsVehicle()) if (IsVehicle())
GetVehicleKit()->Uninstall(); GetVehicleKit()->Uninstall();
@@ -13401,6 +13397,7 @@ void Unit::RemoveFromWorld()
} }
WorldObject::RemoveFromWorld(); WorldObject::RemoveFromWorld();
m_duringRemoveFromWorld = false;
} }
} }
+3 -1
View File
@@ -1942,6 +1942,7 @@ class Unit : public WorldObject
void OutDebugInfo() const; void OutDebugInfo() const;
virtual bool isBeingLoaded() const { return false;} virtual bool isBeingLoaded() const { return false;}
bool IsDuringRemoveFromWorld() const {return m_duringRemoveFromWorld;}
Pet* ToPet(){ if (isPet()) return reinterpret_cast<Pet*>(this); else return NULL; } Pet* ToPet(){ if (isPet()) return reinterpret_cast<Pet*>(this); else return NULL; }
Totem* ToTotem(){ if (isTotem()) return reinterpret_cast<Totem*>(this); else return NULL; } Totem* ToTotem(){ if (isTotem()) return reinterpret_cast<Totem*>(this); else return NULL; }
@@ -2059,7 +2060,8 @@ class Unit : public WorldObject
uint32 m_reducedThreatPercent; uint32 m_reducedThreatPercent;
uint64 m_misdirectionTargetGUID; uint64 m_misdirectionTargetGUID;
bool m_cleanupDone; bool m_cleanupDone; // lock made to not add stuff after cleanup before delete
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
}; };
namespace Trinity namespace Trinity
+38 -5
View File
@@ -280,6 +280,21 @@ Aura * Aura::Create(SpellEntry const* spellproto, uint8 effMask, WorldObject * o
else else
caster = ObjectAccessor::GetUnit(*owner, casterGUID); caster = ObjectAccessor::GetUnit(*owner, casterGUID);
} }
else
{
casterGUID = caster->GetGUID();
}
// check if aura can be owned by owner
if (owner->isType(TYPEMASK_UNIT))
{
if (!owner->IsInWorld() || ((Unit*)owner)->IsDuringRemoveFromWorld())
{
// owner not in world so
// don't allow to own not self casted single target auras
if (casterGUID != owner->GetGUID() && IsSingleTargetSpell(spellproto))
return NULL;
}
}
Aura * aura = NULL; Aura * aura = NULL;
switch(owner->GetTypeId()) switch(owner->GetTypeId())
{ {
@@ -455,7 +470,7 @@ void Aura::UpdateTargetMap(Unit * caster, bool apply)
{ {
// needs readding - remove now, will be applied in next update cycle // needs readding - remove now, will be applied in next update cycle
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed) // (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
if (appIter->second->GetEffectMask() != existing->second) if (appIter->second->GetEffectMask() != existing->second || !CanBeAppliedOn(existing->first))
targetsToRemove.push_back(appIter->second->GetTarget()); targetsToRemove.push_back(appIter->second->GetTarget());
// nothing todo - aura already applied // nothing todo - aura already applied
// remove from auras to register list // remove from auras to register list
@@ -469,8 +484,7 @@ void Aura::UpdateTargetMap(Unit * caster, bool apply)
bool addUnit = true; bool addUnit = true;
// check target immunities // check target immunities
if (itr->first->IsImmunedToSpell(GetSpellProto()) if (itr->first->IsImmunedToSpell(GetSpellProto())
// check area target requirements || !CanBeAppliedOn(itr->first))
|| (itr->first != GetOwner() && !CheckAreaTarget(itr->first)))
addUnit = false; addUnit = false;
if (addUnit) if (addUnit)
@@ -764,8 +778,10 @@ bool Aura::IsVisible() const
void Aura::UnregisterSingleTarget() void Aura::UnregisterSingleTarget()
{ {
ASSERT(m_isSingleTarget); ASSERT(m_isSingleTarget);
Unit * caster = ObjectAccessor::GetObjectInOrOutOfWorld(GetCasterGUID(), (Unit*)NULL);//GetCaster(); Unit * caster = GetCaster();
assert(caster); //if (!caster)
//caster = ObjectAccessor::GetObjectInOrOutOfWorld(GetCasterGUID(), (Unit*)NULL);
ASSERT(caster);
caster->GetSingleCastAuras().remove(this); caster->GetSingleCastAuras().remove(this);
SetIsSingleTarget(false); SetIsSingleTarget(false);
} }
@@ -1494,6 +1510,23 @@ void Aura::HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster,
} }
} }
bool Aura::CanBeAppliedOn(Unit *target)
{
// unit not in world or during remove from world
if (!target->IsInWorld() || target->IsDuringRemoveFromWorld())
{
// area auras mustn't be applied
if (GetOwner() != target)
return false;
// not selfcasted single target auras mustn't be applied
if (GetCasterGUID() != GetOwner()->GetGUID() && IsSingleTargetSpell(GetSpellProto()))
return false;
}
else if (GetOwner() != target)
return CheckAreaTarget(target);
return true;
}
bool Aura::CheckAreaTarget(Unit *target) bool Aura::CheckAreaTarget(Unit *target)
{ {
// for owner check use Spell::CheckTarget // for owner check use Spell::CheckTarget
@@ -163,6 +163,7 @@ class Aura
void SetNeedClientUpdateForTargets() const; void SetNeedClientUpdateForTargets() const;
void HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply); void HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply);
bool CanBeAppliedOn(Unit *target);
bool CheckAreaTarget(Unit *target); bool CheckAreaTarget(Unit *target);
private: private:
void _DeleteRemovedApplications(); void _DeleteRemovedApplications();
-2
View File
@@ -33,7 +33,6 @@ class Aura;
struct SpellEntry; struct SpellEntry;
class SpellScript; class SpellScript;
// These flags are used in client - server communication only
enum SpellCastTargetFlags enum SpellCastTargetFlags
{ {
TARGET_FLAG_SELF = 0x00000000, TARGET_FLAG_SELF = 0x00000000,
@@ -210,7 +209,6 @@ class SpellCastTargets
private: private:
uint32 m_targetMask; uint32 m_targetMask;
uint32 m_intTargetFlags;
// objects (can be used at spell creating and after Update at casting // objects (can be used at spell creating and after Update at casting
Unit *m_unitTarget; Unit *m_unitTarget;
GameObject *m_GOTarget; GameObject *m_GOTarget;