[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