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

Campbell Barton ideasman42 at gmail.com
Fri May 1 00:40:19 CEST 2009


Hi Joe, I was tossing up pro/s and cons of this too.

The deciding factor for me was to think of how YoFrankie would look
when say the characters folder had ~30 py files alongside the blends.
~10 or so for the levels.
A lot of projects use a "//textures" directory to avoid this kind of
mess so Id like to use this for scripts too.

Games tend to use quite a lot of scripts though admittedly this can
now be avoided by having 1 module multiple  functions in it,
nevertheless having 10+ scripts would not be unusual.

So my rationale for choosing this was that small projects would
probably use the internal text (for simplicity and easy distribution),
and large projects would use external scripts for easier
management/version history etc.
For larger projects youll probably have more then 3-4 scripts which
makes it neater to put them in a subdir.

Users can always edit the sys.path for their own project if they
really want. we could add "//scripts" and "//" to the sys.path but
this seems worse to me.

- Campbell

On Thu, Apr 30, 2009 at 3:12 PM, joe <joeedh at gmail.com> wrote:
> 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
>>
> _______________________________________________
> Bf-committers mailing list
> Bf-committers at blender.org
> http://lists.blender.org/mailman/listinfo/bf-committers
>


More information about the Bf-committers mailing list