Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

463 righe
19 KiB

/*
* 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.
*/
#ifndef LUAINTERFACE_H
#define LUAINTERFACE_H
#include "declarations.h"
struct lua_State;
typedef int (*LuaCFunction) (lua_State *L);
/// Class that manages LUA stuff
class LuaInterface
{
public:
LuaInterface();
~LuaInterface();
void init();
void terminate();
/// Register core script functions
void registerFunctions();
// functions that will register all script stuff in lua global environment
void registerSingletonClass(const std::string& className);
void registerClass(const std::string& className, const std::string& baseClass = "LuaObject");
void registerClassStaticFunction(const std::string& className,
const std::string& functionName,
const LuaCppFunction& function);
void registerClassMemberFunction(const std::string& className,
const std::string& functionName,
const LuaCppFunction& function);
void registerClassMemberField(const std::string& className,
const std::string& field,
const LuaCppFunction& getFunction,
const LuaCppFunction& setFunction);
void registerGlobalFunction(const std::string& functionName,
const LuaCppFunction& function);
// register shortcuts using templates
template<class C, class B = LuaObject>
void registerClass() {
registerClass(stdext::demangle_type<C>(), stdext::demangle_type<B>());
}
template<class C>
void registerClassStaticFunction(const std::string& functionName, const LuaCppFunction& function) {
registerClassStaticFunction(stdext::demangle_type<C>(), functionName, function);
}
template<class C>
void registerClassMemberFunction(const std::string& functionName, const LuaCppFunction& function) {
registerClassMemberFunction(stdext::demangle_type<C>(), functionName, function);
}
template<class C>
void registerClassMemberField(const std::string& field,
const LuaCppFunction& getFunction,
const LuaCppFunction& setFunction) {
registerClassMemberField(stdext::demangle_type<C>(), field, getFunction, setFunction);
}
// methods for binding functions
template<class C, typename F>
void bindSingletonFunction(const std::string& functionName, F C::*function, C *instance);
template<class C, typename F>
void bindSingletonFunction(const std::string& className, const std::string& functionName, F C::*function, C *instance);
template<class C, typename F>
void bindClassStaticFunction(const std::string& functionName, const F& function);
template<typename F>
void bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function);
template<class C, typename F, class FC>
void bindClassMemberFunction(const std::string& functionName, F FC::*function);
template<class C, typename F, class FC>
void bindClassMemberFunction(const std::string& className, const std::string& functionName, F FC::*function);
template<class C, typename F1, typename F2, class FC>
void bindClassMemberField(const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction);
template<class C, typename F1, typename F2, class FC>
void bindClassMemberField(const std::string& className, const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction);
template<class C, typename F, class FC>
void bindClassMemberGetField(const std::string& fieldName, F FC::*getFunction);
template<class C, typename F, class FC>
void bindClassMemberGetField(const std::string& className, const std::string& fieldName, F FC::*getFunction);
template<class C, typename F, class FC>
void bindClassMemberSetField(const std::string& fieldName, F FC::*setFunction);
template<class C, typename F, class FC>
void bindClassMemberSetField(const std::string& className, const std::string& fieldName, F FC::*setFunction);
template<typename F>
void bindGlobalFunction(const std::string& functionName, const F& function);
private:
/// Metamethod that will retrieve fields values (that include functions) from the object when using '.' or ':'
static int luaObjectGetEvent(LuaInterface* lua);
/// Metamethod that is called when setting a field of the object by using the keyword '='
static int luaObjectSetEvent(LuaInterface* lua);
/// Metamethod that will check equality of objects by using the keyword '=='
static int luaObjectEqualEvent(LuaInterface* lua);
/// Metamethod that is called every two lua garbage collections
/// for any LuaObject that have no references left in lua environment
/// anymore, thus this creates the possibility of holding an object
/// existence by lua until it got no references left
static int luaObjectCollectEvent(LuaInterface* lua);
public:
/// Loads and runs a script, any errors are printed to stdout and returns false
bool safeRunScript(const std::string& fileName);
/// Loads and runs a script
/// @exception LuaException is thrown on any lua error
void runScript(const std::string& fileName);
/// Loads and runs the script from buffer
/// @exception LuaException is thrown on any lua error
void runBuffer(const std::string& buffer, const std::string& source);
/// Loads a script file and pushes it's main function onto stack,
/// @exception LuaException is thrown on any lua error
void loadScript(const std::string& fileName);
/// Loads a function from buffer and pushes it onto stack,
/// @exception LuaException is thrown on any lua error
void loadFunction(const std::string& buffer, const std::string& source = "lua function buffer");
/// Evaluates a lua expression and pushes the result value onto the stack
/// @exception LuaException is thrown on any lua error
void evaluateExpression(const std::string& expression, const std::string& source = "lua expression");
/// Generates a traceback message for the current call stack
/// @param errorMessage is an additional error message
/// @param level is the level of the traceback, 0 means trace from calling function
/// @return the generated traceback message
std::string traceback(const std::string& errorMessage = "", int level = 0);
/// Throw a lua error if inside a lua call or generates an C++ stdext::exception
/// @param message is the error message wich will be displayed before the error traceback
/// @exception stdext::exception is thrown with the error message if the error is not captured by lua
void throwError(const std::string& message);
/// Searches for the source of the current running function
std::string getCurrentSourcePath(int level = 0);
/// @brief Calls a function
/// The function and arguments must be on top of the stack in order,
/// results are pushed onto the stack.
/// @exception LuaException is thrown on any lua error
/// @return number of results
int safeCall(int numArgs = 0, int numRets = -1);
/// Same as safeCall but catches exceptions and can also calls a table of functions,
/// if any error occurs it will be reported to stdout and returns 0 results
/// @param requestedResults is the number of results requested to pushes onto the stack,
/// if supplied, the call will always pushes that number of results, even if it fails
int signalCall(int numArgs = 0, int numRets = -1);
/// @brief Creates a new environment table
/// The new environment table is redirected to the global environment (aka _G),
/// this allows to access global variables from _G in the new environment and
/// prevents new variables in this new environment to be set on the global environment
int newSandboxEnv();
template<typename... T>
int luaCallGlobalField(const std::string& global, const std::string& field, const T&... args);
template<typename... T>
void callGlobalField(const std::string& global, const std::string& field, const T&... args);
template<typename R, typename... T>
R callGlobalField(const std::string& global, const std::string& field, const T&... args);
bool isInCppCallback() { return m_cppCallbackDepth != 0; }
private:
/// Load scripts requested by lua 'require'
static int luaScriptLoader(lua_State* L);
/// Run scripts requested by lua 'dofile'
static int lua_dofile(lua_State* L);
/// Run scripts requested by lua 'dofiles'
static int lua_dofiles(lua_State* L);
/// Run scripts requested by lua 'dofiles'
static int lua_loadfile(lua_State* L);
/// Handle lua errors from safeCall
static int luaErrorHandler(lua_State* L);
/// Handle bound cpp functions callbacks
static int luaCppFunctionCallback(lua_State* L);
/// Collect bound cpp function pointers
static int luaCollectCppFunction(lua_State* L);
public:
void createLuaState();
void closeLuaState();
void collectGarbage();
void loadBuffer(const std::string& buffer, const std::string& source);
int pcall(int numArgs = 0, int numRets = 0, int errorFuncIndex = 0);
void call(int numArgs = 0, int numRets = 0);
void error();
int ref();
int weakRef();
void unref(int ref);
void useValue() { pushValue(); ref(); }
const char* typeName(int index = -1);
std::string functionSourcePath();
void insert(int index);
void remove(int index);
bool next(int index = -2);
void checkStack() { assert(getTop() <= 20); }
void getStackFunction(int level = 0);
void getRef(int ref);
void getWeakRef(int weakRef);
int getGlobalEnvironment() { return m_globalEnv; }
void setGlobalEnvironment(int env);
void resetGlobalEnvironment() { setGlobalEnvironment(m_globalEnv); }
void setMetatable(int index = -2);
void getMetatable(int index = -1);
void getField(const char* key, int index = -1);
void getField(const std::string& key, int index = -1) { return getField(key.c_str(), index); }
void setField(const char* key, int index = -2);
void setField(const std::string& key, int index = -2) { return setField(key.c_str(), index); }
void getTable(int index = -2);
void setTable(int index = -3);
void clearTable(int index = -1);
void getEnv(int index = -1);
void setEnv(int index = -2);
void getGlobal(const std::string& key);
void getGlobalField(const std::string& globalKey, const std::string& fieldKey);
void setGlobal(const std::string& key);
void rawGet(int index = -1);
void rawGeti(int n, int index = -1);
void rawSet(int index = -3);
void rawSeti(int n, int index = -2);
void newTable();
void* newUserdata(int size);
void pop(int n = 1);
long popInteger();
double popNumber();
bool popBoolean();
std::string popString();
void* popUserdata();
void* popUpvalueUserdata();
LuaObjectPtr popObject();
void pushNil();
void pushInteger(long v);
void pushNumber(double v);
void pushBoolean(bool v);
void pushCString(const char* v);
void pushString(const std::string& v);
void pushLightUserdata(void* p);
void pushThread();
void pushValue(int index = -1);
void pushObject(const LuaObjectPtr& obj);
void pushCFunction(LuaCFunction func, int n = 0);
void pushCppFunction(const LuaCppFunction& func);
bool isNil(int index = -1);
bool isBoolean(int index = -1);
bool isNumber(int index = -1);
bool isString(int index = -1);
bool isTable(int index = -1);
bool isFunction(int index = -1);
bool isCFunction(int index = -1);
bool isLuaFunction(int index = -1) { return (isFunction() && !isCFunction()); }
bool isUserdata(int index = -1);
bool toBoolean(int index = -1);
int toInteger(int index = -1);
double toNumber(int index = -1);
const char* toCString(int index = -1);
std::string toString(int index = -1);
void* toUserdata(int index = -1);
LuaObjectPtr toObject(int index = -1);
int getTop();
int stackSize() { return getTop(); }
void clearStack() { pop(stackSize()); }
bool hasIndex(int index) { return (stackSize() >= (index < 0 ? -index : index) && index != 0); }
void loadFiles(std::string directory, bool recursive = false, std::string contains = "");
/// Pushes any type onto the stack
template<typename T, typename... Args>
int polymorphicPush(const T& v, const Args&... args);
int polymorphicPush() { return 0; }
/// Casts a value from stack to any type
/// @exception LuaBadValueCastException thrown if the cast fails
template<class T>
T castValue(int index = -1);
/// Same as castValue but also pops
template<class T>
T polymorphicPop() { T v = castValue<T>(); pop(1); return v; }
private:
lua_State* L;
int m_weakTableRef;
int m_cppCallbackDepth;
int m_totalObjRefs;
int m_totalFuncRefs;
int m_globalEnv;
};
extern LuaInterface g_lua;
// must be included after, because they need LuaInterface fully declared
#include "luaexception.h"
#include "luabinder.h"
#include "luavaluecasts.h"
template<typename T, typename... Args>
int LuaInterface::polymorphicPush(const T& v, const Args&... args) {
int r = push_luavalue(v);
return r + polymorphicPush(args...);
}
// next templates must be defined after above includes
template<class C, typename F>
void LuaInterface::bindSingletonFunction(const std::string& functionName, F C::*function, C *instance) {
registerClassStaticFunction<C>(functionName, luabinder::bind_singleton_mem_fun(function, instance));
}
template<class C, typename F>
void LuaInterface::bindSingletonFunction(const std::string& className, const std::string& functionName, F C::*function, C *instance) {
registerClassStaticFunction(className, functionName, luabinder::bind_singleton_mem_fun(function, instance));
}
template<class C, typename F>
void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
}
template<typename F>
void LuaInterface::bindClassStaticFunction(const std::string& className, const std::string& functionName, const F& function) {
registerClassStaticFunction(className, functionName, luabinder::bind_fun(function));
}
template<class C, typename F, class FC>
void LuaInterface::bindClassMemberFunction(const std::string& functionName, F FC::*function) {
registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun<C>(function));
}
template<class C, typename F, class FC>
void LuaInterface::bindClassMemberFunction(const std::string& className, const std::string& functionName, F FC::*function) {
registerClassMemberFunction(className, functionName, luabinder::bind_mem_fun<C>(function));
}
template<class C, typename F1, typename F2, class FC>
void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction) {
registerClassMemberField<C>(fieldName, luabinder::bind_mem_fun<C>(getFunction), luabinder::bind_mem_fun<C>(setFunction));
}
template<class C, typename F1, typename F2, class FC>
void LuaInterface::bindClassMemberField(const std::string& className, const std::string& fieldName, F1 FC::*getFunction, F2 FC::*setFunction) {
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun<C>(getFunction), luabinder::bind_mem_fun<C>(setFunction));
}
template<class C, typename F, class FC>
void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F FC::*getFunction) {
registerClassMemberField<C>(fieldName, luabinder::bind_mem_fun<C>(getFunction), LuaCppFunction());
}
template<class C, typename F, class FC>
void LuaInterface::bindClassMemberGetField(const std::string& className, const std::string& fieldName, F FC::*getFunction) {
registerClassMemberField(className, fieldName, luabinder::bind_mem_fun<C>(getFunction), LuaCppFunction());
}
template<class C, typename F, class FC>
void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F FC::*setFunction) {
registerClassMemberField<C>(fieldName, LuaCppFunction(), luabinder::bind_mem_fun<C>(setFunction));
}
template<class C, typename F, class FC>
void LuaInterface::bindClassMemberSetField(const std::string& className, const std::string& fieldName, F FC::*setFunction) {
registerClassMemberField(className, fieldName, LuaCppFunction(), luabinder::bind_mem_fun<C>(setFunction));
}
template<typename F>
void LuaInterface::bindGlobalFunction(const std::string& functionName, const F& function) {
registerGlobalFunction(functionName, luabinder::bind_fun(function));
}
template<class T>
T LuaInterface::castValue(int index) {
T o;
if(!luavalue_cast(index, o))
throw LuaBadValueCastException(typeName(index), stdext::demangle_type<T>());
return o;
}
template<typename... T>
int LuaInterface::luaCallGlobalField(const std::string& global, const std::string& field, const T&... args) {
g_lua.getGlobalField(global, field);
if(!g_lua.isNil()) {
int numArgs = g_lua.polymorphicPush(args...);
return g_lua.signalCall(numArgs);
} else
g_lua.pop(1);
return 0;
}
template<typename... T>
void LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) {
int rets = luaCallGlobalField(global, field, args...);
if(rets > 0)
pop(rets);
}
template<typename R, typename... T>
R LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) {
R result;
int rets = luaCallGlobalField(global, field, args...);
if(rets > 0) {
assert(rets == 1);
result = g_lua.polymorphicPop<R>();
} else
result = R();
return result;
}
#endif