diff options
author | QAston <none@none> | 2010-08-03 06:11:03 +0200 |
---|---|---|
committer | QAston <none@none> | 2010-08-03 06:11:03 +0200 |
commit | c5a9d3b46390c561da58565ae5328358ce0a298b (patch) | |
tree | 8e027eb51b087fc0d3a9ec7a1bf74f4194a1aeb9 | |
parent | 14827321bf3b279a4297a88cf14ace988ff54fcf (diff) |
*Add m_duringRemoveFromWorld lock to prevent adding single target auras during or after remove from world process.
--HG--
branch : trunk
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 59 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 43 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.h | 1 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 2 |
5 files changed, 70 insertions, 39 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index f465b687e1c..334c550d235 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -185,6 +185,7 @@ Unit::Unit() m_reactiveTimer[i] = 0; m_cleanupDone = false; + m_duringRemoveFromWorld = false; } Unit::~Unit() @@ -206,6 +207,7 @@ Unit::~Unit() delete m_charmInfo; delete m_vehicleKit; + ASSERT(!m_duringRemoveFromWorld); ASSERT(!m_attacking); ASSERT(m_attackers.empty()); ASSERT(m_sharedVision.empty()); @@ -3635,6 +3637,7 @@ void Unit::_AddAura(UnitAura * aura, Unit * caster) aura->SetIsSingleTarget(caster && IsSingleTargetSpell(aura->GetSpellProto())); if (aura->IsSingleTarget()) { + ASSERT(IsInWorld() && !IsDuringRemoveFromWorld()); // register single target aura caster->GetSingleCastAuras().push_back(aura); // 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()); if (!newAura) 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 if (newAura->IsSingleTarget()) newAura->UnregisterSingleTarget(); + newAura->SetLoadedState(dur, dur, stealCharge ? 1 : aura->GetCharges(), aura->GetStackAmount(), recalculateMask, &damage[0]); newAura->ApplyForTargets(); } return; @@ -4386,43 +4389,35 @@ void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemo void Unit::RemoveAreaAurasDueToLeaveWorld() { - bool cleanRun; - do + // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later + for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) { - cleanRun = true; - // make sure that all area auras not applied on self are removed - prevent access to deleted pointer later - for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();) + Aura * aura = iter->second; + ++iter; + Aura::ApplicationMap const & appMap = aura->GetApplicationMap(); + for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();) { - Aura * aura = iter->second; - ++iter; - Aura::ApplicationMap const & appMap = aura->GetApplicationMap(); - for (Aura::ApplicationMap::const_iterator itr = appMap.begin(); itr!= appMap.end();) - { - AuraApplication * aurApp = itr->second; - ++itr; - Unit * target = aurApp->GetTarget(); - 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(); - } + AuraApplication * aurApp = itr->second; + ++itr; + Unit * target = aurApp->GetTarget(); + if (target == this) + continue; + target->RemoveAura(aurApp); + // 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();) + // remove area auras owned by others + for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();) + { + if (iter->second->GetBase()->GetOwner() != this) { - if (iter->second->GetBase()->GetOwner() != this) - { - RemoveAura(iter); - cleanRun = false; - } - else - ++iter; + RemoveAura(iter); } + else + ++iter; } - while (!cleanRun); } void Unit::RemoveAllAuras() @@ -13369,6 +13364,7 @@ void Unit::RemoveFromWorld() if (IsInWorld()) { + m_duringRemoveFromWorld = true; if (IsVehicle()) GetVehicleKit()->Uninstall(); @@ -13401,6 +13397,7 @@ void Unit::RemoveFromWorld() } WorldObject::RemoveFromWorld(); + m_duringRemoveFromWorld = false; } } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 692b34cfbcb..fe163da99c1 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1942,6 +1942,7 @@ class Unit : public WorldObject void OutDebugInfo() const; virtual bool isBeingLoaded() const { return false;} + bool IsDuringRemoveFromWorld() const {return m_duringRemoveFromWorld;} Pet* ToPet(){ if (isPet()) return reinterpret_cast<Pet*>(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; 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 diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 1ec2320da9b..7f1f98ebcc6 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -280,6 +280,21 @@ Aura * Aura::Create(SpellEntry const* spellproto, uint8 effMask, WorldObject * o else 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; 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 // (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()); // nothing todo - aura already applied // remove from auras to register list @@ -469,8 +484,7 @@ void Aura::UpdateTargetMap(Unit * caster, bool apply) bool addUnit = true; // check target immunities if (itr->first->IsImmunedToSpell(GetSpellProto()) - // check area target requirements - || (itr->first != GetOwner() && !CheckAreaTarget(itr->first))) + || !CanBeAppliedOn(itr->first)) addUnit = false; if (addUnit) @@ -764,8 +778,10 @@ bool Aura::IsVisible() const void Aura::UnregisterSingleTarget() { ASSERT(m_isSingleTarget); - Unit * caster = ObjectAccessor::GetObjectInOrOutOfWorld(GetCasterGUID(), (Unit*)NULL);//GetCaster(); - assert(caster); + Unit * caster = GetCaster(); + //if (!caster) + //caster = ObjectAccessor::GetObjectInOrOutOfWorld(GetCasterGUID(), (Unit*)NULL); + ASSERT(caster); caster->GetSingleCastAuras().remove(this); 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) { // for owner check use Spell::CheckTarget diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index c598f1b6cdf..16fe91c735d 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -163,6 +163,7 @@ class Aura void SetNeedClientUpdateForTargets() const; void HandleAuraSpecificMods(AuraApplication const * aurApp, Unit * caster, bool apply); + bool CanBeAppliedOn(Unit *target); bool CheckAreaTarget(Unit *target); private: void _DeleteRemovedApplications(); diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index a0e19746a5f..e9ad9dd69e9 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -33,7 +33,6 @@ class Aura; struct SpellEntry; class SpellScript; -// These flags are used in client - server communication only enum SpellCastTargetFlags { TARGET_FLAG_SELF = 0x00000000, @@ -210,7 +209,6 @@ class SpellCastTargets private: uint32 m_targetMask; - uint32 m_intTargetFlags; // objects (can be used at spell creating and after Update at casting Unit *m_unitTarget; GameObject *m_GOTarget; |