*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:
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user