Rework application class and framework

Make otclient's framework flexible enough to run console apps like
servers, so this mean is possible to build otclient versions without
graphical interface and use it's framework to code servers
This commit is contained in:
Eduardo Bart
2012-07-13 22:10:24 -03:00
parent 099716fe03
commit e3298d561c
131 changed files with 1228 additions and 1016 deletions

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2010-2012 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 FRAMEWORK_LUA_DECLARATIONS_H
#define FRAMEWORK_LUA_DECLARATIONS_H
#include <framework/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

View File

@@ -0,0 +1,377 @@
/*
* This is the bit32 library from lua 5.2.0, backported to
* lua 5.1.4.
*
* version 5.2.0-backport4
*
* This backport was assembled by Sean Bolton (sean at smbolton
* dot com) almost entirely from the above mentioned Lua distributions,
* which are:
*
* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved.
*
* 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.
*/
#define LUA_LIB
extern "C" {
#include <lua.h>
#include <lauxlib.h>
}
/* ----- adapted from lua-5.2.0 luaconf.h: ----- */
/*
@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned.
** It must have at least 32 bits.
*/
#ifndef LUAI_INT32
#define LUAI_INT32 int
#endif
#define LUA_UNSIGNED unsigned LUAI_INT32
#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes
with a DirectX idiosyncrasy */
#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
#define MS_ASMTRICK
#else /* }{ */
/* the next definition uses a trick that should work on any machine
using IEEE754 with a 32-bit integer type */
#define LUA_IEEE754TRICK
/*
@@ LUA_IEEEENDIAN is the endianness of doubles in your machine
** (0 for little endian, 1 for big endian); if not defined, Lua will
** check it dynamically.
*/
/* check for known architectures */
#if defined(__i386__) || defined(__i386) || defined(__X86__) || \
defined (__x86_64)
#define LUA_IEEEENDIAN 0
#elif defined(__POWERPC__) || defined(__ppc__)
#define LUA_IEEEENDIAN 1
#endif
#endif /* } */
#endif /* } */
/* ----- from lua-5.2.0 lua.h: ----- */
/* unsigned integer type */
typedef LUA_UNSIGNED lua_Unsigned;
/* ----- adapted from lua-5.2.0 llimits.h: ----- */
/* lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned.
** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number.
*/
#if defined(MS_ASMTRICK) /* { */
/* trick with Microsoft assembler for X86 */
#define lua_number2unsigned(i,n) \
{__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;}
#elif defined(LUA_IEEE754TRICK) /* }{ */
/* the next trick should work on any machine using IEEE754 with
a 32-bit integer type */
union luai_Cast2 { double l_d; LUAI_INT32 l_p[2]; };
#if !defined(LUA_IEEEENDIAN) /* { */
#define LUAI_EXTRAIEEE \
static const union luai_Cast2 ieeeendian = {-(33.0 + 6755399441055744.0)};
#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33)
#else
#define LUAI_EXTRAIEEE /* empty */
#endif /* } */
#define lua_number2int32(i,n,t) \
{ LUAI_EXTRAIEEE \
volatile union luai_Cast2 u; u.l_d = (n) + 6755399441055744.0; \
(i) = (t)u.l_p[LUA_IEEEENDIAN]; }
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
#endif /* } */
#if !defined(lua_number2unsigned) /* { */
/* the following definition assures proper modulo behavior */
#if defined(LUA_NUMBER_DOUBLE)
#include <math.h>
#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
#define lua_number2unsigned(i,n) \
((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED))
#else
#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n))
#endif
#endif /* } */
/* on several machines, coercion from unsigned to double is slow,
so it may be worth to avoid */
#define lua_unsigned2number(u) \
(((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u))
/* ----- adapted from lua-5.2.0 lapi.c: ----- */
static void lua_pushunsigned (lua_State *L, lua_Unsigned u) {
lua_Number n;
n = lua_unsigned2number(u);
lua_pushnumber(L, n);
}
/* ----- adapted from lua-5.2.0-work3 lbitlib.c getuintarg(): ----- */
static lua_Unsigned luaL_checkunsigned (lua_State *L, int arg) {
lua_Unsigned r;
lua_Number x = lua_tonumber(L, arg);
if (x == 0) luaL_checktype(L, arg, LUA_TNUMBER);
lua_number2unsigned(r, x);
return r;
}
/* ----- Lua 5.2 luaL_newlib() compatibility: ----- */
#define LUAMOD_API LUALIB_API
#define LUA_BIT32LIBNAME "bit32"
#define luaL_newlib(x, y) luaL_register(x, LUA_BIT32LIBNAME, y)
/* ----- avoid a 'symbol redefined' warning below ----- */
#undef LUA_LIB
/* ----- here follows the unmodified lbitlib.c from Lua 5.2.0 ----- */
/*
** $Id: lbitlib.c,v 1.16 2011/06/20 16:35:23 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
#define lbitlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
#endif
#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
/* macro to trim extra bits */
#define trim(x) ((x) & ALLONES)
/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
typedef lua_Unsigned b_uint;
static b_uint andaux (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = ~(b_uint)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
b_uint r = andaux(L);
lua_pushunsigned(L, r);
return 1;
}
static int b_test (lua_State *L) {
b_uint r = andaux(L);
lua_pushboolean(L, r != 0);
return 1;
}
static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
b_uint r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_shift (lua_State *L, b_uint r, int i) {
if (i < 0) { /* shift right? */
i = -i;
r = trim(r);
if (i >= LUA_NBITS) r = 0;
else r >>= i;
}
else { /* shift left */
if (i >= LUA_NBITS) r = 0;
else r <<= i;
r = trim(r);
}
lua_pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
}
static int b_rshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
}
static int b_arshift (lua_State *L) {
b_uint r = luaL_checkunsigned(L, 1);
int i = luaL_checkint(L, 2);
if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
else { /* arithmetic shift for 'negative' number */
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */
lua_pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, int i) {
b_uint r = luaL_checkunsigned(L, 1);
i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r);
r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_lrot (lua_State *L) {
return b_rot(L, luaL_checkint(L, 2));
}
static int b_rrot (lua_State *L) {
return b_rot(L, -luaL_checkint(L, 2));
}
/*
** get field and width arguments for field-manipulation functions,
** checking whether they are valid
*/
static int fieldargs (lua_State *L, int farg, int *width) {
int f = luaL_checkint(L, farg);
int w = luaL_optint(L, farg + 1, 1);
luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
if (f + w > LUA_NBITS)
luaL_error(L, "trying to access non-existent bits");
*width = w;
return f;
}
static int b_extract (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
b_uint v = luaL_checkunsigned(L, 2);
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
r = (r & ~(m << f)) | (v << f);
lua_pushunsigned(L, r);
return 1;
}
static const luaL_Reg bitlib[] = {
{"arshift", b_arshift},
{"band", b_and},
{"bnot", b_not},
{"bor", b_or},
{"bxor", b_xor},
{"btest", b_test},
{"extract", b_extract},
{"lrotate", b_lrot},
{"lshift", b_lshift},
{"replace", b_replace},
{"rrotate", b_rrot},
{"rshift", b_rshift},
{NULL, NULL}
};
int luaopen_bit32 (lua_State *L) {
luaL_newlib(L, bitlib);
return 1;
}
#undef trim

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2010-2012 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 LBITLIB_520_BACKPORT4_H
#define LBITLIB_520_BACKPORT4_H
struct lua_State;
int luaopen_bit32 (lua_State *L);
#endif

View File

@@ -0,0 +1,219 @@
/*
* Copyright (c) 2010-2012 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 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 that uses a lot of 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's arguments and then generate 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, const Args&... args) {
Ret ret = f(args...);
int numRets = lua->polymorphicPush(ret);
return numRets;
}
/// 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, const 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, const Args&... args) {
return expand_fun_arguments<N-1,Ret>::call(tuple, f, lua, 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, const 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) -> int {
while(lua->stackSize() != N) {
if(lua->stackSize() < N)
g_lua.pushNil();
else
g_lua.pop();
}
Tuple tuple;
pack_values_into_tuple<N>::call(tuple, lua);
return expand_fun_arguments<N,Ret>::call(tuple, f, lua);
};
}
/// Bind a customized function
inline
LuaCppFunction bind_fun(const std::function<int(LuaInterface*)>& f) {
return f;
}
/// 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);
}
/// Specialization for lambdas
template<typename F>
struct bind_lambda_fun;
template<typename Lambda, typename Ret, typename... Args>
struct bind_lambda_fun<Ret(Lambda::*)(Args...) const> {
static LuaCppFunction call(const Lambda& 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);
}
};
template<typename Lambda>
typename std::enable_if<std::is_constructible<decltype(&Lambda::operator())>::value, LuaCppFunction>::type bind_fun(const Lambda& f) {
typedef decltype(&Lambda::operator()) F;
return bind_lambda_fun<F>::call(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));
}
/// Create member function lambdas
template<typename Ret, typename C, typename... Args>
std::function<Ret(const std::shared_ptr<C>&, const Args&...)> make_mem_func(Ret (C::* f)(Args...)) {
auto mf = std::mem_fn(f);
return [=](const std::shared_ptr<C>& obj, const Args&... args) mutable -> Ret {
if(!obj)
throw LuaException("failed to call a member function because the passed object is nil");
return mf(obj.get(), args...);
};
}
template<typename C, typename... Args>
std::function<void(const std::shared_ptr<C>&, const Args&...)> make_mem_func(void (C::* f)(Args...)) {
auto mf = std::mem_fn(f);
return [=](const std::shared_ptr<C>& obj, const Args&... args) mutable -> void {
if(!obj)
throw LuaException("failed to call a member function because the passed object is nil");
mf(obj.get(), args...);
};
}
/// Create member function lambdas for singleton classes
template<typename Ret, typename C, typename... Args>
std::function<Ret(const Args&...)> make_mem_func_singleton(Ret (C::* f)(Args...), C* instance) {
auto mf = std::mem_fn(f);
return [=](Args... args) mutable -> Ret { return mf(instance, args...); };
}
template<typename C, typename... Args>
std::function<void(const Args&...)> make_mem_func_singleton(void (C::* f)(Args...), C* instance) {
auto mf = std::mem_fn(f);
return [=](Args... args) mutable -> void { mf(instance, args...); };
}
/// Bind member functions
template<typename C, typename Ret, class FC, typename... Args>
LuaCppFunction bind_mem_fun(Ret (FC::* f)(Args...)) {
typedef typename std::tuple<std::shared_ptr<FC>, typename remove_const_ref<Args>::type...> Tuple;
auto lambda = make_mem_func<Ret,FC>(f);
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(lambda),
Tuple>(lambda);
}
/// Bind singleton member functions
template<typename C, typename Ret, class FC, typename... Args>
LuaCppFunction bind_singleton_mem_fun(Ret (FC::*f)(Args...), C *instance) {
typedef typename std::tuple<typename remove_const_ref<Args>::type...> Tuple;
assert(instance);
auto lambda = make_mem_func_singleton<Ret,FC>(f, static_cast<FC*>(instance));
return bind_fun_specializer<typename remove_const_ref<Ret>::type,
decltype(lambda),
Tuple>(lambda);
}
/// Bind customized member functions
template<typename C>
LuaCppFunction bind_mem_fun(int (C::*f)(LuaInterface*)) {
auto mf = std::mem_fn(f);
return [=](LuaInterface* lua) -> int {
auto obj = lua->castValue<std::shared_ptr<C>>(1);
lua->remove(1);
return mf(obj, lua);
};
}
}
#endif

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2010-2012 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 "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 = stdext::format("LUA ERROR: %s", g_lua.traceback(error, traceLevel));
else
m_what = stdext::format("LUA ERROR: %s", 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 = stdext::format("%s (expected %d, but got %d)", error, expected, got);
generateLuaErrorMessage(error, 1);
}
LuaBadValueCastException::LuaBadValueCastException(const std::string& luaTypeName, const std::string& cppTypeName)
{
std::string error = stdext::format("attempt to cast a '%s' lua value to '%s'", luaTypeName, cppTypeName);
generateLuaErrorMessage(error, 0);
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2010-2012 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 LUAEXCEPTION_H
#define LUAEXCEPTION_H
#include "declarations.h"
class LuaException : public stdext::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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,445 @@
/*
* Copyright (c) 2010-2012 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);
/// 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 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();
template<typename... T>
int 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 luaScriptRunner(lua_State* L);
/// Run scripts requested by lua 'dofiles'
static int luaScriptsRunner(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);
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 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);
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);
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>
int polymorphicPush(T v, 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;
};
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(T v, 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::callGlobalField(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 R, typename... T>
R LuaInterface::callGlobalField(const std::string& global, const std::string& field, const T&... args) {
R result;
int rets = callGlobalField(global, field, args...);
if(rets > 0) {
assert(rets == 1);
result = g_lua.polymorphicPop<R>();
} else
result = R();
return result;
}
#endif

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2010-2012 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 "luaobject.h"
#include "luainterface.h"
#include <framework/core/application.h>
LuaObject::LuaObject() :
m_fieldsTableRef(-1),
m_metatableRef(-1)
{
}
LuaObject::~LuaObject()
{
assert(!g_app.isTerminated());
releaseLuaFieldsTable();
if(m_metatableRef != -1) {
g_lua.unref(m_metatableRef);
m_metatableRef = -1;
}
}
bool LuaObject::hasLuaField(const std::string& field)
{
bool ret = false;
if(m_fieldsTableRef != -1) {
g_lua.getRef(m_fieldsTableRef);
g_lua.getField(field); // push the field value
ret = !g_lua.isNil();
g_lua.pop(2);
}
return ret;
}
void LuaObject::releaseLuaFieldsTable()
{
if(m_fieldsTableRef != -1) {
g_lua.unref(m_fieldsTableRef);
m_fieldsTableRef = -1;
}
}
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();
}
}
void LuaObject::luaGetMetatable()
{
if(m_metatableRef == -1) {
// set the userdata metatable
g_lua.getGlobal(stdext::format("%s_mt", getClassName()));
m_metatableRef = g_lua.ref();
}
g_lua.getRef(m_metatableRef);
}
void LuaObject::luaGetFieldsTable()
{
if(m_fieldsTableRef != -1)
g_lua.getRef(m_fieldsTableRef);
else
g_lua.pushNil();
}
int LuaObject::getUseCount()
{
return shared_from_this().use_count() - 1;
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2010-2012 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 LUAOBJECT_H
#define LUAOBJECT_H
#include "declarations.h"
/// LuaObject, all script-able classes have it as base
// @bindclass
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 luaCallField(const std::string& field, const T&... args);
template<typename R, typename... T>
R callLuaField(const std::string& field, const T&... args);
template<typename... T>
void callLuaField(const std::string& field, const T&... args);
/// Returns true if the lua field exists
bool hasLuaField(const std::string& field);
/// 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 releaseLuaFieldsTable();
/// 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);
/// Get object's metatable
void luaGetMetatable();
/// Gets the table containing all stored fields of this lua object, the result is pushed onto the stack
void luaGetFieldsTable();
/// Returns the number of references of this object
/// @note each userdata of this object on lua counts as a reference
int getUseCount();
/// Returns the derived class name, its the same name used in Lua
std::string getClassName() {
// TODO: this could be cached for more performance
return stdext::demangle_name(typeid(*this).name());
}
LuaObjectPtr asLuaObject() { return shared_from_this(); }
private:
int m_fieldsTableRef;
int m_metatableRef;
};
#include "luainterface.h"
template<typename... T>
int LuaObject::luaCallField(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);
if(!g_lua.isNil()) {
// the first argument is always this object (self)
g_lua.insert(-2);
int numArgs = g_lua.polymorphicPush(args...);
return g_lua.signalCall(1 + numArgs);
} else {
g_lua.pop(2);
}
return 0;
}
template<typename R, typename... T>
R LuaObject::callLuaField(const std::string& field, const T&... args) {
R result;
int rets = luaCallField(field, args...);
if(rets > 0) {
assert(rets == 1);
result = g_lua.polymorphicPop<R>();
} else
result = R();
return result;
}
template<typename... T>
void LuaObject::callLuaField(const std::string& field, const T&... args) {
int rets = luaCallField(field, args...);
if(rets > 0)
g_lua.pop(rets);
}
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

View File

@@ -0,0 +1,322 @@
/*
* Copyright (c) 2010-2012 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 "luavaluecasts.h"
#include "luainterface.h"
#include <framework/otml/otmlnode.h>
// bool
int push_luavalue(bool b)
{
g_lua.pushBoolean(b);
return 1;
}
bool luavalue_cast(int index, bool& b)
{
b = g_lua.toBoolean(index);
return true;
}
// int
int push_luavalue(int i)
{
g_lua.pushInteger(i);
return 1;
}
bool luavalue_cast(int index, int& i)
{
i = g_lua.toInteger(index);
if(i == 0 && !g_lua.isNumber(index) && !g_lua.isNil())
return false;
return true;
}
// double
int push_luavalue(double d)
{
g_lua.pushNumber(d);
return 1;
}
bool luavalue_cast(int index, double& d)
{
d = g_lua.toNumber(index);
if(d == 0 && !g_lua.isNumber(index) && !g_lua.isNil())
return false;
return true;
}
// string
int push_luavalue(const char* cstr)
{
g_lua.pushCString(cstr);
return 1;
}
int push_luavalue(const std::string& str)
{
g_lua.pushString(str);
return 1;
}
bool luavalue_cast(int index, std::string& str)
{
str = g_lua.toString(index);
return true;
}
// lua cpp function
int push_luavalue(const LuaCppFunction& func)
{
g_lua.pushCppFunction(func);
return 1;
}
// color
int push_luavalue(const Color& color)
{
g_lua.newTable();
g_lua.pushInteger(color.r());
g_lua.setField("r");
g_lua.pushInteger(color.g());
g_lua.setField("g");
g_lua.pushInteger(color.b());
g_lua.setField("b");
g_lua.pushInteger(color.a());
g_lua.setField("a");
return 1;
}
bool luavalue_cast(int index, Color& color)
{
if(g_lua.isTable(index)) {
g_lua.getField("r", index);
color.setRed(g_lua.popInteger());
g_lua.getField("g", index);
color.setGreen(g_lua.popInteger());
g_lua.getField("b", index);
color.setBlue(g_lua.popInteger());
g_lua.getField("a", index);
color.setAlpha(g_lua.popInteger());
return true;
} else if(g_lua.isString()) {
return stdext::cast(g_lua.toString(index), color);
} else if(g_lua.isNil()) {
color = Color::white;
return true;
}
return false;
}
// rect
int push_luavalue(const Rect& rect)
{
g_lua.newTable();
g_lua.pushInteger(rect.x());
g_lua.setField("x");
g_lua.pushInteger(rect.y());
g_lua.setField("y");
g_lua.pushInteger(rect.width());
g_lua.setField("width");
g_lua.pushInteger(rect.height());
g_lua.setField("height");
return 1;
}
bool luavalue_cast(int index, Rect& rect)
{
if(g_lua.isTable(index)) {
g_lua.getField("x", index);
rect.setX(g_lua.popInteger());
g_lua.getField("y", index);
rect.setY(g_lua.popInteger());
g_lua.getField("width", index);
rect.setWidth(g_lua.popInteger());
g_lua.getField("height", index);
rect.setHeight(g_lua.popInteger());
return true;
} else if(g_lua.isString()) {
return stdext::cast(g_lua.toString(index), rect);
} else if(g_lua.isNil()) {
rect = Rect();
return true;
}
return false;
}
// point
int push_luavalue(const Point& point)
{
g_lua.newTable();
g_lua.pushInteger(point.x);
g_lua.setField("x");
g_lua.pushInteger(point.y);
g_lua.setField("y");
return 1;
}
bool luavalue_cast(int index, Point& point)
{
if(g_lua.isTable(index)) {
g_lua.getField("x", index);
point.x = g_lua.popInteger();
g_lua.getField("y", index);
point.y = g_lua.popInteger();
return true;
} else if(g_lua.isString()) {
return stdext::cast(g_lua.toString(index), point);
} else if(g_lua.isNil()) {
point = Point();
return true;
}
return false;
}
// size
int push_luavalue(const Size& size)
{
g_lua.newTable();
g_lua.pushInteger(size.width());
g_lua.setField("width");
g_lua.pushInteger(size.height());
g_lua.setField("height");
return 1;
}
bool luavalue_cast(int index, Size& size)
{
if(g_lua.isTable(index)) {
g_lua.getField("width", index);
size.setWidth(g_lua.popInteger());
g_lua.getField("height", index);
size.setHeight(g_lua.popInteger());
return true;
} else if(g_lua.isString()) {
return stdext::cast(g_lua.toString(index), size);
} else if(g_lua.isNil()) {
size = Size();
return true;
}
return false;
}
// otml nodes
void push_otml_subnode_luavalue(const OTMLNodePtr& node)
{
if(node->hasValue()) {
// convert boolean types
if(node->value() == "true" || node->value() == "false")
g_lua.pushBoolean(node->value<bool>());
else
g_lua.pushString(node->value());
} else if(node->hasChildren()) {
g_lua.newTable();
bool pushedChild = false;
int currentIndex = 1;
for(const OTMLNodePtr& cnode : node->children()) {
push_otml_subnode_luavalue(cnode);
if(!g_lua.isNil()) {
if(cnode->isUnique()) {
g_lua.pushString(cnode->tag());
g_lua.insert(-2);
g_lua.rawSet();
} else
g_lua.rawSeti(currentIndex++);
pushedChild = true;
} else
g_lua.pop();
}
if(!pushedChild) {
g_lua.pop();
g_lua.pushNil();
}
} else
g_lua.pushNil();
}
int push_luavalue(const OTMLNodePtr& node)
{
if(node) {
g_lua.newTable();
int currentIndex = 1;
for(const OTMLNodePtr& cnode : node->children()) {
push_otml_subnode_luavalue(cnode);
if(cnode->isUnique() && !cnode->tag().empty()) {
g_lua.setField(cnode->tag());
} else
g_lua.rawSeti(currentIndex++);
}
} else
g_lua.pushNil();
return 1;
}
bool luavalue_cast(int index, OTMLNodePtr& node)
{
node = OTMLNode::create();
node->setUnique(true);
if(g_lua.isTable(index)) {
g_lua.pushNil();
while(g_lua.next(index < 0 ? index-1 : index)) {
std::string cnodeName;
if(!g_lua.isNumber(-2))
cnodeName = g_lua.toString(-2);
if(g_lua.isTable()) {
OTMLNodePtr cnode;
if(luavalue_cast(-1, cnode)) {
if(cnodeName.empty())
node->setUnique(false);
else
cnode->setTag(cnodeName);
node->addChild(cnode);
}
} else {
std::string value;
if(g_lua.isBoolean())
value = stdext::unsafe_cast<std::string>(g_lua.toBoolean());
else
value = g_lua.toString();
if(cnodeName.empty())
node->writeIn(value);
else
node->writeAt(cnodeName, value);
}
g_lua.pop();
}
return true;
}
return false;
}
// object ptr
bool luavalue_cast(int index, LuaObjectPtr& obj) {
if(g_lua.isUserdata(index)) {
obj = g_lua.toObject(index);
return true;
} else if(g_lua.isNil(index)) {
obj = nullptr;
return true;
}
return false;
}

View File

@@ -0,0 +1,400 @@
/*
* Copyright (c) 2010-2012 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 LUAVALUECASTS_H
#define LUAVALUECASTS_H
// this file is and must be included only from luainterface.h
#include "declarations.h"
#include <framework/otml/declarations.h>
template<typename T>
int push_internal_luavalue(T v);
// bool
int push_luavalue(bool b);
bool luavalue_cast(int index, bool& b);
// int
int push_luavalue(int i);
bool luavalue_cast(int index, int& i);
// double
int push_luavalue(double d);
bool luavalue_cast(int index, double& d);
// float
inline int push_luavalue(float f) { push_luavalue((double)f); return 1; }
inline bool luavalue_cast(int index, float& f) { double d; bool r = luavalue_cast(index, d); f = d; return r; }
// int8
inline int push_luavalue(int8 v) { push_luavalue((int)v); return 1; }
inline bool luavalue_cast(int index, int8& v) { int i; bool r = luavalue_cast(index, i); v = i; return r; }
// uint8
inline int push_luavalue(uint8 v) { push_luavalue((int)v); return 1; }
inline bool luavalue_cast(int index, uint8& v){ int i; bool r = luavalue_cast(index, i); v = i; return r; }
// int16
inline int push_luavalue(int16 v) { push_luavalue((int)v); return 1; }
inline bool luavalue_cast(int index, int16& v){ int i; bool r = luavalue_cast(index, i); v = i; return r; }
// uint16
inline int push_luavalue(uint16 v) { push_luavalue((int)v); return 1; }
inline bool luavalue_cast(int index, uint16& v){ int i; bool r = luavalue_cast(index, i); v = i; return r; }
// uint32
inline int push_luavalue(uint32 v) { push_luavalue((double)v); return 1; }
inline bool luavalue_cast(int index, uint32& v) { double d; bool r = luavalue_cast(index, d); v = d; return r; }
// int64
inline int push_luavalue(int64 v) { push_luavalue((double)v); return 1; }
inline bool luavalue_cast(int index, int64& v) { double d; bool r = luavalue_cast(index, d); v = d; return r; }
// uint64
inline int push_luavalue(uint64 v) { push_luavalue((double)v); return 1; }
inline bool luavalue_cast(int index, uint64& v) { double d; bool r = luavalue_cast(index, d); v = d; return r; }
// string
int push_luavalue(const char* cstr);
int push_luavalue(const std::string& str);
bool luavalue_cast(int index, std::string& str);
// lua cpp function
int push_luavalue(const LuaCppFunction& func);
// color
int push_luavalue(const Color& color);
bool luavalue_cast(int index, Color& color);
// rect
int push_luavalue(const Rect& rect);
bool luavalue_cast(int index, Rect& rect);
// point
int push_luavalue(const Point& point);
bool luavalue_cast(int index, Point& point);
// size
int push_luavalue(const Size& size);
bool luavalue_cast(int index, Size& size);
// otml nodes
int push_luavalue(const OTMLNodePtr& node);
bool luavalue_cast(int index, OTMLNodePtr& node);
// enum
template<class T>
typename std::enable_if<std::is_enum<T>::value, bool>::type
luavalue_cast(int index, T& myenum);
// LuaObject pointers
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, int>::type
push_luavalue(const T& obj);
bool luavalue_cast(int index, LuaObjectPtr& obj);
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
luavalue_cast(int index, std::shared_ptr<T>& ptr);
// std::function
template<typename Ret, typename... Args>
int push_luavalue(const std::function<Ret(Args...)>& func);
template<typename... Args>
bool luavalue_cast(int index, std::function<void(Args...)>& func);
template<typename Ret, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
luavalue_cast(int index, std::function<Ret(Args...)>& func);
// vector
template<typename T>
int push_luavalue(const std::vector<T>& vec);
template<typename T>
bool luavalue_cast(int index, std::vector<T>& vec);
// deque
template<class T>
int push_luavalue(const std::deque<T>& vec);
template<typename T>
bool luavalue_cast(int index, std::deque<T>& vec);
// map
template<class K, class V>
int push_luavalue(const std::map<K, V>& map);
template<class K, class V>
bool luavalue_cast(int index, std::map<K, V>& map);
// tuple
template<typename... Args>
int push_luavalue(const std::tuple<Args...>& tuple);
template<typename... Args>
int push_internal_luavalue(const std::tuple<Args...>& tuple);
// start definitions
#include "luaexception.h"
#include "luainterface.h"
template<typename T>
int push_internal_luavalue(T v) {
return push_luavalue(v);
}
template<class T>
typename std::enable_if<std::is_enum<T>::value, bool>::type
luavalue_cast(int index, T& myenum) {
return luavalue_cast(index, (int&)myenum);
}
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, typename T::element_type>::value, int>::type
push_luavalue(const T& obj) {
if(obj)
g_lua.pushObject(obj);
else
g_lua.pushNil();
return 1;
}
template<class T>
typename std::enable_if<std::is_base_of<LuaObject, T>::value, bool>::type
luavalue_cast(int index, std::shared_ptr<T>& ptr) {
LuaObjectPtr obj;
if(!luavalue_cast(index, obj))
return false;
ptr = std::dynamic_pointer_cast<T>(obj);
return true;
}
template<typename Ret, typename... Args>
int push_luavalue(const std::function<Ret(Args...)>& func) {
if(func) {
LuaCppFunction f = luabinder::bind_fun(func);
g_lua.pushCppFunction(f);
} else
g_lua.pushNil();
return 1;
}
template<typename... Args>
bool luavalue_cast(int index, std::function<void(Args...)>& func) {
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();
func = [=](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()) {
int numArgs = g_lua.polymorphicPush(args...);
int rets = g_lua.safeCall(numArgs);
g_lua.pop(rets);
} else {
throw LuaException("attempt to call an expired lua function from C++,"
"did you forget to hold a reference for that function?", 0);
}
} catch(LuaException& e) {
g_logger.error(stdext::format("lua function callback failed: %s", e.what()));
}
};
return true;
} else if(g_lua.isNil(index)) {
func = std::function<void(Args...)>();
return true;
}
return false;
}
template<typename Ret, typename... Args>
typename std::enable_if<!std::is_void<Ret>::value, bool>::type
luavalue_cast(int index, std::function<Ret(Args...)>& func) {
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();
func = [=](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()) {
int numArgs = g_lua.polymorphicPush(args...);
if(g_lua.safeCall(numArgs) != 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(LuaException& e) {
g_logger.error(stdext::format("lua function callback failed: %s", e.what()));
}
return Ret();
};
return true;
} else if(g_lua.isNil(index)) {
func = std::function<Ret(Args...)>();
return true;
}
return false;
}
template<typename T>
int push_luavalue(const std::vector<T>& vec) {
g_lua.newTable();
int i = 1;
for(const T& v : vec) {
push_internal_luavalue(v);
g_lua.rawSeti(i);
i++;
}
return 1;
}
template<typename T>
bool luavalue_cast(int index, std::vector<T>& vec)
{
if(g_lua.isTable(index)) {
g_lua.pushNil();
while(g_lua.next(index < 0 ? index-1 : index)) {
T value;
if(luavalue_cast(-1, value))
vec.push_back(value);
g_lua.pop();
}
return true;
}
return false;
}
template<typename T>
int push_luavalue(const std::deque<T>& vec) {
g_lua.newTable();
int i = 1;
for(const T& v : vec) {
push_internal_luavalue(v);
g_lua.rawSeti(i);
i++;
}
return 1;
}
template<typename T>
bool luavalue_cast(int index, std::deque<T>& vec)
{
if(g_lua.isTable(index)) {
g_lua.pushNil();
while(g_lua.next(index < 0 ? index-1 : index)) {
T value;
if(luavalue_cast(-1, value))
vec.push_back(value);
g_lua.pop();
}
return true;
}
return false;
}
template<class K, class V>
int push_luavalue(const std::map<K, V>& map)
{
g_lua.newTable();
for(auto& it : map) {
push_internal_luavalue(it.first);
push_internal_luavalue(it.second);
g_lua.rawSet();
}
return 1;
}
template<class K, class V>
bool luavalue_cast(int index, std::map<K, V>& map)
{
if(g_lua.isTable(index)) {
g_lua.pushNil();
while(g_lua.next(index < 0 ? index-1 : index)) {
K key;
V value;
if(luavalue_cast(-1, value) && luavalue_cast(-2, key))
map[key] = value;
g_lua.pop();
}
return true;
}
return false;
}
template<int N>
struct push_tuple_internal_luavalue {
template<typename Tuple>
static void call(const Tuple& tuple) {
push_internal_luavalue(std::get<N-1>(tuple));
g_lua.rawSeti(N);
push_tuple_internal_luavalue<N-1>::call(tuple);
}
};
template<>
struct push_tuple_internal_luavalue<0> {
template<typename Tuple>
static void call(const Tuple& tuple) { }
};
template<typename... Args>
int push_internal_luavalue(const std::tuple<Args...>& tuple) {
g_lua.newTable();
push_tuple_internal_luavalue<sizeof...(Args)>::call(tuple);
return 1;
}
template<int N>
struct push_tuple_luavalue {
template<typename Tuple>
static void call(const Tuple& tuple) {
push_internal_luavalue(std::get<std::tuple_size<Tuple>::value - N>(tuple));
push_tuple_luavalue<N-1>::call(tuple);
}
};
template<>
struct push_tuple_luavalue<0> {
template<typename Tuple>
static void call(const Tuple& tuple) { }
};
template<typename... Args>
int push_luavalue(const std::tuple<Args...>& tuple) {
push_tuple_luavalue<sizeof...(Args)>::call(tuple);
return sizeof...(Args);
}
#endif