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_valuesCount = DYNAMICOBJECT_END;
m_aura = 0; m_aura = NULL;
m_duration = 0; 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() void DynamicObject::AddToWorld()
{ {
///- Register the dynamicObject for guid lookup ///- Register the dynamicObject for guid lookup and for caster
if (!IsInWorld()) if (!IsInWorld())
{ {
sObjectAccessor->AddObject(this); sObjectAccessor->AddObject(this);
WorldObject::AddToWorld(); WorldObject::AddToWorld();
BindToCaster();
} }
} }
void DynamicObject::RemoveFromWorld() 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 (IsInWorld())
{ {
if (m_isWorldObject) if (m_isViewpoint)
{ RemoveCasterViewpoint();
if (Unit *caster = GetCaster())
{ if (m_aura)
if (caster->GetTypeId() == TYPEID_PLAYER) RemoveAura();
caster->ToPlayer()->SetViewpoint(this, false);
} // dynobj could get removed in Aura::RemoveAura
else if (!IsInWorld())
{ return;
sLog->outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner");
} UnbindFromCaster();
}
WorldObject::RemoveFromWorld(); WorldObject::RemoveFromWorld();
sObjectAccessor->RemoveObject(this); sObjectAccessor->RemoveObject(this);
} }
@@ -102,21 +112,11 @@ bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, const P
return true; return true;
} }
Unit* DynamicObject::GetCaster() const
{
// can be not found in some cases
return ObjectAccessor::GetUnit(*this, GetCasterGUID());
}
void DynamicObject::Update(uint32 p_time) 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 // caster has to be always avalible and in the same map
Unit* caster = GetCaster(); ASSERT(m_caster);
if (!caster) ASSERT(m_caster->GetMap() == GetMap());
{
Delete();
return;
}
bool expired = false; bool expired = false;
@@ -125,7 +125,7 @@ void DynamicObject::Update(uint32 p_time)
if (!m_aura->IsRemoved()) if (!m_aura->IsRemoved())
m_aura->UpdateOwner(p_time, this); 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())) if (m_aura && (m_aura->IsRemoved() || m_aura->IsExpired()))
expired = true; expired = true;
} }
@@ -138,28 +138,19 @@ void DynamicObject::Update(uint32 p_time)
} }
if (expired) if (expired)
{ Remove();
caster->RemoveDynObjectWithGUID(GetGUID());
Delete();
}
else else
sScriptMgr->OnDynamicObjectUpdate(this, p_time); 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 SendObjectDeSpawnAnim(GetGUID());
// so recheck aura here RemoveFromWorld();
if (!m_aura->IsRemoved()) AddObjectToRemoveList();
m_aura->_Remove(AURA_REMOVE_BY_DEFAULT);
delete m_aura;
m_aura = NULL;
} }
SendObjectDeSpawnAnim(GetGUID());
RemoveFromWorld();
AddObjectToRemoveList();
} }
int32 DynamicObject::GetDuration() const int32 DynamicObject::GetDuration() const
@@ -182,3 +173,52 @@ void DynamicObject::Delay(int32 delaytime)
{ {
SetDuration(GetDuration() - 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: public:
explicit DynamicObject(); explicit DynamicObject();
~DynamicObject();
void AddToWorld(); void AddToWorld();
void RemoveFromWorld(); void RemoveFromWorld();
bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active); bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active);
void Update(uint32 p_time); void Update(uint32 p_time);
void Delete(); void Remove();
void SetDuration(int32 newDuration); void SetDuration(int32 newDuration);
int32 GetDuration() const; int32 GetDuration() const;
void SetAura(Aura * aura) {ASSERT (!m_aura && aura); m_aura = aura;}
void Delay(int32 delaytime); 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); } uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); }
uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); } uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); }
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); } float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
Unit* GetCaster() const;
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); } void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(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: protected:
int32 m_duration; // for non-aura dynobjects int32 m_duration; // for non-aura dynobjects
Aura * m_aura; Aura * m_aura;
Unit * m_caster;
bool m_isViewpoint;
}; };
#endif #endif
+30 -37
View File
@@ -4468,24 +4468,40 @@ int32 Unit::GetMaxNegativeAuraModifierByAffectMask(AuraType auratype, SpellEntry
return modifier; 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);
return; }
for (DynObjectGUIDs::iterator i = m_dynObjGUIDs.begin(); i != m_dynObjGUIDs.end();)
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); DynamicObject* dynObj = *i;
if (!dynObj) // may happen if a dynobj is removed when grid unload if (dynObj->GetSpellId() == spellId)
i = m_dynObjGUIDs.erase(i); return dynObj;
else if (spellid == 0 || dynObj->GetSpellId() == spellid) }
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(); dynObj->Remove();
i = m_dynObjGUIDs.erase(i); i = m_dynObj.begin();
} }
else else
++i; ++i;
@@ -4494,31 +4510,8 @@ void Unit::RemoveDynObject(uint32 spellid)
void Unit::RemoveAllDynObjects() void Unit::RemoveAllDynObjects()
{ {
while (!m_dynObjGUIDs.empty()) while (!m_dynObj.empty())
{ m_dynObj.front()->Remove();
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;
} }
GameObject* Unit::GetGameObject(uint32 spellId) const 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;} void setTransForm(uint32 spellid) { m_transform = spellid;}
uint32 getTransForm() const { return m_transform;} uint32 getTransForm() const { return m_transform;}
// DynamicObject management
void _RegisterDynObject(DynamicObject* dynObj);
void _UnregisterDynObject(DynamicObject* dynObj);
DynamicObject* GetDynObject(uint32 spellId); DynamicObject* GetDynObject(uint32 spellId);
void AddDynObject(DynamicObject* dynObj); void RemoveDynObject(uint32 spellId);
void RemoveDynObject(uint32 spellid);
void RemoveDynObjectWithGUID(uint64 guid) { m_dynObjGUIDs.remove(guid); }
void RemoveAllDynObjects(); void RemoveAllDynObjects();
GameObject* GetGameObject(uint32 spellId) const; GameObject* GetGameObject(uint32 spellId) const;
@@ -2078,8 +2079,8 @@ class Unit : public WorldObject
int32 m_procDeep; int32 m_procDeep;
typedef std::list<uint64> DynObjectGUIDs; typedef std::list<DynamicObject*> DynObjectList;
DynObjectGUIDs m_dynObjGUIDs; DynObjectList m_dynObj;
typedef std::list<GameObject*> GameObjectList; typedef std::list<GameObject*> GameObjectList;
GameObjectList m_gameObj; GameObjectList m_gameObj;
+2 -2
View File
@@ -280,13 +280,13 @@ ObjectGridStoper::Visit(CreatureMapType &m)
// stop any fights at grid de-activation and remove dynobjects created at cast by creatures // 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) for (CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{ {
iter->getSource()->RemoveAllDynObjects();
if (iter->getSource()->isInCombat()) if (iter->getSource()->isInCombat())
{ {
iter->getSource()->CombatStop(); iter->getSource()->CombatStop();
iter->getSource()->DeleteThreatList(); 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
} }
} }
+5 -11
View File
@@ -2556,17 +2556,15 @@ void Spell::EffectPersistentAA(SpellEffIndex effIndex)
delete dynObj; delete dynObj;
return; return;
} }
caster->AddDynObject(dynObj);
dynObj->GetMap()->Add(dynObj); dynObj->GetMap()->Add(dynObj);
if (Aura * aura = Aura::TryCreate(m_spellInfo, dynObj, caster, &m_spellValue->EffectBasePoints[0])) if (Aura * aura = Aura::TryCreate(m_spellInfo, dynObj, caster, &m_spellValue->EffectBasePoints[0]))
m_spellAura = aura;
else
{ {
ASSERT(false); m_spellAura = aura;
return; m_spellAura->_RegisterForTargets();
} }
m_spellAura->_RegisterForTargets(); else
return;
} }
ASSERT(m_spellAura->GetDynobjOwner()); ASSERT(m_spellAura->GetDynobjOwner());
m_spellAura->_ApplyEffectForTargets(effIndex); m_spellAura->_ApplyEffectForTargets(effIndex);
@@ -3387,14 +3385,10 @@ void Spell::EffectAddFarsight(SpellEffIndex effIndex)
} }
dynObj->SetDuration(duration); dynObj->SetDuration(duration);
dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002);
m_caster->AddDynObject(dynObj);
dynObj->setActive(true); //must before add to map to be put in world container dynObj->setActive(true); //must before add to map to be put in world container
dynObj->GetMap()->Add(dynObj); //grid will also be loaded dynObj->GetMap()->Add(dynObj); //grid will also be loaded
dynObj->SetCasterViewpoint();
// Need to update visibility of object for client to accept farsight guid
m_caster->ToPlayer()->SetViewpoint(dynObj, true);
//m_caster->ToPlayer()->UpdateVisibilityOf(dynObj);
} }
void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/) void Spell::EffectUntrainTalents(SpellEffIndex /*effIndex*/)