diff options
Diffstat (limited to 'source/ManualBindings.cpp')
-rw-r--r-- | source/ManualBindings.cpp | 769 |
1 files changed, 392 insertions, 377 deletions
diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 5b2b6ff9e..b7d31a79d 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -13,6 +13,8 @@ #include "WebAdmin.h" #include "StringMap.h" #include "ClientHandle.h" +#include "ChestEntity.h" +#include "FurnaceEntity.h" #include "md5/md5.h" @@ -27,6 +29,54 @@ bool report_errors(lua_State* lua, int status); /**************************** + * Better error reporting for Lua + **/ +int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError) +{ + // Retrieve current function name + lua_Debug entry; + ASSERT( lua_getstack(L, 0, &entry) ); + ASSERT( lua_getinfo(L, "n", &entry) ); + + // Insert function name into error msg + AString msg(a_pMsg); + ReplaceString(msg, "#funcname#", entry.name?entry.name:"?"); + + // Send the error to Lua + tolua_error(L, msg.c_str(), a_pToLuaError); + return 0; +} + + + + + +int lua_do_error(lua_State* L, const char * a_pFormat, ...) +{ + // Retrieve current function name + lua_Debug entry; + ASSERT( lua_getstack(L, 0, &entry) ); + ASSERT( lua_getinfo(L, "n", &entry) ); + + // Insert function name into error msg + AString msg(a_pFormat); + ReplaceString(msg, "#funcname#", entry.name?entry.name:"?"); + + // Copied from luaL_error and modified + va_list argp; + va_start(argp, a_pFormat); + luaL_where(L, 1); + lua_pushvfstring(L, msg.c_str(), argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + + + + + +/**************************** * Lua bound functions with special return types **/ @@ -98,390 +148,360 @@ static int tolua_LOGERROR(lua_State* tolua_S) -#define DEFINE_LUA_DOWITH(CONTAINER,ITEM,FOREACH,FNNAME) \ -static int FNNAME(lua_State * tolua_S) \ -{ \ - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ \ - if ((NumArgs != 2) && (NumArgs != 3)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Requires 2 or 3 arguments, got %i", NumArgs ); \ - return 0; \ - } \ - \ - CONTAINER * self = (CONTAINER *) tolua_tousertype(tolua_S, 1, 0); \ - \ - const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); \ - if ((ItemName == NULL) || (ItemName[0] == 0)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Expected a non-empty string for parameter #1"); \ - return 0; \ - } \ - if (!lua_isfunction( tolua_S, 3)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Expected a function for parameter #2"); \ - return 0; \ - } \ - \ - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ \ - int TableRef = LUA_REFNIL; \ - if (NumArgs == 3) \ - { \ - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (TableRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get value reference of parameter #3"); \ - return 0; \ - } \ - } \ - \ - /* table value is popped, and now function is on top of the stack */ \ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (FuncRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get function reference of parameter #2"); \ - return 0; \ - } \ - \ - class cLuaCallback : public cItemCallback<ITEM> \ - { \ - public: \ - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) \ - : LuaState( a_LuaState ) \ - , FuncRef( a_FuncRef ) \ - , TableRef( a_TableRef ) \ - {} \ - \ - private: \ - virtual bool Item(ITEM * a_Item) override \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ \ - tolua_pushusertype(LuaState, a_Item, #ITEM); \ - if (TableRef != LUA_REFNIL) \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ \ - } \ - \ - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); \ - report_errors(LuaState, s); \ - return true; \ - } \ - lua_State * LuaState; \ - int FuncRef; \ - int TableRef; \ - } Callback(tolua_S, FuncRef, TableRef); \ - \ - bool bRetVal = self->FOREACH(ItemName, Callback); \ - \ - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); \ - \ - /* Push return value on stack */ \ - tolua_pushboolean(tolua_S, bRetVal ); \ - return 1; \ +template< + class Ty1, + class Ty2, + bool (Ty1::*Func1)(const AString &, cItemCallback<Ty2> &) + > +static int tolua_DoWith(lua_State* tolua_S) +{ + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 2) && (NumArgs != 3)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs); + } + + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + + const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); + if ((ItemName == NULL) || (ItemName[0] == 0)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a non-empty string for parameter #1", NumArgs); + } + if (!lua_isfunction( tolua_S, 3)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #2", NumArgs); + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 3) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #3", NumArgs); + } + } + + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #2", NumArgs); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } + + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + report_errors(LuaState, s); + return true; + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); + + + bool bRetVal = (self->*Func1)(ItemName, Callback); + + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; } -#define DEFINE_LUA_DOWITH_XYZ(CONTAINER,ITEM,FOREACH,FNNAME) \ - static int FNNAME(lua_State * tolua_S) \ - { \ - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ \ - if ((NumArgs != 4) && (NumArgs != 5)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Requires 4 or 5 arguments, got %i", NumArgs ); \ - return 0; \ - } \ - \ - CONTAINER * self = (CONTAINER *) tolua_tousertype(tolua_S, 1, 0); \ - if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3) || !lua_isnumber(tolua_S, 4)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Expected a number for parameters #1, #2 and #3"); \ - return 0; \ - } \ - \ - int ItemX = ((int)tolua_tonumber(tolua_S, 2, 0)); \ - int ItemY = ((int)tolua_tonumber(tolua_S, 3, 0)); \ - int ItemZ = ((int)tolua_tonumber(tolua_S, 4, 0)); \ - LOG("x %i y %i z %i", ItemX, ItemY, ItemZ ); \ - if (!lua_isfunction( tolua_S, 5)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Expected a function for parameter #2"); \ - return 0; \ - } \ - \ - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ \ - int TableRef = LUA_REFNIL; \ - if (NumArgs == 5) \ - { \ - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (TableRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get value reference of parameter #3"); \ - return 0; \ - } \ - } \ - \ - /* table value is popped, and now function is on top of the stack */ \ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (FuncRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get function reference of parameter #2"); \ - return 0; \ - } \ - \ - class cLuaCallback : public cItemCallback<ITEM> \ - { \ - public: \ - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) \ - : LuaState( a_LuaState ) \ - , FuncRef( a_FuncRef ) \ - , TableRef( a_TableRef ) \ - {} \ - \ - private: \ - virtual bool Item(ITEM * a_Item) override \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ \ - tolua_pushusertype(LuaState, a_Item, #ITEM); \ - if (TableRef != LUA_REFNIL) \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ \ - } \ - \ - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); \ - report_errors(LuaState, s); \ - return true; \ - } \ - lua_State * LuaState; \ - int FuncRef; \ - int TableRef; \ - } Callback(tolua_S, FuncRef, TableRef); \ - \ - bool bRetVal = self->FOREACH(ItemX, ItemY, ItemZ, Callback); \ - \ - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); \ - \ - /* Push return value on stack */ \ - tolua_pushboolean(tolua_S, bRetVal ); \ - return 1; \ - } + +template< class Ty1, + class Ty2, + bool (Ty1::*Func1)(int, int, int, cItemCallback<Ty2> &) > +static int tolua_DoWithXYZ(lua_State* tolua_S) +{ + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 4) && (NumArgs != 5)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 4 or 5 arguments, got %i", NumArgs); + } + + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3) || !lua_isnumber(tolua_S, 4)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); + } + + int ItemX = ((int)tolua_tonumber(tolua_S, 2, 0)); + int ItemY = ((int)tolua_tonumber(tolua_S, 3, 0)); + int ItemZ = ((int)tolua_tonumber(tolua_S, 4, 0)); + LOG("x %i y %i z %i", ItemX, ItemY, ItemZ ); + if (!lua_isfunction( tolua_S, 5)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #4"); + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 5) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #5"); + } + } + + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #4"); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } + + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + report_errors(LuaState, s); + return true; + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); + + bool bRetVal = (self->*Func1)(ItemX, ItemY, ItemZ, Callback); + + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; +} -#define DEFINE_LUA_FOREACHINCHUNK(CONTAINER,ITEM,FOREACH,FNNAME) \ -static int FNNAME(lua_State * tolua_S) \ -{ \ - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ \ - if ((NumArgs != 3) && (NumArgs != 4)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Requires 3 or 4 arguments, got %i", NumArgs); \ - return 0; \ - } \ - \ - CONTAINER * self = (CONTAINER *) tolua_tousertype(tolua_S, 1, 0); \ - if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3)) \ - { \ - LOGWARN("Errorin function call '" #FOREACH "': Expected a number for parameters #1 and #2"); \ - return 0; \ - } \ - \ - int ChunkX = ((int)tolua_tonumber(tolua_S, 2, 0)); \ - int ChunkZ = ((int)tolua_tonumber(tolua_S, 3, 0)); \ - \ - if (!lua_isfunction( tolua_S, 4)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Expected a function for parameter #3"); \ - return 0; \ - } \ - \ - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ \ - int TableRef = LUA_REFNIL; \ - if (NumArgs == 4) \ - { \ - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (TableRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get value reference of parameter #4"); \ - return 0; \ - } \ - } \ - \ - /* table value is popped, and now function is on top of the stack */ \ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (FuncRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get function reference of parameter #3"); \ - return 0; \ - } \ - \ - class cLuaCallback : public cItemCallback<ITEM> \ - { \ - public: \ - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) \ - : LuaState( a_LuaState ) \ - , FuncRef( a_FuncRef ) \ - , TableRef( a_TableRef ) \ - {} \ - \ - private: \ - virtual bool Item(ITEM * a_Item) override \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ \ - tolua_pushusertype(LuaState, a_Item, #ITEM); \ - if (TableRef != LUA_REFNIL) \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ \ - } \ - \ - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); \ - if (report_errors(LuaState, s)) \ - { \ - return true; /* Abort enumeration */ \ - } \ - \ - if (lua_isboolean(LuaState, -1)) \ - { \ - return (tolua_toboolean( LuaState, -1, 0) > 0); \ - } \ - return false; /* Continue enumeration */ \ - } \ - lua_State * LuaState; \ - int FuncRef; \ - int TableRef; \ - } Callback(tolua_S, FuncRef, TableRef); \ - \ - bool bRetVal = self->FOREACH(ChunkX, ChunkZ, Callback); \ - \ - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); \ - \ - /* Push return value on stack */ \ - tolua_pushboolean(tolua_S, bRetVal ); \ - return 1; \ +template< class Ty1, + class Ty2, + bool (Ty1::*Func1)(int, int, cItemCallback<Ty2> &) > +static int tolua_ForEachInChunk(lua_State* tolua_S) +{ + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 3) && (NumArgs != 4)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 3 or 4 arguments, got %i", NumArgs); + } + + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1 and #2"); + } + + int ChunkX = ((int)tolua_tonumber(tolua_S, 2, 0)); + int ChunkZ = ((int)tolua_tonumber(tolua_S, 3, 0)); + + if (!lua_isfunction( tolua_S, 4)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #3"); + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 4) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #4"); + } + } + + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #3"); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } + + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + if (report_errors(LuaState, s)) + { + return true; /* Abort enumeration */ + } + + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean( LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); + + bool bRetVal = (self->*Func1)(ChunkX, ChunkZ, Callback); + + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; } -#define DEFINE_LUA_FOREACH(CONTAINER,ITEM,FOREACH,FNNAME) \ -static int FNNAME(lua_State * tolua_S) \ -{ \ - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ \ - if( NumArgs != 1 && NumArgs != 2) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Requires 1 or 2 arguments, got %i", NumArgs ); \ - return 0; \ - } \ - \ - CONTAINER * self = (CONTAINER *) tolua_tousertype(tolua_S, 1, 0); \ - if (self == NULL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Not called on an object instance"); \ - return 0; \ - } \ - \ - if (!lua_isfunction( tolua_S, 2)) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Expected a function for parameter #1"); \ - return 0; \ - } \ - \ - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ \ - int TableRef = LUA_REFNIL; \ - if (NumArgs == 2) \ - { \ - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (TableRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get value reference of parameter #2"); \ - return 0; \ - } \ - } \ - \ - /* table value is popped, and now function is on top of the stack */ \ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); \ - if (FuncRef == LUA_REFNIL) \ - { \ - LOGWARN("Error in function call '" #FOREACH "': Could not get function reference of parameter #1"); \ - return 0; \ - } \ - \ - class cLuaCallback : public cItemCallback<ITEM> \ - { \ - public: \ - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) \ - : LuaState( a_LuaState ) \ - , FuncRef( a_FuncRef ) \ - , TableRef( a_TableRef ) \ - {} \ - \ - private: \ - virtual bool Item(ITEM * a_Item) override \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ \ - tolua_pushusertype( LuaState, a_Item, #ITEM ); \ - if (TableRef != LUA_REFNIL) \ - { \ - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ \ - } \ - \ - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); \ - if (report_errors(LuaState, s)) \ - { \ - return true; /* Abort enumeration */ \ - } \ - \ - if (lua_isboolean(LuaState, -1)) \ - { \ - return (tolua_toboolean( LuaState, -1, 0) > 0); \ - } \ - return false; /* Continue enumeration */ \ - } \ - lua_State * LuaState; \ - int FuncRef; \ - int TableRef; \ - } Callback(tolua_S, FuncRef, TableRef); \ - \ - bool bRetVal = self->FOREACH(Callback); \ - \ - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); \ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); \ - \ - /* Push return value on stack */ \ - tolua_pushboolean(tolua_S, bRetVal ); \ - return 1; \ -} +template< class Ty1, + class Ty2, + bool (Ty1::*Func1)(cItemCallback<Ty2> &) > +static int tolua_ForEach(lua_State * tolua_S) +{ + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if( NumArgs != 1 && NumArgs != 2) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 1 or 2 arguments, got %i", NumArgs); + } + + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + if (self == NULL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); + } + + if (!lua_isfunction( tolua_S, 2)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); + } + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 2) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #2"); + } + } + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); + } + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype( LuaState, a_Item, Ty2::GetClassStatic() ); + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + if (report_errors(LuaState, s)) + { + return true; /* Abort enumeration */ + } -// Define the DoWith enumerators: (they take a string and a callback class) -DEFINE_LUA_DOWITH(cWorld, cPlayer, DoWithPlayer, tolua_cWorld_DoWithPlayer); -DEFINE_LUA_DOWITH(cWorld, cPlayer, FindAndDoWithPlayer, tolua_cWorld_FindAndDoWithPlayer); -DEFINE_LUA_DOWITH(cRoot, cPlayer, FindAndDoWithPlayer, tolua_cRoot_FindAndDoWithPlayer); + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean( LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); -// Define the DoWith...At enumerators: (takes one 3D coordinate and a callback class) -DEFINE_LUA_DOWITH_XYZ(cWorld, cChestEntity, DoWithChestAt, tolua_cWorld_DoWithChestAt ); + bool bRetVal = (self->*Func1)(Callback); -// Define the ForEach enumerators: -DEFINE_LUA_FOREACH(cWorld, cPlayer, ForEachPlayer, tolua_cWorld_ForEachPlayer); -DEFINE_LUA_FOREACH(cWorld, cEntity, ForEachEntity, tolua_cWorld_ForEachEntity); -DEFINE_LUA_FOREACH(cRoot, cWorld, ForEachWorld, tolua_cRoot_ForEachWorld); -DEFINE_LUA_FOREACH(cRoot, cPlayer, ForEachPlayer, tolua_cRoot_ForEachPlayer); + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); -DEFINE_LUA_FOREACHINCHUNK(cWorld, cEntity, ForEachEntityInChunk, tolua_cWorld_ForEachEntityInChunk); -DEFINE_LUA_FOREACHINCHUNK(cWorld, cChestEntity, ForEachChestInChunk, tolua_cWorld_ForEachChestInChunk); -DEFINE_LUA_FOREACHINCHUNK(cWorld, cFurnaceEntity, ForEachFurnaceInChunk, tolua_cWorld_ForEachFurnaceInChunk); + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; +} @@ -786,12 +806,7 @@ static int tolua_cPlugin_NewLua_AddWebTab(lua_State * tolua_S) } else { - if( tolua_err.type == 0 ) - { - tolua_err.type = "function"; - } - tolua_error(tolua_S,"#ferror in function 'AddWebTab'.",&tolua_err); - return 0; + return tolua_do_error(tolua_S, "#ferror calling function '#funcname#'", &tolua_err); } if( Reference != LUA_REFNIL ) @@ -1020,20 +1035,20 @@ void ManualBindings::Bind( lua_State* tolua_S ) tolua_function(tolua_S, "Log", tolua_LOG); // Deprecated tolua_beginmodule(tolua_S, "cRoot"); - tolua_function(tolua_S, "ForEachWorld", tolua_cRoot_ForEachWorld); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_cRoot_FindAndDoWithPlayer); - tolua_function(tolua_S, "ForEachPlayer", tolua_cRoot_ForEachPlayer); + tolua_function(tolua_S, "ForEachWorld", tolua_ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>); + tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "ForEachPlayer", tolua_cWorld_ForEachPlayer); - tolua_function(tolua_S, "ForEachEntity", tolua_cWorld_ForEachEntity); - tolua_function(tolua_S, "ForEachEntityInChunk", tolua_cWorld_ForEachEntityInChunk); - tolua_function(tolua_S, "ForEachChestInChunk", tolua_cWorld_ForEachChestInChunk); - tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_cWorld_ForEachFurnaceInChunk); - tolua_function(tolua_S, "DoWithPlayer", tolua_cWorld_DoWithPlayer); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_cWorld_FindAndDoWithPlayer); - tolua_function(tolua_S, "DoWithChestAt", tolua_cWorld_DoWithChestAt); + tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cWorld, cPlayer, &cWorld::ForEachPlayer>); + tolua_function(tolua_S, "ForEachEntity", tolua_ForEach<cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); + tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); + tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith<cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith<cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlugin"); |