Core/DynamicObjects: Change the way how dynamic objects are bound to their owners, fixes some crashes in Aura::GetOwner.

This commit is contained in:
QAston
2011-02-04 00:27:43 +01:00
parent 1740df0fac
commit d18193e52d
6 changed files with 138 additions and 102 deletions
@@ -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();
}
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
+30 -37
View File
@@ -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())
return;
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
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 = 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)
return dynObj;
}
return NULL;
}
void Unit::RemoveDynObject(uint32 spellId)
{
if (m_dynObj.empty())
return;
for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();)
{
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
+6 -5
View File
@@ -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;