Added m_zombie to the base python class (PyObjectPlus), when this is set all the...
authorCampbell Barton <ideasman42@gmail.com>
Fri, 17 Apr 2009 20:06:06 +0000 (20:06 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 17 Apr 2009 20:06:06 +0000 (20:06 +0000)
Other small changes...
- KX_Camera and KX_Light didnt have get/setitem access in their PyType definition.
- CList.from_id() error checking for a long was checking for -1 against an unsigned value (own fault)
- CValue::SpecialRelease was incrementing an int for no reason.
- renamed m_attrlist to m_attr_dict since its a PyDict type.
- removed custom getattro/setattro functions for KX_Scene and KX_GameObject, use py_base_getattro, py_base_setattro for all subclasses of PyObjectPlus.
- lowercase windows.h in VideoBase.cpp for cross compiling.

13 files changed:
source/gameengine/Expressions/ListValue.cpp
source/gameengine/Expressions/PyObjectPlus.cpp
source/gameengine/Expressions/PyObjectPlus.h
source/gameengine/Expressions/Value.cpp
source/gameengine/Expressions/Value.h
source/gameengine/GameLogic/SCA_PropertyActuator.cpp
source/gameengine/Ketsji/KX_Camera.cpp
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_Light.cpp
source/gameengine/Ketsji/KX_Scene.cpp
source/gameengine/Ketsji/KX_Scene.h
source/gameengine/VideoTexture/VideoBase.cpp

index 0f163ad07c1772b480455468c97d58347c1afbe0..37feba38f8b61951ddc1ad89706216e736e8a52f 100644 (file)
@@ -513,7 +513,7 @@ PyObject* CListValue::Pyfrom_id(PyObject* self, PyObject* value)
        BGE_ID_TYPE id= PyLong_FromUnsignedLongLong(value);
 #endif
        
-       if (id==-1 && PyErr_Occurred())
+       if (PyErr_Occurred())
                return NULL;
 
        int numelem = GetCount();
index 33335ebef3e9f7fc65cf279c88b4bed235b00e4e..0db2e8991fc73005e1b6a1996cf166e93dc409fb 100644 (file)
@@ -88,6 +88,7 @@ PyObjectPlus::PyObjectPlus(PyTypeObject *T)                           // constructor
        MT_assert(T != NULL);
        this->ob_type = T; 
        _Py_NewReference(this);
+       SetZombie(false);
 };
   
 /*------------------------------
@@ -99,9 +100,15 @@ PyMethodDef PyObjectPlus::Methods[] = {
 };
 
 PyAttributeDef PyObjectPlus::Attributes[] = {
+       KX_PYATTRIBUTE_RO_FUNCTION("isValid",           PyObjectPlus, pyattr_get_is_valid),
        {NULL} //Sentinel
 };
 
+PyObject* PyObjectPlus::pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{      
+       Py_RETURN_TRUE;
+}
+
 /*------------------------------
  * PyObjectPlus Parents                -- Every class, even the abstract one should have parents
 ------------------------------*/
@@ -117,10 +124,19 @@ PyObject *PyObjectPlus::py_getattro(PyObject* attr)
                if (strcmp(PyString_AsString(attr), "__dict__")==0) {
                        return py_getattr_dict(NULL, Type.tp_dict); /* no Attributes yet */
                }
-               PyErr_SetString(PyExc_AttributeError, "attribute not found");
+               PyErr_Format(PyExc_AttributeError, "attribute \"%s\" not found", PyString_AsString(attr));
                return NULL;
        } else {
-               return PyCFunction_New(((PyMethodDescrObject *)descr)->d_method, (PyObject *)this); \
+               /* 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, (PyObject *)this);
+               } else {
+                       fprintf(stderr, "Unknown attribute type (PyObjectPlus::py_getattro)");
+                       return descr;
+               }
+               /* end py_getattro_up copy */
        }
   //if (streq(attr, "type"))
   //  return Py_BuildValue("s", (*(GetParents()))->tp_name);
index ea26ea1d20147846fcea12f5cdcb5a340b8b7b18..58a74e4ca745932b7655ebf702fa748cc9dca355 100644 (file)
@@ -400,10 +400,11 @@ class PyObjectPlus : public PyObject
        
 public:
        PyObjectPlus(PyTypeObject *T);
+       bool m_zombie;
        
        virtual ~PyObjectPlus();                                        // destructor
        static void PyDestructor(PyObject *P)                           // python wrapper
-       {  
+       {
                delete ((PyObjectPlus *) P);  
        };
        
@@ -417,6 +418,14 @@ 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)->IsZombiePyErr(); /* raise an error */
+                       return NULL;
+               }
+               
                return ((PyObjectPlus*) self)->py_getattro(attr); 
        }
        
@@ -432,10 +441,16 @@ 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();
+                       return -1;
+               }
+               
                if (value==NULL)
-                       return ((PyObjectPlus*) self)->py_delattro(attr);
+                       return ((PyObjectPlus*)self)->py_delattro(attr);
                
-               return ((PyObjectPlus*) self)->py_setattro(attr, value); 
+               return ((PyObjectPlus*)self)->py_setattro(attr, value); 
        }
        
        virtual PyObject *py_repr(void);                                // py_repr method
@@ -452,6 +467,41 @@ public:
        {
                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.");
+               }
+               
+               return m_zombie;
+       }
+       
+       void SetZombie(bool is_zombie)
+       {
+               m_zombie= is_zombie;
+       }
+       
 };
 
 PyObject *py_getattr_dict(PyObject *pydict, PyObject *tp_dict);
index b8b7a05aa64d69c17c2a3e0cb113934a8fdfd775..e969f0c33aa2e42498713402ca3e1459237d77a4 100644 (file)
@@ -602,6 +602,12 @@ 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;
        }
@@ -609,6 +615,7 @@ int CValue::Release()
        {
                // Reference count reached 0, delete ourselves and return 0
 //             MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much");
+               
                delete this;
                return 0;
        }
index 4cdc80dc9bd423bdd6848a9d841002846b4bc26c..bcee355cda2ba2982f4f824f7e908bb3108eb22c 100644 (file)
@@ -219,7 +219,7 @@ public:
        //static PyObject*      PyMake(PyObject*,PyObject*);
        virtual PyObject *py_repr(void)
        {
-               return Py_BuildValue("s",(const char*)GetText());
+               return PyString_FromString((const char*)GetText());
        }
 
 
@@ -228,14 +228,10 @@ public:
 
        void    SpecialRelease()
        {
-               int i=0;
-               if (ob_refcnt == 0)
+               if (ob_refcnt == 0) /* make sure python always holds a reference */
                {
                        _Py_NewReference(this);
                        
-               } else
-               {
-                       i++;
                }
                Release();
        }
@@ -280,6 +276,7 @@ public:
        int                                     GetRefCount()                                                                                   { return m_refcount; }
        virtual CValue*         AddRef();                                                                                               // Add a reference to this value
        virtual int                     Release();                                                                                              // Release a reference to this value (when reference count reaches 0, the value is removed from the heap)
+       
 
        /// Property Management
        virtual void            SetProperty(const STR_String& name,CValue* ioProperty);                                         // Set property <ioProperty>, overwrites and releases a previous property with the same name if needed
@@ -355,6 +352,7 @@ 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;
 
index 359ab8adac6dae4af0347fe42b2851875c39ea29..9dbdc0e89d10bc534f89073b2f83d52c62da2b35 100644 (file)
@@ -95,7 +95,7 @@ bool SCA_PropertyActuator::Update()
                }
                newval->Release();
        }
-       else if (userexpr = parser.ProcessText(m_exprtxt)) {
+       else if ((userexpr = parser.ProcessText(m_exprtxt))) {
                switch (m_type)
                {
 
index befc8462aa36b5986353be2ae18df04bc9bd76f0..daa37056d6869128e04e9a77ba171f1fc6a01142 100644 (file)
@@ -517,13 +517,20 @@ PyTypeObject KX_Camera::Type = {
                0,
                0,
                py_base_repr,
-               0,0,0,0,0,0,
+               0,0,
+               &KX_GameObject::Mapping,
+               0,0,0,
                py_base_getattro,
                py_base_setattro,
                0,0,0,0,0,0,0,0,0,
                Methods
 };
 
+
+
+
+
+
 PyParentObject KX_Camera::Parents[] = {
        &KX_Camera::Type,
        &KX_GameObject::Type,
@@ -534,22 +541,11 @@ PyParentObject KX_Camera::Parents[] = {
 
 PyObject* KX_Camera::py_getattro(PyObject *attr)
 {
-       if (ValidPythonToGameObject(this)==false) {
-               if (!strcmp(PyString_AsString(attr), "isValid")) {
-                       PyErr_Clear();
-                       Py_RETURN_FALSE;
-               }
-               return NULL; /* ValidPythonToGameObject sets the error */
-       }
-       
        py_getattro_up(KX_GameObject);
 }
 
 int KX_Camera::py_setattro(PyObject *attr, PyObject *value)
-{
-       if (ValidPythonToGameObject(this)==false)
-               return -1;
-       
+{      
        py_setattro_up(KX_GameObject);
 }
 
index 283b78c294784d68d565ba497454e9b566368439..3e7c99dc472da7bf57547b61d16ebcc707a292cb 100644 (file)
@@ -103,7 +103,7 @@ KX_GameObject::KX_GameObject(
        m_xray(false),
        m_pHitObject(NULL),
        m_isDeformable(false),
-       m_attrlist(NULL)
+       m_attr_dict(NULL)
 {
        m_ignore_activity_culling = false;
        m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR);
@@ -146,9 +146,9 @@ KX_GameObject::~KX_GameObject()
                delete m_pGraphicController;
        }
        
-       if (m_attrlist) {
-               PyDict_Clear(m_attrlist); /* incase of circular refs or other weired cases */
-               Py_DECREF(m_attrlist);
+       if (m_attr_dict) {
+               PyDict_Clear(m_attr_dict); /* incase of circular refs or other weired cases */
+               Py_DECREF(m_attr_dict);
        }
 }
 
@@ -339,8 +339,8 @@ void KX_GameObject::ProcessReplica(KX_GameObject* replica)
        replica->m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info);
        replica->m_pClient_info->m_gameobject = replica;
        replica->m_state = 0;
-       if(m_attrlist)
-               replica->m_attrlist= PyDict_Copy(m_attrlist);
+       if(m_attr_dict)
+               replica->m_attr_dict= PyDict_Copy(m_attr_dict);
                
 }
 
@@ -1123,9 +1123,6 @@ PyAttributeDef KX_GameObject::Attributes[] = {
        KX_PYATTRIBUTE_RO_FUNCTION("sensors",           KX_GameObject, pyattr_get_sensors),
        KX_PYATTRIBUTE_RO_FUNCTION("controllers",       KX_GameObject, pyattr_get_controllers),
        KX_PYATTRIBUTE_RO_FUNCTION("actuators",         KX_GameObject, pyattr_get_actuators),
-       
-       KX_PYATTRIBUTE_RO_FUNCTION("isValid",           KX_GameObject, pyattr_get_is_valid),
-       
        {NULL} //Sentinel
 };
 
@@ -1190,14 +1187,15 @@ Py_ssize_t KX_GameObject::Map_Len(PyObject* self_v)
 {
        KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
        
-       if (ValidPythonToGameObject(self)==false) {
+       if (self->IsZombie()) /* not sure what to do here */
+       {
                PyErr_Clear();
                return 0;
        }
        
        Py_ssize_t len= self->GetPropertyCount();
-       if(self->m_attrlist)
-               len += PyDict_Size(self->m_attrlist);
+       if(self->m_attr_dict)
+               len += PyDict_Size(self->m_attr_dict);
        return len;
 }
 
@@ -1209,7 +1207,7 @@ PyObject *KX_GameObject::Map_GetItem(PyObject *self_v, PyObject *item)
        CValue* resultattr;
        PyObject* pyconvert;
        
-       if (ValidPythonToGameObject(self)==false)
+       if (self->IsZombiePyErr())
                return NULL;
        
        /* first see if the attributes a string and try get the cvalue attribute */
@@ -1217,8 +1215,8 @@ PyObject *KX_GameObject::Map_GetItem(PyObject *self_v, PyObject *item)
                pyconvert = resultattr->ConvertValueToPython();                 
                return pyconvert ? pyconvert:resultattr;
        }
-       /* no CValue attribute, try get the python only m_attrlist attribute */
-       else if (self->m_attrlist && (pyconvert=PyDict_GetItem(self->m_attrlist, item))) {
+       /* no CValue attribute, try get the python only m_attr_dict attribute */
+       else if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) {
                
                if (attr_str)
                        PyErr_Clear();
@@ -1241,7 +1239,7 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
        if(attr_str==NULL)
                PyErr_Clear();
        
-       if (ValidPythonToGameObject(self)==false)
+       if (self->IsZombiePyErr())
                return -1;
        
        if (val==NULL) { /* del ob["key"] */
@@ -1251,15 +1249,15 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
                if(attr_str)
                        del |= (self->RemoveProperty(attr_str)==true) ? 1:0;
                
-               if(self->m_attrlist)
-                       del |= (PyDict_DelItem(self->m_attrlist, key)==0) ? 1:0;
+               if(self->m_attr_dict)
+                       del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0;
                
                if (del==0) {
                        if(attr_str)    PyErr_Format(PyExc_KeyError, "KX_GameObject key \"%s\" not found", attr_str);
                        else                    PyErr_SetString(PyExc_KeyError, "KX_GameObject key not found");
                        return -1;
                }
-               else if (self->m_attrlist) {
+               else if (self->m_attr_dict) {
                        PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */
                }
        }
@@ -1284,8 +1282,8 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
                                set= 1;
                                
                                /* try remove dict value to avoid double ups */
-                               if (self->m_attrlist){
-                                       if (PyDict_DelItem(self->m_attrlist, key) != 0)
+                               if (self->m_attr_dict){
+                                       if (PyDict_DelItem(self->m_attr_dict, key) != 0)
                                                PyErr_Clear();
                                }
                        }
@@ -1296,11 +1294,11 @@ int KX_GameObject::Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val)
                
                if(set==0)
                {
-                       if (self->m_attrlist==NULL) /* lazy init */
-                               self->m_attrlist= PyDict_New();
+                       if (self->m_attr_dict==NULL) /* lazy init */
+                               self->m_attr_dict= PyDict_New();
                        
                        
-                       if(PyDict_SetItem(self->m_attrlist, key, val)==0)
+                       if(PyDict_SetItem(self->m_attr_dict, key, val)==0)
                        {
                                if(attr_str)
                                        self->RemoveProperty(attr_str); /* overwrite the CValue if it exists */
@@ -1343,8 +1341,8 @@ PyTypeObject KX_GameObject::Type = {
                0,0,
                &Mapping,
                0,0,0,
-               py_base_getattro_gameobject,
-               py_base_setattro_gameobject,
+               py_base_getattro,
+               py_base_setattro,
                0,0,0,0,0,0,0,0,0,
                Methods
 };
@@ -1675,11 +1673,6 @@ PyObject* KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DE
        return meshes;
 }
 
-PyObject* KX_GameObject::pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
-{      
-       Py_RETURN_TRUE;
-}
-
 /* experemental! */
 PyObject* KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
@@ -1741,47 +1734,36 @@ PyObject* KX_GameObject::pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_
        
        Py_DECREF(list);
        
-       /* Add m_attrlist if we have it */
-       if(self->m_attrlist)
-               PyDict_Update(dict, self->m_attrlist);
+       /* Add m_attr_dict if we have it */
+       if(self->m_attr_dict)
+               PyDict_Update(dict, self->m_attr_dict);
        
        return dict;
 }
 
-PyObject* KX_GameObject::py_getattro(PyObject *attr)
+/* We need these because the macros have a return in them */
+PyObject* KX_GameObject::py_getattro__internal(PyObject *attr)
 {
        py_getattro_up(SCA_IObject);
 }
 
-int KX_GameObject::py_setattro(PyObject *attr, PyObject *value)        // py_setattro method
+int KX_GameObject::py_setattro__internal(PyObject *attr, PyObject *value)      // py_setattro method
 {
        py_setattro_up(SCA_IObject);
 }
 
 
-/* we need our own getattr and setattr types */
-/* See m_attrlist definition for rules on how this works */
-PyObject *KX_GameObject::py_base_getattro_gameobject(PyObject * self, PyObject *attr)
+PyObject* KX_GameObject::py_getattro(PyObject *attr)
 {
-       if(((KX_GameObject *) self)->GetSGNode()==NULL) {
-               if (!strcmp(PyString_AsString(attr), "isValid")) {
-                       PyErr_Clear();
-                       Py_INCREF(Py_False);
-                       return Py_False;
-               }
-               
-               ValidPythonToGameObject(((KX_GameObject *) self)); // we know its invalid, just get the error
-               return NULL;
-       }
-       
-       PyObject *object= ((KX_GameObject *) self)->py_getattro(attr);
+       PyObject *object= py_getattro__internal(attr);
        
-       if (object==NULL && ((KX_GameObject *) self)->m_attrlist) {
+       if (object==NULL && m_attr_dict)
+       {
                /* backup the exception incase the attr doesnt exist in the dict either */
                PyObject *err_type, *err_value, *err_tb;
                PyErr_Fetch(&err_type, &err_value, &err_tb);
                
-               object= PyDict_GetItem(((KX_GameObject *) self)->m_attrlist, attr);
+               object= PyDict_GetItem(m_attr_dict, attr);
                if (object) {
                        Py_INCREF(object);
                        
@@ -1797,62 +1779,33 @@ PyObject *KX_GameObject::py_base_getattro_gameobject(PyObject * self, PyObject *
        return object;
 }
 
-int KX_GameObject::py_base_setattro_gameobject(PyObject * self, PyObject *attr, PyObject *value)
+int KX_GameObject::py_setattro(PyObject *attr, PyObject *value)        // py_setattro method
 {
        int ret;
        
-       /* Delete the item */
-       if (value==NULL)
-       {
-               ret= ((PyObjectPlus*) self)->py_delattro(attr);
-               
-               if (ret != 0) /* CValue attribute failed, try KX_GameObject m_attrlist dict */
-               {
-                       if (((KX_GameObject *) self)->m_attrlist)
-                       {
-                               /* backup the exception incase the attr doesnt exist in the dict either */
-                               PyObject *err_type, *err_value, *err_tb;
-                               PyErr_Fetch(&err_type, &err_value, &err_tb);
-                               
-                               if (PyDict_DelItem(((KX_GameObject *) self)->m_attrlist, attr) == 0)
-                               {
-                                       ret= 0;
-                                       PyErr_Clear();
-                                       Py_XDECREF( err_type );
-                                       Py_XDECREF( err_value );
-                                       Py_XDECREF( err_tb );
-                               }
-                               else { 
-                                       PyErr_Restore(err_type, err_value, err_tb); /* use the error from the parent function */
-                               }
-                       }
-               }
-               return ret;
-       }
-       
-       
-       ret= ((PyObjectPlus*) self)->py_setattro(attr, value);
+       ret= py_setattro__internal(attr, value);
        
        if (ret==PY_SET_ATTR_SUCCESS) {
                /* remove attribute in our own dict to avoid double ups */
-               if (((KX_GameObject *) self)->m_attrlist) {
-                       if (PyDict_DelItem(((KX_GameObject *) self)->m_attrlist, attr) != 0)
+               /* NOTE: Annoying that we also do this for setting builtin attributes like mass and visibility :/ */
+               if (m_attr_dict) {
+                       if (PyDict_DelItem(m_attr_dict, attr) != 0)
                                PyErr_Clear();
                }
        }
        
        if (ret==PY_SET_ATTR_COERCE_FAIL) {
-               /* CValue attribute exists, remove and add dict value */
-               ((KX_GameObject *) self)->RemoveProperty(STR_String(PyString_AsString(attr)));
+               /* CValue attribute exists, remove CValue and add PyDict value */
+               RemoveProperty(STR_String(PyString_AsString(attr)));
                ret= PY_SET_ATTR_MISSING;
        }
        
        if (ret==PY_SET_ATTR_MISSING) {
                /* Lazy initialization */
-               if (((KX_GameObject *) self)->m_attrlist==NULL)
-                       ((KX_GameObject *) self)->m_attrlist = PyDict_New();
+               if (m_attr_dict==NULL)
+                       m_attr_dict = PyDict_New();
                
-               if (PyDict_SetItem(((KX_GameObject *) self)->m_attrlist, attr, value)==0) {
+               if (PyDict_SetItem(m_attr_dict, attr, value)==0) {
                        PyErr_Clear();
                        ret= PY_SET_ATTR_SUCCESS;
                }
@@ -1862,9 +1815,25 @@ int KX_GameObject::py_base_setattro_gameobject(PyObject * self, PyObject *attr,
                }
        }
        
-       return ret;
+       return ret;     
 }
 
+
+int    KX_GameObject::py_delattro(PyObject *attr)
+{
+       char *attr_str= PyString_AsString(attr); 
+       
+       if (RemoveProperty(STR_String(attr_str))) // XXX - should call CValues instead but its only 2 lines here
+               return 0;
+       
+       if (m_attr_dict && (PyDict_DelItem(m_attr_dict, attr) == 0))
+               return 0;
+       
+       PyErr_Format(PyExc_AttributeError, "attribute \"%s\" dosnt exist", attr_str);
+       return 1;
+}
+
+
 PyObject* KX_GameObject::PyApplyForce(PyObject* self, PyObject* args)
 {
        int local = 0;
@@ -2374,11 +2343,11 @@ PyObject* KX_GameObject::PyGetPropertyNames(PyObject* self)
 {
        PyObject *list=  ConvertKeysToPython();
        
-       if(m_attrlist) {
+       if(m_attr_dict) {
                PyObject *key, *value;
                Py_ssize_t pos = 0;
 
-               while (PyDict_Next(m_attrlist, &pos, &key, &value)) {
+               while (PyDict_Next(m_attr_dict, &pos, &key, &value)) {
                        PyList_Append(list, key);
                }
        }
@@ -2685,8 +2654,8 @@ KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage,
 "to = Name of object to send the message to")
 {
        char* subject;
-       char* body = "";
-       char* to = "";
+       char* body = (char *)"";
+       char* to = (char *)"";
        const STR_String& from = GetName();
 
        if (!PyArg_ParseTuple(args, "s|sss:sendMessage", &subject, &body, &to))
@@ -2753,7 +2722,7 @@ bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py
                *object = static_cast<KX_GameObject*>(value);
                
                /* sets the error */
-               if (ValidPythonToGameObject(*object)==false)
+               if ((*object)->IsZombiePyErr())
                        return false;
                
                return true;
@@ -2769,17 +2738,3 @@ bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py
        
        return false;
 }
-
-bool ValidPythonToGameObject(KX_GameObject *object)
-{
-       if (object->GetSGNode()==NULL) {
-               PyErr_Format(
-                               PyExc_RuntimeError,
-                               "KX_GameObject \"%s\" is not longer in a scene, "
-                               "check for this case with the \"isValid\" attribute",
-                               object->GetName().ReadPtr() );
-               return false;
-       }
-       
-       return true;
-}
\ No newline at end of file
index cf0c0e6b0f58051f051bad69e8d5977316843b67..dd85c2f2faaeaff5498f0d2e06bd5e903904cede 100644 (file)
@@ -62,7 +62,6 @@ struct Object;
 
 /* utility conversion function */
 bool ConvertPythonToGameObject(PyObject * value, KX_GameObject **object, bool py_none_ok);
-bool ValidPythonToGameObject(KX_GameObject *object);
 
 /**
  * KX_GameObject is the main class for dynamic objects.
@@ -119,15 +118,15 @@ public:
        // these can be used with property actuators
        //
        // For the python API, For types that cannot be converted into CValues (lists, dicts, GameObjects)
-       // these will be put into "m_attrlist", logic bricks cannot access them.
+       // these will be put into "m_attr_dict", logic bricks cannot access them.
        // 
        // rules for setting attributes.
        // 
-       // * there should NEVER be a CValue and a m_attrlist attribute with matching names. get/sets make sure of this.
-       // * if CValue conversion fails, use a PyObject in "m_attrlist"
-       // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attrlist" and set the CValue
+       // * there should NEVER be a CValue and a m_attr_dict attribute with matching names. get/sets make sure of this.
+       // * if CValue conversion fails, use a PyObject in "m_attr_dict"
+       // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attr_dict" and set the CValue
        // 
-       PyObject*                                                       m_attrlist; 
+       PyObject*                                                       m_attr_dict; 
 
        virtual void    /* This function should be virtual - derived classed override it */
        Relink(
@@ -814,16 +813,21 @@ public:
        
        virtual PyObject* py_getattro(PyObject *attr);
        virtual int py_setattro(PyObject *attr, PyObject *value);               // py_setattro method
+       virtual int                             py_delattro(PyObject *attr);
        virtual PyObject* py_repr(void)
        {
-               if (ValidPythonToGameObject(this)==false)
+               if (IsZombiePyErr())
                        return NULL;
                return PyString_FromString(GetName().ReadPtr());
        }
        
-       static PyObject *py_base_getattro_gameobject(PyObject * self, PyObject *attr);
-       static int py_base_setattro_gameobject(PyObject * self, PyObject *attr, PyObject *value);
        
+       /* quite annoying that we need these but the bloody 
+        * py_getattro_up and py_setattro_up macro's have a returns in them! */
+       PyObject* py_getattro__internal(PyObject *attr);
+       int py_setattro__internal(PyObject *attr, PyObject *value);             // py_setattro method
+       
+               
        KX_PYMETHOD_NOARGS(KX_GameObject,GetPosition);
        KX_PYMETHOD_O(KX_GameObject,SetPosition);
        KX_PYMETHOD_O(KX_GameObject,SetWorldPosition);
@@ -897,7 +901,6 @@ public:
        static PyObject*        pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static int                      pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
        static PyObject*        pyattr_get_meshes(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef);
-       static PyObject*        pyattr_get_is_valid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        
        /* for dir(), python3 uses __dir__() */
        static PyObject*        pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
@@ -913,7 +916,6 @@ public:
        static PyObject*                        Map_GetItem(PyObject *self_v, PyObject *item);
        static int                                      Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val);
        
-       
 private :
 
        /**     
@@ -931,5 +933,7 @@ private :
 
 };
 
+
+
 #endif //__KX_GAMEOBJECT
 
index 0fcd2c390783e0b4b58fee05faba2dc28aaa9740..29033c2d802179ad897300047b1c3b63977e4d25 100644 (file)
@@ -177,14 +177,6 @@ PyObject* KX_LightObject::py_getattro(PyObject *attr)
 {
        char *attr_str= PyString_AsString(attr);
        
-       if (ValidPythonToGameObject(this)==false) {
-               if (!strcmp(attr_str, "isValid")) {
-                       PyErr_Clear();
-                       Py_RETURN_FALSE;
-               }
-               return NULL;
-       }
-       
        if (!strcmp(attr_str, "layer"))
                return PyInt_FromLong(m_lightobj.m_layer);
        
@@ -229,9 +221,6 @@ int KX_LightObject::py_setattro(PyObject *attr, PyObject *pyvalue)
 {
        char *attr_str= PyString_AsString(attr);
        
-       if (ValidPythonToGameObject(this)==false)
-               return -1;
-       
        if (PyInt_Check(pyvalue))
        {
                int value = PyInt_AsLong(pyvalue);
@@ -347,7 +336,9 @@ PyTypeObject KX_LightObject::Type = {
                0,
                0,
                py_base_repr,
-               0,0,0,0,0,0,
+               0,0,
+               &KX_GameObject::Mapping,
+               0,0,0,
                py_base_getattro,
                py_base_setattro,
                0,0,0,0,0,0,0,0,0,
index c63167e2d5629fe194b6b377e83f0ce9ec9fc2c6..c99fa363ffe6ae77d45edb35c1b8572e7b24d9d1 100644 (file)
@@ -196,7 +196,7 @@ KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice,
        m_canvasDesignWidth = 0;
        m_canvasDesignHeight = 0;
        
-       m_attrlist = PyDict_New(); /* new ref */
+       m_attr_dict = PyDict_New(); /* new ref */
 }
 
 
@@ -250,8 +250,8 @@ KX_Scene::~KX_Scene()
        {
                delete m_bucketmanager;
        }
-       PyDict_Clear(m_attrlist);
-       Py_DECREF(m_attrlist);
+       PyDict_Clear(m_attr_dict);
+       Py_DECREF(m_attr_dict);
 }
 
 void KX_Scene::SetProjectionMatrix(MT_CmMatrix4x4& pmat)
@@ -924,6 +924,8 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
 {
        int ret;
        KX_GameObject* newobj = (KX_GameObject*) gameobj;
+       
+       gameobj->SetZombie(true); /* disallow future python access */
 
        // keep the blender->game object association up to date
        // note that all the replicas of an object will have the same
@@ -998,6 +1000,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
        if (m_sceneConverter)
                m_sceneConverter->UnregisterGameObject(newobj);
        // return value will be 0 if the object is actually deleted (all reference gone)
+       
        return ret;
 }
 
@@ -1591,7 +1594,7 @@ PyTypeObject KX_Scene::Type = {
                py_base_repr,
                0,0,0,0,0,0,
                py_base_getattro,
-               py_base_setattro_scene, /* unlike almost all other types we need out own because user attributes are supported */
+               py_base_setattro,
                0,0,0,0,0,0,0,0,0,
                Methods
 };
@@ -1633,12 +1636,12 @@ PyObject* KX_Scene::pyattr_get_active_camera(void *self_v, const KX_PYATTRIBUTE_
 PyObject* KX_Scene::pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
        KX_Scene* self= static_cast<KX_Scene*>(self_v);
-       /* Useually done by py_getattro_up but in this case we want to include m_attrlist dict */
+       /* Useually done by py_getattro_up but in this case we want to include m_attr_dict dict */
        PyObject *dict_str= PyString_FromString("__dict__");
        PyObject *dict= py_getattr_dict(self->PyObjectPlus::py_getattro(dict_str), Type.tp_dict);
        Py_DECREF(dict_str);
        
-       PyDict_Update(dict, self->m_attrlist);
+       PyDict_Update(dict, self->m_attr_dict);
        return dict;
 }
 
@@ -1654,28 +1657,59 @@ PyAttributeDef KX_Scene::Attributes[] = {
        { NULL }        //Sentinel
 };
 
+
+PyObject* KX_Scene::py_getattro__internal(PyObject *attr)
+{      
+       py_getattro_up(PyObjectPlus);
+}
+
+int KX_Scene::py_setattro__internal(PyObject *attr, PyObject *pyvalue)
+{
+       return PyObjectPlus::py_setattro(attr, pyvalue);
+}
+
 PyObject* KX_Scene::py_getattro(PyObject *attr)
 {
-       PyObject *object = PyDict_GetItem(m_attrlist, attr);
-       if (object)
+       PyObject *object = py_getattro__internal(attr);
+       
+       if (object==NULL)
        {
-               Py_INCREF(object);
-               return object;
+               PyErr_Clear();
+               object = PyDict_GetItem(m_attr_dict, attr);
+               if(object) {
+                       Py_INCREF(object);
+               }
+               else {
+                       PyErr_Format(PyExc_AttributeError, "KX_Scene attribute \"%s\" not found", PyString_AsString(attr));
+               }
        }
        
-       py_getattro_up(PyObjectPlus);
+       return object;
 }
 
-int KX_Scene::py_delattro(PyObject *attr)
+
+int KX_Scene::py_setattro(PyObject *attr, PyObject *value)
 {
-       PyDict_DelItem(m_attrlist, attr);
-       return 0;
+       int ret= py_setattro__internal(attr, value);
+       
+       if (ret==PY_SET_ATTR_MISSING) {
+               if (PyDict_SetItem(m_attr_dict, attr, value)==0) {
+                       PyErr_Clear();
+                       ret= PY_SET_ATTR_SUCCESS;
+               }
+               else {
+                       PyErr_SetString(PyExc_AttributeError, "failed assigning value to KX_Scenes internal dictionary");
+                       ret= PY_SET_ATTR_FAIL;
+               }
+       }
+       
+       return ret;
 }
 
-/* py_base_setattro_scene deals with setting the dict, it will run if this returns an error */
-int KX_Scene::py_setattro(PyObject *attr, PyObject *pyvalue)
+int KX_Scene::py_delattro(PyObject *attr)
 {
-       return PyObjectPlus::py_setattro(attr, pyvalue);
+       PyDict_DelItem(m_attr_dict, attr);
+       return 0;
 }
 
 KX_PYMETHODDEF_DOC_NOARGS(KX_Scene, getLightList,
index e1e89e253ed31ab7320f4589fafb5d888c7bbc44..a06c66ec5dd0dfd9a8ca645958a3cd6adf4117ee 100644 (file)
@@ -295,7 +295,7 @@ protected:
        /**
         * This stores anything from python
         */
-       PyObject* m_attrlist;
+       PyObject* m_attr_dict;
 
        struct Scene* m_blenderScene;
 
@@ -597,34 +597,14 @@ public:
        /* for dir(), python3 uses __dir__() */
        static PyObject*        pyattr_get_dir_dict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        
-       static int py_base_setattro_scene(PyObject * self, PyObject *attr, PyObject *value)
-       {
-               if (value==NULL)
-                       return ((PyObjectPlus*) self)->py_delattro(attr);
-               
-               int ret= ((PyObjectPlus*) self)->py_setattro(attr, value);
-               
-               if (ret==PY_SET_ATTR_MISSING) {
-                       if (PyDict_SetItem(((KX_Scene *) self)->m_attrlist, attr, value)==0) {
-                               PyErr_Clear();
-                               ret= PY_SET_ATTR_SUCCESS;
-                       }
-                       else {
-                               PyErr_Format(PyExc_AttributeError, "failed assigning value to KX_Scenes internal dictionary");
-                               ret= PY_SET_ATTR_FAIL;
-                       }
-               }
-               
-               return ret;
-       }
-       
-       
 
        virtual PyObject* py_getattro(PyObject *attr); /* name, active_camera, gravity, suspended, viewport, framing, activity_culling, activity_culling_radius */
        virtual int py_setattro(PyObject *attr, PyObject *pyvalue);
        virtual int py_delattro(PyObject *attr);
        virtual PyObject* py_repr(void) { return PyString_FromString(GetName().ReadPtr()); }
 
+       PyObject* py_getattro__internal(PyObject *attr);
+       int py_setattro__internal(PyObject *attr, PyObject *pyvalue);
                
        /**
         * Sets the time the scene was suspended
index 10117c3af9e08d5b304f54384354b62890c7bd89..3c703d75cdaba6c7f92f6cbebb7a71d356746c17 100644 (file)
@@ -22,7 +22,7 @@ http://www.gnu.org/copyleft/lesser.txt.
 
 #if defined WIN32
 #define WINDOWS_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
 #endif
 
 #include "VideoBase.h"