[Bf-committers] [Bf-blender-cvs] SVN commit: /data/svn/bf-blender [19999] trunk/blender/source: BGE Python sys.path for the blenderplayer and blender

joe joeedh at gmail.com
Fri May 1 00:12:24 CEST 2009


I think having the option to load scripts next to the .blend kindof
makes sense, though. . .might be annoying having to *always* make
scripts/ directories.

Joe

On Thu, Apr 30, 2009 at 2:01 AM, Campbell Barton <ideasman42 at gmail.com> wrote:
> Revision: 19999
>          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=19999
> Author:   campbellbarton
> Date:     2009-04-30 10:01:31 +0200 (Thu, 30 Apr 2009)
>
> Log Message:
> -----------
> BGE Python sys.path for the blenderplayer and blender
> sys.path is the search path for python modules. This is useful so people making games can put all their scripts in a folder and be sure they will always load into the BGE.
>
> for each blend file a scripts directory is added to the path
>  /home/me/foo.blend
> will look for modules in...
>  /home/me/scripts/*.py
>
> It could also default to look for modules in the same directory as the blend file but I think this is messy.
> Added a note in the tooltip about //scripts so its not such a hidden feature.
>
> This works by storing the original sys.path, then adding the paths for the blendfile and all its libs,
> when a new blendfile is loaded, the original sys.path is restored before adding the blendfiles paths again so the sys.path wont get junk in it.
>
> One problem with this - when using linked libs the module names must be unique else it will load the wrong module for one of the controllers.
>
> also fixed 2 bugs
> - sys.path in the blenderplayer was growing by 1 for every file load in blenderplayer
> - the relative path (gp_GamePythonPath), wasnt being set when loading files in the blenderlayer (as I wrongly said in the last commit).
>
> Modified Paths:
> --------------
>    trunk/blender/source/blender/src/buttons_logic.c
>    trunk/blender/source/gameengine/GamePlayer/ActiveX/BlenderPlayerCtl.cpp
>    trunk/blender/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
>    trunk/blender/source/gameengine/Ketsji/KX_PythonInit.cpp
>
> Modified: trunk/blender/source/blender/src/buttons_logic.c
> ===================================================================
> --- trunk/blender/source/blender/src/buttons_logic.c    2009-04-30 03:46:31 UTC (rev 19998)
> +++ trunk/blender/source/blender/src/buttons_logic.c    2009-04-30 08:01:31 UTC (rev 19999)
> @@ -1580,12 +1580,12 @@
>
>
>                uiBlockBeginAlign(block);
> -               uiDefButI(block, MENU, B_REDR, "Execution Method%t|Script%x0|Module%x1", xco+24,yco-24, 66, 19, &pc->mode, 0, 0, 0, 0, "Python script type (textblock or module)");
> +               uiDefButI(block, MENU, B_REDR, "Execution Method%t|Script%x0|Module%x1", xco+24,yco-24, 66, 19, &pc->mode, 0, 0, 0, 0, "Python script type (textblock or module - faster)");
>                if(pc->mode==0)
>                        uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "", xco+90,yco-24,width-90, 19, &pc->text, "Blender textblock to run as a script");
>                else {
> -                       uiDefBut(block, TEX, 1, "", xco+90,yco-24,(width-90)-25, 19, pc->module, 0, 63, 0, 0, "Module name and function to run eg \"someModule.main\"");
> -                       uiDefButBitI(block, TOG, CONT_PY_DEBUG, B_REDR, "D", (xco+width)-25, yco-24, 19, 19, &pc->flag, 0, 0, 0, 0, "Continuously reload the module from disk for editing external modules without restrting, (slow)");
> +                       uiDefBut(block, TEX, 1, "", xco+90,yco-24,(width-90)-25, 19, pc->module, 0, 63, 0, 0, "Module name and function to run eg \"someModule.main\", internal texts and //scripts/*.py on the filesystem can be used");
> +                       uiDefButBitI(block, TOG, CONT_PY_DEBUG, B_REDR, "D", (xco+width)-25, yco-24, 19, 19, &pc->flag, 0, 0, 0, 0, "Continuously reload the module from disk for editing external modules without restrting");
>                }
>                uiBlockEndAlign(block);
>
>
> Modified: trunk/blender/source/gameengine/GamePlayer/ActiveX/BlenderPlayerCtl.cpp
> ===================================================================
> --- trunk/blender/source/gameengine/GamePlayer/ActiveX/BlenderPlayerCtl.cpp     2009-04-30 03:46:31 UTC (rev 19998)
> +++ trunk/blender/source/gameengine/GamePlayer/ActiveX/BlenderPlayerCtl.cpp     2009-04-30 08:01:31 UTC (rev 19999)
> @@ -662,9 +662,6 @@
>                                m_gamedata->curscene);
>
>                        PyObject* m_dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Highest, m_gamedata->main, 0, NULL);
> -                       //PyObject* m_dictionaryobject = initGamePlayerPythonScripting("Ketsji", psl_Lowest, m_gamedata->main, 0, NULL);
> -
> -                       ///python scripting doesn't work
>                        m_ketsjiengine->SetPythonDictionary(m_dictionaryobject);
>
>                        initRasterizer(m_rasterizer, m_canvas);
>
> Modified: trunk/blender/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
> ===================================================================
> --- trunk/blender/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp      2009-04-30 03:46:31 UTC (rev 19998)
> +++ trunk/blender/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp      2009-04-30 08:01:31 UTC (rev 19999)
> @@ -704,10 +704,10 @@
>
>                                                BLI_strncpy(pathname, maggie->name, sizeof(pathname));
>                                                BLI_strncpy(G.sce, maggie->name, sizeof(G.sce));
> +                                               setGamePythonPath(G.sce);
>
>                                                if (firstTimeRunning)
>                                                {
> -                                                       setGamePythonPath(G.sce);
>                                                        firstTimeRunning = false;
>
>                                                        if (fullScreen)
>
> Modified: trunk/blender/source/gameengine/Ketsji/KX_PythonInit.cpp
> ===================================================================
> --- trunk/blender/source/gameengine/Ketsji/KX_PythonInit.cpp    2009-04-30 03:46:31 UTC (rev 19998)
> +++ trunk/blender/source/gameengine/Ketsji/KX_PythonInit.cpp    2009-04-30 08:01:31 UTC (rev 19999)
> @@ -80,6 +80,10 @@
>
>  #include "KX_PythonInitTypes.h"
>
> +/* we only need this to get a list of libraries from the main struct */
> +#include "DNA_ID.h"
> +#include "BKE_main.h"
> +
>  extern "C" {
>        #include "Mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use.
>        #include "bpy_internal_import.h"  /* from the blender python api, but we want to import text too! */
> @@ -110,6 +114,7 @@
>  static KX_KetsjiEngine*        gp_KetsjiEngine = NULL;
>  static RAS_IRasterizer* gp_Rasterizer = NULL;
>  static char gp_GamePythonPath[FILE_MAXDIR + FILE_MAXFILE] = "";
> +static PyObject *gp_OrigPythonSysPath= NULL;
>
>  void   KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color)
>  {
> @@ -1522,11 +1527,111 @@
>        }
>  }
>
> +/* Explanation of
> + *
> + * - backupPySysPath()         : stores sys.path in gp_OrigPythonSysPath
> + * - initPySysPath(main)       : initializes the blendfile and library paths
> + * - restorePySysPath()                : restores sys.path from gp_OrigPythonSysPath
> + *
> + * These exist so the //scripts folder can always be used to import modules from.
> + * the reason we need a few functions for this is that python is not only used by the game engine
> + * so we cant just add to sys.path all the time, it would leave pythons state in a mess.
> + * It would also be incorrect since loading blend files for new levels etc would alwasy add to sys.path
> + *
> + * To play nice with blenders python, the sys.path is backed up and the current blendfile along
> + * with all its lib paths are added to the sys path.
> + * When loading a new blendfile, the original sys.path is restored and the new paths are added over the top.
> + */
> +
>  /**
> + * So we can have external modules mixed with our blend files.
> + */
> +static void backupPySysPath(void)
> +{
> +       PyObject *sys_path= PySys_GetObject("path"); /* should never fail */
> +
> +       /* just incase its set */
> +       Py_XDECREF(gp_OrigPythonSysPath);
> +       gp_OrigPythonSysPath= NULL;
> +
> +       gp_OrigPythonSysPath = PyList_GetSlice(sys_path, 0, INT_MAX); /* copy the list */
> +}
> +
> +/* for initPySysPath only,
> + * takes a blend path and adds a scripts dir from it
> + *
> + * "/home/me/foo.blend" -> "/home/me/scripts"
> + */
> +static void initPySysPath__append(PyObject *sys_path, char *filename)
> +{
> +       PyObject *item;
> +       char expanded[FILE_MAXDIR + FILE_MAXFILE] = "//";
> +
> +       BLI_convertstringcode(expanded, filename);
> +       BLI_join_dirfile(expanded, expanded, "scripts"); /* double checked and using the dir twice is safe */
> +
> +       item= PyString_FromString(expanded);
> +
> +       if(PySequence_Index(sys_path, item) == -1) {
> +               PyList_Insert(sys_path, 0, item);
> +       }
> +
> +       Py_DECREF(item);
> +}
> +static void initPySysPath(Main *maggie)
> +{
> +       PyObject *sys_path= PySys_GetObject("path"); /* should never fail */
> +
> +       if (gp_OrigPythonSysPath==NULL) {
> +               /* backup */
> +               backupPySysPath();
> +       }
> +       else {
> +               /* get the original sys path when the BGE started */
> +               PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath);
> +       }
> +
> +       Library *lib= (Library *)maggie->library.first;
> +
> +       while(lib) {
> +               initPySysPath__append(sys_path, lib->name);
> +               lib= (Library *)lib->id.next;
> +       }
> +
> +       initPySysPath__append(sys_path, gp_GamePythonPath);
> +
> +//     fprintf(stderr, "\nNew Path: %d ", PyList_Size(sys_path));
> +//     PyObject_Print(sys_path, stderr, 0);
> +}
> +
> +static void restorePySysPath(void)
> +{
> +       if (gp_OrigPythonSysPath==NULL)
> +               return;
> +
> +       PyObject *sys_path= PySys_GetObject("path"); /* should never fail */
> +
> +       PyList_SetSlice(sys_path, 0, INT_MAX, gp_OrigPythonSysPath);
> +       Py_DECREF(gp_OrigPythonSysPath);
> +       gp_OrigPythonSysPath= NULL;
> +
> +//     fprintf(stderr, "\nRestore Path: %d ", PyList_Size(sys_path));
> +//     PyObject_Print(sys_path, stderr, 0);
> +}
> +
> +/**
>  * Python is not initialised.
>  */
>  PyObject* initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv)
>  {
> +       /* Yet another gotcha in the py api
> +        * Cant run PySys_SetArgv more then once because this adds the
> +        * binary dir to the sys.path each time.
> +        * Id have thaught python being totally restarted would make this ok but
> +        * somehow it remembers the sys.path - Campbell
> +        */
> +       static bool first_time = true;
> +
>  #if (PY_VERSION_HEX < 0x03000000)
>        STR_String pname = progname;
>        Py_SetProgramName(pname.Ptr());
> @@ -1536,7 +1641,7 @@
>        Py_Initialize();
>
>  #if (PY_VERSION_HEX < 0x03000000)
> -       if(argv) /* browser plugins dont currently set this */
> +       if(argv && first_time) /* browser plugins dont currently set this */
>                PySys_SetArgv(argc, argv);
>  #endif
>        //importBlenderModules()
> @@ -1546,6 +1651,10 @@
>
>        bpy_import_main_set(maggie);
>
> +       initPySysPath(maggie);
> +
> +       first_time = false;
> +
>        PyObject* moduleobj = PyImport_AddModule("__main__");
>        return PyModule_GetDict(moduleobj);
>  }
> @@ -1553,10 +1662,16 @@
>  void exitGamePlayerPythonScripting()
>  {
>        //clearGameModules(); // were closing python anyway
> +
> +       /* since python restarts we cant let the python backup of the sys.path hang around in a global pointer */
> +       restorePySysPath(); /* get back the original sys.path and clear the backup */
> +
>        Py_Finalize();
>        bpy_import_main_set(NULL);
>  }
>
> +
> +
>  /**
>  * Python is already initialized.
>  */
> @@ -1574,6 +1689,8 @@
>
>        bpy_import_main_set(maggie);
>
> +       initPySysPath(maggie);
> +
>        /* clear user defined modules that may contain data from the last run */
>        clearGameModules();
>
> @@ -1619,6 +1736,7 @@
>  void exitGamePythonScripting()
>  {
>        clearGameModules();
> +       restorePySysPath(); /* get back the original sys.path and clear the backup */
>        bpy_import_main_set(NULL);
>  }
>
>
>
> _______________________________________________
> Bf-blender-cvs mailing list
> Bf-blender-cvs at blender.org
> http://lists.blender.org/mailman/listinfo/bf-blender-cvs
>


More information about the Bf-committers mailing list