[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [20030] trunk/blender/source/gameengine/ GameLogic: BGE PyController module type.

Campbell Barton ideasman42 at gmail.com
Sat May 2 17:09:06 CEST 2009


Revision: 20030
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=20030
Author:   campbellbarton
Date:     2009-05-02 17:09:06 +0200 (Sat, 02 May 2009)

Log Message:
-----------
BGE PyController module type.
- Added support for any number of attributes, this means packages are supported automatically.
 so as well as "myModule.myFunc" you can do "myPackage.myModule.myFunc", nested packages work too.
- pass the controller to the python function as an argument for functions that take 1 arg, this check is only done at startup so it wont slow things down.

added support for 

Modified Paths:
--------------
    trunk/blender/source/gameengine/GameLogic/SCA_PythonController.cpp
    trunk/blender/source/gameengine/GameLogic/SCA_PythonController.h

Modified: trunk/blender/source/gameengine/GameLogic/SCA_PythonController.cpp
===================================================================
--- trunk/blender/source/gameengine/GameLogic/SCA_PythonController.cpp	2009-05-02 04:53:01 UTC (rev 20029)
+++ trunk/blender/source/gameengine/GameLogic/SCA_PythonController.cpp	2009-05-02 15:09:06 UTC (rev 20030)
@@ -53,6 +53,7 @@
 	: SCA_IController(gameobj, T),
 	m_bytecode(NULL),
 	m_function(NULL),
+	m_function_argc(0),
 	m_bModified(true),
 	m_debug(false),
 	m_mode(mode),
@@ -325,14 +326,14 @@
 	Py_XDECREF(m_function);
 	m_function= NULL;
 	
-	vector<STR_String> module_func = m_scriptText.Explode('.');
+	vector<STR_String> py_function_path = m_scriptText.Explode('.');
 	
-	if(module_func.size() != 2 || module_func[0].Length()==0 || module_func[1].Length()==0) {
-		printf("Python module name formatting error \"%s\":\n\texpected \"SomeModule.Func\", got \"%s\"", GetName().Ptr(), m_scriptText.Ptr());
+	if(py_function_path.size() < 2) {
+		printf("Python module name formatting error \"%s\":\n\texpected \"SomeModule.Func\", got \"%s\"\n", GetName().Ptr(), m_scriptText.Ptr());
 		return false;
 	}
 	
-	PyObject *mod = PyImport_ImportModule((char *)module_func[0].Ptr());
+	PyObject *mod = PyImport_ImportModule((char *)py_function_path[0].Ptr());
 	if(mod && m_debug) {
 		Py_DECREF(mod); /* getting a new one so dont hold a ref to the old one */
 		mod= PyImport_ReloadModule(mod);
@@ -342,25 +343,51 @@
 		ErrorPrint("Python module not found");
 		return false;
 	}
-	Py_DECREF(mod); /* will be added to sys.modules so no need to keep a ref */
+	/* 'mod' will be DECREF'd as 'base' 
+	 * 'm_function' will be left holding a reference that the controller owns */
 	
+	PyObject *base= mod;
 	
-	PyObject *dict=  PyModule_GetDict(mod);
-	m_function= PyDict_GetItemString(dict, module_func[1]); /* borrow */
+	for(unsigned int i=1; i < py_function_path.size(); i++) {
+		m_function = PyObject_GetAttrString(base, py_function_path[i].Ptr());
+		Py_DECREF(base);
+		base = m_function; /* for the next loop if there is on */
+		
+		if(m_function==NULL) {
+			PyErr_Clear(); /* print our own error below */
+			break;
+		}
+	}
 	
 	if(m_function==NULL) {
-		printf("Python module error \"%s\":\n \"%s\" module fount but function missing\n", GetName().Ptr(), m_scriptText.Ptr());
+		printf("Python module error \"%s\":\n \"%s\" module found but function missing\n", GetName().Ptr(), m_scriptText.Ptr());
 		return false;
 	}
 	
 	if(!PyCallable_Check(m_function)) {
-		printf("Python module function error \"%s\":\n \"%s\" not callable", GetName().Ptr(), m_scriptText.Ptr());
+		Py_DECREF(m_function);
+		printf("Python module function error \"%s\":\n \"%s\" not callable\n", GetName().Ptr(), m_scriptText.Ptr());
 		return false;
 	}
 	
-	Py_INCREF(m_function);
-	Py_INCREF(mod);
+	m_function_argc = 0; /* rare cases this could be a function that isnt defined in python, assume zero args */
+	if (PyFunction_Check(m_function)) {
+		PyObject *py_arg_count = PyObject_GetAttrString(PyFunction_GET_CODE(m_function), "co_argcount");
+		if(py_arg_count) {
+			m_function_argc = PyLong_AsLong(py_arg_count);
+			Py_DECREF(py_arg_count);
+		}
+		else {
+			PyErr_Clear(); /* unlikely to fail but just incase */
+		}
+	}
 	
+	if(m_function_argc > 1) {
+		Py_DECREF(m_function);
+		printf("Python module function has \"%s\":\n \"%s\" takes %d args, should be zero or 1 controller arg\n", GetName().Ptr(), m_scriptText.Ptr(), m_function_argc);
+		return false;
+	}
+	
 	return true;
 }
 
@@ -412,7 +439,15 @@
 		if (!m_function)
 			return;
 		
-		resultobj = PyObject_CallObject(m_function, NULL);
+		PyObject *args= NULL;
+		
+		if(m_function_argc==1) {
+			args = PyTuple_New(1);
+			PyTuple_SET_ITEM(args, 0, GetProxy());
+		}
+		
+		resultobj = PyObject_CallObject(m_function, args);
+		Py_XDECREF(args);
 		break;
 	}
 	
@@ -428,7 +463,7 @@
 	else
 	{
 		// something is wrong, tell the user what went wrong
-		printf("Python script error from controller \"%s\": \n", GetName().Ptr());
+		printf("Python script error from controller \"%s\":\n", GetName().Ptr());
 		PyErr_Print();
 		
 		/* Added in 2.48a, the last_traceback can reference Objects for example, increasing

Modified: trunk/blender/source/gameengine/GameLogic/SCA_PythonController.h
===================================================================
--- trunk/blender/source/gameengine/GameLogic/SCA_PythonController.h	2009-05-02 04:53:01 UTC (rev 20029)
+++ trunk/blender/source/gameengine/GameLogic/SCA_PythonController.h	2009-05-02 15:09:06 UTC (rev 20030)
@@ -44,9 +44,11 @@
 	Py_Header;
 	struct _object *		m_bytecode; /* SCA_PYEXEC_SCRIPT only */
 	PyObject*				m_function; /* SCA_PYEXEC_MODULE only */
+	int						m_function_argc;
 	bool					m_bModified;
 	bool					m_debug;	/* use with SCA_PYEXEC_MODULE for reloading every logic run */
 	int						m_mode;
+
 	
  protected:
 	STR_String				m_scriptText;





More information about the Bf-blender-cvs mailing list