From c8cc9b28f86bc01a2307c290d4b413c85e2c675d Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sat, 8 Aug 2009 11:03:45 +0400 Subject: [PATCH] [8329] Implement aura deleting delay in case aura lock as currently used. * Use counter for aura uses lock for recursivly mark as used in some cases. * At aura remove add aura to deleting delayed auras list for aura target. * Remove now unneeded hacks from aura handlers and aura tick code (maybe not all found yet) * Use new aura delete locking for simplify proc spell event code. * Prevent apply aura boost spells if aura deleted while adding to target by triggered spells. * Re-implement aura list updating at auras update for target to better way skip removed from aura list auras while auras update. --- src/game/SpellAuras.cpp | 76 +++++++----------- src/game/SpellAuras.h | 31 ++++++-- src/game/SpellEffects.cpp | 5 -- src/game/Unit.cpp | 162 +++++++++++++++++++------------------- src/game/Unit.h | 5 +- src/shared/revision_nr.h | 2 +- 6 files changed, 139 insertions(+), 142 deletions(-) diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index c4f74e0d6..74bb4ea0b 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -354,7 +354,7 @@ m_spellmod(NULL), m_caster_guid(0), m_target(target), m_castItemGuid(castItem?ca m_timeCla(1000), m_periodicTimer(0), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_AuraDRGroup(DIMINISHING_NONE), m_effIndex(eff), m_auraSlot(MAX_AURAS), m_auraFlags(AFLAG_NONE), m_auraLevel(1), m_procCharges(0), m_stackAmount(1), m_positive(false), m_permanent(false), m_isPeriodic(false), m_isAreaAura(false), m_isPersistent(false), -m_isRemovedOnShapeLost(true), m_updated(false), m_in_use(false) +m_isRemovedOnShapeLost(true), m_in_use(0), m_deleted(false) { assert(target); @@ -789,12 +789,8 @@ void AreaAura::Update(uint32 diff) } else // aura at non-caster { - Unit * tmp_target = m_target; Unit* caster = GetCaster(); - uint32 tmp_spellId = GetId(), tmp_effIndex = m_effIndex; - // WARNING: the aura may get deleted during the update - // DO NOT access its members after update! Aura::Update(diff); // remove aura if out-of-range from caster (after teleport for example) @@ -802,53 +798,53 @@ void AreaAura::Update(uint32 diff) // or caster is (no longer) friendly bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true); if( !caster || caster->hasUnitState(UNIT_STAT_ISOLATED) || - !caster->IsWithinDistInMap(tmp_target, m_radius) || - !caster->HasAura(tmp_spellId, tmp_effIndex) || - caster->IsFriendlyTo(tmp_target) != needFriendly + !caster->IsWithinDistInMap(m_target, m_radius) || + !caster->HasAura(GetId(), GetEffIndex()) || + caster->IsFriendlyTo(m_target) != needFriendly ) { - tmp_target->RemoveAura(tmp_spellId, tmp_effIndex); + m_target->RemoveAura(GetId(), GetEffIndex()); } else if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group { // not check group if target == owner or target == pet - if (caster->GetCharmerOrOwnerGUID() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID()) + if (caster->GetCharmerOrOwnerGUID() != m_target->GetGUID() && caster->GetGUID() != m_target->GetCharmerOrOwnerGUID()) { Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself(); Group *pGroup = check ? check->GetGroup() : NULL; if( pGroup ) { - Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself(); + Player* checkTarget = m_target->GetCharmerOrOwnerPlayerOrPlayerItself(); if(!checkTarget || !pGroup->SameSubGroup(check, checkTarget)) - tmp_target->RemoveAura(tmp_spellId, tmp_effIndex); + m_target->RemoveAura(GetId(), GetEffIndex()); } else - tmp_target->RemoveAura(tmp_spellId, tmp_effIndex); + m_target->RemoveAura(GetId(), GetEffIndex()); } } else if( m_areaAuraType == AREA_AURA_RAID) // TODO: fix me! { // not check group if target == owner or target == pet - if (caster->GetCharmerOrOwnerGUID() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID()) + if (caster->GetCharmerOrOwnerGUID() != m_target->GetGUID() && caster->GetGUID() != m_target->GetCharmerOrOwnerGUID()) { Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself(); Group *pGroup = check ? check->GetGroup() : NULL; if( pGroup ) { - Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself(); + Player* checkTarget = m_target->GetCharmerOrOwnerPlayerOrPlayerItself(); if(!checkTarget) - tmp_target->RemoveAura(tmp_spellId, tmp_effIndex); + m_target->RemoveAura(GetId(), GetEffIndex()); } else - tmp_target->RemoveAura(tmp_spellId, tmp_effIndex); + m_target->RemoveAura(GetId(), GetEffIndex()); } } else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER ) { - if( tmp_target->GetGUID() != caster->GetCharmerOrOwnerGUID() ) - tmp_target->RemoveAura(tmp_spellId, tmp_effIndex); + if( m_target->GetGUID() != caster->GetCharmerOrOwnerGUID() ) + m_target->RemoveAura(GetId(), GetEffIndex()); } } } @@ -859,8 +855,7 @@ void PersistentAreaAura::Update(uint32 diff) // remove the aura if its caster or the dynamic object causing it was removed // or if the target moves too far from the dynamic object - Unit *caster = GetCaster(); - if (caster) + if(Unit *caster = GetCaster()) { DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex()); if (dynObj) @@ -874,25 +869,20 @@ void PersistentAreaAura::Update(uint32 diff) else remove = true; - Unit *tmp_target = m_target; - uint32 tmp_id = GetId(), tmp_index = GetEffIndex(); - - // WARNING: the aura may get deleted during the update - // DO NOT access its members after update! Aura::Update(diff); if(remove) - tmp_target->RemoveAura(tmp_id, tmp_index); + m_target->RemoveAura(GetId(), GetEffIndex()); } void Aura::ApplyModifier(bool apply, bool Real) { AuraType aura = m_modifier.m_auraname; - m_in_use = true; + SetInUse(true); if(aura < TOTAL_AURAS) (*this.*AuraHandler [aura])(apply, Real); - m_in_use = false; + SetInUse(false); } void Aura::_AddAura() @@ -6109,18 +6099,15 @@ void Aura::PeriodicTick() SpellPeriodicAuraLogInfo pInfo(this, pdamage, 0, absorb, resist, 0.0f, isCrit); m_target->SendPeriodicAuraLog(&pInfo); - Unit* target = m_target; // aura can be deleted in DealDamage - SpellEntry const* spellProto = GetSpellProto(); - // Set trigger flag uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC; // | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT; uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT; pdamage = (pdamage <= absorb + resist) ? 0 : (pdamage - absorb - resist); if (pdamage) procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE; - pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto); + pCaster->ProcDamageAndSpell(m_target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, GetSpellProto()); - pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, true); + pCaster->DealDamage(m_target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true); break; } case SPELL_AURA_PERIODIC_LEECH: @@ -6172,10 +6159,7 @@ void Aura::PeriodicTick() pCaster->SendSpellNonMeleeDamageLog(m_target, GetId(), pdamage, GetSpellSchoolMask(GetSpellProto()), absorb, resist, false, 0); - Unit* target = m_target; // aura can be deleted in DealDamage - SpellEntry const* spellProto = GetSpellProto(); - float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1; - int32 stackAmount = GetStackAmount(); + float multiplier = GetSpellProto()->EffectMultipleValue[GetEffIndex()] > 0 ? GetSpellProto()->EffectMultipleValue[GetEffIndex()] : 1; // Set trigger flag uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC; // | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT; @@ -6183,26 +6167,26 @@ void Aura::PeriodicTick() pdamage = (pdamage <= absorb + resist) ? 0 : (pdamage-absorb-resist); if (pdamage) procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE; - pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto); - int32 new_damage = pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, false); + pCaster->ProcDamageAndSpell(m_target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, GetSpellProto()); + int32 new_damage = pCaster->DealDamage(m_target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), false); - if (!target->isAlive() && pCaster->IsNonMeleeSpellCasted(false)) + if (!m_target->isAlive() && pCaster->IsNonMeleeSpellCasted(false)) { for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; ++i) { - if (pCaster->m_currentSpells[i] && pCaster->m_currentSpells[i]->m_spellInfo->Id == spellProto->Id) + if (pCaster->m_currentSpells[i] && pCaster->m_currentSpells[i]->m_spellInfo->Id == GetId()) pCaster->m_currentSpells[i]->cancel(); } } if(Player *modOwner = pCaster->GetSpellModOwner()) - modOwner->ApplySpellMod(spellProto->Id, SPELLMOD_MULTIPLE_VALUE, multiplier); + modOwner->ApplySpellMod(GetId(), SPELLMOD_MULTIPLE_VALUE, multiplier); - uint32 heal = pCaster->SpellHealingBonus(pCaster, spellProto, uint32(new_damage * multiplier), DOT, stackAmount); + uint32 heal = pCaster->SpellHealingBonus(pCaster, GetSpellProto(), uint32(new_damage * multiplier), DOT, GetStackAmount()); - int32 gain = pCaster->DealHeal(pCaster, heal, spellProto); - pCaster->getHostilRefManager().threatAssist(pCaster, gain * 0.5f, spellProto); + int32 gain = pCaster->DealHeal(pCaster, heal, GetSpellProto()); + pCaster->getHostilRefManager().threatAssist(pCaster, gain * 0.5f, GetSpellProto()); break; } case SPELL_AURA_PERIODIC_HEAL: diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h index 6fc9d83a9..c84415440 100644 --- a/src/game/SpellAuras.h +++ b/src/game/SpellAuras.h @@ -292,16 +292,24 @@ class MANGOS_DLL_SPEC Aura bool IsDeathPersistent() const { return m_isDeathPersist; } bool IsRemovedOnShapeLost() const { return m_isRemovedOnShapeLost; } bool IsInUse() const { return m_in_use;} + bool IsDeleted() const { return m_deleted;} - virtual void Update(uint32 diff); + void SetInUse(bool state) + { + if(state) + ++m_in_use; + else + { + if(m_in_use) + --m_in_use; + } + } void ApplyModifier(bool apply, bool Real = false); + void UpdateAura(uint32 diff) { SetInUse(true); Update(diff); SetInUse(false); } void _AddAura(); bool _RemoveAura(); - bool IsUpdated() { return m_updated; } - void SetUpdated(bool val) { m_updated = val; } - bool IsSingleTarget() {return m_isSingleTargetAura;} void SetIsSingleTarget(bool val) { m_isSingleTargetAura = val;} @@ -319,14 +327,19 @@ class MANGOS_DLL_SPEC Aura void TriggerSpell(); void TriggerSpellWithValue(); - void PeriodicTick(); - void PeriodicDummyTick(); uint32 const *getAuraSpellClassMask() const { return m_spellProto->EffectSpellClassMaskA + m_effIndex * 3; } bool isAffectedOnSpell(SpellEntry const *spell) const; protected: Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL); + // must be called only from Aura::UpdateAura + virtual void Update(uint32 diff); + + // must be called only from Aura*::Update + void PeriodicTick(); + void PeriodicDummyTick(); + bool IsCritFromAbilityAura(Unit* caster, uint32& damage); Modifier m_modifier; @@ -362,10 +375,10 @@ class MANGOS_DLL_SPEC Aura bool m_isPersistent:1; bool m_isDeathPersist:1; bool m_isRemovedOnShapeLost:1; - bool m_updated:1; // Prevent remove aura by stack if set - bool m_in_use:1; // true while in Aura::ApplyModifier call + bool m_deleted:1; // true if RemoveAura(iterator) called while in Aura::ApplyModifier call (added to Unit::m_deletedAuras) bool m_isSingleTargetAura:1; // true if it's a single target spell and registered at caster - can change at spell steal for example + uint32 m_in_use; // > 0 while in Aura::ApplyModifier call/Aura::Update/etc private: void CleanupTriggeredSpells(); }; @@ -375,6 +388,7 @@ class MANGOS_DLL_SPEC AreaAura : public Aura public: AreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL); ~AreaAura(); + protected: void Update(uint32 diff); private: float m_radius; @@ -386,6 +400,7 @@ class MANGOS_DLL_SPEC PersistentAreaAura : public Aura public: PersistentAreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL); ~PersistentAreaAura(); + protected: void Update(uint32 diff); }; diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index bc583618d..af08c7312 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -2413,11 +2413,6 @@ void Spell::EffectApplyAura(uint32 i) if (!added) return; - // found crash at character loading, broken pointer to Aur... - // Aur was deleted in AddAura()... - if(!Aur) - return; - // Prayer of Mending (jump animation), we need formal caster instead original for correct animation if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000002000000000))) m_caster->CastSpell(unitTarget, 41637, true, NULL, Aur, m_originalCasterGUID); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 885de4c0a..32345e283 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -102,7 +102,7 @@ Unit::Unit() //m_Aura = NULL; //m_AurasCheck = 2000; //m_removeAuraTimer = 4; - //tmpAura = NULL; + m_AurasUpdateIterator = m_Auras.end(); m_Visibility = VISIBILITY_ON; @@ -148,7 +148,6 @@ Unit::Unit() for (int i = 0; i < MAX_MOVE_TYPE; ++i) m_speed_rate[i] = 1.0f; - m_removedAuras = 0; m_charmInfo = NULL; // remove aurastates allowing special moves @@ -192,6 +191,11 @@ void Unit::Update( uint32 p_time ) m_Events.Update( p_time ); _UpdateSpells( p_time ); + // really delete auras "deleted" while processing its ApplyModify code + for(AuraList::const_iterator itr = m_deletedAuras.begin(); itr != m_deletedAuras.begin(); ++itr) + delete *itr; + m_deletedAuras.clear(); + // update combat timer only for players and pets if (isInCombat() && (GetTypeId() == TYPEID_PLAYER || ((Creature*)this)->isPet() || ((Creature*)this)->isCharmed())) { @@ -1509,11 +1513,9 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) // victim's damage shield std::set alreadyDone; - uint32 removedAuras = pVictim->m_removedAuras; AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD); - for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next) + for(AuraList::const_iterator i = vDamageShields.begin(); i != vDamageShields.end();) { - next++; if (alreadyDone.find(*i) == alreadyDone.end()) { alreadyDone.insert(*i); @@ -1540,12 +1542,10 @@ void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss) pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true); - if (pVictim->m_removedAuras > removedAuras) - { - removedAuras = pVictim->m_removedAuras; - next = vDamageShields.begin(); - } + i = vDamageShields.begin(); } + else + ++i; } } } @@ -2962,50 +2962,27 @@ void Unit::_UpdateSpells( uint32 time ) } } - // TODO: Find a better way to prevent crash when multiple auras are removed. - m_removedAuras = 0; - for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end(); ++i) - if ((*i).second) - (*i).second->SetUpdated(false); - - for (AuraMap::iterator i = m_Auras.begin(), next; i != m_Auras.end(); i = next) + // update auras + // m_AurasUpdateIterator can be updated in inderect called code at aura remove to skip next planned to update but removed auras + for (m_AurasUpdateIterator = m_Auras.begin(); m_AurasUpdateIterator != m_Auras.end();) { - next = i; - ++next; - if ((*i).second) - { - // prevent double update - if ((*i).second->IsUpdated()) - continue; - (*i).second->SetUpdated(true); - (*i).second->Update( time ); - // several auras can be deleted due to update - if (m_removedAuras) - { - if (m_Auras.empty()) break; - next = m_Auras.begin(); - m_removedAuras = 0; - } - } + Aura* i_aura = m_AurasUpdateIterator->second; + ++m_AurasUpdateIterator; // need shift to next for allow update if need into aura update + i_aura->UpdateAura(time); } + // remove expired auras for (AuraMap::iterator i = m_Auras.begin(); i != m_Auras.end();) { if ((*i).second) { if ( !(*i).second->GetAuraDuration() && !((*i).second->IsPermanent() || ((*i).second->IsPassive())) ) - { RemoveAura(i); - } else - { ++i; - } } else - { ++i; - } } if(!m_gameObj.empty()) @@ -3538,6 +3515,11 @@ bool Unit::AddAura(Aura *Aur) Aur->ApplyModifier(true,true); sLog.outDebug("Aura %u now is in use", aurName); + // if aura deleted before boosts apply ignore + // this can be possible it it removed indirectly by triggered spell effect at ApplyModifier + if (Aur->IsDeleted()) + return false; + if(IsSpellLastAuraEffect(aurSpellInfo,Aur->GetEffIndex())) Aur->HandleSpellSpecificBoosts(true); @@ -3955,10 +3937,16 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) // Set remove mode Aur->SetRemoveMode(mode); + + // if unit currently update aura list then make safe update iterator shift to next + if (m_AurasUpdateIterator == i) + ++m_AurasUpdateIterator; + // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura // remove aura from list before to prevent deleting it before m_Auras.erase(i); - ++m_removedAuras; // internal count used by unit update + + // now aura removed from from list and can't be deleted by indirect call but can be referenced from callers // Statue unsummoned at aura remove Totem* statue = NULL; @@ -3986,7 +3974,12 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) Aur->HandleSpellSpecificBoosts(false); } - delete Aur; + // If aura in use (removed from code that plan access to it data after return) + // store it in aura list with delayed deletion + if (Aur->IsInUse()) + m_deletedAuras.push_back(Aur); + else + delete Aur; if(caster_channeled) RemoveAurasAtChanneledTarget (AurSpellInfo); @@ -10940,6 +10933,7 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag if(!IsTriggeredAtSpellProcEvent(pTarget, itr->second, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent)) continue; + itr->second->SetInUse(true); // prevent aura deletion procTriggered.push_back( ProcTriggeredData(spellProcEvent, itr->second) ); } @@ -10951,33 +10945,11 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag for(ProcTriggeredList::const_iterator i = procTriggered.begin(); i != procTriggered.end(); ++i) { // Some auras can be deleted in function called in this loop (except first, ofc) - // Until storing auars in std::multimap to hard check deleting by another way - if(i != procTriggered.begin()) - { - bool found = false; - AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); - AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); - for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) - { - if(itr->second==i->triggeredByAura) - { - found = true; - break; - } - } - if(!found) - { -// sLog.outDebug("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler", i->triggeredByAura->GetModifier()->m_auraname, i->triggeredByAura_SpellPair.first, i->triggeredByAura_SpellPair.second); -// sLog.outDebug("It can be deleted one from early proccesed auras:"); -// for(ProcTriggeredList::const_iterator i2 = procTriggered.begin(); i != i2; ++i2) -// sLog.outDebug(" Spell aura %u (id:%u effect:%u)", i->triggeredByAura->GetModifier()->m_auraname,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second); -// sLog.outDebug(" "); - continue; - } - } + Aura *triggeredByAura = i->triggeredByAura; + if(triggeredByAura->IsDeleted()) + continue; SpellProcEventEntry const *spellProcEvent = i->spellProcEvent; - Aura *triggeredByAura = i->triggeredByAura; Modifier *auraModifier = triggeredByAura->GetModifier(); SpellEntry const *spellInfo = triggeredByAura->GetSpellProto(); bool useCharges = triggeredByAura->GetAuraCharges() > 0; @@ -10993,7 +10965,10 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); // Don`t drop charge or add cooldown for not started trigger if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + triggeredByAura->SetInUse(false); continue; + } break; } case SPELL_AURA_PROC_TRIGGER_DAMAGE: @@ -11013,21 +10988,30 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag { sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + triggeredByAura->SetInUse(false); continue; + } break; } case SPELL_AURA_MOD_HASTE: { sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + triggeredByAura->SetInUse(false); continue; + } break; } case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS: { sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); if (!HandleOverrideClassScriptAuraProc(pTarget, damage, triggeredByAura, procSpell, cooldown)) + { + triggeredByAura->SetInUse(false); continue; + } break; } case SPELL_AURA_PRAYER_OF_MENDING: @@ -11043,18 +11027,27 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered with value by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId()); if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown)) + { + triggeredByAura->SetInUse(false); continue; + } break; } case SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK: // Skip melee hits or instant cast spells if (procSpell == NULL || GetSpellCastTime(procSpell) == 0) + { + triggeredByAura->SetInUse(false); continue; + } break; case SPELL_AURA_REFLECT_SPELLS_SCHOOL: // Skip Melee hits and spells ws wrong school if (procSpell == NULL || (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0) + { + triggeredByAura->SetInUse(false); continue; + } break; case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT: case SPELL_AURA_MOD_POWER_COST_SCHOOL: @@ -11062,47 +11055,56 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag if (procSpell == NULL || (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0) // School check + { + triggeredByAura->SetInUse(false); continue; + } break; case SPELL_AURA_MECHANIC_IMMUNITY: // Compare mechanic if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue) + { + triggeredByAura->SetInUse(false); continue; + } break; case SPELL_AURA_MOD_MECHANIC_RESISTANCE: // Compare mechanic if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue) + { + triggeredByAura->SetInUse(false); continue; + } break; case SPELL_AURA_MOD_DAMAGE_FROM_CASTER: // Compare casters if (triggeredByAura->GetCasterGUID() != pTarget->GetGUID()) + { + triggeredByAura->SetInUse(false); continue; + } break; case SPELL_AURA_MOD_SPELL_CRIT_CHANCE: if (!procSpell) + { + triggeredByAura->SetInUse(false); continue; + } break; default: // nothing do, just charges counter break; } + // Remove charge (aura can be removed by triggers) - if(useCharges) + if(useCharges && !triggeredByAura->IsDeleted()) { - // need found aura on drop (can be dropped by triggers) - AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair); - AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair); - for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr) - { - // If last charge dropped add spell to remove list - if(itr->second == i->triggeredByAura && triggeredByAura->DropAuraCharge()) - { - removedSpells.push_back(triggeredByAura->GetId()); - break; - } - } + // If last charge dropped add spell to remove list + if(triggeredByAura->DropAuraCharge()) + removedSpells.push_back(triggeredByAura->GetId()); } + + triggeredByAura->SetInUse(false); } if (!removedSpells.empty()) { diff --git a/src/game/Unit.h b/src/game/Unit.h index 89fdf816e..1bea36611 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1514,8 +1514,10 @@ class MANGOS_DLL_SPEC Unit : public WorldObject DeathState m_deathState; AuraMap m_Auras; + AuraMap::iterator m_AurasUpdateIterator; // != end() in Unit::m_Auras update and point to next element + AuraList m_deletedAuras; // auras removed while in ApplyModifier and waiting deleted - std::list m_scAuras; // casted singlecast auras + AuraList m_scAuras; // casted by unit single per-caster auras typedef std::list DynObjectGUIDs; DynObjectGUIDs m_dynObjGUIDs; @@ -1524,7 +1526,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject GameObjectList m_gameObj; bool m_isSorted; uint32 m_transform; - uint32 m_removedAuras; AuraList m_modAuras[TOTAL_AURAS]; float m_auraModifiersGroup[UNIT_MOD_END][MODIFIER_TYPE_END]; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d5215441e..bd9a3b7e8 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8328" + #define REVISION_NR "8329" #endif // __REVISION_NR_H__