From 8d2cb5bea44f4245dd17f2d82cbd0251d8090fd5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 19 Apr 2009 12:46:39 +0000 Subject: BGE Python API This changes how the BGE classes and Python work together, which hasnt changed since blender went opensource. The main difference is PyObjectPlus - the base class for most game engine classes, no longer inherit from PyObject, and cannot be cast to a PyObject. This has the advantage that the BGE does not have to keep 2 reference counts valid for C++ and Python. Previously C++ classes would never be freed while python held a reference, however this reference could be problematic eg: a GameObject that isnt in a scene anymore should not be used by python, doing so could even crash blender in some cases. Instead PyObjectPlus has a member "PyObject *m_proxy" which is lazily initialized when python needs it. m_proxy reference counts are managed by python, though it should never be freed while the C++ class exists since it holds a reference to avoid making and freeing it all the time. When the C++ class is free'd it sets the m_proxy reference to NULL, If python accesses this variable it will raise a RuntimeError, (check the isValid attribute to see if its valid without raising an error). - This replaces the m_zombie bool and IsZombie() tests added recently. In python return values that used to be.. return value->AddRef(); Are now return value->GetProxy(); or... return value->NewProxy(true); // true means python owns this C++ value which will be deleted when the PyObject is freed --- source/gameengine/Expressions/InputParser.cpp | 2 +- source/gameengine/Expressions/ListValue.cpp | 67 ++++++++---- source/gameengine/Expressions/ListValue.h | 4 +- source/gameengine/Expressions/PyObjectPlus.cpp | 69 +++++++++++-- source/gameengine/Expressions/PyObjectPlus.h | 137 +++++++++++++------------ source/gameengine/Expressions/Value.cpp | 11 +- source/gameengine/Expressions/Value.h | 16 --- 7 files changed, 186 insertions(+), 120 deletions(-) (limited to 'source/gameengine/Expressions') diff --git a/source/gameengine/Expressions/InputParser.cpp b/source/gameengine/Expressions/InputParser.cpp index 1698f1919d1..66075dd8d42 100644 --- a/source/gameengine/Expressions/InputParser.cpp +++ b/source/gameengine/Expressions/InputParser.cpp @@ -649,7 +649,7 @@ PyObject* CParserPyMake(PyObject* ignored,PyObject* args) CExpression* expr = parser.ProcessText(txt); CValue* val = expr->Calculate(); expr->Release(); - return val; + return val->GetProxy(); } static PyMethodDef CParserMethods[] = diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp index 37feba38f8b..eaed2b5c400 100644 --- a/source/gameengine/Expressions/ListValue.cpp +++ b/source/gameengine/Expressions/ListValue.cpp @@ -27,45 +27,61 @@ #define Py_ssize_t int #endif -Py_ssize_t listvalue_bufferlen(PyObject* list) +Py_ssize_t listvalue_bufferlen(PyObject* self) { - return (Py_ssize_t)( ((CListValue*)list)->GetCount()); + CListValue *list= static_cast(BGE_PROXY_REF(self)); + if (list==NULL) + return 0; + + return (Py_ssize_t)list->GetCount(); } -PyObject* listvalue_buffer_item(PyObject* list,Py_ssize_t index) +PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index) { - int count = ((CListValue*) list)->GetCount(); + CListValue *list= static_cast(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + + int count = list->GetCount(); if (index < 0) index = count+index; if (index >= 0 && index < count) { - PyObject* pyobj = ((CListValue*) list)->GetValue(index)->ConvertValueToPython(); + PyObject* pyobj = list->GetValue(index)->ConvertValueToPython(); if (pyobj) return pyobj; else - return ((CListValue*) list)->GetValue(index)->AddRef(); + return list->GetValue(index)->GetProxy(); } PyErr_SetString(PyExc_IndexError, "Python ListIndex out of range"); return NULL; } -PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex) +PyObject* listvalue_mapping_subscript(PyObject* self, PyObject* pyindex) { + CListValue *list= static_cast(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + if (PyString_Check(pyindex)) { STR_String index(PyString_AsString(pyindex)); CValue *item = ((CListValue*) list)->FindValue(index); if (item) - return (PyObject*) item; + return item->GetProxy(); } if (PyInt_Check(pyindex)) { int index = PyInt_AsLong(pyindex); - return listvalue_buffer_item(list, index); + return listvalue_buffer_item(self, index); } PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */ @@ -76,10 +92,16 @@ PyObject* listvalue_mapping_subscript(PyObject* list,PyObject* pyindex) /* just slice it into a python list... */ -PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihigh) +PyObject* listvalue_buffer_slice(PyObject* self,Py_ssize_t ilow, Py_ssize_t ihigh) { + CListValue *list= static_cast(BGE_PROXY_REF(self)); + if (list==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + int i, j; - PyListObject *newlist; + PyObject *newlist; if (ilow < 0) ilow = 0; @@ -90,18 +112,18 @@ PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihig if (ihigh < ilow) ihigh = ilow; - newlist = (PyListObject *) PyList_New(ihigh - ilow); + newlist = PyList_New(ihigh - ilow); if (!newlist) return NULL; for (i = ilow, j = 0; i < ihigh; i++, j++) { - PyObject* pyobj = ((CListValue*) list)->GetValue(i)->ConvertValueToPython(); + PyObject* pyobj = list->GetValue(i)->ConvertValueToPython(); if (!pyobj) - pyobj = ((CListValue*) list)->GetValue(i)->AddRef(); - newlist->ob_item[j] = pyobj; + pyobj = list->GetValue(i)->GetProxy(); + PyList_SET_ITEM(newlist, i, pyobj); } - return (PyObject *) newlist; + return newlist; } @@ -109,11 +131,16 @@ PyObject* listvalue_buffer_slice(PyObject* list,Py_ssize_t ilow, Py_ssize_t ihig static PyObject * listvalue_buffer_concat(PyObject * self, PyObject * other) { + CListValue *listval= static_cast(BGE_PROXY_REF(self)); + if (listval==NULL) { + PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG); + return NULL; + } + // for now, we support CListValue concatenated with items // and CListValue concatenated to Python Lists // and CListValue concatenated with another CListValue - - CListValue* listval = (CListValue*) self; + listval->AddRef(); if (other->ob_type == &PyList_Type) { @@ -519,8 +546,8 @@ PyObject* CListValue::Pyfrom_id(PyObject* self, PyObject* value) int numelem = GetCount(); for (int i=0;i(static_cast(m_pValueArray[i])) == id) - return GetValue(i); + if (reinterpret_cast(m_pValueArray[i]->m_proxy) == id) + return GetValue(i)->GetProxy(); } PyErr_SetString(PyExc_IndexError, "from_id(#), id not found in CValueList"); diff --git a/source/gameengine/Expressions/ListValue.h b/source/gameengine/Expressions/ListValue.h index cf2976c2bbb..2af5a330c43 100644 --- a/source/gameengine/Expressions/ListValue.h +++ b/source/gameengine/Expressions/ListValue.h @@ -61,9 +61,11 @@ public: virtual PyObject* py_getattro(PyObject* attr); virtual PyObject* py_repr(void) { - PyObject *py_list= PySequence_List((PyObject *)this); + PyObject *py_proxy= this->GetProxy(); + PyObject *py_list= PySequence_List(py_proxy); PyObject *py_string= PyObject_Repr(py_list); Py_DECREF(py_list); + Py_DECREF(py_proxy); return py_string; } diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 0db2e8991fc..2c5ba3f39fc 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -54,6 +54,7 @@ * PyObjectPlus Type -- Every class, even the abstract one should have a Type ------------------------------*/ + PyTypeObject PyObjectPlus::Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ @@ -74,21 +75,33 @@ PyTypeObject PyObjectPlus::Type = { Methods }; + PyObjectPlus::~PyObjectPlus() { - if (ob_refcnt) - { - _Py_ForgetReference(this); + if(m_proxy) { + Py_DECREF(m_proxy); /* Remove own reference, python may still have 1 */ + BGE_PROXY_REF(m_proxy)= NULL; } // assert(ob_refcnt==0); } +void PyObjectPlus::PyDestructor(PyObject *self) // python wrapper +{ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus) { + if(BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ + delete self_plus; + } + + BGE_PROXY_REF(self)= NULL; // not really needed + } + PyObject_DEL( self ); +}; + PyObjectPlus::PyObjectPlus(PyTypeObject *T) // constructor { MT_assert(T != NULL); - this->ob_type = T; - _Py_NewReference(this); - SetZombie(false); + m_proxy= NULL; }; /*------------------------------ @@ -131,7 +144,7 @@ PyObject *PyObjectPlus::py_getattro(PyObject* attr) 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, (PyObject *)this); + return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); } else { fprintf(stderr, "Unknown attribute type (PyObjectPlus::py_getattro)"); return descr; @@ -794,5 +807,47 @@ PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict) return pydict; } + + +PyObject *PyObjectPlus::GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp) +{ + if (self->m_proxy==NULL) + { + self->m_proxy = reinterpret_castPyObject_NEW( PyObjectPlus_Proxy, tp); + BGE_PROXY_PYOWNS(self->m_proxy) = false; + } + //PyObject_Print(self->m_proxy, stdout, 0); + //printf("ref %d\n", self->m_proxy->ob_refcnt); + + BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */ + Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */ + return self->m_proxy; +} + +PyObject *PyObjectPlus::NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns) +{ + if (self->m_proxy) + { + if(py_owns) + { /* Free */ + BGE_PROXY_REF(self->m_proxy) = NULL; + Py_DECREF(self->m_proxy); + self->m_proxy= NULL; + } + else { + Py_INCREF(self->m_proxy); + return self->m_proxy; + } + + } + + GetProxy_Ext(self, tp); + if(py_owns) { + BGE_PROXY_PYOWNS(self->m_proxy) = py_owns; + Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */ + } + return self->m_proxy; +} + #endif //NO_EXP_PYTHON_EMBEDDING diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 58a74e4ca74..3be9a2f2bcb 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -81,6 +81,20 @@ static inline void Py_Fatal(const char *M) { exit(-1); }; +typedef struct { + PyObject_HEAD /* required python macro */ + class PyObjectPlus *ref; + bool py_owns; +} PyObjectPlus_Proxy; + +#define BGE_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable" +#define BGE_PROXY_REF(_self) (((PyObjectPlus_Proxy *)_self)->ref) +#define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) + +/* Note, sometimes we dont care what BGE type this is as long as its a proxy */ +#define BGE_PROXY_CHECK_TYPE(_self) ((_self)->ob_type->tp_dealloc == PyDestructor) + + // This must be the first line of each // PyC++ class #define Py_Header \ @@ -90,7 +104,10 @@ static inline void Py_Fatal(const char *M) { static PyAttributeDef Attributes[]; \ static PyParentObject Parents[]; \ virtual PyTypeObject *GetType(void) {return &Type;}; \ - virtual PyParentObject *GetParents(void) {return Parents;} + virtual PyParentObject *GetParents(void) {return Parents;} \ + virtual PyObject *GetProxy() {return GetProxy_Ext(this, &Type);}; \ + virtual PyObject *NewProxy(bool py_owns) {return NewProxy_Ext(this, &Type, py_owns);}; \ + @@ -106,7 +123,7 @@ static inline void Py_Fatal(const char *M) { 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, (PyObject *)this); \ + return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, this->m_proxy); \ } else { \ fprintf(stderr, "unknown attribute type"); \ return descr; \ @@ -165,52 +182,60 @@ static inline void Py_Fatal(const char *M) { #define KX_PYMETHOD(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ - return ((class_name*) self)->Py##method_name(self, args, kwds); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self, args, kwds); \ }; \ #define KX_PYMETHOD_VARARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ - return ((class_name*) self)->Py##method_name(self, args); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self, args); \ }; \ #define KX_PYMETHOD_NOARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self); \ static PyObject* sPy##method_name( PyObject* self) { \ - return ((class_name*) self)->Py##method_name(self); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self); \ }; \ #define KX_PYMETHOD_O(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ - return ((class_name*) self)->Py##method_name(self, value); \ + PyObjectPlus *self_plus= ((PyObjectPlus_Proxy *)self)->ref; \ + return ((class_name*) self_plus)->Py##method_name(self, value); \ }; \ #define KX_PYMETHOD_DOC(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* args, PyObject* kwds); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args, PyObject* kwds) { \ - return ((class_name*) self)->Py##method_name(self, args, kwds); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self, args, kwds); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_VARARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* args); \ static PyObject* sPy##method_name( PyObject* self, PyObject* args) { \ - return ((class_name*) self)->Py##method_name(self, args); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self, args); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_O(class_name, method_name) \ PyObject* Py##method_name(PyObject* self, PyObject* value); \ static PyObject* sPy##method_name( PyObject* self, PyObject* value) { \ - return ((class_name*) self)->Py##method_name(self, value); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self, value); \ }; \ static const char method_name##_doc[]; \ #define KX_PYMETHOD_DOC_NOARGS(class_name, method_name) \ PyObject* Py##method_name(PyObject* self); \ static PyObject* sPy##method_name( PyObject* self) { \ - return ((class_name*) self)->Py##method_name(self); \ + PyObjectPlus *self_plus= BGE_PROXY_REF(self); \ + return ((class_name*)self_plus)->Py##method_name(self); \ }; \ static const char method_name##_doc[]; \ @@ -233,19 +258,19 @@ static inline void Py_Fatal(const char *M) { */ #define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* args, PyObject*) +PyObject* class_name::Py##method_name(PyObject* self, PyObject* args, PyObject*) #define KX_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* args) +PyObject* class_name::Py##method_name(PyObject* self, PyObject* args) #define KX_PYMETHODDEF_DOC_O(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*, PyObject* value) +PyObject* class_name::Py##method_name(PyObject* self, PyObject* value) #define KX_PYMETHODDEF_DOC_NOARGS(class_name, method_name, doc_string) \ const char class_name::method_name##_doc[] = doc_string; \ -PyObject* class_name::Py##method_name(PyObject*) +PyObject* class_name::Py##method_name(PyObject* self) /** * Attribute management @@ -394,19 +419,17 @@ typedef struct KX_PYATTRIBUTE_DEF { ------------------------------*/ typedef PyTypeObject * PyParentObject; // Define the PyParent Object -class PyObjectPlus : public PyObject +class PyObjectPlus { // The PyObjectPlus abstract class Py_Header; // Always start with Py_Header public: PyObjectPlus(PyTypeObject *T); - bool m_zombie; + + PyObject *m_proxy; /* actually a PyObjectPlus_Proxy */ virtual ~PyObjectPlus(); // destructor - static void PyDestructor(PyObject *P) // python wrapper - { - delete ((PyObjectPlus *) P); - }; + static void PyDestructor(PyObject *self); // python wrapper // void INCREF(void) { // Py_INCREF(this); @@ -418,15 +441,15 @@ public: virtual PyObject *py_getattro(PyObject *attr); // py_getattro method static PyObject *py_base_getattro(PyObject * self, PyObject *attr) // This should be the entry in Type. { - if (((PyObjectPlus*)self)->IsZombie()) { - if (!strcmp(PyString_AsString(attr), "isValid")) { - Py_RETURN_FALSE; + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + if(!strcmp("isValid", PyString_AsString(attr))) { + Py_RETURN_TRUE; } - ((PyObjectPlus*)self)->IsZombiePyErr(); /* raise an error */ + PyErr_SetString(PyExc_RuntimeError, "data has been removed"); return NULL; } - - return ((PyObjectPlus*) self)->py_getattro(attr); + return self_plus->py_getattro(attr); } static PyObject* py_get_attrdef(void *self, const PyAttributeDef *attrdef); @@ -441,22 +464,29 @@ public: virtual int py_setattro(PyObject *attr, PyObject *value); // py_setattro method static int py_base_setattro(PyObject *self, PyObject *attr, PyObject *value) // the PyType should reference this { - if (((PyObjectPlus*)self)->IsZombie()) { - /* you cant set isValid anyway */ - ((PyObjectPlus*)self)->IsZombiePyErr(); + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + PyErr_SetString(PyExc_RuntimeError, "data has been removed"); return -1; } if (value==NULL) - return ((PyObjectPlus*)self)->py_delattro(attr); + return self_plus->py_delattro(attr); - return ((PyObjectPlus*)self)->py_setattro(attr, value); + return self_plus->py_setattro(attr, value); } virtual PyObject *py_repr(void); // py_repr method - static PyObject *py_base_repr(PyObject *PyObj) // This should be the entry in Type. + static PyObject *py_base_repr(PyObject *self) // This should be the entry in Type. { - return ((PyObjectPlus*) PyObj)->py_repr(); + + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + PyErr_SetString(PyExc_RuntimeError, "data has been removed"); + return NULL; + } + + return self_plus->py_repr(); } // isA methods @@ -465,43 +495,20 @@ public: PyObject *Py_isA(PyObject *value); static PyObject *sPy_isA(PyObject *self, PyObject *value) { - return ((PyObjectPlus*)self)->Py_isA(value); - } - - /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ - static PyObject* pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - bool IsZombie() - { - return m_zombie; - } - - bool IsZombiePyErr() - { - if(m_zombie) { - /* - PyObject *this_pystr = PyObject_Repr(this); - - PyErr_Format( - PyExc_RuntimeError, - "\"%s\" of type \"%s\" has been freed by the blender game engine, " - "scripts cannot access this anymore, check for this case with the \"isValid\" attribute", - PyString_AsString(this_pystr), ob_type->tp_name ); - - Py_DECREF(this_pystr); - */ - - PyErr_SetString(PyExc_RuntimeError, "This value has been freed by the blender game engine but python is still holding a reference, this value cant be used."); + PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if(self_plus==NULL) { + PyErr_SetString(PyExc_RuntimeError, "data has been removed"); + return NULL; } - return m_zombie; + return self_plus->Py_isA(value); } - void SetZombie(bool is_zombie) - { - m_zombie= is_zombie; - } + /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ + static PyObject* pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp); + static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, bool py_owns); }; PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict); diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp index 63776c39d70..7958c16ca81 100644 --- a/source/gameengine/Expressions/Value.cpp +++ b/source/gameengine/Expressions/Value.cpp @@ -501,12 +501,6 @@ int CValue::Release() // Decrease local reference count, if it reaches 0 the object should be freed if (--m_refcount > 0) { - // Benoit suggest this as a way to automatically set the zombie flag, but I couldnt get it working - Campbell - /* - if (m_refcount == 1 && ob_refcnt > 1) - SetZombie(true); // the remaining refcount is held by Python!! - */ - // Reference count normal, return new reference count return m_refcount; } @@ -544,9 +538,6 @@ void CValue::AddDataToReplica(CValue *replica) { replica->m_refcount = 1; - //register with Python - _Py_NewReference(replica); - #ifdef _DEBUG //gRefCountValue++; #endif @@ -616,7 +607,7 @@ PyObject* CValue::py_getattro(PyObject *attr) if (pyconvert) return pyconvert; else - return resultattr; // also check if it's already in pythoninterpreter! + return resultattr->GetProxy(); } py_getattro_up(PyObjectPlus); } diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h index bcee355cda2..a687e1a493c 100644 --- a/source/gameengine/Expressions/Value.h +++ b/source/gameengine/Expressions/Value.h @@ -225,21 +225,6 @@ public: virtual PyObject* py_getattro(PyObject *attr); - - void SpecialRelease() - { - if (ob_refcnt == 0) /* make sure python always holds a reference */ - { - _Py_NewReference(this); - - } - Release(); - } - static void PyDestructor(PyObject *P) // python wrapper - { - ((CValue*)P)->SpecialRelease(); - }; - virtual PyObject* ConvertValueToPython() { return NULL; } @@ -352,7 +337,6 @@ private: std::map* m_pNamedPropertyArray; // Properties for user/game etc ValueFlags m_ValFlags; // Frequently used flags in a bitfield (low memoryusage) int m_refcount; // Reference Counter - bool m_zombie; // Object is invalid put its still being referenced (by python) static double m_sZeroVec[3]; static bool m_ignore_deprecation_warnings; -- cgit v1.2.3