Core/DynamicObjects: Change the way how dynamic objects are bound to their owners, fixes some crashes in Aura::GetOwner.
This commit is contained in:
@@ -36,37 +36,47 @@ DynamicObject::DynamicObject() : WorldObject()
|
||||
|
||||
m_valuesCount = DYNAMICOBJECT_END;
|
||||
|
||||
m_aura = 0;
|
||||
m_aura = NULL;
|
||||
m_duration = 0;
|
||||
m_caster = NULL;
|
||||
m_isViewpoint = false;
|
||||
}
|
||||
|
||||
DynamicObject::~DynamicObject()
|
||||
{
|
||||
// make sure all references were properly removed
|
||||
ASSERT(!m_aura);
|
||||
ASSERT(!m_caster);
|
||||
ASSERT(!m_isViewpoint);
|
||||
}
|
||||
|
||||
void DynamicObject::AddToWorld()
|
||||
{
|
||||
///- Register the dynamicObject for guid lookup
|
||||
///- Register the dynamicObject for guid lookup and for caster
|
||||
if (!IsInWorld())
|
||||
{
|
||||
sObjectAccessor->AddObject(this);
|
||||
WorldObject::AddToWorld();
|
||||
BindToCaster();
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveFromWorld()
|
||||
{
|
||||
///- Remove the dynamicObject from the accessor
|
||||
///- Remove the dynamicObject from the accessor and from all lists of objects in world
|
||||
if (IsInWorld())
|
||||
{
|
||||
if (m_isWorldObject)
|
||||
{
|
||||
if (Unit *caster = GetCaster())
|
||||
{
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER)
|
||||
caster->ToPlayer()->SetViewpoint(this, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
sLog->outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner");
|
||||
}
|
||||
}
|
||||
if (m_isViewpoint)
|
||||
RemoveCasterViewpoint();
|
||||
|
||||
if (m_aura)
|
||||
RemoveAura();
|
||||
|
||||
// dynobj could get removed in Aura::RemoveAura
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
UnbindFromCaster();
|
||||
WorldObject::RemoveFromWorld();
|
||||
sObjectAccessor->RemoveObject(this);
|
||||
}
|
||||
@@ -102,21 +112,11 @@ bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, const P
|
||||
return true;
|
||||
}
|
||||
|
||||
Unit* DynamicObject::GetCaster() const
|
||||
{
|
||||
// can be not found in some cases
|
||||
return ObjectAccessor::GetUnit(*this, GetCasterGUID());
|
||||
}
|
||||
|
||||
void DynamicObject::Update(uint32 p_time)
|
||||
{
|
||||
// caster can be not in world at time dynamic object update, but dynamic object not yet deleted in Unit destructor
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
{
|
||||
Delete();
|
||||
return;
|
||||
}
|
||||
// caster has to be always avalible and in the same map
|
||||
ASSERT(m_caster);
|
||||
ASSERT(m_caster->GetMap() == GetMap());
|
||||
|
||||
bool expired = false;
|
||||
|
||||
@@ -125,7 +125,7 @@ void DynamicObject::Update(uint32 p_time)
|
||||
if (!m_aura->IsRemoved())
|
||||
m_aura->UpdateOwner(p_time, this);
|
||||
|
||||
// m_aura may be set to null in Unit::RemoveGameObject call
|
||||
// m_aura may be set to null in Aura::UpdateOwner call
|
||||
if (m_aura && (m_aura->IsRemoved() || m_aura->IsExpired()))
|
||||
expired = true;
|
||||
}
|
||||
@@ -138,28 +138,19 @@ void DynamicObject::Update(uint32 p_time)
|
||||
}
|
||||
|
||||
if (expired)
|
||||
{
|
||||
caster->RemoveDynObjectWithGUID(GetGUID());
|
||||
Delete();
|
||||
}
|
||||
Remove();
|
||||
else
|
||||
sScriptMgr->OnDynamicObjectUpdate(this, p_time);
|
||||
}
|
||||
|
||||
void DynamicObject::Delete()
|
||||
void DynamicObject::Remove()
|
||||
{
|
||||
if (m_aura)
|
||||
if (IsInWorld())
|
||||
{
|
||||
// dynObj may be removed in Aura::Remove - we cannot delete there
|
||||
// so recheck aura here
|
||||
if (!m_aura->IsRemoved())
|
||||
m_aura->_Remove(AURA_REMOVE_BY_DEFAULT);
|
||||
delete m_aura;
|
||||
m_aura = NULL;
|
||||
}
|
||||
SendObjectDeSpawnAnim(GetGUID());
|
||||
RemoveFromWorld();
|
||||
AddObjectToRemoveList();
|
||||
}
|
||||
}
|
||||
|
||||
int32 DynamicObject::GetDuration() const
|
||||
@@ -182,3 +173,52 @@ void DynamicObject::Delay(int32 delaytime)
|
||||
{
|
||||
SetDuration(GetDuration() - delaytime);
|
||||
}
|
||||
|
||||
void DynamicObject::SetAura(Aura * aura)
|
||||
{
|
||||
ASSERT (!m_aura && aura);
|
||||
m_aura = aura;
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveAura()
|
||||
{
|
||||
ASSERT (m_aura);
|
||||
if (!m_aura->IsRemoved())
|
||||
m_aura->_Remove(AURA_REMOVE_BY_DEFAULT);
|
||||
delete m_aura;
|
||||
m_aura = NULL;
|
||||
}
|
||||
|
||||
void DynamicObject::SetCasterViewpoint()
|
||||
{
|
||||
if (Player * caster = m_caster->ToPlayer())
|
||||
{
|
||||
caster->SetViewpoint(this, true);
|
||||
m_isViewpoint = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::RemoveCasterViewpoint()
|
||||
{
|
||||
if (Player * caster = m_caster->ToPlayer())
|
||||
{
|
||||
caster->SetViewpoint(this, false);
|
||||
m_isViewpoint = false;
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicObject::BindToCaster()
|
||||
{
|
||||
ASSERT(!m_caster);
|
||||
m_caster = ObjectAccessor::GetUnit(*this, GetCasterGUID());
|
||||
ASSERT(m_caster);
|
||||
ASSERT(m_caster->GetMap() == GetMap());
|
||||
m_caster->_RegisterDynObject(this);
|
||||
}
|
||||
|
||||
void DynamicObject::UnbindFromCaster()
|
||||
{
|
||||
ASSERT(m_caster);
|
||||
m_caster->_UnregisterDynObject(this);
|
||||
m_caster = NULL;
|
||||
}
|
||||
|
||||
@@ -29,21 +29,27 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>
|
||||
{
|
||||
public:
|
||||
explicit DynamicObject();
|
||||
~DynamicObject();
|
||||
|
||||
void AddToWorld();
|
||||
void RemoveFromWorld();
|
||||
|
||||
bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active);
|
||||
void Update(uint32 p_time);
|
||||
void Delete();
|
||||
void Remove();
|
||||
void SetDuration(int32 newDuration);
|
||||
int32 GetDuration() const;
|
||||
void SetAura(Aura * aura) {ASSERT (!m_aura && aura); m_aura = aura;}
|
||||
void Delay(int32 delaytime);
|
||||
void SetAura(Aura * aura);
|
||||
void RemoveAura();
|
||||
void SetCasterViewpoint();
|
||||
void RemoveCasterViewpoint();
|
||||
Unit * GetCaster() const { return m_caster; }
|
||||
void BindToCaster();
|
||||
void UnbindFromCaster();
|
||||
uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); }
|
||||
uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); }
|
||||
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
|
||||
Unit* GetCaster() const;
|
||||
|
||||
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
|
||||
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
|
||||
@@ -54,5 +60,7 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>
|
||||
protected:
|
||||
int32 m_duration; // for non-aura dynobjects
|
||||
Aura * m_aura;
|
||||
Unit * m_caster;
|
||||
bool m_isViewpoint;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -4468,24 +4468,40 @@ int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellEntry
|
||||
return modifier;
|
||||
}
|
||||
|
||||
void Unit::AddDynObject(DynamicObject* dynObj)
|
||||
void Unit::_RegisterDynObject(DynamicObject* dynObj)
|
||||
{
|
||||
m_dynObjGUIDs.push_back(dynObj->GetGUID());
|
||||
m_dynObj.push_back(dynObj);
|
||||
}
|
||||
|
||||
void Unit::RemoveDynObject(uint32 spellid)
|
||||
void Unit::_UnregisterDynObject(DynamicObject* dynObj)
|
||||
{
|
||||
if (m_dynObjGUIDs.empty())
|
||||
m_dynObj.remove(dynObj);
|
||||
}
|
||||
|
||||
DynamicObject * Unit::GetDynObject(uint32 spellId)
|
||||
{
|
||||
if (m_dynObj.empty())
|
||||
return NULL;
|
||||
for (DynObjectList::const_iterator i = m_dynObj.begin(); i != m_dynObj.end();++i)
|
||||
{
|
||||
DynamicObject* dynObj = *i;
|
||||
if (dynObj->GetSpellId() == spellId)
|
||||
return dynObj;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Unit::RemoveDynObject(uint32 spellId)
|
||||
{
|
||||
if (m_dynObj.empty())
|
||||
return;
|
||||
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
|
||||
for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
|
||||
{
|
||||
DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
|
||||
if (!dynObj) // may happen if a dynobj is removed when grid unload
|
||||
i = m_dynObjGUIDs.erase(i);
|
||||
else if (spellid == 0 || dynObj->GetSpellId() == spellid)
|
||||
DynamicObject* dynObj = *i;
|
||||
if (dynObj->GetSpellId() == spellId)
|
||||
{
|
||||
dynObj->Delete();
|
||||
i = m_dynObjGUIDs.erase(i);
|
||||
dynObj->Remove();
|
||||
i = m_dynObj.begin();
|
||||
}
|
||||
else
|
||||
++i;
|
||||
@@ -4494,31 +4510,8 @@ void Unit::RemoveDynObject(uint32 spellid)
|
||||
|
||||
void Unit::RemoveAllDynObjects()
|
||||
{
|
||||
while (!m_dynObjGUIDs.empty())
|
||||
{
|
||||
DynamicObject* dynObj = GetMap()->GetDynamicObject(*m_dynObjGUIDs.begin());
|
||||
if (dynObj)
|
||||
dynObj->Delete();
|
||||
m_dynObjGUIDs.erase(m_dynObjGUIDs.begin());
|
||||
}
|
||||
}
|
||||
|
||||
DynamicObject * Unit::GetDynObject(uint32 spellId)
|
||||
{
|
||||
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
|
||||
{
|
||||
DynamicObject* dynObj = GetMap()->GetDynamicObject(*i);
|
||||
if (!dynObj)
|
||||
{
|
||||
i = m_dynObjGUIDs.erase(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dynObj->GetSpellId() == spellId)
|
||||
return dynObj;
|
||||
++i;
|
||||
}
|
||||
return NULL;
|
||||
while (!m_dynObj.empty())
|
||||
m_dynObj.front()->Remove();
|
||||
}
|
||||
|
||||
GameObject* Unit::GetGameObject(uint32 spellId) const
|
||||
|
||||
@@ -1863,10 +1863,11 @@ class Unit : public WorldObject
|
||||
void setTransForm(uint32 spellid) { m_transform = spellid;}
|
||||
uint32 getTransForm() const { return m_transform;}
|
||||
|
||||
// DynamicObject management
|
||||
void _RegisterDynObject(DynamicObject* dynObj);
|
||||
void _UnregisterDynObject(DynamicObject* dynObj);
|
||||
DynamicObject* GetDynObject(uint32 spellId);
|
||||
void AddDynObject(DynamicObject* dynObj);
|
||||
void RemoveDynObject(uint32 spellid);
|
||||
void RemoveDynObjectWithGUID(uint64 guid) { m_dynObjGUIDs.remove(guid); }
|
||||
void RemoveDynObject(uint32 spellId);
|
||||
void RemoveAllDynObjects();
|
||||
|
||||
GameObject* GetGameObject(uint32 spellId) const;
|
||||
@@ -2078,8 +2079,8 @@ class Unit : public WorldObject
|
||||
|
||||
int32 m_procDeep;
|
||||
|
||||
typedef std::list<uint64> DynObjectGUIDs;
|
||||
DynObjectGUIDs m_dynObjGUIDs;
|
||||
typedef std::list<DynamicObject*> DynObjectList;
|
||||
DynObjectList m_dynObj;
|
||||
|
||||
typedef std::list<GameObject*> GameObjectList;
|
||||
GameObjectList m_gameObj;
|
||||
|
||||
@@ -280,13 +280,13 @@ ObjectGridStoper::Visit(CreatureMapType &m)
|
||||
// stop any fights at grid de-activation and remove dynobjects created at cast by creatures
|
||||
for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
|
||||
{
|
||||
iter->getSource()->RemoveAllDynObjects();
|
||||
if (iter->getSource()->isInCombat())
|
||||
{
|
||||
iter->getSource()->CombatStop();
|
||||
iter->getSource()->DeleteThreatList();
|
||||
iter->getSource()->AI()->EnterEvadeMode(); // Calls RemoveAllAuras
|
||||
iter->getSource()->AI()->EnterEvadeMode();
|
||||
}
|
||||
iter->getSource()->RemoveAllDynObjects(); // Calls RemoveFromWorld, needs to be after RemoveAllAuras or we invalidate the Owner pointer of the aura
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2556,18 +2556,16 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex)
|
||||
delete dynObj;
|
||||
return;
|
||||
}
|
||||
caster->AddDynObject(dynObj);
|
||||
dynObj->GetMap()->Add(dynObj);
|
||||
|
||||
if (Aura * aura = Aura::TryCreate(m_spellInfo, dynObj, caster, &m_spellValue->EffectBasePoints[0]))
|
||||
m_spellAura = aura;
|
||||
else
|
||||
{
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
m_spellAura = aura;
|
||||
m_spellAura->_RegisterForTargets();
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
ASSERT(m_spellAura->GetDynobjOwner());
|
||||
m_spellAura->_ApplyEffectForTargets(effIndex);
|
||||
}
|
||||
@@ -3387,14 +3385,10 @@ void Spell::EffectAddFarsight(SpellEffIndex effIndex)
|
||||
}
|
||||
dynObj->SetDuration(duration);
|
||||
dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
|
||||
m_caster->AddDynObject(dynObj);
|
||||
|
||||
dynObj->setActive(true); //must before add to map to be put in world container
|
||||
dynObj->GetMap()->Add(dynObj); //grid will also be loaded
|
||||
|
||||
// Need to update visibility of object for client to accept farsight guid
|
||||
m_caster->ToPlayer()->SetViewpoint(dynObj, true);
|
||||
//m_caster->ToPlayer()->UpdateVisibilityOf(dynObj);
|
||||
dynObj->SetCasterViewpoint();
|
||||
}
|
||||
|
||||
void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/)
|
||||
|
||||
Reference in New Issue
Block a user