12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274 |
- /*
- * Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
- #include "luainterface.h"
- #include "luaobject.h"
-
- #include <framework/core/resourcemanager.h>
- #include <lua.hpp>
-
- #include "lbitlib.h"
-
- LuaInterface g_lua;
-
- LuaInterface::LuaInterface()
- {
- L = nullptr;
- m_cppCallbackDepth = 0;
- m_weakTableRef = 0;
- m_totalObjRefs = 0;
- m_totalFuncRefs = 0;
- }
-
- LuaInterface::~LuaInterface()
- {
- }
-
- void LuaInterface::init()
- {
- createLuaState();
-
- // store global environment reference
- pushThread();
- getEnv();
- m_globalEnv = ref();
- pop();
-
- // check if demangle_type is working as expected
- assert(stdext::demangle_type<LuaObject>() == "LuaObject");
-
- // register LuaObject, the base of all other objects
- registerClass<LuaObject>();
- bindClassMemberFunction<LuaObject>("getUseCount", &LuaObject::getUseCount);
- bindClassMemberFunction<LuaObject>("getClassName", &LuaObject::getClassName);
-
- registerClassMemberFunction<LuaObject>("getFieldsTable", (LuaCppFunction) ([](LuaInterface* lua) -> int {
- LuaObjectPtr obj = g_lua.popObject();
- obj->luaGetFieldsTable();
- return 1;
- }));
- }
-
- void LuaInterface::terminate()
- {
- // close lua state, it will release all objects
- closeLuaState();
- assert(m_totalFuncRefs == 0);
- assert(m_totalObjRefs == 0);
- }
-
- void LuaInterface::registerSingletonClass(const std::string& className)
- {
- newTable();
- pushValue();
- setGlobal(className);
- pop();
- }
-
- void LuaInterface::registerClass(const std::string& className, const std::string& baseClass)
- {
- // creates the class table (that it's also the class methods table)
- newTable();
- pushValue();
- setGlobal(className);
- const int klass = getTop();
-
- // creates the class fieldmethods table
- newTable();
- pushValue();
- setGlobal(className + "_fieldmethods");
- int klass_fieldmethods = getTop();
-
- // creates the class metatable
- newTable();
- pushValue();
- setGlobal(className + "_mt");
- int klass_mt = getTop();
-
- // set metatable metamethods
- pushCppFunction(&LuaInterface::luaObjectGetEvent);
- setField("__index", klass_mt);
- pushCppFunction(&LuaInterface::luaObjectSetEvent);
- setField("__newindex", klass_mt);
- pushCppFunction(&LuaInterface::luaObjectEqualEvent);
- setField("__eq", klass_mt);
- pushCppFunction(&LuaInterface::luaObjectCollectEvent);
- setField("__gc", klass_mt);
-
- // set some fields that will be used later in metatable
- pushValue(klass);
- setField("methods", klass_mt);
- pushValue(klass_fieldmethods);
- setField("fieldmethods", klass_mt);
-
- // redirect methods and fieldmethods to the base class ones
- if(!className.empty() && className != "LuaObject") {
- // the following code is what create classes hierarchy for lua, by reproducing:
- // DerivedClass = { __index = BaseClass }
- // DerivedClass_fieldmethods = { __index = BaseClass_methods }
-
- // redirect the class methods to the base methods
- pushValue(klass);
- newTable();
- getGlobal(baseClass);
- setField("__index");
- setMetatable();
- pop();
-
- // redirect the class fieldmethods to the base fieldmethods
- pushValue(klass_fieldmethods);
- newTable();
- getGlobal(baseClass + "_fieldmethods");
- setField("__index");
- setMetatable();
- pop();
- }
-
- // pops klass, klass_mt, klass_fieldmethods
- pop(3);
- }
-
- void LuaInterface::registerClassStaticFunction(const std::string& className,
- const std::string& functionName,
- const LuaCppFunction& function)
- {
- registerClassMemberFunction(className, functionName, function);
- }
-
- void LuaInterface::registerClassMemberFunction(const std::string& className,
- const std::string& functionName,
- const LuaCppFunction& function)
- {
- getGlobal(className);
- pushCppFunction(function);
- setField(functionName);
- pop();
- }
-
- void LuaInterface::registerClassMemberField(const std::string& className,
- const std::string& field,
- const LuaCppFunction& getFunction,
- const LuaCppFunction& setFunction)
- {
- getGlobal(className + "_fieldmethods");
-
- if(getFunction) {
- pushCppFunction(getFunction);
- setField(stdext::format("get_%s", field));
- }
-
- if(setFunction) {
- pushCppFunction(setFunction);
- setField(stdext::format("set_%s", field));
- }
-
- pop();
- }
-
- void LuaInterface::registerGlobalFunction(const std::string& functionName, const LuaCppFunction& function)
- {
- pushCppFunction(function);
- setGlobal(functionName);
- }
-
- int LuaInterface::luaObjectGetEvent(LuaInterface* lua)
- {
- // stack: obj, key
- LuaObjectPtr obj = lua->toObject(-2);
- std::string key = lua->toString(-1);
- assert(obj);
-
- lua->remove(-1); // removes key
-
- // if a get method for this key exists, calls it
- lua->getMetatable(); // pushes obj metatable
- lua->getField("fieldmethods"); // push obj fieldmethods
- lua->remove(-2); // removes obj metatable
- lua->getField("get_" + key); // pushes get method
- lua->remove(-2); // remove obj fieldmethods
- if(!lua->isNil()) { // is the get method not nil?
- lua->insert(-2); // moves obj to the top
- lua->signalCall(1, 1); // calls get method, arguments: obj
- return 1;
- }
- lua->pop(); // pops the nil get method
-
- // if the field for this key exists, returns it
- obj->luaGetField(key);
- if(!lua->isNil()) {
- lua->remove(-2); // removes the obj
- // field value is on the stack
- return 1;
- }
- lua->pop(); // pops the nil field
-
- // pushes the method assigned by this key
- lua->getMetatable(); // pushes obj metatable
- lua->getField("methods"); // push obj methods
- lua->remove(-2); // removes obj metatable
- lua->getField(key); // pushes obj method
- lua->remove(-2); // remove obj methods
- lua->remove(-2); // removes obj
-
- // the result value is on the stack
- return 1;
- }
-
- int LuaInterface::luaObjectSetEvent(LuaInterface* lua)
- {
- // stack: obj, key, value
- LuaObjectPtr obj = lua->toObject(-3);
- std::string key = lua->toString(-2);
- assert(obj);
-
- lua->remove(-2); // removes key
- lua->insert(-2); // moves obj to the top
-
- // check if a set method for this field exists and call it
- lua->getMetatable(); // pushes obj metatable
- lua->getField("fieldmethods"); // push obj fieldmethods
- lua->remove(-2); // removes obj metatable
- lua->getField("set_" + key); // pushes set method
- lua->remove(-2); // remove obj fieldmethods
- if(!lua->isNil()) { // is the set method not nil?
- lua->insert(-3); // moves func to -3
- lua->insert(-2); // moves obj to -2, and value to -1
- lua->signalCall(2, 0); // calls set method, arguments: obj, value
- return 0;
- }
- lua->pop(); // pops the nil set method
-
- // no set method exists, then treats as an field and set it
- lua->pop(); // pops the object
- obj->luaSetField(key); // sets the obj field
- return 0;
- }
-
- int LuaInterface::luaObjectEqualEvent(LuaInterface* lua)
- {
- // stack: obj1, obj2
- bool ret = false;
-
- // check if obj1 == obj2
- if(lua->isUserdata(-1) && lua->isUserdata(-2)) {
- LuaObjectPtr* objPtr2 = static_cast<LuaObjectPtr*>(lua->popUserdata());
- LuaObjectPtr* objPtr1 = static_cast<LuaObjectPtr*>(lua->popUserdata());
- assert(objPtr1 && objPtr2);
- if(*objPtr1 == *objPtr2)
- ret = true;
- } else
- lua->pop(2);
-
- lua->pushBoolean(ret);
- return 1;
- }
-
- int LuaInterface::luaObjectCollectEvent(LuaInterface* lua)
- {
- // gets object pointer
- auto objPtr = static_cast<LuaObjectPtr*>(lua->popUserdata());
- assert(objPtr);
-
- // resets pointer to decrease object use count
- objPtr->reset();
- g_lua.m_totalObjRefs--;
- return 0;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
-
-
- bool LuaInterface::safeRunScript(const std::string& fileName)
- {
- try {
- runScript(fileName);
- return true;
- } catch(stdext::exception& e) {
- g_logger.error(stdext::format("Failed to load script '%s': %s", fileName, e.what()));
- return false;
- }
- }
-
- void LuaInterface::runScript(const std::string& fileName)
- {
- loadScript(fileName);
- safeCall(0, 0);
- }
-
- void LuaInterface::runBuffer(const std::string& buffer, const std::string& source)
- {
- loadBuffer(buffer, source);
- safeCall(0, 0);
- }
-
- void LuaInterface::loadScript(const std::string& fileName)
- {
- // resolve file full path
- std::string filePath = fileName;
- if(!stdext::starts_with(fileName, "/"))
- filePath = getCurrentSourcePath() + "/" + filePath;
-
- filePath = g_resources.guessFilePath(filePath, "lua");
-
- std::string buffer = g_resources.readFileContents(filePath);
- std::string source = "@" + filePath;
- loadBuffer(buffer, source);
- }
-
- void LuaInterface::loadFunction(const std::string& buffer, const std::string& source)
- {
- if(buffer.empty()) {
- pushNil();
- return;
- }
-
- std::string buf;
- if(stdext::starts_with(buffer, "function"))
- buf = stdext::format("__func = %s", buffer);
- else
- buf = stdext::format("__func = function(self)\n%s\nend", buffer);
-
- loadBuffer(buf, source);
- safeCall();
-
- // get the function
- getGlobal("__func");
-
- // reset the global __func
- pushNil();
- setGlobal("__func");
- }
-
- void LuaInterface::evaluateExpression(const std::string& expression, const std::string& source)
- {
- // evaluates the expression
- if(!expression.empty()) {
- std::string buffer = stdext::format("__exp = (%s)", expression);
- loadBuffer(buffer, source);
- safeCall();
-
- // gets the expression result
- getGlobal("__exp");
-
- // resets global __exp
- pushNil();
- setGlobal("__exp");
- } else
- pushNil();
- }
-
- std::string LuaInterface::traceback(const std::string& errorMessage, int level)
- {
- // gets debug.traceback
- getGlobal("debug");
- getField("traceback");
- remove(-2); // remove debug
-
- // calls debug.traceback(errorMessage, level)
- pushString(errorMessage);
- pushInteger(level);
- call(2,1);
-
- // returns the traceback message
- return popString();
- }
-
- void LuaInterface::throwError(const std::string& message)
- {
- if(isInCppCallback()) {
- pushString(message);
- error();
- } else
- throw stdext::exception(message);
- }
-
- std::string LuaInterface::getCurrentSourcePath(int level)
- {
- std::string path;
- if(!L)
- return path;
-
- // check all stack functions for script source path
- while(true) {
- getStackFunction(level); // pushes stack function
-
- // only lua functions is wanted, because only them have a working directory
- if(isLuaFunction()) {
- path = functionSourcePath();
- break;
- } else if(isNil()) {
- pop();
- break;
- } else
- pop();
-
- // next level
- level++;
- }
-
- return path;
- }
-
- int LuaInterface::safeCall(int numArgs, int numRets)
- {
- assert(hasIndex(-numArgs-1));
-
- // saves the current stack size for calculating the number of results later
- int previousStackSize = stackSize();
-
- // pushes error function
- int errorFuncIndex = previousStackSize - numArgs;
- pushCFunction(&LuaInterface::luaErrorHandler);
- insert(errorFuncIndex);
-
- // calls the function in protected mode (means errors will be caught)
- int ret = pcall(numArgs, LUA_MULTRET, errorFuncIndex);
-
- remove(errorFuncIndex); // remove error func
-
- // if there was an error throw an exception
- if(ret != 0)
- throw LuaException(popString());
-
- int rets = (stackSize() + numArgs + 1) - previousStackSize;
- while(numRets != -1 && rets != numRets) {
- if(rets < numRets) {
- pushNil();
- rets++;
- } else {
- pop();
- rets--;
- }
- }
-
- // returns the number of results
- return rets;
- }
-
- int LuaInterface::signalCall(int numArgs, int numRets)
- {
- int rets = 0;
- int funcIndex = -numArgs-1;
-
- try {
- // must be a function
- if(isFunction(funcIndex)) {
- rets = safeCall(numArgs);
-
- if(numRets != -1) {
- if(rets != numRets)
- throw LuaException("function call didn't return the expected number of results", 0);
- }
- }
- // can also calls table of functions
- else if(isTable(funcIndex)) {
- // loop through table values
- pushNil();
- bool done = false;
- while(next(funcIndex-1)) {
- if(isFunction()) {
- // repush arguments
- for(int i=0;i<numArgs;++i)
- pushValue(-numArgs-2);
-
- int rets = safeCall(numArgs);
- if(rets == 1) {
- done = popBoolean();
- if(done) {
- pop();
- break;
- }
- } else if(rets != 0)
- throw LuaException("function call didn't return the expected number of results", 0);
- } else {
- throw LuaException("attempt to call a non function", 0);
- }
- }
- pop(numArgs + 1); // pops the table of function and arguments
-
- if(numRets == 1 || numRets == -1) {
- rets = 1;
- pushBoolean(done);
- }
- }
- // nil values are ignored
- else if(isNil(funcIndex)) {
- pop(numArgs + 1); // pops the function and arguments
- }
- // if not nil, warn
- else {
- throw LuaException("attempt to call a non function value", 0);
- }
- } catch(stdext::exception& e) {
- g_logger.error(stdext::format("protected lua call failed: %s", e.what()));
- }
-
- // pushes nil values if needed
- while(numRets != -1 && rets < numRets) {
- pushNil();
- rets++;
- }
-
- // returns the number of results on the stack
- return rets;
- }
-
- int LuaInterface::newSandboxEnv()
- {
- newTable(); // pushes the new environment table
- newTable(); // pushes the new environment metatable
- getRef(getGlobalEnvironment()); // pushes the global environment
- setField("__index"); // sets metatable __index to the global environment
- setMetatable(); // assigns environment metatable
- return ref(); // return a reference to the environment table
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // lua C functions
-
- int LuaInterface::luaScriptLoader(lua_State* L)
- {
- // loads the script as a function
- std::string fileName = g_lua.popString();
-
- try {
- g_lua.loadScript(fileName);
- return 1;
- } catch(stdext::exception& e) {
- g_lua.pushString(std::string("\n\t") + e.what());
- return 1;
- }
- }
-
- int LuaInterface::lua_dofile(lua_State* L)
- {
- std::string file = g_lua.popString();
-
- try {
- g_lua.loadScript(file);
- g_lua.call(0, LUA_MULTRET);
- return g_lua.stackSize();
- } catch(stdext::exception& e) {
- g_lua.pushString(e.what());
- g_lua.error();
- return 0;
- }
- }
-
- int LuaInterface::lua_dofiles(lua_State* L)
- {
- std::string contains = "";
- if(g_lua.getTop() > 2) {
- contains = g_lua.popString();
- }
-
- bool recursive = false;
- if(g_lua.getTop() > 1) {
- recursive = g_lua.popBoolean();
- }
-
- std::string directory = g_lua.popString();
- g_lua.loadFiles(directory, recursive, contains);
-
- return 0;
- }
-
- int LuaInterface::lua_loadfile(lua_State* L)
- {
- std::string fileName = g_lua.popString();
-
- try {
- g_lua.loadScript(fileName);
- return 1;
- } catch(stdext::exception& e) {
- g_lua.pushNil();
- g_lua.pushString(e.what());
- g_lua.error();
- return 2;
- }
- }
-
- int LuaInterface::luaErrorHandler(lua_State* L)
- {
- // pops the error message
- auto error = g_lua.popString();
-
- // prevents repeated tracebacks
- if(error.find("stack traceback:") == std::string::npos)
- error = g_lua.traceback(error, 1);
-
- // pushes the new error message with traceback information
- g_lua.pushString(error);
- return 1;
- }
-
- int LuaInterface::luaCppFunctionCallback(lua_State* L)
- {
- // retrieves function pointer from userdata
- auto funcPtr = static_cast<LuaCppFunctionPtr*>(g_lua.popUpvalueUserdata());
- assert(funcPtr);
-
- int numRets = 0;
-
- // do the call
- try {
- g_lua.m_cppCallbackDepth++;
- numRets = (*(funcPtr->get()))(&g_lua);
- g_lua.m_cppCallbackDepth--;
- assert(numRets == g_lua.stackSize());
- } catch(stdext::exception& e) {
- // cleanup stack
- while(g_lua.stackSize() > 0)
- g_lua.pop();
- numRets = 0;
- g_lua.pushString(stdext::format("C++ call failed: %s", g_lua.traceback(e.what())));
- g_lua.error();
- }
-
- return numRets;
- }
-
- int LuaInterface::luaCollectCppFunction(lua_State* L)
- {
- auto funcPtr = static_cast<LuaCppFunctionPtr*>(g_lua.popUserdata());
- assert(funcPtr);
- funcPtr->reset();
- g_lua.m_totalFuncRefs--;
- return 0;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // from here all next functions are interfaces for the Lua API
-
- void LuaInterface::createLuaState()
- {
- // creates lua state
- L = luaL_newstate();
- if(!L)
- g_logger.fatal("Unable to create lua state");
-
- // load lua standard libraries
- luaL_openlibs(L);
-
- // load bit32 lib for bitwise operations
- luaopen_bit32(L);
-
- // creates weak table
- newTable();
- newTable();
- pushString("v");
- setField("__mode");
- setMetatable();
- m_weakTableRef = ref();
-
- // installs script loader
- getGlobal("package");
- getField("loaders");
- pushCFunction(&LuaInterface::luaScriptLoader);
- rawSeti(5);
- pop(2);
-
- // replace dofile
- pushCFunction(&LuaInterface::lua_dofile);
- setGlobal("dofile");
-
- // dofiles
- pushCFunction(&LuaInterface::lua_dofiles);
- setGlobal("dofiles");
-
- // replace loadfile
- pushCFunction(&LuaInterface::lua_loadfile);
- setGlobal("loadfile");
- }
-
- void LuaInterface::closeLuaState()
- {
- if(L) {
- // close lua, it also collects
- lua_close(L);
- L = NULL;
- }
- }
-
- void LuaInterface::collectGarbage()
- {
- // prevents recursive collects
- static bool collecting = false;
- if(!collecting) {
- collecting = true;
-
- // we must collect two times because __gc metamethod
- // is called on uservalues only the second time
- for(int i=0;i<2;++i)
- lua_gc(L, LUA_GCCOLLECT, 0);
-
- collecting = false;
- }
- }
-
- void LuaInterface::loadBuffer(const std::string& buffer, const std::string& source)
- {
- // loads lua buffer
- int ret = luaL_loadbuffer(L, buffer.c_str(), buffer.length(), source.c_str());
- if(ret != 0)
- throw LuaException(popString(), 0);
- }
-
- int LuaInterface::pcall(int numArgs, int numRets, int errorFuncIndex)
- {
- assert(hasIndex(-numArgs - 1));
- return lua_pcall(L, numArgs, numRets, errorFuncIndex);
- }
-
- void LuaInterface::call(int numArgs, int numRets)
- {
- assert(hasIndex(-numArgs - 1));
- lua_call(L, numArgs, numRets);
- }
-
- void LuaInterface::error()
- {
- assert(hasIndex(-1));
- lua_error(L);
- }
-
- int LuaInterface::ref()
- {
- int ref = luaL_ref(L, LUA_REGISTRYINDEX);
- assert(ref != LUA_NOREF);
- assert(ref < 2147483647);
- return ref;
- }
-
- int LuaInterface::weakRef()
- {
- static int id = 0;
-
- // generates a new id
- ++id;
- if(id == 2147483647)
- id = 0;
-
- // gets weak table
- getRef(m_weakTableRef);
- insert(-2);
-
- // sets weak_table[id] = v
- rawSeti(id);
-
- // pops weak table
- pop();
-
- return id;
- }
-
- void LuaInterface::unref(int ref)
- {
- if(ref >= 0 && L != NULL)
- luaL_unref(L, LUA_REGISTRYINDEX, ref);
- }
-
- const char* LuaInterface::typeName(int index)
- {
- assert(hasIndex(index));
- int type = lua_type(L, index);
- return lua_typename(L, type);
- }
-
- std::string LuaInterface::functionSourcePath()
- {
- std::string path;
-
- // gets function source path
- lua_Debug ar;
- memset(&ar, 0, sizeof(ar));
- lua_getinfo(L, ">Sn", &ar);
- if(ar.source) {
- // scripts coming from files has source beginning with '@'
- if(ar.source[0] == '@') {
- path = ar.source;
- path = path.substr(1, path.find_last_of("/") - 1);
- path = path.substr(0, path.find_last_of(":"));
- }
- }
-
- return path;
- }
-
- void LuaInterface::insert(int index)
- {
- assert(hasIndex(index));
- lua_insert(L, index);
- }
-
- void LuaInterface::remove(int index)
- {
- assert(hasIndex(index));
- lua_remove(L, index);
- }
-
- bool LuaInterface::next(int index)
- {
- assert(hasIndex(index));
- return lua_next(L, index);
- }
-
- void LuaInterface::getStackFunction(int level)
- {
- lua_Debug ar;
- if(lua_getstack(L, level, &ar) == 1)
- lua_getinfo(L, "f", &ar);
- else
- pushNil();
- }
-
- void LuaInterface::getRef(int ref)
- {
- lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
- }
-
- void LuaInterface::getWeakRef(int weakRef)
- {
- // pushes weak_table[weakRef]
- getRef(m_weakTableRef);
- rawGeti(weakRef);
- remove(-2);
- }
-
- void LuaInterface::setGlobalEnvironment(int env)
- {
- pushThread();
- getRef(env);
- assert(isTable());
- setEnv();
- pop();
- }
-
- void LuaInterface::setMetatable(int index)
- {
- assert(hasIndex(index));
- lua_setmetatable(L, index);
- }
-
- void LuaInterface::getMetatable(int index)
- {
- assert(hasIndex(index));
- lua_getmetatable(L, index);
- }
-
- void LuaInterface::getField(const char* key, int index)
- {
- assert(hasIndex(index));
- assert(isUserdata(index) || isTable(index));
- lua_getfield(L, index, key);
- }
-
- void LuaInterface::setField(const char* key, int index)
- {
- assert(hasIndex(index));
- assert(isUserdata(index) || isTable(index));
- lua_setfield(L, index, key);
- }
-
- void LuaInterface::getEnv(int index)
- {
- assert(hasIndex(index));
- lua_getfenv(L, index);
- }
-
- void LuaInterface::setEnv(int index)
- {
- assert(hasIndex(index));
- lua_setfenv(L, index);
- }
-
- void LuaInterface::getTable(int index)
- {
- assert(hasIndex(index));
- lua_gettable(L, index);
- }
-
- void LuaInterface::setTable(int index)
- {
- assert(hasIndex(index));
- lua_settable(L, index);
- }
-
- void LuaInterface::clearTable(int index)
- {
- assert(hasIndex(index) && isTable(index));
- pushNil(); // table, nil
- bool stop = false;
- while(next(index-1)) { // table, key, value
- pop(); // table, key
- pushValue(); // table, key, key
- if(next(index-2)) { // table, key, nextkey, value
- pop(); // table, key, nextkey
- insert(-2); // table, nextkey, key
- pushNil(); // table, nextkey, key, nil
- rawSet(index-3); // table, nextkey
- } else { // table, key
- pushNil(); // table, key, nil
- rawSet(index-2); // table
- break;
- }
- }
- }
-
- void LuaInterface::getGlobal(const std::string& key)
- {
- lua_getglobal(L, key.c_str());
- }
-
- void LuaInterface::getGlobalField(const std::string& globalKey, const std::string& fieldKey)
- {
- getGlobal(globalKey);
- if(!isNil()) {
- assert(isTable() || isUserdata());
- getField(fieldKey);
- remove(-2);
- }
- }
-
- void LuaInterface::setGlobal(const std::string& key)
- {
- assert(hasIndex(-1));
- lua_setglobal(L, key.c_str());
- }
-
- void LuaInterface::rawGet(int index)
- {
- assert(hasIndex(index));
- lua_rawget(L, index);
- }
-
- void LuaInterface::rawGeti(int n, int index)
- {
- assert(hasIndex(index));
- lua_rawgeti(L, index, n);
- }
-
- void LuaInterface::rawSet(int index)
- {
- assert(hasIndex(index));
- lua_rawset(L, index);
- }
-
- void LuaInterface::rawSeti(int n, int index)
- {
- assert(hasIndex(index));
- lua_rawseti(L, index, n);
- }
-
- void LuaInterface::newTable()
- {
- lua_newtable(L);
- }
-
- void* LuaInterface::newUserdata(int size)
- {
- return lua_newuserdata(L, size);
- }
-
- void LuaInterface::pop(int n)
- {
- if(n > 0) {
- assert(hasIndex(-n));
- lua_pop(L, n);
- }
- }
-
- long LuaInterface::popInteger()
- {
- assert(hasIndex(-1));
- long v = toInteger(-1);
- pop();
- return v;
- }
-
- double LuaInterface::popNumber()
- {
- assert(hasIndex(-1));
- double v = toNumber(-1);
- pop();
- return v;
- }
-
- bool LuaInterface::popBoolean()
- {
- assert(hasIndex(-1));
- bool v = toBoolean(-1);
- pop();
- return v;
- }
-
- std::string LuaInterface::popString()
- {
- assert(hasIndex(-1));
- std::string v = toString(-1);
- pop();
- return v;
- }
-
- void* LuaInterface::popUserdata()
- {
- assert(hasIndex(-1));
- void* v = toUserdata(-1);
- pop();
- return v;
- }
-
- LuaObjectPtr LuaInterface::popObject()
- {
- assert(hasIndex(-1));
- LuaObjectPtr v = toObject(-1);
- pop();
- return v;
- }
-
- void* LuaInterface::popUpvalueUserdata()
- {
- return lua_touserdata(L, lua_upvalueindex(1));
- }
-
- void LuaInterface::pushNil()
- {
- lua_pushnil(L);
- checkStack();
- }
-
- void LuaInterface::pushInteger(long v)
- {
- lua_pushinteger(L, v);
- checkStack();
- }
-
- void LuaInterface::pushNumber(double v)
- {
- lua_pushnumber(L, v);
- checkStack();
- }
-
- void LuaInterface::pushBoolean(bool v)
- {
- lua_pushboolean(L, v);
- checkStack();
- }
-
- void LuaInterface::pushCString(const char* v)
- {
- assert(v);
- lua_pushstring(L, v);
- checkStack();
- }
-
- void LuaInterface::pushString(const std::string& v)
- {
- lua_pushlstring(L, v.c_str(), v.length());
- checkStack();
- }
-
- void LuaInterface::pushLightUserdata(void* p)
- {
- lua_pushlightuserdata(L, p);
- checkStack();
- }
-
- void LuaInterface::pushThread()
- {
- lua_pushthread(L);
- checkStack();
- }
-
- void LuaInterface::pushObject(const LuaObjectPtr& obj)
- {
- // fills a new userdata with a new LuaObjectPtr pointer
- new(newUserdata(sizeof(LuaObjectPtr))) LuaObjectPtr(obj);
- m_totalObjRefs++;
-
- obj->luaGetMetatable();
- if(isNil())
- g_logger.fatal(stdext::format("metatable for class '%s' not found, did you bind the C++ class?", obj->getClassName()));
- setMetatable();
- }
-
- void LuaInterface::pushCFunction(LuaCFunction func, int n)
- {
- lua_pushcclosure(L, func, n);
- checkStack();
- }
-
- void LuaInterface::pushCppFunction(const LuaCppFunction& func)
- {
- // create a pointer to func (this pointer will hold the function existence)
- new(newUserdata(sizeof(LuaCppFunctionPtr))) LuaCppFunctionPtr(new LuaCppFunction(func));
- m_totalFuncRefs++;
-
- // sets the userdata __gc metamethod, needed to free the function pointer when it gets collected
- newTable();
- pushCFunction(&LuaInterface::luaCollectCppFunction);
- setField("__gc");
- setMetatable();
-
- // actually pushes a C function callback that will call the cpp function
- pushCFunction(&LuaInterface::luaCppFunctionCallback, 1);
- }
-
- void LuaInterface::pushValue(int index)
- {
- assert(hasIndex(index));
- lua_pushvalue(L, index);
- checkStack();
- }
-
- bool LuaInterface::isNil(int index)
- {
- assert(hasIndex(index));
- return lua_isnil(L, index);
- }
-
- bool LuaInterface::isBoolean(int index)
- {
- assert(hasIndex(index));
- return lua_isboolean(L, index);
- }
-
- bool LuaInterface::isNumber(int index)
- {
- assert(hasIndex(index));
- return lua_isnumber(L, index);
- }
-
- bool LuaInterface::isString(int index)
- {
- assert(hasIndex(index));
- return lua_isstring(L, index);
- }
-
- bool LuaInterface::isTable(int index)
- {
- assert(hasIndex(index));
- return lua_istable(L, index);
- }
-
- bool LuaInterface::isFunction(int index)
- {
- assert(hasIndex(index));
- return lua_isfunction(L, index);
- }
-
- bool LuaInterface::isCFunction(int index)
- {
- assert(hasIndex(index));
- return lua_iscfunction(L, index);
- }
-
- bool LuaInterface::isUserdata(int index)
- {
- assert(hasIndex(index));
- return lua_isuserdata(L, index);
- }
-
- bool LuaInterface::toBoolean(int index)
- {
- assert(hasIndex(index));
- return (bool)lua_toboolean(L, index);
- }
-
- int LuaInterface::toInteger(int index)
- {
- assert(hasIndex(index));
- return lua_tointeger(L, index);
- }
-
- double LuaInterface::toNumber(int index)
- {
- assert(hasIndex(index));
- return lua_tonumber(L, index);
- }
-
- const char* LuaInterface::toCString(int index)
- {
- assert(hasIndex(index));
- return lua_tostring(L, index);
- }
-
- std::string LuaInterface::toString(int index)
- {
- assert(hasIndex(index));
- std::string str;
- size_t len;
- const char *c_str = lua_tolstring(L, index, &len);
- if(c_str && len > 0)
- str.assign(c_str, len);
- return str;
- }
-
- void* LuaInterface::toUserdata(int index)
- {
- assert(hasIndex(index));
- return lua_touserdata(L, index);
- }
-
- LuaObjectPtr LuaInterface::toObject(int index)
- {
- assert(hasIndex(index));
- if(isUserdata(index)) {
- LuaObjectPtr* objRef = static_cast<LuaObjectPtr*>(toUserdata(index));
- if(objRef && *objRef)
- return *objRef;
- }
- return nullptr;
- }
-
- int LuaInterface::getTop()
- {
- return lua_gettop(L);
- }
-
- void LuaInterface::loadFiles(std::string directory, bool recursive, std::string contains)
- {
- for(const std::string& fileName : g_resources.listDirectoryFiles(directory)) {
- std::string fullPath = directory + "/" + fileName;
-
- if(recursive && g_resources.directoryExists(fullPath)) {
- loadFiles(fullPath, true, contains);
- continue;
- }
-
- if(!g_resources.isFileType(fileName, "lua"))
- continue;
-
- if(!contains.empty() && fileName.find(contains) == std::string::npos)
- continue;
-
- try {
- g_lua.loadScript(fullPath);
- g_lua.call(0, 0);
- } catch(stdext::exception& e) {
- g_lua.pushString(e.what());
- g_lua.error();
- }
- }
- }
|