[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [19885] trunk/blender/source/gameengine: BGE Python API
Campbell Barton
ideasman42 at gmail.com
Thu Apr 23 02:32:33 CEST 2009
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. @@
More information about the Bf-blender-cvs
mailing list