[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