From 08624348f4e84fdc9909eb5de4478443bad8cc8d Mon Sep 17 00:00:00 2001 From: Mattes D Date: Thu, 23 Apr 2015 19:41:01 +0200 Subject: Implemented cPluginManager:DoWithPlugin(), fixed ForEachPlugin(). Both functions are exported as static. --- src/Bindings/LuaState.cpp | 108 ++++++++++++--- src/Bindings/LuaState.h | 75 +++++------ src/Bindings/ManualBindings.cpp | 281 ++++++++++++++++++++++++---------------- 3 files changed, 294 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 25c77a652..468e54f32 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -740,6 +740,18 @@ void cLuaState::Push(cPlayer * a_Player) +void cLuaState::Push(cPlugin * a_Plugin) +{ + ASSERT(IsValid()); + + tolua_pushusertype(m_LuaState, a_Plugin, "cPlugin"); + m_NumCurrentFunctionArgs += 1; +} + + + + + void cLuaState::Push(cPluginLua * a_Plugin) { ASSERT(IsValid()); @@ -911,6 +923,20 @@ void cLuaState::PushUserType(void * a_Object, const char * a_Type) +void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) +{ + size_t len = 0; + const char * data = lua_tolstring(m_LuaState, a_StackPos, &len); + if (data != nullptr) + { + a_Value.assign(data, len); + } +} + + + + + void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) { a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0); @@ -920,25 +946,20 @@ void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) +void cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) { - size_t len = 0; - const char * data = lua_tolstring(m_LuaState, a_StackPos, &len); - if (data != nullptr) - { - a_Value.assign(data, len); - } + a_Ref.RefStack(*this, a_StackPos); } -void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal) { if (lua_isnumber(m_LuaState, a_StackPos)) { - a_ReturnedVal = (int)tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal); + a_ReturnedVal = tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal); } } @@ -946,23 +967,27 @@ void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) { - if (lua_isnumber(m_LuaState, a_StackPos)) + if (!lua_isnumber(m_LuaState, a_StackPos)) { - a_ReturnedVal = tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal); + return; } + a_ReturnedVal = static_cast(Clamp( + static_cast(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)), + static_cast(wSunny), static_cast(wThunderstorm)) + ); } -void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal) { if (lua_isnumber(m_LuaState, a_StackPos)) { - a_ReturnedVal = (eWeather)Clamp((int)tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal), (int)wSunny, (int)wThunderstorm); + a_ReturnedVal = static_cast(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)); } } @@ -988,7 +1013,7 @@ void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, pPluginManager & a_ReturnedVal) { if (lua_isnil(m_LuaState, a_StackPos)) { @@ -996,9 +1021,9 @@ void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) return; } tolua_Error err; - if (tolua_isusertype(m_LuaState, a_StackPos, "cWorld", false, &err)) + if (tolua_isusertype(m_LuaState, a_StackPos, "cPluginManager", false, &err)) { - a_ReturnedVal = *((cWorld **)lua_touserdata(m_LuaState, a_StackPos)); + a_ReturnedVal = *(reinterpret_cast(lua_touserdata(m_LuaState, a_StackPos))); } } @@ -1006,9 +1031,54 @@ void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) +void cLuaState::GetStackValue(int a_StackPos, pRoot & a_ReturnedVal) { - a_Ref.RefStack(*this, a_StackPos); + if (lua_isnil(m_LuaState, a_StackPos)) + { + a_ReturnedVal = nullptr; + return; + } + tolua_Error err; + if (tolua_isusertype(m_LuaState, a_StackPos, "cRoot", false, &err)) + { + a_ReturnedVal = *(reinterpret_cast(lua_touserdata(m_LuaState, a_StackPos))); + } +} + + + + + +void cLuaState::GetStackValue(int a_StackPos, pScoreboard & a_ReturnedVal) +{ + if (lua_isnil(m_LuaState, a_StackPos)) + { + a_ReturnedVal = nullptr; + return; + } + tolua_Error err; + if (tolua_isusertype(m_LuaState, a_StackPos, "cScoreboard", false, &err)) + { + a_ReturnedVal = *(reinterpret_cast(lua_touserdata(m_LuaState, a_StackPos))); + } +} + + + + + +void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) +{ + if (lua_isnil(m_LuaState, a_StackPos)) + { + a_ReturnedVal = nullptr; + return; + } + tolua_Error err; + if (tolua_isusertype(m_LuaState, a_StackPos, "cWorld", false, &err)) + { + a_ReturnedVal = *(reinterpret_cast(lua_touserdata(m_LuaState, a_StackPos))); + } } diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 159483634..b77556117 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -37,34 +37,41 @@ extern "C" -class cWorld; -class cPlayer; +class cBlockEntity; +class cBoundingBox; +class cChunkDesc; +class cClientHandle; +class cCraftingGrid; +class cCraftingRecipe; class cEntity; -class cProjectileEntity; -class cMonster; +class cHopperEntity; class cItem; class cItems; -class cClientHandle; +class cLuaServerHandle; +class cLuaTCPLink; +class cLuaUDPEndpoint; +class cMonster; class cPickup; -class cChunkDesc; -class cCraftingGrid; -class cCraftingRecipe; -struct TakeDamageInfo; -class cWindow; +class cPlayer; +class cPlugin; class cPluginLua; -struct HTTPRequest; +class cPluginManager; +class cProjectileEntity; +class cRoot; +class cScoreboard; +class cTNTEntity; class cWebAdmin; +class cWindow; +class cWorld; +struct HTTPRequest; struct HTTPTemplateRequest; -class cTNTEntity; -class cHopperEntity; -class cBlockEntity; -class cBoundingBox; -class cLuaTCPLink; -class cLuaServerHandle; -class cLuaUDPEndpoint; +struct TakeDamageInfo; -typedef cBoundingBox * pBoundingBox; -typedef cWorld * pWorld; +typedef cBoundingBox * pBoundingBox; +typedef cPluginManager * pPluginManager; +typedef cRoot * pRoot; +typedef cScoreboard * pScoreboard; +typedef cWorld * pWorld; @@ -217,6 +224,7 @@ public: void Push(cMonster * a_Monster); void Push(cPickup * a_Pickup); void Push(cPlayer * a_Player); + void Push(cPlugin * a_Plugin); void Push(cPluginLua * a_Plugin); void Push(cProjectileEntity * a_ProjectileEntity); void Push(cTNTEntity * a_TNTEntity); @@ -231,30 +239,19 @@ public: void Push(void * a_Ptr); void Push(std::chrono::milliseconds a_time); - /** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */ - void GetStackValue(int a_StackPos, bool & a_Value); - - /** Retrieve value at a_StackPos, if it is a valid string. If not, a_Value is unchanged */ + // GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged. + // Enum values are clamped to their allowed range. void GetStackValue(int a_StackPos, AString & a_Value); - - /** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */ - void GetStackValue(int a_StackPos, int & a_Value); - - /** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */ + void GetStackValue(int a_StackPos, bool & a_Value); + void GetStackValue(int a_StackPos, cRef & a_Ref); void GetStackValue(int a_StackPos, double & a_Value); - - /** Retrieve value at a_StackPos, if it is a valid number, converting and clamping it to eWeather. - If not, a_Value is unchanged. */ void GetStackValue(int a_StackPos, eWeather & a_Value); - - /** Retrieve value at a_StackPos, if it is a valid cBoundingBox class. If not, a_Value is unchanged */ + void GetStackValue(int a_StackPos, int & a_Value); void GetStackValue(int a_StackPos, pBoundingBox & a_Value); - - /** Retrieve value at a_StackPos, if it is a valid cWorld class. If not, a_Value is unchanged */ + void GetStackValue(int a_StackPos, pPluginManager & a_Value); + void GetStackValue(int a_StackPos, pRoot & a_Value); + void GetStackValue(int a_StackPos, pScoreboard & a_Value); void GetStackValue(int a_StackPos, pWorld & a_Value); - - /** Store the value at a_StackPos as a reference. */ - void GetStackValue(int a_StackPos, cRef & a_Ref); /** Call the specified Lua function. Returns true if call succeeded, false if there was an error. diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 4c8d9ff96..ddd77b75b 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -67,7 +67,7 @@ static int lua_do_error(lua_State* L, const char * a_pFormat, ...) // Insert function name into error msg AString msg(a_pFormat); - ReplaceString(msg, "#funcname#", entry.name?entry.name:"?"); + ReplaceString(msg, "#funcname#", (entry.name != nullptr) ? entry.name : "?"); // Copied from luaL_error and modified va_list argp; @@ -493,94 +493,130 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) +/** Binds the DoWith(ItemName) functions of regular classes. */ template < class Ty1, class Ty2, - bool (Ty1::*Func1)(const AString &, cItemCallback &) + bool (Ty1::*DoWithFn)(const AString &, cItemCallback &) > -static int tolua_DoWith(lua_State* tolua_S) +static int tolua_DoWith(lua_State * tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if ((NumArgs != 2) && (NumArgs != 3)) + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamString(2) || + !L.CheckParamFunction(3) + ) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs); + return 0; } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, nullptr); - - const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); - if ((ItemName == nullptr) || (ItemName[0] == 0)) + // Get parameters: + Ty1 * Self; + AString ItemName; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, ItemName, FnRef); + if (Self == nullptr) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a non-empty string for parameter #1", NumArgs); + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); } - if (!lua_isfunction(tolua_S, 3)) + if (ItemName.empty() || (ItemName[0] == 0)) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #2", NumArgs); + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a non-empty string for parameter #1"); + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); } - /* 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) + class cLuaCallback : public cItemCallback { - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (TableRef == LUA_REFNIL) + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #3", NumArgs); } + + private: + virtual bool Item(Ty2 * a_Item) override + { + bool ret = false; + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret); + return ret; + } + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); + + // Call the DoWith function: + bool res = (Self->*DoWithFn)(ItemName, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; +} + + + + + +/** Template for static functions DoWith(ItemName), on a type that has a static ::Get() function. */ +template < + class Ty1, + class Ty2, + bool (Ty1::*DoWithFn)(const AString &, cItemCallback &) +> +static int tolua_StaticDoWith(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamString(2) || + !L.CheckParamFunction(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) + // Get parameters: + AString ItemName; + cLuaState::cRef FnRef; + L.GetStackValues(2, ItemName, FnRef); + if (ItemName.empty() || (ItemName[0] == 0)) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #2", NumArgs); + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a non-empty string for parameter #1"); + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); } class cLuaCallback : public cItemCallback { public: - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef): - LuaState(a_LuaState), - FuncRef(a_FuncRef), - TableRef(a_TableRef) + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) { } 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 (cLuaState::ReportErrors(LuaState, s)) - { - return true; // Abort enumeration - } - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ + bool ret = false; + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret); + return ret; } - lua_State * LuaState; - int FuncRef; - int TableRef; - } Callback(tolua_S, FuncRef, TableRef); - - - bool bRetVal = (self->*Func1)(ItemName, Callback); + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); - /* 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); + // Call the DoWith function: + bool res = (Ty1::Get()->*DoWithFn)(ItemName, Callback); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Push the result as the return value: + L.Push(res); return 1; } @@ -916,6 +952,9 @@ static int tolua_ForEachInBox(lua_State * tolua_S) } private: + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + // cItemCallback overrides: virtual bool Item(Ty2 * a_Item) override { @@ -929,8 +968,6 @@ static int tolua_ForEachInBox(lua_State * tolua_S) return res; } - cLuaState & m_LuaState; - cLuaState::cRef & m_FnRef; } Callback(L, FnRef); bool bRetVal = (Self->*Func1)(*Box, Callback); @@ -953,86 +990,105 @@ template < > static int tolua_ForEach(lua_State * tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if ((NumArgs != 1) && (NumArgs != 2)) + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 1 or 2 arguments, got %i", NumArgs); + return 0; } - Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, nullptr); + // Get the params: + Ty1 * self; + L.GetStackValues(1, self); + cLuaState::cRef FnRef(L, 2); if (self == nullptr) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'."); } - if (!lua_isfunction(tolua_S, 2)) + class cLuaCallback : public cItemCallback { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); - } + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } - /* 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) + private: + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + + virtual bool Item(Ty2 * a_Item) override { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #2"); + bool res = false; // By default continue the enumeration + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res); + return res; } - } + } Callback(L, FnRef); - /* 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) + // Call the enumeration: + bool res = (self->*Func1)(Callback); + + // Push the return value: + L.Push(res); + return 1; +} + + + + + +/** Implements bindings for ForEach() functions in a class that is static (has a ::Get() static function). */ +template < + class Ty1, + class Ty2, + bool (Ty1::*Func1)(cItemCallback &) +> +static int tolua_StaticForEach(lua_State * tolua_S) +{ + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); + return 0; } + // Get the params: + cLuaState::cRef FnRef(L, 2); + class cLuaCallback : public cItemCallback { public: - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef): - LuaState(a_LuaState), - FuncRef(a_FuncRef), - TableRef(a_TableRef) + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) { } private: + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + 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 (cLuaState::ReportErrors(LuaState, s)) - { - return true; /* Abort enumeration */ - } - - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ + bool res = false; // By default continue the enumeration + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res); + return res; } - lua_State * LuaState; - int FuncRef; - int TableRef; - } Callback(tolua_S, FuncRef, TableRef); - - bool bRetVal = (self->*Func1)(Callback); + } Callback(L, FnRef); - /* 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); + // Call the enumeration: + bool res = (Ty1::Get()->*Func1)(Callback); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Push the return value: + L.Push(res); return 1; } @@ -3814,10 +3870,11 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "BindCommand", tolua_cPluginManager_BindCommand); tolua_function(tolua_S, "BindConsoleCommand", tolua_cPluginManager_BindConsoleCommand); tolua_function(tolua_S, "CallPlugin", tolua_cPluginManager_CallPlugin); + tolua_function(tolua_S, "DoWithPlugin", tolua_StaticDoWith); tolua_function(tolua_S, "FindPlugins", tolua_cPluginManager_FindPlugins); tolua_function(tolua_S, "ForEachCommand", tolua_cPluginManager_ForEachCommand); tolua_function(tolua_S, "ForEachConsoleCommand", tolua_cPluginManager_ForEachConsoleCommand); - tolua_function(tolua_S, "ForEachPlugin", tolua_ForEach); + tolua_function(tolua_S, "ForEachPlugin", tolua_StaticForEach); tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); tolua_function(tolua_S, "GetCurrentPlugin", tolua_cPluginManager_GetCurrentPlugin); tolua_function(tolua_S, "GetPlugin", tolua_cPluginManager_GetPlugin); -- cgit v1.2.3