Revision: 19885
          
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19885
Author:   campbellbarton
Date:     2009-04-23 02:32:33 +0200 (Thu, 23 Apr 2009)

Log Message:
-----------
BGE Python API

CListValue fixes
- Disable changing CValueLists that the BGE uses internally 
(scene.objects.append(1) would crash when drawing)
- val=clist+list would modify clist in place, now return a new value.
- clist.append([....]), was working like extend.
- clist.append(val) didnt work for most CValue types like KX_GameObjects.

Other changes
- "isValid" was always returning True.
- Set all errors for invalid proxy access to PyExc_SystemError (was using a mix 
of error types)
- Added PyObjectPlus::InvalidateProxy() to manually invalidate, though if 
python ever gains access again, it will make a new valid proxy. This is so 
removing an object from a scene can invalidate the object even if its stored 
elsewhere in a CValueList for eg.

Modified Paths:
--------------
    trunk/blender/source/gameengine/Expressions/ListValue.cpp
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
    trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
    trunk/blender/source/gameengine/Expressions/Value.cpp
    trunk/blender/source/gameengine/Expressions/Value.h
    trunk/blender/source/gameengine/Ketsji/KX_GameObject.cpp
    trunk/blender/source/gameengine/Ketsji/KX_MeshProxy.cpp
    trunk/blender/source/gameengine/Ketsji/KX_Scene.cpp
    trunk/blender/source/gameengine/Ketsji/KX_SceneActuator.cpp

Modified: trunk/blender/source/gameengine/Expressions/ListValue.cpp
===================================================================
--- trunk/blender/source/gameengine/Expressions/ListValue.cpp   2009-04-22 
23:01:40 UTC (rev 19884)
+++ trunk/blender/source/gameengine/Expressions/ListValue.cpp   2009-04-23 
00:32:33 UTC (rev 19885)
@@ -39,8 +39,10 @@
 PyObject* listvalue_buffer_item(PyObject* self, Py_ssize_t index)
 {
        CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
+       CValue *cval;
+       
        if (list==NULL) {
-               PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
+               PyErr_SetString(PyExc_SystemError, "val = CList[i], 
"BGE_PROXY_ERROR_MSG);
                return NULL;
        }
        
@@ -49,24 +51,25 @@
        if (index < 0)
                index = count+index;
        
-       if (index >= 0 && index < count)
-       {
-               PyObject* pyobj = list->GetValue(index)->ConvertValueToPython();
-               if (pyobj)
-                       return pyobj;
-               else
-                       return list->GetValue(index)->GetProxy();
-
+       if (index < 0 || index >= count) {
+               PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex 
out of range in CValueList");
+               return NULL;
        }
-       PyErr_SetString(PyExc_IndexError, "list[i]: Python ListIndex out of 
range in CValueList");
-       return NULL;
+       
+       cval= list->GetValue(index);
+       
+       PyObject* pyobj = cval->ConvertValueToPython();
+       if (pyobj)
+               return pyobj;
+       else
+               return cval->GetProxy();
 }
 
 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);
+               PyErr_SetString(PyExc_SystemError, "value = CList[i], 
"BGE_PROXY_ERROR_MSG);
                return NULL;
        }
        
@@ -85,7 +88,7 @@
        }
        
        PyObject *pyindex_str = PyObject_Repr(pyindex); /* new ref */
-       PyErr_Format(PyExc_KeyError, "list[key]: '%s' key not in list", 
PyString_AsString(pyindex_str));
+       PyErr_Format(PyExc_KeyError, "CList[key]: '%s' key not in list", 
PyString_AsString(pyindex_str));
        Py_DECREF(pyindex_str);
        return NULL;
 }
@@ -96,7 +99,7 @@
 {
        CListValue *list= static_cast<CListValue *>(BGE_PROXY_REF(self));
        if (list==NULL) {
-               PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
+               PyErr_SetString(PyExc_SystemError, "val = CList[i:j], 
"BGE_PROXY_ERROR_MSG);
                return NULL;
        }
        
@@ -127,73 +130,79 @@
 }
 
 
-
-static PyObject *
-listvalue_buffer_concat(PyObject * self, PyObject * other)
+/* clist + list, return a list that python owns */
+static PyObject *listvalue_buffer_concat(PyObject * self, PyObject * other)
 {
        CListValue *listval= static_cast<CListValue *>(BGE_PROXY_REF(self));
+       int i, numitems, numitems_orig;
+       
        if (listval==NULL) {
-               PyErr_SetString(PyExc_IndexError, BGE_PROXY_ERROR_MSG);
+               PyErr_SetString(PyExc_SystemError, "CList+other, 
"BGE_PROXY_ERROR_MSG);
                return NULL;
        }
        
+       numitems_orig= listval->GetCount();
+       
        // for now, we support CListValue concatenated with items
        // and CListValue concatenated to Python Lists
        // and CListValue concatenated with another CListValue
        
-       listval->AddRef();
-       if (other->ob_type == &PyList_Type)
+       /* Shallow copy, dont use listval->GetReplica(), it will screw up with 
KX_GameObjects */
+       CListValue* listval_new = new CListValue();
+       
+       if (PyList_Check(other))
        {
+               CValue* listitemval;
                bool error = false;
-
-               int i;
-               int numitems = PyList_Size(other);
+               
+               numitems = PyList_Size(other);
+               
+               /* copy the first part of the list */
+               listval_new->Resize(numitems_orig + numitems);
+               for (i=0;i<numitems_orig;i++)
+                       listval_new->SetValue(i, 
listval->GetValue(i)->AddRef());
+               
                for (i=0;i<numitems;i++)
                {
-                       PyObject* listitem = PyList_GetItem(other,i);
-                       CValue* listitemval = 
listval->ConvertPythonToValue(listitem);
-                       if (listitemval)
-                       {
-                               listval->Add(listitemval);
-                       } else
-                       {
-                               error = true;
+                       listitemval = 
listval->ConvertPythonToValue(PyList_GetItem(other,i), "cList + pyList: 
CListValue, ");
+                       
+                       if (listitemval) {
+                               listval_new->SetValue(i+numitems_orig, 
listitemval);
+                       } else {
+                               error= true;
+                               break;
                        }
                }
-
+               
                if (error) {
-                       PyErr_SetString(PyExc_SystemError, "list.append(val): 
couldn't add one or more items to this CValueList");
+                       listval_new->Resize(numitems_orig+i); /* resize so we 
dont try release NULL pointers */
+                       listval_new->Release();
+                       return NULL; /* ConvertPythonToValue above sets the 
error */ 
+               }
+       
+       }
+       else if (PyObject_TypeCheck(other, &CListValue::Type)) {
+               // add items from otherlist to this list
+               CListValue* otherval = static_cast<CListValue 
*>(BGE_PROXY_REF(other));
+               if(otherval==NULL) {
+                       listval_new->Release();
+                       PyErr_SetString(PyExc_SystemError, "CList+other, 
"BGE_PROXY_ERROR_MSG);
                        return NULL;
                }
-
-       } else
-       {
-               if (other->ob_type == &CListValue::Type)
-               {
-                       // add items from otherlist to this list
-                       CListValue* otherval = (CListValue*) other;
-                       
-
-                       for (int i=0;i<otherval->GetCount();i++)
-                       {
-                               otherval->Add(listval->GetValue(i)->AddRef());
-                       }
-               }
-               else
-               {
-                       CValue* objval = listval->ConvertPythonToValue(other);
-                       if (objval)
-                       {
-                               listval->Add(objval);
-                       } else
-                       {
-                               PyErr_SetString(PyExc_SystemError, 
"list.append(i): couldn't add item to this CValueList");
-                               return NULL;
-                       }
-               }
+               
+               numitems = otherval->GetCount();
+               
+               /* copy the first part of the list */
+               listval_new->Resize(numitems_orig + numitems); /* resize so we 
dont try release NULL pointers */
+               for (i=0;i<numitems_orig;i++)
+                       listval_new->SetValue(i, 
listval->GetValue(i)->AddRef());
+               
+               /* now copy the other part of the list */
+               for (i=0;i<numitems;i++)
+                       listval_new->SetValue(i+numitems_orig, 
otherval->GetValue(i)->AddRef());
+               
        }
-
-       return self;
+       return listval_new->NewProxy(true); /* python owns this list */
 }
 
 
@@ -437,14 +446,24 @@
        {
                SetValue(i+numelements,otherlist->GetValue(i)->AddRef());
        }
-
 }
 
 
-
 PyObject* CListValue::Pyappend(PyObject* value)
 {
-       return listvalue_buffer_concat(m_proxy, value); /* m_proxy is the same 
as self */
+       CValue* objval = ConvertPythonToValue(value, "CList.append(i): 
CValueList, ");
+
+       if (!objval) /* ConvertPythonToValue sets the error */
+               return NULL;
+       
+       if (!BGE_PROXY_PYOWNS(m_proxy)) {
+               PyErr_SetString(PyExc_TypeError, "CList.append(i): this 
CValueList is used internally for the game engine and can't be modified");
+               return NULL;
+       }
+       
+       Add(objval);
+       
+       Py_RETURN_NONE;
 }
 
 
@@ -482,7 +501,7 @@
 {
        PyObject* result = NULL;
 
-       CValue* checkobj = ConvertPythonToValue(value);
+       CValue* checkobj = ConvertPythonToValue(value, "val = cList[i]: 
CValueList, ");
        if (checkobj==NULL)
                return NULL; /* ConvertPythonToValue sets the error */
 
@@ -499,7 +518,7 @@
        checkobj->Release();
 
        if (result==NULL) {
-               PyErr_SetString(PyExc_ValueError, "list.index(x): x not in 
CListValue");
+               PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in 
CListValue");
        }
        return result;
        
@@ -511,7 +530,7 @@
 {
        int numfound = 0;
 
-       CValue* checkobj = ConvertPythonToValue(value);
+       CValue* checkobj = ConvertPythonToValue(value, "cList.count(val): 
CValueList, ");
        
        if (checkobj==NULL) { /* in this case just return that there are no 
items in the list */
                PyErr_Clear();

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp        
2009-04-22 23:01:40 UTC (rev 19884)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.cpp        
2009-04-23 00:32:33 UTC (rev 19885)
@@ -138,9 +138,9 @@
        PyObjectPlus *self_plus= BGE_PROXY_REF(self);
        if(self_plus==NULL) {
                if(!strcmp("isValid", PyString_AsString(attr))) {
-                       Py_RETURN_TRUE;
+                       Py_RETURN_FALSE;
                }
-               PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG);
+               PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
                return NULL;
        }
        
@@ -171,7 +171,7 @@
 {
        PyObjectPlus *self_plus= BGE_PROXY_REF(self);
        if(self_plus==NULL) {
-               PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG);
+               PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
                return -1;
        }
        
@@ -186,7 +186,7 @@
        
        PyObjectPlus *self_plus= BGE_PROXY_REF(self);
        if(self_plus==NULL) {
-               PyErr_SetString(PyExc_RuntimeError, BGE_PROXY_ERROR_MSG);
+               PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG);
                return NULL;
        }
        
@@ -818,6 +818,23 @@
        m_proxy= NULL;
 }
 
+/* Sometimes we might want to manually invalidate a BGE type even if
+ * it hasnt been released by the BGE, say for example when an object
+ * is removed from a scene, accessing it may cause problems.
+ * 
+ * In this case the current proxy is made invalid, disowned,
+ * and will raise an error on access. However if python can get access
+ * to this class again it will make a new proxy and work as expected.
+ */
+void PyObjectPlus::InvalidateProxy()           // check typename of each parent
+{
+       if(m_proxy) { 
+               BGE_PROXY_REF(m_proxy)=NULL;
+               Py_DECREF(m_proxy);
+               m_proxy= NULL;
+       }
+}
+
 /* 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

Modified: trunk/blender/source/gameengine/Expressions/PyObjectPlus.h
===================================================================
--- trunk/blender/source/gameengine/Expressions/PyObjectPlus.h  2009-04-22 
23:01:40 UTC (rev 19884)
+++ trunk/blender/source/gameengine/Expressions/PyObjectPlus.h  2009-04-23 
00:32:33 UTC (rev 19885)
@@ -451,6 +451,8 @@
        static PyObject *GetProxy_Ext(PyObjectPlus *self, PyTypeObject *tp);
        static PyObject *NewProxy_Ext(PyObjectPlus *self, PyTypeObject *tp, 
bool py_owns);
        
+       void    InvalidateProxy();
+       
        /**
         * Makes sure any internal data owned by this class is deep copied.
         */

Modified: trunk/blender/source/gameengine/Expressions/Value.cpp
===================================================================
--- trunk/blender/source/gameengine/Expressions/Value.cpp       2009-04-22 
23:01:40 UTC (rev 19884)
+++ trunk/blender/source/gameengine/Expressions/Value.cpp       2009-04-23 
00:32:33 UTC (rev 19885)
@@ -604,7 +604,7 @@
        py_getattro_dict_up(PyObjectPlus);
 }
 
-CValue* CValue::ConvertPythonToValue(PyObject* pyobj)
+CValue* CValue::ConvertPythonToValue(PyObject* pyobj, const char *error_prefix)
 {
 
        CValue* vallie = NULL;
@@ -620,7 +620,7 @@
                for (i=0;i<numitems;i++)
                {
                        PyObject* listitem = PyList_GetItem(pyobj,i); /* 
borrowed ref */
-                       CValue* listitemval = ConvertPythonToValue(listitem);

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
Bf-blender-cvs@blender.org
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to