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_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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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*/)
|
||||||
|
|||||||
Reference in New Issue
Block a user