synched with trunk at revision 36569
[blender.git] / source / gameengine / Ketsji / KX_PythonInit.cpp
index a920237..69d6ebc 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * Initialize Python thingies.
  */
 
+/** \file gameengine/Ketsji/KX_PythonInit.cpp
+ *  \ingroup ketsji
+ */
+
+
 #include "GL/glew.h"
 
 #if defined(WIN32) && !defined(FREE_WINDOWS)
@@ -642,7 +647,7 @@ static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *)
        Py_RETURN_NONE;
 }
 
-static PyObject *gLibLoad(PyObject*, PyObject* args)
+static PyObject *gLibLoad(PyObject*, PyObject* args, PyObject* kwds)
 {
        KX_Scene *kx_scene= gp_KetsjiScene;
        char *path;
@@ -650,20 +655,37 @@ static PyObject *gLibLoad(PyObject*, PyObject* args)
        Py_buffer py_buffer;
        py_buffer.buf = NULL;
        char *err_str= NULL;
+
+       short options=0;
+       int load_actions=0, verbose=0;
+
+       static const char *kwlist[] = {"path", "group", "buffer", "load_actions", "verbose", NULL};
        
-       if (!PyArg_ParseTuple(args,"ss|y*:LibLoad",&path, &group, &py_buffer))
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|y*ii:LibLoad", const_cast<char**>(kwlist),
+                                                                       &path, &group, &py_buffer, &load_actions, &verbose))
                return NULL;
 
+       /* setup options */
+       if (load_actions != 0)
+               options |= KX_BlenderSceneConverter::LIB_LOAD_LOAD_ACTIONS;
+       if (verbose != 0)
+               options |= KX_BlenderSceneConverter::LIB_LOAD_VERBOSE;
+
        if (!py_buffer.buf)
        {
-               if(kx_scene->GetSceneConverter()->LinkBlendFilePath(path, group, kx_scene, &err_str)) {
+               char abs_path[FILE_MAX];
+               // Make the path absolute
+               BLI_strncpy(abs_path, path, sizeof(abs_path));
+               BLI_path_abs(abs_path, gp_GamePythonPath);
+
+               if(kx_scene->GetSceneConverter()->LinkBlendFilePath(abs_path, group, kx_scene, &err_str, options)) {
                        Py_RETURN_TRUE;
                }
        }
        else
        {
 
-               if(kx_scene->GetSceneConverter()->LinkBlendFileMemory(py_buffer.buf, py_buffer.len, path, group, kx_scene, &err_str))   {
+               if(kx_scene->GetSceneConverter()->LinkBlendFileMemory(py_buffer.buf, py_buffer.len, path, group, kx_scene, &err_str, options))  {
                        PyBuffer_Release(&py_buffer);
                        Py_RETURN_TRUE;
                }
@@ -797,7 +819,7 @@ static struct PyMethodDef game_methods[] = {
        {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine stastics"},
        
        /* library functions */
-       {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS, (const char *)""},
+       {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS|METH_KEYWORDS, (const char *)""},
        {"LibNew", (PyCFunction)gLibNew, METH_VARARGS, (const char *)""},
        {"LibFree", (PyCFunction)gLibFree, METH_VARARGS, (const char *)""},
        {"LibList", (PyCFunction)gLibList, METH_VARARGS, (const char *)""},
@@ -930,12 +952,12 @@ static PyObject* gPySetBackgroundColor(PyObject*, PyObject* value)
        
        if (gp_Canvas)
        {
-               gp_Rasterizer->SetBackColor(vec[0], vec[1], vec[2], vec[3]);
+               gp_Rasterizer->SetBackColor((float)vec[0], (float)vec[1], (float)vec[2], (float)vec[3]);
        }
 
        KX_WorldInfo *wi = gp_KetsjiScene->GetWorldInfo();
        if (wi->hasWorld())
-               wi->setBackColor(vec[0], vec[1], vec[2]);
+               wi->setBackColor((float)vec[0], (float)vec[1], (float)vec[2]);
 
        Py_RETURN_NONE;
 }
@@ -953,7 +975,7 @@ static PyObject* gPySetMistColor(PyObject*, PyObject* value)
                PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMistColor(color), Rasterizer not available");
                return NULL;
        }       
-       gp_Rasterizer->SetFogColor(vec[0], vec[1], vec[2]);
+       gp_Rasterizer->SetFogColor((float)vec[0], (float)vec[1], (float)vec[2]);
        
        Py_RETURN_NONE;
 }
@@ -1018,7 +1040,7 @@ static PyObject* gPySetAmbientColor(PyObject*, PyObject* value)
                PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setAmbientColor(color), Rasterizer not available");
                return NULL;
        }       
-       gp_Rasterizer->SetAmbientColor(vec[0], vec[1], vec[2]);
+       gp_Rasterizer->SetAmbientColor((float)vec[0], (float)vec[1], (float)vec[2]);
        
        Py_RETURN_NONE;
 }
@@ -1407,6 +1429,7 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack
 
        /* 7. Action actuator                                                                                                      */
        KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PLAY,        ACT_ACTION_PLAY);
+       KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PINGPONG,    ACT_ACTION_PINGPONG);
        KX_MACRO_addTypesToDict(d, KX_ACTIONACT_FLIPPER,     ACT_ACTION_FLIPPER);
        KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPSTOP,    ACT_ACTION_LOOP_STOP);
        KX_MACRO_addTypesToDict(d, KX_ACTIONACT_LOOPEND,     ACT_ACTION_LOOP_END);
@@ -1633,176 +1656,6 @@ PyObject* initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack
        return m;
 }
 
-// Python Sandbox code
-// override builtin functions import() and open()
-
-
-PyObject *KXpy_open(PyObject *self, PyObject *args) {
-       PyErr_SetString(PyExc_RuntimeError, "Sandbox: open() function disabled!\nGame Scripts should not use this function.");
-       return NULL;
-}
-
-PyObject *KXpy_file(PyObject *self, PyObject *args) {
-       PyErr_SetString(PyExc_RuntimeError, "Sandbox: file() function disabled!\nGame Scripts should not use this function.");
-       return NULL;
-}
-
-PyObject *KXpy_execfile(PyObject *self, PyObject *args) {
-       PyErr_SetString(PyExc_RuntimeError, "Sandbox: execfile() function disabled!\nGame Scripts should not use this function.");
-       return NULL;
-}
-
-PyObject *KXpy_compile(PyObject *self, PyObject *args) {
-       PyErr_SetString(PyExc_RuntimeError, "Sandbox: compile() function disabled!\nGame Scripts should not use this function.");
-       return NULL;
-}
-
-PyObject *KXpy_import(PyObject *self, PyObject *args)
-{
-       char *name;
-       int found;
-       PyObject *globals = NULL;
-       PyObject *locals = NULL;
-       PyObject *fromlist = NULL;
-       PyObject *l, *m, *n;
-       int level; /* not used yet */
-       
-       if (!PyArg_ParseTuple(args, "s|OOOi:m_import",
-               &name, &globals, &locals, &fromlist, &level))
-           return NULL;
-
-       /* check for builtin modules */
-       m = PyImport_AddModule("sys");
-       l = PyObject_GetAttrString(m, "builtin_module_names");
-       n = PyUnicode_FromString(name);
-       
-       if (PySequence_Contains(l, n)) {
-               return PyImport_ImportModuleEx(name, globals, locals, fromlist);
-       }
-
-       /* quick hack for GamePython modules 
-               TODO: register builtin modules properly by ExtendInittab */
-       if (!strcmp(name, "GameLogic") || !strcmp(name, "GameKeys") || !strcmp(name, "PhysicsConstraints") ||
-               !strcmp(name, "Rasterizer") || !strcmp(name, "mathutils") || !strcmp(name, "bgl") || !strcmp(name, "geometry")) {
-               return PyImport_ImportModuleEx(name, globals, locals, fromlist);
-       }
-       
-       /* Import blender texts as python modules */
-       m= bpy_text_import_name(name, &found);
-       if (m)
-               return m;
-       
-       if(found==0) /* if its found but could not import then it has its own error */
-               PyErr_Format(PyExc_ImportError, "Import of external Module %.20s not allowed.", name);
-       
-       return NULL;
-
-}
-
-PyObject *KXpy_reload(PyObject *self, PyObject *args) {
-       
-       /* Used to be sandboxed, bettet to allow importing of internal text only */ 
-#if 0
-       PyErr_SetString(PyExc_RuntimeError, "Sandbox: reload() function disabled!\nGame Scripts should not use this function.");
-       return NULL;
-#endif
-       int found;
-       PyObject *module = NULL;
-       PyObject *newmodule = NULL;
-
-       /* check for a module arg */
-       if( !PyArg_ParseTuple( args, "O:bpy_reload_meth", &module ) )
-               return NULL;
-       
-       newmodule= bpy_text_reimport( module, &found );
-       if (newmodule)
-               return newmodule;
-       
-       if (found==0) /* if its found but could not import then it has its own error */
-               PyErr_SetString(PyExc_ImportError, "reload(module): failed to reload from blenders internal text");
-       
-       return newmodule;
-}
-
-/* override python file type functions */
-#if 0
-static int
-file_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
-       KXpy_file(NULL, NULL);
-       return -1;
-}
-
-static PyObject *
-file_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-       return KXpy_file(NULL, NULL);
-}
-#endif
-
-static PyMethodDef meth_open[] = {{ "open", KXpy_open, METH_VARARGS, "(disabled)"}};
-static PyMethodDef meth_reload[] = {{ "reload", KXpy_reload, METH_VARARGS, "(disabled)"}};
-static PyMethodDef meth_file[] = {{ "file", KXpy_file, METH_VARARGS, "(disabled)"}};
-static PyMethodDef meth_execfile[] = {{ "execfile", KXpy_execfile, METH_VARARGS, "(disabled)"}};
-static PyMethodDef meth_compile[] = {{ "compile", KXpy_compile, METH_VARARGS, "(disabled)"}};
-
-static PyMethodDef meth_import[] = {{ "import", KXpy_import, METH_VARARGS, "our own import"}};
-
-//static PyObject *g_oldopen = 0;
-//static PyObject *g_oldimport = 0;
-//static int g_security = 0;
-
-static void setSandbox(TPythonSecurityLevel level)
-{
-    PyObject *m = PyImport_AddModule("__builtin__");
-    PyObject *d = PyModule_GetDict(m);
-       PyObject *item;
-       switch (level) {
-       case psl_Highest:
-               //if (!g_security) {
-                       //g_oldopen = PyDict_GetItemString(d, "open");
-       
-                       // functions we cant trust
-                       PyDict_SetItemString(d, "open", item=PyCFunction_New(meth_open, NULL));                 Py_DECREF(item);
-                       PyDict_SetItemString(d, "reload", item=PyCFunction_New(meth_reload, NULL));             Py_DECREF(item);
-                       PyDict_SetItemString(d, "file", item=PyCFunction_New(meth_file, NULL));                 Py_DECREF(item);
-                       PyDict_SetItemString(d, "execfile", item=PyCFunction_New(meth_execfile, NULL)); Py_DECREF(item);
-                       PyDict_SetItemString(d, "compile", item=PyCFunction_New(meth_compile, NULL));           Py_DECREF(item);
-                       
-                       // our own import
-                       PyDict_SetItemString(d, "__import__", PyCFunction_New(meth_import, NULL));
-                       //g_security = level;
-                       
-                       // Overiding file dosnt stop it being accessed if your sneaky
-                       //    f =  [ t for t in (1).__class__.__mro__[-1].__subclasses__() if t.__name__ == 'file'][0]('/some_file.txt', 'w')
-                       //    f.write('...')
-                       // so overwrite the file types functions. be very careful here still, since python uses python.
-                       // ps - python devs frown deeply upon this.
-       
-                       /* this could mess up pythons internals, if we are serious about sandboxing
-                        * issues like the one above need to be solved, possibly modify __subclasses__ is safer? */
-#if 0
-                       PyFile_Type.tp_init = file_init;
-                       PyFile_Type.tp_new = file_new;
-#endif
-               //}
-               break;
-       /*
-       case psl_Lowest:
-               if (g_security) {
-                       PyDict_SetItemString(d, "open", g_oldopen);
-                       PyDict_SetItemString(d, "__import__", g_oldimport);
-                       g_security = level;
-               }
-       */
-       default:
-                       /* Allow importing internal text, from bpy_internal_import.py */
-                       PyDict_SetItemString(d, "reload", item=PyCFunction_New(&bpy_reload_meth, NULL));                Py_DECREF(item);
-                       PyDict_SetItemString(d, "__import__", item=PyCFunction_New(&bpy_import_meth, NULL));    Py_DECREF(item);
-               break;
-       }
-}
-
 /* Explanation of 
  * 
  * - backupPySysObjects()              : stores sys.path in gp_OrigPythonSysPath
@@ -1913,8 +1766,18 @@ static void restorePySysObjects(void)
 //     PyObject_Print(sys_path, stderr, 0);
 }
 
+// Copied from bpy_interface.c
+static struct _inittab bge_internal_modules[]= {
+       {(char *)"mathutils", BPyInit_mathutils},
+       {(char *)"bgl", BPyInit_bgl},
+       {(char *)"blf", BPyInit_blf},
+       {(char *)"aud", AUD_initPython},
+       {NULL, NULL}
+};
+
 /**
  * Python is not initialised.
+ * see bpy_interface.c's BPY_python_start() which shares the same functionality in blender.
  */
 PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv)
 {
@@ -1932,6 +1795,13 @@ PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur
 #endif
        Py_NoSiteFlag=1;
        Py_FrozenFlag=1;
+
+       /* must run before python initializes */
+       PyImport_ExtendInittab(bge_internal_modules);
+
+       /* find local python installation */
+       PyC_SetHomePath(BLI_get_folder(BLENDER_PYTHON, NULL));
+
        Py_Initialize();
        
        if(argv && first_time) { /* browser plugins dont currently set this */
@@ -1946,8 +1816,15 @@ PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur
                PySys_SetObject("argv", py_argv);
                Py_DECREF(py_argv);
        }
-       
-       setSandbox(level);
+
+       bpy_import_init(PyEval_GetBuiltins());
+
+       /* mathutils types are used by the BGE even if we dont import them */
+       {
+               PyObject *mod= PyImport_ImportModuleLevel((char *)"mathutils", NULL, NULL, NULL, 0);
+               Py_DECREF(mod);
+       }
+
        initPyTypes();
        
        bpy_import_main_set(maggie);
@@ -1992,7 +1869,6 @@ PyObject* initGamePythonScripting(const STR_String& progname, TPythonSecurityLev
        Py_NoSiteFlag=1;
        Py_FrozenFlag=1;
 
-       setSandbox(level);
        initPyTypes();
        
        bpy_import_main_set(maggie);
@@ -2041,11 +1917,6 @@ void setupGamePython(KX_KetsjiEngine* ketsjiengine, KX_Scene* startscene, Main *
 
        initGameKeys();
        initPythonConstraintBinding();
-       initMathutils();
-       initGeometry();
-       initBGL();
-       initBLF();
-       AUD_initPython();
        initVideoTexture();
 
        /* could be done a lot more nicely, but for now a quick way to get bge.* working */
@@ -2354,26 +2225,6 @@ PyObject* initGameKeys()
        return d;
 }
 
-PyObject* initMathutils()
-{
-       return BPyInit_mathutils();
-}
-
-PyObject* initGeometry()
-{
-       return BPyInit_mathutils_geometry();
-}
-
-PyObject* initBGL()
-{
-       return BPyInit_bgl();
-}
-
-PyObject* initBLF()
-{
-       return BPyInit_blf();
-}
-
 // utility function for loading and saving the globalDict
 int saveGamePythonConfig( char **marshal_buffer)
 {