BGE bug: crash when an object being tracked-to is deleted (bad practice anyway). Fix by creating a generic cross reference between actuators (only TrackTo uses it at the moment) and objects so that the actuator is informed when the target object is deleted
This commit is contained in:
@@ -46,6 +46,15 @@ public:
|
||||
SCA_IActuator(SCA_IObject* gameobj,
|
||||
PyTypeObject* T =&Type);
|
||||
|
||||
/**
|
||||
* UnlinkObject(...)
|
||||
* Certain actuator use gameobject pointers (like TractTo actuator)
|
||||
* This function can be called when an object is removed to make
|
||||
* sure that the actuator will not use it anymore.
|
||||
*/
|
||||
|
||||
virtual bool UnlinkObject(SCA_IObject* clientobj) { return false; }
|
||||
|
||||
/**
|
||||
* Update(...)
|
||||
* Update the actuator based upon the events received since
|
||||
|
||||
@@ -62,6 +62,10 @@ SCA_IObject::~SCA_IObject()
|
||||
((CValue*)(*itc))->Release();
|
||||
}
|
||||
SCA_ActuatorList::iterator ita;
|
||||
for (ita = m_registeredActuators.begin(); !(ita==m_registeredActuators.end()); ++ita)
|
||||
{
|
||||
(*ita)->UnlinkObject(this);
|
||||
}
|
||||
for (ita = m_actuators.begin(); !(ita==m_actuators.end()); ++ita)
|
||||
{
|
||||
((CValue*)(*ita))->Release();
|
||||
@@ -118,7 +122,24 @@ void SCA_IObject::AddActuator(SCA_IActuator* act)
|
||||
m_actuators.push_back(act);
|
||||
}
|
||||
|
||||
void SCA_IObject::RegisterActuator(SCA_IActuator* act)
|
||||
{
|
||||
// don't increase ref count, it would create dead lock
|
||||
m_registeredActuators.push_back(act);
|
||||
}
|
||||
|
||||
void SCA_IObject::UnregisterActuator(SCA_IActuator* act)
|
||||
{
|
||||
SCA_ActuatorList::iterator ita;
|
||||
for (ita = m_registeredActuators.begin(); ita != m_registeredActuators.end(); ita++)
|
||||
{
|
||||
if ((*ita) == act) {
|
||||
(*ita) = m_registeredActuators.back();
|
||||
m_registeredActuators.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SCA_IObject::SetIgnoreActivityCulling(bool b)
|
||||
{
|
||||
@@ -168,6 +189,8 @@ void SCA_IObject::ReParentLogic()
|
||||
newactuator->SetActive(false);
|
||||
oldactuators[act++] = newactuator;
|
||||
}
|
||||
// a new object cannot be client of any actuator
|
||||
m_registeredActuators.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ protected:
|
||||
SCA_SensorList m_sensors;
|
||||
SCA_ControllerList m_controllers;
|
||||
SCA_ActuatorList m_actuators;
|
||||
SCA_ActuatorList m_registeredActuators; // actuators that use a pointer to this object
|
||||
static class MT_Point3 m_sDummy;
|
||||
|
||||
/**
|
||||
@@ -79,6 +80,8 @@ public:
|
||||
void AddSensor(SCA_ISensor* act);
|
||||
void AddController(SCA_IController* act);
|
||||
void AddActuator(SCA_IActuator* act);
|
||||
void RegisterActuator(SCA_IActuator* act);
|
||||
void UnregisterActuator(SCA_IActuator* act);
|
||||
|
||||
SCA_ISensor* FindSensor(const STR_String& sensorname);
|
||||
SCA_IActuator* FindActuator(const STR_String& actuatorname);
|
||||
|
||||
@@ -70,6 +70,7 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj,
|
||||
m_parentobj = 0;
|
||||
|
||||
if (m_object){
|
||||
m_object->RegisterActuator(this);
|
||||
KX_GameObject* curobj = (KX_GameObject*) GetParent();
|
||||
|
||||
m_parentobj = curobj->GetParent(); // check if the object is parented
|
||||
@@ -176,12 +177,31 @@ MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_tim
|
||||
|
||||
|
||||
KX_TrackToActuator::~KX_TrackToActuator()
|
||||
{
|
||||
// there's nothing to be done here, really....
|
||||
{
|
||||
if (m_object)
|
||||
m_object->UnregisterActuator(this);
|
||||
} /* end of destructor */
|
||||
|
||||
void KX_TrackToActuator::ProcessReplica()
|
||||
{
|
||||
// the replica is tracking the same object => register it
|
||||
if (m_object)
|
||||
m_object->RegisterActuator(this);
|
||||
SCA_IActuator::ProcessReplica();
|
||||
}
|
||||
|
||||
|
||||
bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj)
|
||||
{
|
||||
if (clientobj == m_object)
|
||||
{
|
||||
// this object is being deleted, we cannot continue to track it.
|
||||
m_object = NULL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KX_TrackToActuator::Update(double curtime, bool frame)
|
||||
{
|
||||
bool result = false;
|
||||
@@ -430,8 +450,11 @@ PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* args, PyObje
|
||||
PyObject* gameobj;
|
||||
if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
|
||||
{
|
||||
if (m_object != NULL)
|
||||
m_object->UnregisterActuator(this);
|
||||
m_object = (SCA_IObject*)gameobj;
|
||||
|
||||
if (m_object)
|
||||
m_object->RegisterActuator(this);
|
||||
Py_Return;
|
||||
}
|
||||
PyErr_Clear();
|
||||
@@ -439,8 +462,11 @@ PyObject* KX_TrackToActuator::PySetObject(PyObject* self, PyObject* args, PyObje
|
||||
char* objectname;
|
||||
if (PyArg_ParseTuple(args, "s", &objectname))
|
||||
{
|
||||
if (m_object != NULL)
|
||||
m_object->UnregisterActuator(this);
|
||||
m_object= static_cast<SCA_IObject*>(SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname)));
|
||||
|
||||
if (m_object)
|
||||
m_object->RegisterActuator(this);
|
||||
Py_Return;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,8 @@ class KX_TrackToActuator : public SCA_IActuator
|
||||
return replica;
|
||||
};
|
||||
|
||||
virtual void ProcessReplica();
|
||||
virtual bool UnlinkObject(SCA_IObject* clientobj);
|
||||
virtual bool Update(double curtime, bool frame);
|
||||
|
||||
/* Python part */
|
||||
|
||||
Reference in New Issue
Block a user