mirror of
https://github.com/edubart/otclient.git
synced 2025-10-20 06:23:26 +02:00
merge total remake
This commit is contained in:
207
src/framework/luascript/luabinder.h
Normal file
207
src/framework/luascript/luabinder.h
Normal file
@@ -0,0 +1,207 @@
|
||||
#ifndef LUABINDER_H
|
||||
#define LUABINDER_H
|
||||
|
||||
// this file is and must be included only from luainterface.h
|
||||
#include "luainterface.h"
|
||||
#include "luaexception.h"
|
||||
|
||||
/// This namespace contains some dirty metaprogamming with C++0x features
|
||||
/// The purpose here is to create templates that can bind any function from C++
|
||||
/// and expose in lua environment. This is done combining variadic templates,
|
||||
/// lambdas, tuples and some type traits features from the new C++0x standard to create
|
||||
/// templates that can detect functions arguments to generate a lambdas. These lambdas
|
||||
/// pops arguments from lua stack, call the bound C++ function and then
|
||||
/// pushes the result to lua.
|
||||
namespace luabinder
|
||||
{
|
||||
/// Removes const references, transforming 'const T&' into 'T'
|
||||
template<typename T>
|
||||
struct remove_const_ref {
|
||||
typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
|
||||
};
|
||||
|
||||
/// Pack arguments from lua stack into a tuple recursively
|
||||
template<int N>
|
||||
struct pack_values_into_tuple {
|
||||
template<typename Tuple>
|
||||
static void call(Tuple& tuple, LuaInterface* lua) {
|
||||
typedef typename std::tuple_element<N-1, Tuple>::type ValueType;
|
||||
std::get<N-1>(tuple) = lua->polymorphicPop<ValueType>();
|
||||
pack_values_into_tuple<N-1>::call(tuple, lua);
|
||||
}
|
||||
};
|
||||
template<>
|
||||
struct pack_values_into_tuple<0> {
|
||||
template<typename Tuple>
|
||||
static void call(Tuple &tuple, LuaInterface* lua) { }
|
||||
};
|
||||
|
||||
/// C++ function caller that can push results to lua
|
||||
template<typename Ret, typename F, typename... Args>
|
||||
typename std::enable_if<!std::is_void<Ret>::value, int>::type
|
||||
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
|
||||
Ret ret = f(args...);
|
||||
lua->polymorphicPush(ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// C++ void function caller
|
||||
template<typename Ret, typename F, typename... Args>
|
||||
typename std::enable_if<std::is_void<Ret>::value, int>::type
|
||||
call_fun_and_push_result(const F& f, LuaInterface* lua, Args... args) {
|
||||
f(args...);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Expand arguments from tuple for later calling the C++ function
|
||||
template<int N, typename Ret>
|
||||
struct expand_fun_arguments {
|
||||
template<typename Tuple, typename F, typename... Args>
|
||||
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
|
||||
return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, std::cref(std::get<N-1>(tuple)), args...);
|
||||
}
|
||||
};
|
||||
template<typename Ret>
|
||||
struct expand_fun_arguments<0,Ret> {
|
||||
template<typename Tuple, typename F, typename... Args>
|
||||
static int call(const Tuple& tuple, const F& f, LuaInterface* lua, Args... args) {
|
||||
return call_fun_and_push_result<Ret>(f, lua, args...);
|
||||
}
|
||||
};
|
||||
|
||||
/// Bind different types of functions generating a lambda
|
||||
template<typename Ret, typename F, typename Tuple>
|
||||
LuaCppFunction bind_fun_specializer(const F& f) {
|
||||
enum { N = std::tuple_size<Tuple>::value };
|
||||
return [=](LuaInterface* lua) {
|
||||
if(lua->stackSize() != N)
|
||||
throw LuaBadNumberOfArgumentsException(N, lua->stackSize());
|
||||
Tuple tuple;
|
||||
pack_values_into_tuple<N>::call(tuple, lua);
|
||||
return expand_fun_arguments<N,Ret>::call(tuple, f, lua);
|
||||
};
|
||||
}
|
||||
|
||||
/// Bind a std::function
|
||||
template<typename Ret, typename... Args>
|
||||
LuaCppFunction bind_fun(const std::function<Ret(Args...)>& f) {
|
||||
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
|
||||
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
|
||||
decltype(f),
|
||||
Tuple>(f);
|
||||
}
|
||||
|
||||
/// Bind a customized functions
|
||||
template<>
|
||||
inline
|
||||
LuaCppFunction bind_fun(const std::function<int(LuaInterface*)>& f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
/// Convert to C++ functions pointers to std::function then bind
|
||||
template<typename Ret, typename... Args>
|
||||
LuaCppFunction bind_fun(Ret (*f)(Args...)) {
|
||||
return bind_fun(std::function<Ret(Args...)>(f));
|
||||
}
|
||||
|
||||
// a tuple_element that works with the next algorithm
|
||||
template<std::size_t __i, typename _Tp>
|
||||
struct tuple_element;
|
||||
template<std::size_t __i, typename _Head, typename... _Tail>
|
||||
struct tuple_element<__i, std::tuple<_Head, _Tail...> >
|
||||
: tuple_element<__i - 1, std::tuple<_Tail...> > { };
|
||||
template<typename _Head, typename... _Tail>
|
||||
struct tuple_element<0, std::tuple<_Head, _Tail...> > { typedef _Head type; };
|
||||
template<typename _Head>
|
||||
struct tuple_element<-1,std::tuple<_Head>> { typedef void type; };
|
||||
template<std::size_t __i>
|
||||
struct tuple_element<__i,std::tuple<>> { typedef void type; };
|
||||
|
||||
template<typename Enable, int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
|
||||
struct get_holded_tuple;
|
||||
|
||||
// some dirty stuff to extract arguments from std::bind holders
|
||||
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
|
||||
struct get_holded_tuple<
|
||||
typename std::enable_if<
|
||||
(N > 0 && std::is_placeholder<
|
||||
typename tuple_element<N-1, HoldersTuple>::type
|
||||
>::value > 0), void
|
||||
>::type, N, ArgsTuple, HoldersTuple, Args...> {
|
||||
typedef typename std::tuple_element<N-1, HoldersTuple>::type holder_type;
|
||||
typedef typename tuple_element<std::is_placeholder<holder_type>::value-1, ArgsTuple>::type _arg_type;
|
||||
typedef typename remove_const_ref<_arg_type>::type arg_type;
|
||||
typedef typename get_holded_tuple<void, N-1, ArgsTuple, HoldersTuple, arg_type, Args...>::type type;
|
||||
};
|
||||
template<int N, typename ArgsTuple, typename HoldersTuple, typename... Args>
|
||||
struct get_holded_tuple<typename std::enable_if<(N > 0 && std::is_placeholder<typename tuple_element<N-1, HoldersTuple>::type>::value == 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> {
|
||||
typedef typename get_holded_tuple<void, N-1, ArgsTuple, HoldersTuple, Args...>::type type;
|
||||
};
|
||||
template<typename ArgsTuple, typename HoldersTuple, typename... Args>
|
||||
struct get_holded_tuple<void, 0, ArgsTuple, HoldersTuple, Args...> {
|
||||
typedef typename std::tuple<Args...> type;
|
||||
};
|
||||
|
||||
/// Rebind functions already bound by std::bind handling it's placeholders
|
||||
template<typename Ret, typename... Args, typename... Holders>
|
||||
LuaCppFunction bind_fun(const std::_Bind<Ret (*(Holders...))(Args...)>& f) {
|
||||
typedef typename std::tuple<Args...> ArgsTuple;
|
||||
typedef typename std::tuple<Holders...> HoldersTuple;
|
||||
typedef typename get_holded_tuple<void, sizeof...(Holders), ArgsTuple, HoldersTuple>::type Tuple;
|
||||
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
|
||||
decltype(f),
|
||||
Tuple>(f);
|
||||
}
|
||||
|
||||
/// Rebind member functions already bound by std::bind handling it's placeholders
|
||||
template<typename Obj, typename Ret, typename... Args, typename... Holders>
|
||||
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<Ret (Obj::*)(Args...)>(Obj*, Holders...)>& f) {
|
||||
typedef typename std::tuple<Args...> ArgsTuple;
|
||||
typedef typename std::tuple<Holders...> HoldersTuple;
|
||||
typedef typename get_holded_tuple<void, sizeof...(Holders), ArgsTuple, HoldersTuple>::type Tuple;
|
||||
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
|
||||
decltype(f),
|
||||
Tuple>(f);
|
||||
}
|
||||
|
||||
/// Bind customized functions already bound by std::bind
|
||||
template<typename Obj>
|
||||
LuaCppFunction bind_fun(const std::_Bind<std::_Mem_fn<int (Obj::*)(LuaInterface*)>(Obj*, std::_Placeholder<1>)>& f) {
|
||||
return f;
|
||||
}
|
||||
inline
|
||||
LuaCppFunction bind_fun(const std::_Bind<int (*(std::_Placeholder<1>))(LuaInterface*)>& f) {
|
||||
return f;
|
||||
}
|
||||
|
||||
/// Bind member functions
|
||||
template<typename Ret, typename Obj, typename... Args>
|
||||
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) {
|
||||
auto mf = std::mem_fn(f);
|
||||
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
|
||||
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
|
||||
decltype(mf),
|
||||
Tuple>(mf);
|
||||
}
|
||||
template<typename Ret, typename Obj, typename... Args>
|
||||
LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) {
|
||||
auto mf = std::mem_fn(f);
|
||||
typedef typename std::tuple<Obj*, typename remove_const_ref<Args>::type...> Tuple;
|
||||
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
|
||||
decltype(mf),
|
||||
Tuple>(mf);
|
||||
}
|
||||
|
||||
/// Bind customized member functions
|
||||
template<typename Obj>
|
||||
LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaInterface*)) {
|
||||
auto mf = std::mem_fn(f);
|
||||
return [=](LuaInterface* lua) {
|
||||
auto obj = lua->castValue<Obj*>(1);
|
||||
lua->remove(1);
|
||||
return mf(obj, lua);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
12
src/framework/luascript/luadeclarations.h
Normal file
12
src/framework/luascript/luadeclarations.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LUADECLARATIONS_H
|
||||
#define LUADECLARATIONS_H
|
||||
|
||||
#include <global.h>
|
||||
|
||||
class LuaInterface;
|
||||
class LuaObject;
|
||||
typedef std::function<int(LuaInterface*)> LuaCppFunction;
|
||||
typedef std::unique_ptr<LuaCppFunction> LuaCppFunctionPtr;
|
||||
typedef std::shared_ptr<LuaObject> LuaObjectPtr;
|
||||
|
||||
#endif
|
31
src/framework/luascript/luaexception.cpp
Normal file
31
src/framework/luascript/luaexception.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "luaexception.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaException::LuaException(const std::string& error, int traceLevel)
|
||||
{
|
||||
g_lua.clearStack(); // on every exception, clear lua stack
|
||||
generateLuaErrorMessage(error, traceLevel);
|
||||
}
|
||||
|
||||
void LuaException::generateLuaErrorMessage(const std::string& error, int traceLevel)
|
||||
{
|
||||
// append trace level to error message
|
||||
if(traceLevel >= 0)
|
||||
m_what = aux::make_string("LUA ERROR: ", g_lua.traceback(error, traceLevel));
|
||||
else
|
||||
m_what = aux::make_string("LUA ERROR: ", error);
|
||||
}
|
||||
|
||||
LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got)
|
||||
{
|
||||
std::string error = "attempt to call a function with wrong number of arguments";
|
||||
if(expected >= 0 && got >= 0)
|
||||
error = aux::make_string(error, " (expected ", expected, ", but got ", got, ")");
|
||||
generateLuaErrorMessage(error, 1);
|
||||
}
|
||||
|
||||
LuaBadValueCastException::LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName)
|
||||
{
|
||||
std::string error = aux::make_string("attempt to cast a '", luaTypeName, "' lua value to '", cppTypeName, "'");
|
||||
generateLuaErrorMessage(error, 0);
|
||||
}
|
34
src/framework/luascript/luaexception.h
Normal file
34
src/framework/luascript/luaexception.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef LUAEXCEPTION_H
|
||||
#define LUAEXCEPTION_H
|
||||
|
||||
#include "luadeclarations.h"
|
||||
|
||||
class LuaException : public std::exception
|
||||
{
|
||||
public:
|
||||
LuaException(const std::string& error, int traceLevel = -1);
|
||||
virtual ~LuaException() throw() { }
|
||||
|
||||
void generateLuaErrorMessage(const std::string& error, int traceLevel);
|
||||
|
||||
virtual const char* what() const throw() { return m_what.c_str(); }
|
||||
|
||||
protected:
|
||||
LuaException() { }
|
||||
|
||||
std::string m_what;
|
||||
};
|
||||
|
||||
class LuaBadNumberOfArgumentsException : public LuaException
|
||||
{
|
||||
public:
|
||||
LuaBadNumberOfArgumentsException(int expected = -1, int got = -1);
|
||||
};
|
||||
|
||||
class LuaBadValueCastException : public LuaException
|
||||
{
|
||||
public:
|
||||
LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName);
|
||||
};
|
||||
|
||||
#endif
|
63
src/framework/luascript/luafunctions.cpp
Normal file
63
src/framework/luascript/luafunctions.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "luainterface.h"
|
||||
#include <graphics/fontmanager.h>
|
||||
#include <ui/ui.h>
|
||||
#include <net/protocol.h>
|
||||
|
||||
void LuaInterface::registerFunctions()
|
||||
{
|
||||
// easy typing _1, _2, ...
|
||||
using namespace std::placeholders;
|
||||
|
||||
// UIWidget
|
||||
g_lua.registerClass<UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIWidget>("create", &UIWidget::create);
|
||||
|
||||
g_lua.bindClassMemberFunction("destroy", &UIWidget::destroy);
|
||||
g_lua.bindClassMemberFunction("addChild", &UIWidget::addChild);
|
||||
|
||||
g_lua.bindClassMemberField<UIWidget>("id", &UIWidget::getId, &UIWidget::setId);
|
||||
g_lua.bindClassMemberField<UIWidget>("enabled", &UIWidget::isEnabled, &UIWidget::setEnabled);
|
||||
g_lua.bindClassMemberField<UIWidget>("visible", &UIWidget::isVisible, &UIWidget::setVisible);
|
||||
g_lua.bindClassMemberField<UIWidget>("width", &UIWidget::getWidth, &UIWidget::setWidth);
|
||||
g_lua.bindClassMemberField<UIWidget>("height", &UIWidget::getHeight, &UIWidget::setHeight);
|
||||
g_lua.bindClassMemberField<UIWidget>("parent", &UIWidget::getParent, &UIWidget::setParent);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginTop", &UIWidget::getMarginTop, &UIWidget::setMarginTop);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginBottom", &UIWidget::getMarginBottom, &UIWidget::setMarginBottom);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginLeft", &UIWidget::getMarginLeft, &UIWidget::setMarginLeft);
|
||||
g_lua.bindClassMemberField<UIWidget>("marginRight", &UIWidget::getMarginRight, &UIWidget::setMarginRight);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("centerIn", &UIWidget::centerIn);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("addAnchor", &UIWidget::addAnchor);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("getChild", &UIWidget::getChildById);
|
||||
g_lua.bindClassMemberFunction<UIWidget>("addChild", &UIWidget::addChild);
|
||||
|
||||
// UILabel
|
||||
g_lua.registerClass<UILabel, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UILabel>("create", &UILabel::create);
|
||||
g_lua.bindClassMemberField("text", &UILabel::getText, &UILabel::setText);
|
||||
g_lua.bindClassMemberFunction("resizeToText", &UILabel::resizeToText);
|
||||
|
||||
// UIButton
|
||||
g_lua.registerClass<UIButton, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIButton>("create", &UIButton::create);
|
||||
g_lua.bindClassMemberField("text", &UIButton::getText, &UIButton::setText);
|
||||
|
||||
// UILineEdit
|
||||
g_lua.registerClass<UILineEdit, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UILineEdit>("create", &UILineEdit::create);
|
||||
g_lua.bindClassMemberField("text", &UILineEdit::getText, &UILineEdit::setText);
|
||||
|
||||
// UIWindow
|
||||
g_lua.registerClass<UIWindow, UIWidget>();
|
||||
g_lua.bindClassStaticFunction<UIWindow>("create", &UIWindow::create);
|
||||
g_lua.bindClassMemberField("title", &UIWindow::getTitle, &UIWindow::setTitle);
|
||||
|
||||
// Protocol
|
||||
g_lua.registerClass<Protocol>();
|
||||
|
||||
// global functions
|
||||
g_lua.bindGlobalFunction("importFont", std::bind(&FontManager::importFont, &g_fonts, _1));
|
||||
g_lua.bindGlobalFunction("setDefaultFont", std::bind(&FontManager::setDefaultFont, &g_fonts, _1));
|
||||
g_lua.bindGlobalFunction("importStyles", std::bind(&UIManager::importStyles, &g_ui, _1));
|
||||
g_lua.bindGlobalFunction("loadUI", std::bind(&UIManager::loadUI, &g_ui, _1));
|
||||
g_lua.bindGlobalFunction("getRootWidget", std::bind(&UIManager::getRootWidget, &g_ui));
|
||||
}
|
1035
src/framework/luascript/luainterface.cpp
Normal file
1035
src/framework/luascript/luainterface.cpp
Normal file
File diff suppressed because it is too large
Load Diff
329
src/framework/luascript/luainterface.h
Normal file
329
src/framework/luascript/luainterface.h
Normal file
@@ -0,0 +1,329 @@
|
||||
#ifndef LUAINTERFACE_H
|
||||
#define LUAINTERFACE_H
|
||||
|
||||
#include "luadeclarations.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 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(aux::demangle_type<C>(), aux::demangle_type<B>());
|
||||
}
|
||||
|
||||
template<class C>
|
||||
void registerClassStaticFunction(const std::string& functionName, const LuaCppFunction& function) {
|
||||
registerClassStaticFunction(aux::demangle_type<C>(), functionName, function);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
void registerClassMemberFunction(const std::string& functionName, const LuaCppFunction& function) {
|
||||
registerClassMemberFunction(aux::demangle_type<C>(), functionName, function);
|
||||
}
|
||||
|
||||
template<class C>
|
||||
void registerClassMemberField(const std::string& field,
|
||||
const LuaCppFunction& getFunction,
|
||||
const LuaCppFunction& setFunction) {
|
||||
registerClassMemberField(aux::demangle_type<C>(), field, getFunction, setFunction);
|
||||
}
|
||||
|
||||
// methods for binding functions
|
||||
template<class C, typename F>
|
||||
void bindClassStaticFunction(const std::string& functionName, const F& function);
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberFunction(const std::string& functionName, F C::*function);
|
||||
|
||||
template<class C, typename F1, typename F2>
|
||||
void bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction);
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberGetField(const std::string& fieldName, F C::*getFunction);
|
||||
|
||||
template<class C, typename F>
|
||||
void bindClassMemberSetField(const std::string& fieldName, F C::*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
|
||||
/// @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);
|
||||
|
||||
/// Searches for the source of the current running function
|
||||
std::string currentSourcePath();
|
||||
|
||||
/// @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);
|
||||
|
||||
/// 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 protectedCall(int numArgs = 0, int requestedResults = -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
|
||||
void newEnvironment();
|
||||
|
||||
private:
|
||||
/// Load scripts requested by lua 'require'
|
||||
static int luaScriptLoader(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 throwError();
|
||||
|
||||
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 copy(int index = -1);
|
||||
|
||||
void getStackFunction(int level = 0);
|
||||
|
||||
void getRef(int ref);
|
||||
void getWeakRef(int weakRef);
|
||||
|
||||
void getGlobalEnvironment();
|
||||
void setGlobalEnvironment();
|
||||
|
||||
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 getEnv(int index = -1);
|
||||
void setEnv(int index = -2);
|
||||
|
||||
void getGlobal(const std::string& key);
|
||||
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);
|
||||
int popInteger();
|
||||
double popNumber();
|
||||
bool popBoolean();
|
||||
std::string popString();
|
||||
void* popUserdata();
|
||||
void* popUpvalueUserdata();
|
||||
LuaObjectPtr popObject();
|
||||
|
||||
void pushNil();
|
||||
void pushInteger(int v);
|
||||
void pushNumber(double v);
|
||||
void pushBoolean(bool v);
|
||||
void pushCString(const char* v);
|
||||
void pushString(const std::string& v) { pushCString(v.c_str()); }
|
||||
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); }
|
||||
|
||||
/// Pushes any type onto the stack
|
||||
template<typename T, typename... Args>
|
||||
void polymorphicPush(T v, Args... args) { push_luavalue(v); polymorphicPush(args...); }
|
||||
void polymorphicPush() { }
|
||||
|
||||
/// 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;
|
||||
};
|
||||
|
||||
extern LuaInterface g_lua;
|
||||
|
||||
// must be included after, because they need LuaInterface fully declared
|
||||
#include "luaexception.h"
|
||||
#include "luabinder.h"
|
||||
#include "luavaluecasts.h"
|
||||
|
||||
// next templates must be defined after above includes
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassStaticFunction(const std::string& functionName, const F& function) {
|
||||
registerClassStaticFunction<C>(functionName, luabinder::bind_fun(function));
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassMemberFunction(const std::string& functionName, F C::*function) {
|
||||
registerClassMemberFunction<C>(functionName, luabinder::bind_mem_fun(function));
|
||||
}
|
||||
|
||||
template<class C, typename F1, typename F2>
|
||||
void LuaInterface::bindClassMemberField(const std::string& fieldName, F1 C::*getFunction, F2 C::*setFunction) {
|
||||
registerClassMemberField<C>(fieldName,
|
||||
luabinder::bind_mem_fun(getFunction),
|
||||
luabinder::bind_mem_fun(setFunction));
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassMemberGetField(const std::string& fieldName, F C::*getFunction) {
|
||||
registerClassMemberField<C>(fieldName,
|
||||
luabinder::bind_mem_fun(getFunction),
|
||||
LuaCppFunction());
|
||||
}
|
||||
|
||||
template<class C, typename F>
|
||||
void LuaInterface::bindClassMemberSetField(const std::string& fieldName, F C::*setFunction) {
|
||||
registerClassMemberField<C>(fieldName,
|
||||
LuaCppFunction(),
|
||||
luabinder::bind_mem_fun(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), aux::demangle_type<T>());
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif
|
47
src/framework/luascript/luaobject.cpp
Normal file
47
src/framework/luascript/luaobject.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "luaobject.h"
|
||||
#include "luainterface.h"
|
||||
|
||||
LuaObject::LuaObject() : m_fieldsTableRef(-1)
|
||||
{
|
||||
}
|
||||
|
||||
LuaObject::~LuaObject()
|
||||
{
|
||||
luaReleaseFieldsTable();
|
||||
}
|
||||
|
||||
void LuaObject::luaReleaseFieldsTable()
|
||||
{
|
||||
if(m_fieldsTableRef != -1)
|
||||
g_lua.unref(m_fieldsTableRef);
|
||||
}
|
||||
|
||||
void LuaObject::luaSetField(const std::string& key)
|
||||
{
|
||||
// create fields table on the fly
|
||||
if(m_fieldsTableRef == -1) {
|
||||
g_lua.newTable(); // create fields table
|
||||
m_fieldsTableRef = g_lua.ref(); // save a reference for it
|
||||
}
|
||||
|
||||
g_lua.getRef(m_fieldsTableRef); // push the table
|
||||
g_lua.insert(-2); // move the value to the top
|
||||
g_lua.setField(key); // set the field
|
||||
g_lua.pop(); // pop the fields table
|
||||
}
|
||||
|
||||
void LuaObject::luaGetField(const std::string& key)
|
||||
{
|
||||
if(m_fieldsTableRef != -1) {
|
||||
g_lua.getRef(m_fieldsTableRef); // push the obj's fields table
|
||||
g_lua.getField(key); // push the field value
|
||||
g_lua.remove(-2); // remove the table
|
||||
} else {
|
||||
g_lua.pushNil();
|
||||
}
|
||||
}
|
||||
|
||||
int LuaObject::getUseCount()
|
||||
{
|
||||
return shared_from_this().use_count() - 1;
|
||||
}
|
81
src/framework/luascript/luaobject.h
Normal file
81
src/framework/luascript/luaobject.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef LUAOBJECT_H
|
||||
#define LUAOBJECT_H
|
||||
|
||||
#include "luadeclarations.h"
|
||||
|
||||
/// LuaObject, all script-able classes have it as base
|
||||
class LuaObject : public std::enable_shared_from_this<LuaObject>
|
||||
{
|
||||
public:
|
||||
LuaObject();
|
||||
virtual ~LuaObject() ;
|
||||
|
||||
/// Calls a function or table of functions stored in a lua field, results are pushed onto the stack,
|
||||
/// if any lua error occurs, it will be reported to stdout and return 0 results
|
||||
/// @return the number of results
|
||||
template<typename... T>
|
||||
int callLuaField(const std::string& field, const T&... args);
|
||||
|
||||
/// Sets a field in this lua object
|
||||
template<typename T>
|
||||
void setLuaField(const std::string& key, const T& value);
|
||||
|
||||
/// Gets a field from this lua object
|
||||
template<typename T>
|
||||
T getLuaField(const std::string& key);
|
||||
|
||||
/// Release fields table reference
|
||||
void luaReleaseFieldsTable();
|
||||
|
||||
/// Sets a field from this lua object, the value must be on the stack
|
||||
void luaSetField(const std::string& key);
|
||||
|
||||
/// Gets a field from this lua object, the result is pushed onto the stack
|
||||
void luaGetField(const std::string& key);
|
||||
|
||||
/// Returns the number of references of this object
|
||||
/// @note each userdata of this object on lua counts as a reference
|
||||
int getUseCount();
|
||||
|
||||
/// Returns the class name used in Lua
|
||||
virtual std::string getLuaObjectName() const {
|
||||
// this could later be cached for more performance
|
||||
return aux::demangle_name(typeid(*this).name());
|
||||
}
|
||||
|
||||
LuaObjectPtr asLuaObject() { return shared_from_this(); }
|
||||
|
||||
private:
|
||||
int m_fieldsTableRef;
|
||||
};
|
||||
|
||||
#include "luainterface.h"
|
||||
|
||||
template<typename... T>
|
||||
int LuaObject::callLuaField(const std::string& field, const T&... args) {
|
||||
// note that the field must be retrieved from this object lua value
|
||||
// to force using the __index metamethod of it's metatable
|
||||
// so cannot use LuaObject::getField here
|
||||
// push field
|
||||
g_lua.pushObject(asLuaObject());
|
||||
g_lua.getField(field);
|
||||
|
||||
// the first argument is always this object (self)
|
||||
g_lua.insert(-2);
|
||||
g_lua.polymorphicPush(args...);
|
||||
return g_lua.protectedCall(1 + sizeof...(args));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LuaObject::setLuaField(const std::string& key, const T& value) {
|
||||
g_lua.polymorphicPush(value);
|
||||
luaSetField(key);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LuaObject::getLuaField(const std::string& key) {
|
||||
luaGetField(key);
|
||||
return g_lua.polymorphicPop<T>();
|
||||
}
|
||||
|
||||
#endif
|
195
src/framework/luascript/luavaluecasts.h
Normal file
195
src/framework/luascript/luavaluecasts.h
Normal file
@@ -0,0 +1,195 @@
|
||||
#ifndef LUAVALUECASTS_H
|
||||
#define LUAVALUECASTS_H
|
||||
|
||||
// this file is and must be included only from luainterface.h
|
||||
#include "luainterface.h"
|
||||
#include "luaexception.h"
|
||||
|
||||
/// Pushes bool
|
||||
inline void push_luavalue(bool v) {
|
||||
g_lua.pushBoolean(v);
|
||||
}
|
||||
|
||||
/// Pushes int
|
||||
inline void push_luavalue(int v) {
|
||||
g_lua.pushInteger(v);
|
||||
}
|
||||
|
||||
/// Pushes double
|
||||
inline void push_luavalue(double v) {
|
||||
g_lua.pushNumber(v);
|
||||
}
|
||||
|
||||
/// Pushes std::string
|
||||
inline void push_luavalue(const std::string& v) {
|
||||
g_lua.pushString(v);
|
||||
}
|
||||
|
||||
/// Pushes const char*
|
||||
inline void push_luavalue(const char* v) {
|
||||
g_lua.pushCString(v);
|
||||
}
|
||||
|
||||
/// Pushes LuaCppFunction
|
||||
inline void push_luavalue(const LuaCppFunction& v) {
|
||||
g_lua.pushCppFunction(v);
|
||||
}
|
||||
|
||||
/// Pushes LuaObjectPtr
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, void>::type
|
||||
push_luavalue(const T& v) {
|
||||
if(v)
|
||||
return g_lua.pushObject(v);
|
||||
return g_lua.pushNil();
|
||||
}
|
||||
|
||||
/// Push std::function types
|
||||
template<typename Ret, typename... Args>
|
||||
void push_luavalue(const std::function<Ret(Args...)>& v) {
|
||||
if(v) {
|
||||
LuaCppFunction f = luabinder::bind_fun(v);
|
||||
g_lua.pushCppFunction(f);
|
||||
} else
|
||||
g_lua.pushNil();
|
||||
}
|
||||
|
||||
/// Casts lua value to bool
|
||||
inline bool luavalue_cast(int index, bool& o) {
|
||||
o = g_lua.toBoolean(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to int
|
||||
inline bool luavalue_cast(int index, int& o) {
|
||||
o = g_lua.toInteger(index);
|
||||
if(o == 0 && !g_lua.isNumber(index))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to double
|
||||
inline bool luavalue_cast(int index, double& o) {
|
||||
o = g_lua.toNumber(index);
|
||||
if(o == 0 && !g_lua.isNumber(index))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to std::string
|
||||
inline bool luavalue_cast(int index, std::string& o) {
|
||||
o = g_lua.toString(index);
|
||||
if(o.empty() && !g_lua.isString(index))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Casts lua value to LuaObjectPtr
|
||||
inline bool luavalue_cast(int index, LuaObjectPtr& o) {
|
||||
if(g_lua.isUserdata(index)) {
|
||||
o = g_lua.toObject(index);
|
||||
return true;
|
||||
} else if(g_lua.isNil(index)) {
|
||||
o = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Casts lua value to enum
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_enum<T>::value, bool>::type
|
||||
luavalue_cast(int index, T& o) {
|
||||
return luavalue_cast(index, (int&)o);
|
||||
}
|
||||
|
||||
/// Cast lua userdata to a class pointer
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
|
||||
luavalue_cast(int index, T*& o) {
|
||||
LuaObjectPtr obj;
|
||||
if(!luavalue_cast(index, obj))
|
||||
return false;
|
||||
o = std::dynamic_pointer_cast<T>(obj).get();
|
||||
return !!o;
|
||||
}
|
||||
|
||||
/// Cast lua userdata to a class shared pointer
|
||||
template<class T>
|
||||
bool luavalue_cast(int index, std::shared_ptr<T>& o) {
|
||||
LuaObjectPtr obj;
|
||||
if(!luavalue_cast(index, obj))
|
||||
return false;
|
||||
o = std::dynamic_pointer_cast<T>(obj);
|
||||
return !!o;
|
||||
}
|
||||
|
||||
/// Cast a lua function to a std::function
|
||||
template<typename... Args>
|
||||
bool luavalue_cast(int index, std::function<void(Args...)>& o) {
|
||||
if(g_lua.isFunction(index)) {
|
||||
g_lua.pushValue(index);
|
||||
// weak references are used here, this means that the script must hold another reference
|
||||
// to this function, otherwise it will expire
|
||||
int funcWeakRef = g_lua.weakRef();
|
||||
o = [=](Args... args...) {
|
||||
// note that we must catch exceptions, because this lambda can be called from anywhere
|
||||
// and most of them won't catch exceptions (e.g. dispatcher)
|
||||
g_lua.getWeakRef(funcWeakRef);
|
||||
try {
|
||||
if(g_lua.isFunction()) {
|
||||
g_lua.polymorphicPush(args...);
|
||||
assert(g_lua.safeCall(sizeof...(Args)) == 0);
|
||||
} else {
|
||||
throw LuaException("attempt to call an expired lua function from C++,"
|
||||
"did you forget to hold a reference for that function?", 0);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
logError(e.what());
|
||||
}
|
||||
};
|
||||
return true;
|
||||
} else if(g_lua.isNil(index)) {
|
||||
o = std::function<void(Args...)>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Cast a lua function to a std::function that can return
|
||||
template<typename Ret, typename... Args>
|
||||
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
|
||||
luavalue_cast(int index, std::function<Ret(Args...)>& o) {
|
||||
if(g_lua.isFunction(index)) {
|
||||
g_lua.pushValue(index);
|
||||
// weak references are used here, this means that the script must hold another reference
|
||||
// to this function, otherwise it will expire
|
||||
int funcWeakRef = g_lua.weakRef();
|
||||
o = [=](Args... args...) -> Ret {
|
||||
// note that we must catch exceptions, because this lambda can be called from anywhere
|
||||
// and most of them won't catch exceptions (e.g. dispatcher)
|
||||
try {
|
||||
g_lua.getWeakRef(funcWeakRef);
|
||||
if(g_lua.isFunction()) {
|
||||
g_lua.polymorphicPush(args...);
|
||||
if(g_lua.safeCall(sizeof...(Args)) != 1)
|
||||
throw LuaException("a function from lua didn't retrieve the expected number of results", 0);
|
||||
return g_lua.polymorphicPop<Ret>();
|
||||
} else {
|
||||
throw LuaException("attempt to call an expired lua function from C++,"
|
||||
"did you forget to hold a reference for that function?", 0);
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
logError(e.what());
|
||||
}
|
||||
return Ret();
|
||||
};
|
||||
return true;
|
||||
} else if(g_lua.isNil(index)) {
|
||||
o = std::function<Ret(Args...)>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user