mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 13:37:05 +00:00
[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.
This commit is contained in:
parent
7baebcd2de
commit
c8cc9b28f8
6 changed files with 139 additions and 142 deletions
|
|
@ -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<Aura*> 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(" <end of list>");
|
||||
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())
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue