BGE patch: Relink actuators with target within group when duplicating group; generalize protection against object deletion for all actuators that point to objects.

Certain actuators hold a pointer to an objects: Property,
SceneCamera, AddObject, Camera, Parent, TractTo. When a
group is duplicated, the actuators that point to objects
within the group will be relinked to point to the
replicated objects and not to the original objects.
This helps to setup self-contained group with a camera
following a character for example.
This feature also works when adding a single object
(and all its children) with the AddObject actuator.

The second part of the patch extends the protection
against object deletion to all the actuators of the above
list (previously, only the TrackTo, AddObject and
Property actuators were protected). In case the target
object of these actuators is deleted, the BGE won't
crash.
This commit is contained in:
Benoit Bolsee 2008-07-19 07:45:19 +00:00
parent 5e2ee19187
commit 9ed079bf5c
18 changed files with 258 additions and 54 deletions

@ -60,6 +60,7 @@ public:
{ {
if (m_pDeformer) if (m_pDeformer)
m_pDeformer->Relink (map); m_pDeformer->Relink (map);
KX_GameObject::Relink(map);
}; };
void ProcessReplica(KX_GameObject* replica); void ProcessReplica(KX_GameObject* replica);

@ -503,7 +503,7 @@ void BL_ConvertActuators(char* maggiename,
case ACT_PROPERTY: case ACT_PROPERTY:
{ {
bPropertyActuator* propact = (bPropertyActuator*) bact->data; bPropertyActuator* propact = (bPropertyActuator*) bact->data;
CValue* destinationObj = NULL; SCA_IObject* destinationObj = NULL;
/* /*
here the destinationobject is searched. problem with multiple scenes: other scenes here the destinationobject is searched. problem with multiple scenes: other scenes

@ -82,7 +82,10 @@ void SCA_ILogicBrick::ReParent(SCA_IObject* parent)
m_gameobj = parent; m_gameobj = parent;
} }
void SCA_ILogicBrick::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
// nothing to do
}
CValue* SCA_ILogicBrick::Calc(VALUE_OPERATOR op, CValue *val) CValue* SCA_ILogicBrick::Calc(VALUE_OPERATOR op, CValue *val)
{ {

@ -32,6 +32,8 @@
#include "Value.h" #include "Value.h"
#include "SCA_IObject.h" #include "SCA_IObject.h"
#include "BoolValue.h" #include "BoolValue.h"
#include "GEN_Map.h"
#include "GEN_HashedPtr.h"
class SCA_ILogicBrick : public CValue class SCA_ILogicBrick : public CValue
{ {
@ -59,6 +61,7 @@ public:
SCA_IObject* GetParent(); SCA_IObject* GetParent();
virtual void ReParent(SCA_IObject* parent); virtual void ReParent(SCA_IObject* parent);
virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
// act as a BoolValue (with value IsPositiveTrigger) // act as a BoolValue (with value IsPositiveTrigger)
virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);

@ -42,7 +42,7 @@
/* Native functions */ /* Native functions */
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,CValue* sourceObj,const STR_String& propname,const STR_String& expr,int acttype,PyTypeObject* T ) SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,SCA_IObject* sourceObj,const STR_String& propname,const STR_String& expr,int acttype,PyTypeObject* T )
: SCA_IActuator(gameobj,T), : SCA_IActuator(gameobj,T),
m_type(acttype), m_type(acttype),
m_propname(propname), m_propname(propname),
@ -51,14 +51,14 @@ SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,CValue* sourceOb
{ {
// protect ourselves against someone else deleting the source object // protect ourselves against someone else deleting the source object
// don't protect against ourselves: it would create a dead lock // don't protect against ourselves: it would create a dead lock
if (m_sourceObj && m_sourceObj != GetParent()) if (m_sourceObj)
m_sourceObj->AddRef(); m_sourceObj->RegisterActuator(this);
} }
SCA_PropertyActuator::~SCA_PropertyActuator() SCA_PropertyActuator::~SCA_PropertyActuator()
{ {
if (m_sourceObj && m_sourceObj != GetParent()) if (m_sourceObj)
m_sourceObj->Release(); m_sourceObj->UnregisterActuator(this);
} }
bool SCA_PropertyActuator::Update() bool SCA_PropertyActuator::Update()
@ -185,10 +185,31 @@ void SCA_PropertyActuator::ProcessReplica()
// no need to check for self reference like in the constructor: // no need to check for self reference like in the constructor:
// the replica will always have a different parent // the replica will always have a different parent
if (m_sourceObj) if (m_sourceObj)
m_sourceObj->AddRef(); m_sourceObj->RegisterActuator(this);
SCA_IActuator::ProcessReplica(); SCA_IActuator::ProcessReplica();
} }
bool SCA_PropertyActuator::UnlinkObject(SCA_IObject* clientobj)
{
if (clientobj == m_sourceObj)
{
// this object is being deleted, we cannot continue to track it.
m_sourceObj = NULL;
return true;
}
return false;
}
void SCA_PropertyActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
void **h_obj = (*obj_map)[m_sourceObj];
if (h_obj) {
if (m_sourceObj)
m_sourceObj->UnregisterActuator(this);
m_sourceObj = (SCA_IObject*)(*h_obj);
m_sourceObj->RegisterActuator(this);
}
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */

@ -52,7 +52,7 @@ class SCA_PropertyActuator : public SCA_IActuator
int m_type; int m_type;
STR_String m_propname; STR_String m_propname;
STR_String m_exprtxt; STR_String m_exprtxt;
CValue* m_sourceObj; // for copy property actuator SCA_IObject* m_sourceObj; // for copy property actuator
public: public:
@ -60,7 +60,7 @@ public:
SCA_PropertyActuator( SCA_PropertyActuator(
SCA_IObject* gameobj, SCA_IObject* gameobj,
CValue* sourceObj, SCA_IObject* sourceObj,
const STR_String& propname, const STR_String& propname,
const STR_String& expr, const STR_String& expr,
int acttype, int acttype,
@ -74,7 +74,9 @@ public:
GetReplica( GetReplica(
); );
void ProcessReplica(); virtual void ProcessReplica();
virtual bool UnlinkObject(SCA_IObject* clientobj);
virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool virtual bool
Update(); Update();

@ -49,7 +49,7 @@ STR_String KX_CameraActuator::Y_AXIS_STRING = "y";
KX_CameraActuator::KX_CameraActuator( KX_CameraActuator::KX_CameraActuator(
SCA_IObject* gameobj, SCA_IObject* gameobj,
CValue *obj, SCA_IObject *obj,
MT_Scalar hght, MT_Scalar hght,
MT_Scalar minhght, MT_Scalar minhght,
MT_Scalar maxhght, MT_Scalar maxhght,
@ -63,11 +63,14 @@ KX_CameraActuator::KX_CameraActuator(
m_maxHeight (maxhght), m_maxHeight (maxhght),
m_x (xytog) m_x (xytog)
{ {
if (m_ob)
m_ob->RegisterActuator(this);
} }
KX_CameraActuator::~KX_CameraActuator() KX_CameraActuator::~KX_CameraActuator()
{ {
//nothing to do if (m_ob)
m_ob->UnregisterActuator(this);
} }
CValue* CValue*
@ -81,8 +84,35 @@ GetReplica(
return replica; return replica;
}; };
void KX_CameraActuator::ProcessReplica()
{
if (m_ob)
m_ob->RegisterActuator(this);
SCA_IActuator::ProcessReplica();
}
bool KX_CameraActuator::UnlinkObject(SCA_IObject* clientobj)
{
if (clientobj == m_ob)
{
// this object is being deleted, we cannot continue to track it.
m_ob = NULL;
return true;
}
return false;
}
void KX_CameraActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
void **h_obj = (*obj_map)[m_ob];
if (h_obj) {
if (m_ob)
m_ob->UnregisterActuator(this);
m_ob = (SCA_IObject*)(*h_obj);
m_ob->RegisterActuator(this);
}
}
/* three functions copied from blender arith... don't know if there's an equivalent */ /* three functions copied from blender arith... don't know if there's an equivalent */
@ -181,7 +211,13 @@ static void Kx_VecUpMat3(float *vec, float mat[][3], short axis)
bool KX_CameraActuator::Update(double curtime, bool frame) bool KX_CameraActuator::Update(double curtime, bool frame)
{ {
bool result = true; /* wondering... is it really neccesary/desirable to suppress negative */
/* events here? */
bool bNegativeEvent = IsNegativeEvent();
RemoveAllEvents();
if (bNegativeEvent || !m_ob)
return false;
KX_GameObject *obj = (KX_GameObject*) GetParent(); KX_GameObject *obj = (KX_GameObject*) GetParent();
MT_Point3 from = obj->NodeGetWorldPosition(); MT_Point3 from = obj->NodeGetWorldPosition();
@ -195,13 +231,6 @@ bool KX_CameraActuator::Update(double curtime, bool frame)
float mindistsq, maxdistsq, distsq; float mindistsq, maxdistsq, distsq;
float mat[3][3]; float mat[3][3];
/* wondering... is it really neccesary/desirable to suppress negative */
/* events here? */
bool bNegativeEvent = IsNegativeEvent();
RemoveAllEvents();
if (bNegativeEvent) return false;
/* The rules: */ /* The rules: */
/* CONSTRAINT 1: not implemented */ /* CONSTRAINT 1: not implemented */
/* CONSTRAINT 2: can camera see actor? */ /* CONSTRAINT 2: can camera see actor? */
@ -315,7 +344,7 @@ bool KX_CameraActuator::Update(double curtime, bool frame)
actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2]; actormat[2][0]= mat[0][2]; actormat[2][1]= mat[1][2]; actormat[2][2]= mat[2][2];
obj->NodeSetLocalOrientation(actormat); obj->NodeSetLocalOrientation(actormat);
return result; return true;
} }
CValue *KX_CameraActuator::findObject(char *obName) CValue *KX_CameraActuator::findObject(char *obName)
@ -404,7 +433,11 @@ PyObject* KX_CameraActuator::PySetObject(PyObject* self,
PyObject* gameobj; PyObject* gameobj;
if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj)) if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
{ {
m_ob = (CValue*)gameobj; if (m_ob)
m_ob->UnregisterActuator(this);
m_ob = (SCA_IObject*)gameobj;
if (m_ob)
m_ob->RegisterActuator(this);
Py_Return; Py_Return;
} }
PyErr_Clear(); PyErr_Clear();
@ -412,10 +445,13 @@ PyObject* KX_CameraActuator::PySetObject(PyObject* self,
char* objectname; char* objectname;
if (PyArg_ParseTuple(args, "s", &objectname)) if (PyArg_ParseTuple(args, "s", &objectname))
{ {
CValue *object = (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname)); SCA_IObject *object = (SCA_IObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));
if(object) if(object)
{ {
if (m_ob != NULL)
m_ob->UnregisterActuator(this);
m_ob = object; m_ob = object;
m_ob->RegisterActuator(this);
Py_Return; Py_Return;
} }
} }

@ -49,7 +49,7 @@ class KX_CameraActuator : public SCA_IActuator
Py_Header; Py_Header;
private : private :
/** Object that will be tracked. */ /** Object that will be tracked. */
CValue *m_ob; SCA_IObject *m_ob;
/** height (float), */ /** height (float), */
//const MT_Scalar m_height; //const MT_Scalar m_height;
@ -87,7 +87,7 @@ private :
SCA_IObject *gameobj, SCA_IObject *gameobj,
//const CValue *ob, //const CValue *ob,
CValue *ob, SCA_IObject *ob,
MT_Scalar hght, MT_Scalar hght,
MT_Scalar minhght, MT_Scalar minhght,
MT_Scalar maxhght, MT_Scalar maxhght,
@ -103,6 +103,7 @@ private :
/** Methods Inherited from CValue */ /** Methods Inherited from CValue */
CValue* GetReplica(); CValue* GetReplica();
virtual void ProcessReplica();
/** Methods inherited from SCA_IActuator */ /** Methods inherited from SCA_IActuator */
@ -110,7 +111,10 @@ private :
double curtime, double curtime,
bool frame bool frame
); );
virtual bool UnlinkObject(SCA_IObject* clientobj);
/** Methods inherited from SCA_ILogicBrick */
virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */ /* Python interface ---------------------------------------------------- */

@ -61,6 +61,8 @@ typedef unsigned long uint_ptr;
#include "KX_RayCast.h" #include "KX_RayCast.h"
#include "KX_PythonInit.h" #include "KX_PythonInit.h"
#include "KX_PyMath.h" #include "KX_PyMath.h"
#include "SCA_IActuator.h"
#include "SCA_ISensor.h"
// This file defines relationships between parents and children // This file defines relationships between parents and children
// in the game engine. // in the game engine.
@ -1668,6 +1670,20 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
* --------------------------------------------------------------------- */ * --------------------------------------------------------------------- */
void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter) void KX_GameObject::Relink(GEN_Map<GEN_HashedPtr, void*> *map_parameter)
{ {
/* intentionally empty ? */ // we will relink the sensors and actuators that use object references
// if the object is part of the replicated hierarchy, use the new
// object reference instead
SCA_SensorList& sensorlist = GetSensors();
SCA_SensorList::iterator sit;
for (sit=sensorlist.begin(); sit != sensorlist.end(); sit++)
{
(*sit)->Relink(map_parameter);
}
SCA_ActuatorList& actuatorlist = GetActuators();
SCA_ActuatorList::iterator ait;
for (ait=actuatorlist.begin(); ait != actuatorlist.end(); ait++)
{
(*ait)->Relink(map_parameter);
}
} }

@ -46,19 +46,22 @@
KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj, KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj,
int mode, int mode,
CValue *ob, SCA_IObject *ob,
PyTypeObject* T) PyTypeObject* T)
: SCA_IActuator(gameobj, T), : SCA_IActuator(gameobj, T),
m_mode(mode), m_mode(mode),
m_ob(ob) m_ob(ob)
{ {
if (m_ob)
m_ob->RegisterActuator(this);
} }
KX_ParentActuator::~KX_ParentActuator() KX_ParentActuator::~KX_ParentActuator()
{ {
/* intentionally empty */ if (m_ob)
m_ob->UnregisterActuator(this);
} }
@ -73,6 +76,36 @@ CValue* KX_ParentActuator::GetReplica()
return replica; return replica;
} }
void KX_ParentActuator::ProcessReplica()
{
if (m_ob)
m_ob->RegisterActuator(this);
SCA_IActuator::ProcessReplica();
}
bool KX_ParentActuator::UnlinkObject(SCA_IObject* clientobj)
{
if (clientobj == m_ob)
{
// this object is being deleted, we cannot continue to track it.
m_ob = NULL;
return true;
}
return false;
}
void KX_ParentActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
void **h_obj = (*obj_map)[m_ob];
if (h_obj) {
if (m_ob)
m_ob->UnregisterActuator(this);
m_ob = (SCA_IObject*)(*h_obj);
m_ob->RegisterActuator(this);
}
}
bool KX_ParentActuator::Update() bool KX_ParentActuator::Update()
@ -87,6 +120,7 @@ bool KX_ParentActuator::Update()
KX_Scene *scene = PHY_GetActiveScene(); KX_Scene *scene = PHY_GetActiveScene();
switch (m_mode) { switch (m_mode) {
case KX_PARENT_SET: case KX_PARENT_SET:
if (m_ob)
obj->SetParent(scene, (KX_GameObject*)m_ob); obj->SetParent(scene, (KX_GameObject*)m_ob);
break; break;
case KX_PARENT_REMOVE: case KX_PARENT_REMOVE:
@ -148,7 +182,11 @@ PyObject* KX_ParentActuator::PySetObject(PyObject* self, PyObject* args, PyObjec
PyObject* gameobj; PyObject* gameobj;
if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj)) if (PyArg_ParseTuple(args, "O!", &KX_GameObject::Type, &gameobj))
{ {
m_ob = (CValue*)gameobj; if (m_ob != NULL)
m_ob->UnregisterActuator(this);
m_ob = (SCA_IObject*)gameobj;
if (m_ob)
m_ob->RegisterActuator(this);
Py_Return; Py_Return;
} }
PyErr_Clear(); PyErr_Clear();
@ -156,10 +194,13 @@ PyObject* KX_ParentActuator::PySetObject(PyObject* self, PyObject* args, PyObjec
char* objectname; char* objectname;
if (PyArg_ParseTuple(args, "s", &objectname)) if (PyArg_ParseTuple(args, "s", &objectname))
{ {
CValue *object = (CValue*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname)); SCA_IObject *object = (SCA_IObject*)SCA_ILogicBrick::m_sCurrentLogicManager->GetGameObjectByName(STR_String(objectname));
if(object) if(object)
{ {
if (m_ob != NULL)
m_ob->UnregisterActuator(this);
m_ob = object; m_ob = object;
m_ob->RegisterActuator(this);
Py_Return; Py_Return;
} }
} }

@ -47,7 +47,7 @@ class KX_ParentActuator : public SCA_IActuator
int m_mode; int m_mode;
/** Object to set as parent */ /** Object to set as parent */
CValue *m_ob; SCA_IObject *m_ob;
@ -62,12 +62,15 @@ class KX_ParentActuator : public SCA_IActuator
KX_ParentActuator(class SCA_IObject* gameobj, KX_ParentActuator(class SCA_IObject* gameobj,
int mode, int mode,
CValue *ob, SCA_IObject *ob,
PyTypeObject* T=&Type); PyTypeObject* T=&Type);
virtual ~KX_ParentActuator(); virtual ~KX_ParentActuator();
virtual bool Update(); virtual bool Update();
virtual CValue* GetReplica(); virtual CValue* GetReplica();
virtual void ProcessReplica();
virtual void KX_ParentActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool KX_ParentActuator::UnlinkObject(SCA_IObject* clientobj);
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* Python interface ---------------------------------------------------- */ /* Python interface ---------------------------------------------------- */

@ -137,6 +137,17 @@ bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj)
return false; return false;
} }
void KX_SCA_AddObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
void **h_obj = (*obj_map)[m_OriginalObject];
if (h_obj) {
if (m_OriginalObject)
m_OriginalObject->UnregisterActuator(this);
m_OriginalObject = (SCA_IObject*)(*h_obj);
m_OriginalObject->RegisterActuator(this);
}
}
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Python functions */ /* Python functions */

@ -95,6 +95,9 @@ public:
virtual bool virtual bool
UnlinkObject(SCA_IObject* clientobj); UnlinkObject(SCA_IObject* clientobj);
virtual void
Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool virtual bool
Update(); Update();

@ -724,21 +724,23 @@ void KX_Scene::DupliGroupRecurse(CValue* obj, int level)
replica->Release(); replica->Release();
} }
// relink any pointers as necessary, sort of a temporary solution // the logic must be replicated first because we need
// the new logic bricks before relinking
vector<KX_GameObject*>::iterator git; vector<KX_GameObject*>::iterator git;
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{ {
(*git)->ReParentLogic();
}
// relink any pointers as necessary, sort of a temporary solution
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
// this will also relink the actuator to objects within the hierarchy
(*git)->Relink(&m_map_gameobject_to_replica); (*git)->Relink(&m_map_gameobject_to_replica);
// add the object in the layer of the parent // add the object in the layer of the parent
(*git)->SetLayer(groupobj->GetLayer()); (*git)->SetLayer(groupobj->GetLayer());
} }
// now replicate logic
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
(*git)->ReParentLogic();
}
// replicate crosslinks etc. between logic bricks // replicate crosslinks etc. between logic bricks
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{ {
@ -805,21 +807,22 @@ SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject,
replica->GetSGNode()->AddChild(childreplicanode); replica->GetSGNode()->AddChild(childreplicanode);
} }
// relink any pointers as necessary, sort of a temporary solution // now replicate logic
vector<KX_GameObject*>::iterator git; vector<KX_GameObject*>::iterator git;
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{ {
(*git)->ReParentLogic();
}
// relink any pointers as necessary, sort of a temporary solution
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
// this will also relink the actuators in the hierarchy
(*git)->Relink(&m_map_gameobject_to_replica); (*git)->Relink(&m_map_gameobject_to_replica);
// add the object in the layer of the parent // add the object in the layer of the parent
(*git)->SetLayer(parentobj->GetLayer()); (*git)->SetLayer(parentobj->GetLayer());
} }
// now replicate logic
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{
(*git)->ReParentLogic();
}
// replicate crosslinks etc. between logic bricks // replicate crosslinks etc. between logic bricks
for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git)
{ {

@ -58,13 +58,16 @@ KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj,
m_KetsjiEngine=ketsjiEngine; m_KetsjiEngine=ketsjiEngine;
m_camera = camera; m_camera = camera;
m_nextSceneName = nextSceneName; m_nextSceneName = nextSceneName;
if (m_camera)
m_camera->RegisterActuator(this);
} /* End of constructor */ } /* End of constructor */
KX_SceneActuator::~KX_SceneActuator() KX_SceneActuator::~KX_SceneActuator()
{ {
// there's nothing to be done here, really.... if (m_camera)
m_camera->UnregisterActuator(this);
} /* end of destructor */ } /* end of destructor */
@ -79,6 +82,34 @@ CValue* KX_SceneActuator::GetReplica()
return replica; return replica;
} }
void KX_SceneActuator::ProcessReplica()
{
if (m_camera)
m_camera->RegisterActuator(this);
SCA_IActuator::ProcessReplica();
}
bool KX_SceneActuator::UnlinkObject(SCA_IObject* clientobj)
{
if (clientobj == (SCA_IObject*)m_camera)
{
// this object is being deleted, we cannot continue to track it.
m_camera = NULL;
return true;
}
return false;
}
void KX_SceneActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
void **h_obj = (*obj_map)[m_camera];
if (h_obj) {
if (m_camera)
m_camera->UnregisterActuator(this);
m_camera = (KX_Camera*)(*h_obj);
m_camera->RegisterActuator(this);
}
}
bool KX_SceneActuator::Update() bool KX_SceneActuator::Update()
@ -332,7 +363,11 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self,
PyObject *cam; PyObject *cam;
if (PyArg_ParseTuple(args, "O!", &KX_Camera::Type, &cam)) if (PyArg_ParseTuple(args, "O!", &KX_Camera::Type, &cam))
{ {
if (m_camera)
m_camera->UnregisterActuator(this);
m_camera = (KX_Camera*) cam; m_camera = (KX_Camera*) cam;
if (m_camera)
m_camera->RegisterActuator(this);
Py_Return; Py_Return;
} }
PyErr_Clear(); PyErr_Clear();
@ -345,7 +380,13 @@ PyObject* KX_SceneActuator::PySetCamera(PyObject* self,
} }
KX_Camera *camOb = FindCamera(camName); KX_Camera *camOb = FindCamera(camName);
if (camOb) m_camera = camOb; if (camOb)
{
if (m_camera)
m_camera->UnregisterActuator(this);
m_camera = camOb;
m_camera->RegisterActuator(this);
}
Py_Return; Py_Return;
} }

@ -82,6 +82,9 @@ class KX_SceneActuator : public SCA_IActuator
virtual ~KX_SceneActuator(); virtual ~KX_SceneActuator();
virtual CValue* GetReplica(); virtual CValue* GetReplica();
virtual void ProcessReplica();
virtual bool UnlinkObject(SCA_IObject* clientobj);
virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool Update(); virtual bool Update();

@ -210,6 +210,18 @@ bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj)
return false; return false;
} }
void KX_TrackToActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
{
void **h_obj = (*obj_map)[m_object];
if (h_obj) {
if (m_object)
m_object->UnregisterActuator(this);
m_object = (SCA_IObject*)(*h_obj);
m_object->RegisterActuator(this);
}
}
bool KX_TrackToActuator::Update(double curtime, bool frame) bool KX_TrackToActuator::Update(double curtime, bool frame)
{ {
bool result = false; bool result = false;

@ -68,6 +68,7 @@ class KX_TrackToActuator : public SCA_IActuator
virtual void ProcessReplica(); virtual void ProcessReplica();
virtual bool UnlinkObject(SCA_IObject* clientobj); virtual bool UnlinkObject(SCA_IObject* clientobj);
virtual void Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map);
virtual bool Update(double curtime, bool frame); virtual bool Update(double curtime, bool frame);
/* Python part */ /* Python part */