diff options
Diffstat (limited to 'source/gameengine/Expressions/PyObjectPlus.cpp')
-rw-r--r-- | source/gameengine/Expressions/PyObjectPlus.cpp | 338 |
1 files changed, 142 insertions, 196 deletions
diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 921f608b772..04454f8232a 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -74,11 +74,13 @@ PyTypeObject PyObjectPlus::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0, - py_base_getattro, - py_base_setattro, 0,0,0,0,0,0,0,0,0, - Methods + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0,0,0,0,0,0,0, + Methods, + 0, + 0, + NULL // no subtype }; @@ -91,6 +93,88 @@ PyObjectPlus::~PyObjectPlus() // 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); @@ -99,143 +183,56 @@ void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper 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(PyTypeObject *T) : SG_QList() // constructor +PyObjectPlus::PyObjectPlus() : SG_QList() // constructor { - MT_assert(T != NULL); m_proxy= NULL; }; - + /*------------------------------ * PyObjectPlus Methods -- Every class, even the abstract one should have a Methods ------------------------------*/ PyMethodDef PyObjectPlus::Methods[] = { - {"isA", (PyCFunction) sPyisA, METH_O}, {NULL, NULL} /* Sentinel */ }; +#define attr_invalid (&(PyObjectPlus::Attributes[0])) PyAttributeDef PyObjectPlus::Attributes[] = { KX_PYATTRIBUTE_RO_FUNCTION("invalid", PyObjectPlus, pyattr_get_invalid), {NULL} //Sentinel }; -PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - Py_RETURN_FALSE; -} -/*------------------------------ - * PyObjectPlus Parents -- Every class, even the abstract one should have parents -------------------------------*/ -PyParentObject PyObjectPlus::Parents[] = {&PyObjectPlus::Type, NULL}; -/*------------------------------ - * PyObjectPlus attributes -- attributes -------------------------------*/ - - -/* This should be the entry in Type since it takes the C++ class from PyObjectPlus_Proxy */ -PyObject *PyObjectPlus::py_base_getattro(PyObject * self, PyObject *attr) +PyObject* PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) { - PyObjectPlus *self_plus= BGE_PROXY_REF(self); - if(self_plus==NULL) { - if(!strcmp("invalid", PyString_AsString(attr))) { - Py_RETURN_TRUE; - } - PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); - return NULL; - } - - PyObject *ret= self_plus->py_getattro(attr); - - /* Attribute not found, was this a __dict__ lookup?, otherwise set an error if none is set */ - if(ret==NULL) { - char *attr_str= PyString_AsString(attr); - - if (strcmp(attr_str, "__dict__")==0) - { - /* the error string will probably not - * be set but just incase clear it */ - PyErr_Clear(); - ret= self_plus->py_getattro_dict(); - } - else if (!PyErr_Occurred()) { - /* We looked for an attribute but it wasnt found - * since py_getattro didnt set the error, set it here */ - PyErr_Format(PyExc_AttributeError, "'%s' object has no attribute '%s'", self->ob_type->tp_name, attr_str); - } - } - return ret; + return PyBool_FromLong(self_v ? 1:0); } -/* This should be the entry in Type since it takes the C++ class from PyObjectPlus_Proxy */ -int PyObjectPlus::py_base_setattro(PyObject *self, PyObject *attr, PyObject *value) +/* note, this is called as a python 'getset, where the PyAttributeDef is the closure */ +PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef) { - PyObjectPlus *self_plus= BGE_PROXY_REF(self); - if(self_plus==NULL) { - PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); - return -1; - } - - if (value==NULL) - return self_plus->py_delattro(attr); - - return self_plus->py_setattro(attr, value); -} + void *self= (void *)(BGE_PROXY_REF(self_py)); + if(self==NULL) { + if(attrdef == attr_invalid) + Py_RETURN_TRUE; // dont bother running the function -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_getattro(PyObject* attr) -{ - PyObject *descr = PyDict_GetItem(Type.tp_dict, attr); \ - if (descr == NULL) { - return NULL; /* py_base_getattro sets the error, this way we can avoid setting the error at many levels */ - } else { - /* Copied from py_getattro_up */ - if (PyCObject_Check(descr)) { - return py_get_attrdef((void *)this, (const PyAttributeDef*)PyCObject_AsVoidPtr(descr)); - } else if (descr->ob_type->tp_descr_get) { - return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); - } else { - return NULL; - } - /* end py_getattro_up copy */ - } -} - -PyObject* PyObjectPlus::py_getattro_dict() { - return py_getattr_dict(NULL, Type.tp_dict); -} -int PyObjectPlus::py_delattro(PyObject* attr) -{ - PyErr_SetString(PyExc_AttributeError, "attribute cant be deleted"); - return 1; -} - -int PyObjectPlus::py_setattro(PyObject *attr, PyObject* value) -{ - PyErr_SetString(PyExc_AttributeError, "attribute cant be set"); - return PY_SET_ATTR_MISSING; -} - -PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef) -{ if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) { // fake attribute, ignore @@ -259,14 +256,14 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef { bool *val = reinterpret_cast<bool*>(ptr); ptr += sizeof(bool); - PyList_SET_ITEM(resultlist,i,PyInt_FromLong(*val)); + PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val)); break; } case KX_PYATTRIBUTE_TYPE_SHORT: { short int *val = reinterpret_cast<short int*>(ptr); ptr += sizeof(short int); - PyList_SET_ITEM(resultlist,i,PyInt_FromLong(*val)); + PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val)); break; } case KX_PYATTRIBUTE_TYPE_ENUM: @@ -281,7 +278,7 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef { int *val = reinterpret_cast<int*>(ptr); ptr += sizeof(int); - PyList_SET_ITEM(resultlist,i,PyInt_FromLong(*val)); + PyList_SET_ITEM(resultlist,i,PyLong_FromSsize_t(*val)); break; } case KX_PYATTRIBUTE_TYPE_FLOAT: @@ -305,12 +302,12 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef case KX_PYATTRIBUTE_TYPE_BOOL: { bool *val = reinterpret_cast<bool*>(ptr); - return PyInt_FromLong(*val); + return PyLong_FromSsize_t(*val); } case KX_PYATTRIBUTE_TYPE_SHORT: { short int *val = reinterpret_cast<short int*>(ptr); - return PyInt_FromLong(*val); + return PyLong_FromSsize_t(*val); } case KX_PYATTRIBUTE_TYPE_ENUM: // enum are like int, just make sure the field size is the same @@ -322,7 +319,7 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef case KX_PYATTRIBUTE_TYPE_INT: { int *val = reinterpret_cast<int*>(ptr); - return PyInt_FromLong(*val); + return PyLong_FromSsize_t(*val); } case KX_PYATTRIBUTE_TYPE_FLOAT: { @@ -331,18 +328,23 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef } case KX_PYATTRIBUTE_TYPE_VECTOR: { - PyObject* resultlist = PyList_New(3); MT_Vector3 *val = reinterpret_cast<MT_Vector3*>(ptr); +#ifdef USE_MATHUTILS + float fval[3]= {(*val)[0], (*val)[1], (*val)[2]}; + return newVectorObject(fval, 3, Py_NEW, NULL); +#else + PyObject* resultlist = PyList_New(3); for (unsigned int i=0; i<3; i++) { PyList_SET_ITEM(resultlist,i,PyFloat_FromDouble((*val)[i])); } return resultlist; +#endif } case KX_PYATTRIBUTE_TYPE_STRING: { STR_String *val = reinterpret_cast<STR_String*>(ptr); - return PyString_FromString(*val); + return PyUnicode_FromString(*val); } default: return NULL; @@ -350,8 +352,15 @@ PyObject *PyObjectPlus::py_get_attrdef(void *self, const PyAttributeDef *attrdef } } -int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyObject *value) +/* note, this is called as a python getset */ +int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef) { + void *self= (void *)(BGE_PROXY_REF(self_py)); + if(self==NULL) { + PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + return PY_SET_ATTR_FAIL; + } + void *undoBuffer = NULL; void *sourceBuffer = NULL; size_t bufferSize = 0; @@ -416,9 +425,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb { bool *var = reinterpret_cast<bool*>(ptr); ptr += sizeof(bool); - if (PyInt_Check(item)) + if (PyLong_Check(item)) { - *var = (PyInt_AsLong(item) != 0); + *var = (PyLong_AsSsize_t(item) != 0); } else if (PyBool_Check(item)) { @@ -435,9 +444,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb { short int *var = reinterpret_cast<short int*>(ptr); ptr += sizeof(short int); - if (PyInt_Check(item)) + if (PyLong_Check(item)) { - long val = PyInt_AsLong(item); + long val = PyLong_AsSsize_t(item); if (attrdef->m_clamp) { if (val < attrdef->m_imin) @@ -471,9 +480,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb { int *var = reinterpret_cast<int*>(ptr); ptr += sizeof(int); - if (PyInt_Check(item)) + if (PyLong_Check(item)) { - long val = PyInt_AsLong(item); + long val = PyLong_AsSsize_t(item); if (attrdef->m_clamp) { if (val < attrdef->m_imin) @@ -606,9 +615,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb case KX_PYATTRIBUTE_TYPE_BOOL: { bool *var = reinterpret_cast<bool*>(ptr); - if (PyInt_Check(value)) + if (PyLong_Check(value)) { - *var = (PyInt_AsLong(value) != 0); + *var = (PyLong_AsSsize_t(value) != 0); } else if (PyBool_Check(value)) { @@ -624,9 +633,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb case KX_PYATTRIBUTE_TYPE_SHORT: { short int *var = reinterpret_cast<short int*>(ptr); - if (PyInt_Check(value)) + if (PyLong_Check(value)) { - long val = PyInt_AsLong(value); + long val = PyLong_AsSsize_t(value); if (attrdef->m_clamp) { if (val < attrdef->m_imin) @@ -659,9 +668,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb case KX_PYATTRIBUTE_TYPE_INT: { int *var = reinterpret_cast<int*>(ptr); - if (PyInt_Check(value)) + if (PyLong_Check(value)) { - long val = PyInt_AsLong(value); + long val = PyLong_AsSsize_t(value); if (attrdef->m_clamp) { if (val < attrdef->m_imin) @@ -746,9 +755,9 @@ int PyObjectPlus::py_set_attrdef(void *self, const PyAttributeDef *attrdef, PyOb case KX_PYATTRIBUTE_TYPE_STRING: { STR_String *var = reinterpret_cast<STR_String*>(ptr); - if (PyString_Check(value)) + if (PyUnicode_Check(value)) { - char *val = PyString_AsString(value); + char *val = _PyUnicode_AsString(value); if (attrdef->m_clamp) { if (strlen(val) < attrdef->m_imin) @@ -829,48 +838,6 @@ PyObject *PyObjectPlus::py_repr(void) return NULL; } -/*------------------------------ - * PyObjectPlus isA -- the isA functions -------------------------------*/ -bool PyObjectPlus::isA(PyTypeObject *T) // if called with a Type, use "typename" -{ - int i; - PyParentObject P; - PyParentObject *Ps = GetParents(); - - for (P = Ps[i=0]; P != NULL; P = Ps[i++]) - if (P==T) - return true; - - return false; -} - - -bool PyObjectPlus::isA(const char *mytypename) // check typename of each parent -{ - int i; - PyParentObject P; - PyParentObject *Ps = GetParents(); - - for (P = Ps[i=0]; P != NULL; P = Ps[i++]) - if (strcmp(P->tp_name, mytypename)==0) - return true; - - return false; -} - -PyObject *PyObjectPlus::PyisA(PyObject *value) // Python wrapper for isA -{ - if (PyType_Check(value)) { - return PyBool_FromLong(isA((PyTypeObject *)value)); - } else if (PyString_Check(value)) { - return PyBool_FromLong(isA(PyString_AsString(value))); - } - PyErr_SetString(PyExc_TypeError, "object.isA(value): expected a type or a string"); - return NULL; -} - - void PyObjectPlus::ProcessReplica() { /* Clear the proxy, will be created again if needed with GetProxy() @@ -895,27 +862,6 @@ void PyObjectPlus::InvalidateProxy() // check typename of each parent } } -/* Utility function called by the macro py_getattro_up() - * for getting ob.__dict__() values from our PyObject - * this is used by python for doing dir() on an object, so its good - * if we return a list of attributes and methods. - * - * Other then making dir() useful the value returned from __dict__() is not useful - * since every value is a Py_None - * */ -PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict) -{ - if(pydict==NULL) { /* incase calling __dict__ on the parent of this object raised an error */ - PyErr_Clear(); - pydict = PyDict_New(); - } - - PyDict_Update(pydict, tp_dict); - return pydict; -} - - - PyObject *PyObjectPlus::GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp) { if (self->m_proxy==NULL) @@ -986,7 +932,7 @@ void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* n co_filename= PyObject_GetAttrString(f_code, "co_filename"); if (co_filename) { - printf("\t%s:%d\n", PyString_AsString(co_filename), (int)PyInt_AsLong(f_lineno)); + printf("\t%s:%d\n", _PyUnicode_AsString(co_filename), (int)PyLong_AsSsize_t(f_lineno)); Py_DECREF(f_lineno); Py_DECREF(f_code); |