Changeset 904 – HoverRace

Changeset 904

Show
Ignore:
Timestamp:
03/09/10 23:15:31 (5 months ago)
Author:
zoogie
Message:

Moving forward on the quest for a single scripting state with multiple sandboxed environments:

  • Implemented Script::Env.
  • Client::SysConsole is now a subclass of Script::Env.
  • GameApp now manages what will be the single global scripting state.
Location:
trunk
Files:
6 modified

Legend:

Unmodified
Added
Removed
  • trunk/client/Game2/GameApp.cpp

    r890 r904  
    4343#include "../../engine/VideoServices/VideoBuffer.h" 
    4444#include "../../engine/MainCharacter/MainCharacter.h" 
     45#include "../../engine/Script/Core.h" 
    4546#include "../../engine/Util/FuzzyLogic.h" 
    4647#include "../../engine/Util/Profiler.h" 
     
    569570 
    570571MR_GameApp::MR_GameApp(HINSTANCE pInstance, bool safeMode) : 
    571     introMovie(NULL), sysConsole(NULL) 
     572    introMovie(NULL), scripting(NULL), sysConsole(NULL) 
    572573{ 
    573574    This = this; 
     
    612613        delete sysConsole; 
    613614        sysConsole = NULL; 
     615    } 
     616    if (scripting != NULL) { 
     617        delete scripting; 
     618        scripting = NULL; 
    614619    } 
    615620 
     
    11361141    // Create the system console and execute the init script. 
    11371142    // This allows the script to modify the configuration (e.g. for unit tests). 
    1138     sysConsole = new SysConsole(); 
    1139     sysConsole->Init(); 
     1143    scripting = new Script::Core(); 
     1144    sysConsole = new SysConsole(scripting); 
    11401145    if (!initScript.empty()) { 
    11411146        sysConsole->RunScript(initScript); 
  • trunk/client/Game2/GameApp.h

    r896 r904  
    3737        typedef boost::shared_ptr<Rulebook> RulebookPtr; 
    3838        class SysConsole; 
     39    } 
     40    namespace Script { 
     41        class Core; 
    3942    } 
    4043} 
     
    8386        HoverRace::Client::IntroMovie *introMovie; 
    8487        HoverRace::Client::FullscreenTest *fullscreenTest; 
     88        HoverRace::Script::Core *scripting; 
    8589        HoverRace::Client::SysConsole *sysConsole; 
    8690        MR_ClientSession *mCurrentSession; 
  • trunk/client/Game2/SysConsole.cpp

    r895 r904  
    2929#include <boost/format.hpp> 
    3030 
    31 #include "../../engine/Script/Core.h" 
    32  
    3331#include "SysConsole.h" 
    3432 
    3533namespace fs = boost::filesystem; 
    3634 
    37 using namespace HoverRace; 
    38 using namespace HoverRace::Client; 
    39 using namespace HoverRace::Script; 
    40  
    41 SysConsole::SysConsole() : 
    42     SUPER(), onInitRef(-1) 
    43 { 
     35namespace { 
     36    class LogStreamBuf : public std::stringbuf 
     37    { 
     38        typedef std::stringbuf SUPER; 
     39        public: 
     40            LogStreamBuf() { } 
     41            virtual ~LogStreamBuf() { sync(); } 
     42 
     43        protected: 
     44            virtual int sync() 
     45            { 
     46                std::string s = str(); 
     47 
     48#               ifdef _WIN32 
     49                    OutputDebugString(s.c_str()); 
     50#               endif 
     51                std::cout << s << std::flush; 
     52 
     53                str(std::string()); 
     54                return 0; 
     55            } 
     56    }; 
     57 
     58    class LogStream : public std::ostream 
     59    { 
     60        typedef std::ostream SUPER; 
     61        public: 
     62            LogStream() : SUPER(new LogStreamBuf()) { } 
     63            virtual ~LogStream() { delete rdbuf(); } 
     64    }; 
     65} 
     66 
     67namespace HoverRace { 
     68namespace Client { 
     69 
     70SysConsole::SysConsole(Script::Core *scripting) : 
     71    SUPER(scripting), outHandle(scripting->AddOutput(boost::make_shared<LogStream>())) 
     72{ 
     73    lua_State *state = scripting->GetState(); 
     74 
     75    scripting->PrintStack(); 
     76 
     77    // Initial table for callbacks. 
     78    lua_newtable(state); 
     79    onInitRef = luaL_ref(scripting->GetState(), LUA_REGISTRYINDEX); 
    4480} 
    4581 
    4682SysConsole::~SysConsole() 
    4783{ 
    48     if (onInitRef >= 0) { 
    49         lua_State *state = GetScripting()->GetState(); 
    50         luaL_unref(state, LUA_REGISTRYINDEX, onInitRef); 
    51     } 
    52 } 
    53  
    54 void SysConsole::InitEnv(Script::Core *scripting) 
    55 { 
    56     SUPER::InitEnv(scripting); 
    57     onInitRef = luaL_ref(scripting->GetState(), LUA_REGISTRYINDEX); 
    58 } 
    59  
    60 void SysConsole::InitGlobals(Script::Core *scripting) 
    61 { 
    62     SUPER::InitGlobals(scripting); 
    63  
     84    Script::Core *scripting = GetScripting(); 
     85    luaL_unref(scripting->GetState(), LUA_REGISTRYINDEX, onInitRef); 
     86    scripting->RemoveOutput(outHandle); 
     87} 
     88 
     89void SysConsole::InitEnv() 
     90{ 
     91    Script::Core *scripting = GetScripting(); 
    6492    lua_State *state = scripting->GetState(); 
    6593 
    66     lua_pushlightuserdata(state, this); 
    67     lua_pushcclosure(state, SysConsole::LOnInit, 1); 
    68     lua_setglobal(state, "on_init"); 
    69  
    70     lua_pushlightuserdata(state, this); 
    71     lua_pushcclosure(state, SysConsole::LGetOnInit, 1); 
    72     lua_setglobal(state, "get_on_init"); 
    73  
    74     // Initial arrays for callbacks. 
    75     lua_newtable(state); 
    76     lua_rawseti(state, LUA_REGISTRYINDEX, onInitRef); 
     94    // Start with the standard global environment. 
     95    CopyGlobals(); 
     96 
     97    lua_pushlightuserdata(state, this);  // table this 
     98    lua_pushcclosure(state, SysConsole::LOnInit, 1);  // table fn 
     99    lua_pushstring(state, "on_init");  // table fn str 
     100    lua_insert(state, -2);  // table str fn 
     101    lua_rawset(state, -3);  // table 
     102 
     103    lua_pushlightuserdata(state, this);  // table this 
     104    lua_pushcclosure(state, SysConsole::LGetOnInit, 1);  // table fn 
     105    lua_pushstring(state, "get_on_init");  // table fn str 
     106    lua_insert(state, -2);  // table str fn 
     107    lua_rawset(state, -3);  // table 
    77108} 
    78109 
     
    113144    fs::ifstream ifs(scriptPath, std::ios_base::in); 
    114145    std::string ris((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); 
    115     SubmitChunk(ris); 
     146    try { 
     147        Execute(ris); 
     148    } 
     149    catch (Script::ScriptExn &ex) { 
     150        LogError(ex.what()); 
     151    } 
    116152} 
    117153 
     
    166202    return 1; 
    167203} 
     204 
     205}  // namespace Client 
     206}  // namespace HoverRace 
  • trunk/client/Game2/SysConsole.h

    r895 r904  
    2323#pragma once 
    2424 
    25 #include "Console.h" 
     25#include "../../engine/Script/Core.h" 
     26#include "../../engine/Script/Env.h" 
     27 
     28namespace HoverRace { 
     29    namespace Script { 
     30        class Core; 
     31    } 
     32} 
    2633 
    2734namespace HoverRace { 
    2835namespace Client { 
    2936 
    30 class SysConsole : public Console 
     37class SysConsole : private Script::Env 
    3138{ 
    32     typedef Console SUPER; 
     39    typedef Script::Env SUPER; 
    3340 
    3441    public: 
    35         SysConsole(); 
     42        SysConsole(Script::Core *scripting); 
    3643        virtual ~SysConsole(); 
    3744 
    3845    protected: 
    39         virtual void InitEnv(Script::Core *scripting); 
    40         virtual void InitGlobals(Script::Core *scripting); 
     46        virtual void InitEnv(); 
    4147 
    42     public: 
    43         virtual void Advance(Util::OS::timestamp_t tick) { }; 
    44         virtual void Clear() { }; 
    45      
    4648    protected: 
    4749        virtual void LogInfo(const std::string &s); 
     
    5961 
    6062    private: 
     63        Script::Core::OutHandle outHandle; 
    6164        int onInitRef; 
    6265}; 
  • trunk/engine/Script/Env.cpp

    r898 r904  
    2323#include "StdAfx.h" 
    2424 
     25#include "Core.h" 
     26 
    2527#include "Env.h" 
    2628 
     
    2830namespace Script { 
    2931 
     32/** 
     33 * Constructor. 
     34 * @param scripting The scripting engine (may not be @c NULL). 
     35 */ 
    3036Env::Env(Core *scripting) : 
    31     scripting(scripting) 
     37    scripting(scripting), initialized(false) 
    3238{ 
     39    lua_State *state = scripting->GetState(); 
     40 
     41    // Store a placeholder at the registry location. 
     42    lua_pushinteger(state, 1); 
     43    envRef = luaL_ref(state, LUA_REGISTRYINDEX); 
    3344} 
    3445 
    3546Env::~Env() 
    3647{ 
     48    luaL_unref(scripting->GetState(), LUA_REGISTRYINDEX, envRef); 
     49} 
     50 
     51/** 
     52 * Initialize the environment in which scripts will run in. 
     53 * Upon entry, the Lua stack will have at least one entry, the table which 
     54 * represents the environment.  Implementing functions will fill this table 
     55 * with the globals which will be available to the functions which are run 
     56 * in this environment.  Upon return, this same table must be at the top of 
     57 * the stack. 
     58 */ 
     59void Env::InitEnv() 
     60{ 
     61} 
     62 
     63/** 
     64 * Copy the global environment into the current table at the top of the stack. 
     65 * This is meant to be called from InitEnv() as a convenience. 
     66 */ 
     67void Env::CopyGlobals() 
     68{ 
     69    lua_State *state = scripting->GetState(); 
     70 
     71    lua_pushnil(state);  // table nil 
     72    while (lua_next(state, LUA_GLOBALSINDEX) != 0) { 
     73        // table key value 
     74        lua_pushvalue(state, -2);  // table key value key 
     75        lua_insert(state, -2);  // table key key value 
     76        lua_rawset(state, -4);  // table key 
     77    } 
     78    // table 
     79} 
     80 
     81/** 
     82 * Execute a chunk of code in the current environment. 
     83 * @param chunk The code to execute. 
     84 * @throw IncompleteExn If the code does not complete a statement; i.e., 
     85 *                      expecting more tokens.  Callers can catch this 
     86 *                      to keep reading more data to finish the statement. 
     87 * @throw ScriptExn The code either failed to compile or signaled an error 
     88 *                  while executing. 
     89 */ 
     90void Env::Execute(const std::string &chunk) 
     91{ 
     92    lua_State *state = scripting->GetState(); 
     93 
     94    // May throw ScriptExn or IncompleteExn, in which case stack will be unchanged. 
     95    scripting->Compile(chunk); 
     96 
     97    if (initialized) { 
     98        lua_rawgeti(state, LUA_REGISTRYINDEX, envRef); 
     99    } 
     100    else { 
     101        lua_newtable(state); 
     102        InitEnv(); 
     103        initialized = true; 
     104        lua_pushvalue(state, -1); 
     105        lua_rawseti(state, LUA_REGISTRYINDEX, envRef); 
     106    } 
     107    lua_setfenv(state, -2); 
     108 
     109    // May throw ScriptExn, but the function on the stack will be consumed anyway. 
     110    scripting->CallAndPrint(); 
    37111} 
    38112 
  • trunk/engine/Script/Env.h

    r898 r904  
    2323#pragma once 
    2424 
    25 #include "Core.h" 
    26  
    2725#ifdef _WIN32 
    2826#   ifdef MR_ENGINE 
     
    4644        virtual ~Env(); 
    4745 
     46    protected: 
     47        Core *GetScripting() const { return scripting; } 
     48 
     49        virtual void InitEnv() = 0; 
     50        void CopyGlobals(); 
     51 
     52        void Execute(const std::string &chunk); 
     53 
    4854    private: 
    4955        Core *scripting; 
     56        bool initialized; 
     57        int envRef; 
    5058}; 
    5159