#include #include #include #include "luaincl.h" #include "Script.h" #include "RestoreStack.h" #include "This.h" #include "LuaCallback.h" // --------------------------------------------------------------------------- namespace OrxScript { #define BEGIN_LUA_CHECK(vm) lua_State *state = (lua_State *) vm; \ if (vm.isOk ()) { #define END_LUA_CHECK } /** * @brief Constructor. Sets up the lua stack and the "this" table * * * */ LuaScript::LuaScript () : methodCount (0) , argumentCount (0), functionName() { virtualMachine.init(); lua_State *state = (lua_State *) virtualMachine; if (virtualMachine.isOk ()) { // Create a reference to the "this" table. Each reference is unique lua_newtable (state); thisReference = luaL_ref (state, LUA_REGISTRYINDEX); // Save the "this" table to index 0 of the "this" table LuaRestoreStack rs (virtualMachine); lua_rawgeti (state, LUA_REGISTRYINDEX, thisReference); lua_pushlightuserdata (state, (void *) this); lua_rawseti (state, -2, 0); } } /** * @brief Deconstructor * */ LuaScript::~LuaScript (void) { LuaRestoreStack rs (virtualMachine); BEGIN_LUA_CHECK (virtualMachine) // Get the reference "this" table lua_rawgeti (state, LUA_REGISTRYINDEX, thisReference); // Clear index 0 lua_pushnil (state); lua_rawseti (state, -2, 0); END_LUA_CHECK } /** * @brief Compiles a given buffer. (reads it into the lua stack) * @param pbBuffer buffer to compile * @param size_t length of the buffer * * @return true if it succeeded */ bool LuaScript::compileBuffer (unsigned char *pbBuffer, size_t szLen) { assert (pbBuffer != NULL && "LuaScript::compileBuffer -> pbBuffer == NULL"); assert (szLen != 0 && "LuaScript::compileBuffer -> szLen == 0"); assert (virtualMachine.isOk () && "VM Not OK"); // Make sure we have the correct "this" table LuaThis luaThis (virtualMachine, thisReference); return virtualMachine.runBuffer (pbBuffer, szLen); } /** * @brief Compiles a given file. (reads it into the lua stack) * @param strFilename filename * * @return true if it succeeded */ bool LuaScript::compileFile (const std::string& strFilename) { //assert (strFilename != NULL && "LuaScript::compileFile -> strFilename == NULL"); assert (virtualMachine.isOk () && "VM Not OK"); // Make sure we have the correct "this" table LuaThis luaThis (virtualMachine, thisReference); return virtualMachine.runFile (strFilename); } /** * @brief Registers a function with Lua, the function will be registered in the "this" table * @param strFuncName name of the function by which it goes by in lua * * @return the pseudoindex of the function */ int LuaScript::registerFunction (const std::string& strFuncName) { // assert (strFuncName != NULL && "LuaScript::registerFunction -> strFuncName == NULL"); assert (virtualMachine.isOk () && "VM Not OK"); int iMethodIdx = -1; LuaRestoreStack rs (virtualMachine); BEGIN_LUA_CHECK (virtualMachine) iMethodIdx = ++methodCount; // Register a function with the lua script. Added it to the "this" table lua_rawgeti (state, LUA_REGISTRYINDEX, thisReference); // Push the function and parameters lua_pushstring (state, strFuncName.c_str()); lua_pushnumber (state, (lua_Number) iMethodIdx); lua_pushcclosure (state, luaCallback, 1); lua_settable (state, -3); END_LUA_CHECK return iMethodIdx; } /** * @brief Selects a script function to run * @param strFuncName name of the function to run * * @return true on success */ bool LuaScript::selectScriptFunction (const std::string& strFuncName) { // assert (strFuncName != NULL && "LuaScript::selectScriptFunction -> strFuncName == NULL"); assert (virtualMachine.isOk () && "VM Not OK"); bool fSuccess = true; BEGIN_LUA_CHECK (virtualMachine) // Look up function name lua_rawgeti (state, LUA_REGISTRYINDEX, thisReference); lua_pushstring (state, strFuncName.c_str()); lua_rawget (state, -2); lua_remove (state, -2); // Put the "this" table back lua_rawgeti (state, LUA_REGISTRYINDEX, thisReference); // Check that we have a valid function if (!lua_isfunction (state, -2)) { fSuccess = false; lua_pop (state, 2); } else { argumentCount = 0; functionName = strFuncName; } END_LUA_CHECK return fSuccess; } /** * @brief Checks to see if a function exists * @param functionName Function name * * @return true if the function exists */ bool LuaScript::scriptHasFunction (const std::string& functionName) { // printf("entered scriptHasFunction\n"); // assert (strScriptName != NULL && "LuaScript::scriptHasFunction -> strScriptName == NULL"); assert (virtualMachine.isOk () && "VM Not OK"); // printf("assertions passed\n"); LuaRestoreStack rs (virtualMachine); bool fFoundFunc = false; BEGIN_LUA_CHECK (virtualMachine) lua_rawgeti (state, LUA_REGISTRYINDEX, thisReference); lua_pushstring (state, functionName.c_str()); lua_rawget (state, -2); lua_remove (state, -2); if (lua_isfunction (state, -1)) { fFoundFunc = true; } END_LUA_CHECK return fFoundFunc; } /** * @brief Adds a parameter to the parameter list * @param string string to be added as parameter for a function. * */ void LuaScript::addParam (const std::string& string) { assert (virtualMachine.isOk () && "VM Not OK"); BEGIN_LUA_CHECK (virtualMachine); lua_pushstring (state, string.c_str()); ++argumentCount; END_LUA_CHECK; } /** * @brief Adds a parameter to the parameter list * @param iInt integer to be added as parameter for a function. * */ void LuaScript::addParam (int iInt) { assert (virtualMachine.isOk () && "VM Not OK"); BEGIN_LUA_CHECK (virtualMachine) lua_pushnumber (state, (lua_Number) iInt); ++argumentCount; END_LUA_CHECK } /** * @brief Adds a parameter to the parameter list * @param fFloat float to be added as parameter for a function. * */ void LuaScript::addParam (float fFloat) { assert (virtualMachine.isOk () && "VM Not OK"); BEGIN_LUA_CHECK (virtualMachine) lua_pushnumber (state, (lua_Number) fFloat); ++argumentCount; END_LUA_CHECK } /** * @brief Runs the selected script function * @param nReturns the count of return values * * @return true on success */ bool LuaScript::run (int nReturns /* = 0 */) { assert (virtualMachine.isOk () && "VM Not OK"); // At this point there should be a parameters and a function on the // Lua stack. Each function get a "this" parameter as default and is // pushed onto the stack when the method is selected bool fSuccess = virtualMachine.callFunction (argumentCount + 1, nReturns); if (fSuccess == true && nReturns > 0) { // Check for returns handleReturns (virtualMachine, functionName); lua_pop ((lua_State *) virtualMachine, nReturns); } return fSuccess; } /** * @brief This function adds an object to a script so that the object is accessable from within the luascript. * * @param scriptable the scriptable object to add. * @param strObjName the name that the object goes by in the script. * @param luaScript the script to which the scrtiptable is added * * @return a lua reference to the added object * * * */ int LuaScript::addScriptableToScript(Scriptable* scriptable, const std::string& strObjName) { lua_State *state = (lua_State *) (this->virtualMachine); if(strObjName.compare(std::string("this")) != 0) { if (virtualMachine.isOk ()) { /*create object table*/ // Create a reference to the "object" table and set a name for the reference. Each reference is unique lua_newtable (state); int objRef = luaL_ref (state, LUA_REGISTRYINDEX); lua_rawgeti (state, LUA_REGISTRYINDEX, objRef); lua_setglobal (state, strObjName.c_str()); // Save the "object" table to index 0 of the "object" table LuaRestoreStack rs(virtualMachine); lua_rawgeti (state, LUA_REGISTRYINDEX, objRef); lua_pushlightuserdata (state, scriptable); lua_rawseti (state, -2, 0); if(! addScriptableToList(scriptable,objRef)) std::cout<<"scriptable not added"<scriptableAdded(this,thisReference,objRef))) std::cout<<"scriptableAdded returned false"< strFuncName == NULL"); assert (virtualMachine.isOk () && "VM Not OK"); //get the last method index from the Script Scriptable* scriptable = getScriptableByReference(toScriptable); int iMethodIdx = -1; if(scriptable) { LuaRestoreStack rs (virtualMachine); BEGIN_LUA_CHECK (virtualMachine) // Register a function with the lua script. Added it to the "toScrtiptable" table lua_rawgeti (state, LUA_REGISTRYINDEX, toScriptable); if (lua_istable (state, 1)) { iMethodIdx = ++lastMethodIndex; // Push the function and parameters lua_pushstring (state, strFuncName.c_str()); lua_pushnumber (state, (lua_Number) iMethodIdx); lua_pushcclosure (state, luaCallback, 1); lua_settable (state, -3); } END_LUA_CHECK } return iMethodIdx; } Scriptable* LuaScript::getScriptableByReference(int scrptblRef) { bool notFound = true; std::list::iterator it = scriptableList.begin(); while(notFound && it != scriptableList.end() ) { if((*it).scriptableRef == scrptblRef) { notFound = false; return (*it).scriptable; } it++; } if(notFound) return NULL; } int LuaScript::getReferenceByScriptable(Scriptable* scrptbl) { bool notFound = true; std::list::iterator it = scriptableList.begin(); while(notFound && it != scriptableList.end() ) { if((*it).scriptable == scrptbl) { notFound = false; return (*it).scriptableRef; } it++; } if(notFound) return -1; } bool LuaScript::addScriptableToList(Scriptable* scrptbl, int scriptableRef) { if(scrptbl) { if(getReferenceByScriptable(scrptbl) == -1) // Script isn't there yet { Scrptbl scriptableTmp; scriptableTmp.scriptable = scrptbl; scriptableTmp.scriptableRef = scriptableRef; scriptableList.push_back(scriptableTmp); return true; } } return false; } bool LuaScript::removeScriptableFromList(Scriptable* toRemove) { if(toRemove) { int scrptbl = getReferenceByScriptable(toRemove); if(scrptbl != -1)// if the scriptable is on the list { std::list::iterator it = scriptableList.begin(); while((*it).scriptable != toRemove && it != scriptableList.end() ) { it++; } if(it != scriptableList.end()) { scriptableList.erase(it); return true; } } } return false; } bool LuaScript::removeScriptableFromList(int scriptable) { return removeScriptableFromList(getScriptableByReference(scriptable)); } char LuaScript::whatIsThis() { char result = 'l'; return result; } }