Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2009-04-19 16:46:39 +0400
committerCampbell Barton <ideasman42@gmail.com>2009-04-19 16:46:39 +0400
commit8d2cb5bea44f4245dd17f2d82cbd0251d8090fd5 (patch)
treeb28e45f1edaf083c15d2176079836a4497685e57 /source/gameengine/Expressions
parent92cea7c1b1540d11ed9729bacfabd23ccb7a79c7 (diff)
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
Diffstat (limited to 'source/gameengine/Expressions')
-rw-r--r--source/gameengine/Expressions/InputParser.cpp2
-rw-r--r--source/gameengine/Expressions/ListValue.cpp67
-rw-r--r--source/gameengine/Expressions/ListValue.h4
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.cpp69
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.h137
-rw-r--r--source/gameengine/Expressions/Value.cpp11
-rw-r--r--source/gameengine/Expressions/Value.h16
7 files changed, 186 insertions, 120 deletions
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<CListValue *>(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<CListValue *>(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<CListValue *>(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<CListValue *>(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<CListValue *>(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<numelem;i++)
{
- if (reinterpret_cast<BGE_ID_TYPE>(static_cast<PyObject*>(m_pValueArray[i])) == id)
- return GetValue(i);
+ if (reinterpret_cast<BGE_ID_TYPE>(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_cast<PyObject *>PyObject_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<STR_String,CValue*>* 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;