[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [21234] branches/blender2.5/blender/source : BGE PyAPI support for subclassing any BGE game type from python, scripters define extra functions on gameObjects.
Campbell Barton
ideasman42 at gmail.com
Mon Jun 29 14:06:46 CEST 2009
Revision: 21234
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=21234
Author: campbellbarton
Date: 2009-06-29 14:06:46 +0200 (Mon, 29 Jun 2009)
Log Message:
-----------
BGE PyAPI support for subclassing any BGE game type from python, scripters define extra functions on gameObjects.
Adding a UI to set the type on startup can be added easily.
# ----
class myPlayer(GameTypes.KX_GameObject):
def die(self):
# ... do stuff ...
self.endObject()
# make an instance
player = myPlayer(gameOb) # gameOb is made invalid now.
player.die()
# ----
One limitation (which could also be an advantage), is making the subclass instance will return that subclass everywhere, you cant have 2 different subclasses of the same BGE data at once.
Modified Paths:
--------------
branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c
branches/blender2.5/blender/source/blender/windowmanager/WM_api.h
branches/blender2.5/blender/source/blender/windowmanager/intern/wm_keymap.c
branches/blender2.5/blender/source/gameengine/Converter/BL_ActionActuator.cpp
branches/blender2.5/blender/source/gameengine/Converter/BL_ShapeActionActuator.cpp
branches/blender2.5/blender/source/gameengine/Expressions/BoolValue.cpp
branches/blender2.5/blender/source/gameengine/Expressions/ListValue.cpp
branches/blender2.5/blender/source/gameengine/Expressions/PyObjectPlus.cpp
branches/blender2.5/blender/source/gameengine/Expressions/PyObjectPlus.h
branches/blender2.5/blender/source/gameengine/Expressions/Value.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_ANDController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_DelaySensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_IController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_ILogicBrick.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_IObject.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_ISensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_LogicManager.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_MouseSensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_NANDController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_NORController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_ORController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_PropertySensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_PythonController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_RandomActuator.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_RandomSensor.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_XNORController.cpp
branches/blender2.5/blender/source/gameengine/GameLogic/SCA_XORController.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/BL_Shader.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_CDActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_Camera.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_CameraActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_ConstraintActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_GameActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_GameObject.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_IpoActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_Light.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_MeshProxy.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_NearSensor.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_ObjectActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_ParentActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_PhysicsObjectWrapper.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_PolyProxy.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_PolygonMaterial.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_PyMath.h
branches/blender2.5/blender/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_RadarSensor.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_RaySensor.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_Scene.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_SceneActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_SoundActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_StateActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_TouchSensor.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_TrackToActuator.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_VertexProxy.cpp
branches/blender2.5/blender/source/gameengine/Ketsji/KX_VisibilityActuator.cpp
Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c
===================================================================
--- branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c 2009-06-29 12:06:46 UTC (rev 21234)
@@ -204,13 +204,13 @@
/* use our own dealloc so we can free a property if we use one */
static void pyrna_struct_dealloc( BPy_StructRNA * self )
{
- /* Note!! for some weired reason calling PyObject_DEL() directly crashes blender! */
if (self->freeptr && self->ptr.data) {
IDP_FreeProperty(self->ptr.data);
MEM_freeN(self->ptr.data);
self->ptr.data= NULL;
}
+ /* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */
Py_TYPE(self)->tp_free(self);
return;
}
Modified: branches/blender2.5/blender/source/blender/windowmanager/WM_api.h
===================================================================
--- branches/blender2.5/blender/source/blender/windowmanager/WM_api.h 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/blender/windowmanager/WM_api.h 2009-06-29 12:06:46 UTC (rev 21234)
@@ -79,7 +79,7 @@
ListBase *WM_keymap_listbase (struct wmWindowManager *wm, const char *nameid,
int spaceid, int regionid);
-char *WM_key_event_string(short type);
+const char *WM_key_event_string(short type);
char *WM_key_event_operator_string(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, char *str, int len);
/* handlers */
Modified: branches/blender2.5/blender/source/blender/windowmanager/intern/wm_keymap.c
===================================================================
--- branches/blender2.5/blender/source/blender/windowmanager/intern/wm_keymap.c 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/blender/windowmanager/intern/wm_keymap.c 2009-06-29 12:06:46 UTC (rev 21234)
@@ -154,7 +154,7 @@
/* ***************** get string from key events **************** */
-char *WM_key_event_string(short type)
+const char *WM_key_event_string(short type)
{
const char *name= NULL;
if(RNA_enum_name(event_type_items, (int)type, &name))
Modified: branches/blender2.5/blender/source/gameengine/Converter/BL_ActionActuator.cpp
===================================================================
--- branches/blender2.5/blender/source/gameengine/Converter/BL_ActionActuator.cpp 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/gameengine/Converter/BL_ActionActuator.cpp 2009-06-29 12:06:46 UTC (rev 21234)
@@ -1005,19 +1005,17 @@
0,
0,
py_base_repr,
- 0,0,0,0,0,0,
- NULL, //py_base_getattro,
- NULL, //py_base_setattro,
- 0,
+ 0,0,0,0,0,0,0,0,0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
0,
0,
- &SCA_IActuator::Type
+ &SCA_IActuator::Type,
+ 0,0,0,0,0,0,
+ py_base_new
};
-
PyMethodDef BL_ActionActuator::Methods[] = {
//Deprecated ----->
{"setAction", (PyCFunction) BL_ActionActuator::sPySetAction, METH_VARARGS, (PY_METHODCHAR)SetAction_doc},
Modified: branches/blender2.5/blender/source/gameengine/Converter/BL_ShapeActionActuator.cpp
===================================================================
--- branches/blender2.5/blender/source/gameengine/Converter/BL_ShapeActionActuator.cpp 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/gameengine/Converter/BL_ShapeActionActuator.cpp 2009-06-29 12:06:46 UTC (rev 21234)
@@ -427,16 +427,15 @@
0,
0,
py_base_repr,
- 0,0,0,0,0,0,
- NULL, //py_base_getattro,
- NULL, //py_base_setattro,
- 0,
+ 0,0,0,0,0,0,0,0,0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
0,
0,
- &SCA_IActuator::Type
+ &SCA_IActuator::Type,
+ 0,0,0,0,0,0,
+ py_base_new
};
Modified: branches/blender2.5/blender/source/gameengine/Expressions/BoolValue.cpp
===================================================================
--- branches/blender2.5/blender/source/gameengine/Expressions/BoolValue.cpp 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/gameengine/Expressions/BoolValue.cpp 2009-06-29 12:06:46 UTC (rev 21234)
@@ -29,7 +29,6 @@
const STR_String CBoolValue::sTrueString = "TRUE";
const STR_String CBoolValue::sFalseString = "FALSE";
-
CBoolValue::CBoolValue()
/*
pre: false
Modified: branches/blender2.5/blender/source/gameengine/Expressions/ListValue.cpp
===================================================================
--- branches/blender2.5/blender/source/gameengine/Expressions/ListValue.cpp 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/gameengine/Expressions/ListValue.cpp 2009-06-29 12:06:46 UTC (rev 21234)
@@ -225,7 +225,7 @@
return 1;
}
}
- else if (BGE_PROXY_CHECK_TYPE(value)) { /* not dict like at all but this worked before __contains__ was used */
+ else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */
CValue *item= static_cast<CValue *>(BGE_PROXY_REF(value));
for (int i=0; i < self->GetCount(); i++)
if (self->GetValue(i) == item) // Com
@@ -289,15 +289,17 @@
0, /*tp_hash*/
0, /*tp_call */
0,
- NULL, //py_base_getattro,
- NULL, //py_base_setattro,
+ NULL,
+ NULL,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
0,
0,
- &CValue::Type
+ &CValue::Type,
+ 0,0,0,0,0,0,
+ py_base_new
};
PyMethodDef CListValue::Methods[] = {
Modified: branches/blender2.5/blender/source/gameengine/Expressions/PyObjectPlus.cpp
===================================================================
--- branches/blender2.5/blender/source/gameengine/Expressions/PyObjectPlus.cpp 2009-06-29 11:29:52 UTC (rev 21233)
+++ branches/blender2.5/blender/source/gameengine/Expressions/PyObjectPlus.cpp 2009-06-29 12:06:46 UTC (rev 21234)
@@ -74,10 +74,7 @@
0,
0,
py_base_repr,
- 0,0,0,0,0,0,
- NULL, //py_base_getattro,
- NULL, //py_base_setattro,
- 0,
+ 0,0,0,0,0,0,0,0,0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0,0,0,0,0,0,0,
Methods,
@@ -96,6 +93,88 @@
// assert(ob_refcnt==0);
}
+
+PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the entry in Type.
+{
+ PyObjectPlus *self_plus= BGE_PROXY_REF(self);
+ if(self_plus==NULL) {
+ PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
+ return NULL;
+ }
+
+ return self_plus->py_repr();
+}
+
+
+PyObject * PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyTypeObject *base_type;
+ PyObjectPlus_Proxy *base = NULL;
+
+ if (!PyArg_ParseTuple(args, "O:Base PyObjectPlus", &base))
+ return NULL;
+
+ /* the 'base' PyObject may be subclassed (multiple times even)
+ * we need to find the first C++ defined class to check 'type'
+ * is a subclass of the base arguments type.
+ *
+ * This way we can share one tp_new function for every PyObjectPlus
+ *
+ * eg.
+ *
+ * # CustomOb is called 'type' in this C code
+ * class CustomOb(GameTypes.KX_GameObject):
+ * pass
+ *
+ * # this calls py_base_new(...), the type of 'CustomOb' is checked to be a subclass of the 'cont.owner' type
+ * ob = CustomOb(cont.owner)
+ *
+ * */
+ base_type= Py_TYPE(base);
+ while(base_type && !BGE_PROXY_CHECK_TYPE(base_type))
+ base_type= base_type->tp_base;
+
+ if(base_type==NULL || !BGE_PROXY_CHECK_TYPE(base_type)) {
+ PyErr_SetString(PyExc_TypeError, "can't subclass from a blender game type because the argument given is not a game class or subclass");
+ return NULL;
+ }
+
+ /* use base_type rather then Py_TYPE(base) because we could alredy be subtyped */
+ if(!PyType_IsSubtype(type, base_type)) {
+ PyErr_Format(PyExc_TypeError, "can't subclass blender game type <%s> from <%s> because it is not a subclass", base_type->tp_name, type->tp_name);
+ return NULL;
+ }
+
+ /* invalidate the existing base and return a new subclassed one,
+ * this is a bit dodgy in that it also attaches its self to the existing object
+ * which is not really 'correct' python OO but for our use its OK. */
+
+ PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */
+ ret->ref= base->ref;
+ base->ref= NULL; /* invalidate! disallow further access */
+
+ ret->py_owns= base->py_owns;
+
+ ret->ref->m_proxy= NULL;
+
+ /* 'base' may be free'd after this func finished but not necessarily
+ * there is no reference to the BGE data now so it will throw an error on access */
+ Py_DECREF(base);
+
+ ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */
+ Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */
+
+
+ /* 'ret' will have 2 references.
+ * - One ref is needed because ret->ref->m_proxy holds a refcount to the current proxy.
+ * - Another is needed for returning the value.
+ *
+ * So we should be ok with 2 refs, but for some reason this crashes. so adding a new ref...
+ * */
+
+ return (PyObject *)ret;
+}
+
void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper
{
PyObjectPlus *self_plus= BGE_PROXY_REF(self);
@@ -104,17 +183,23 @@
self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */
delete self_plus;
}
-
+
BGE_PROXY_REF(self)= NULL; // not really needed
}
+
+#if 0
+ /* is ok normally but not for subtyping, use tp_free instead. */
PyObject_DEL( self );
+#else
+ Py_TYPE(self)->tp_free(self);
+#endif
};
PyObjectPlus::PyObjectPlus() : SG_QList() // constructor
{
m_proxy= NULL;
};
-
+
/*------------------------------
* PyObjectPlus Methods -- Every class, even the abstract one should have a Methods
------------------------------*/
@@ -131,22 +216,10 @@
PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
-{
+{
return PyBool_FromLong(self_v ? 1:0);
}
-PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the entry in Type.
-{
-
- PyObjectPlus *self_plus= BGE_PROXY_REF(self);
- if(self_plus==NULL) {
- PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
- return NULL;
- }
-
- return self_plus->py_repr();
-}
-
/* note, this is called as a python 'getset, where the PyAttributeDef is the closure */
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list