diff options
Diffstat (limited to 'src/Bindings')
-rw-r--r-- | src/Bindings/.gitignore | 4 | ||||
-rw-r--r-- | src/Bindings/AllToLua.bat | 2 | ||||
-rw-r--r-- | src/Bindings/AllToLua.sh | 2 | ||||
-rw-r--r-- | src/Bindings/AllToLua_lua.bat | 2 | ||||
-rw-r--r-- | src/Bindings/BindingsProcessor.lua | 161 | ||||
-rw-r--r-- | src/Bindings/CMakeLists.txt | 16 | ||||
-rw-r--r-- | src/Bindings/LuaState.cpp | 363 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 100 | ||||
-rw-r--r-- | src/Bindings/LuaWindow.cpp | 6 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 1663 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.h | 549 | ||||
-rw-r--r-- | src/Bindings/ManualBindings_Network.cpp | 22 | ||||
-rw-r--r-- | src/Bindings/ManualBindings_RankManager.cpp | 320 | ||||
-rw-r--r-- | src/Bindings/ManualBindings_World.cpp | 588 | ||||
-rw-r--r-- | src/Bindings/Plugin.cpp | 34 | ||||
-rw-r--r-- | src/Bindings/Plugin.h | 99 | ||||
-rw-r--r-- | src/Bindings/PluginLua.cpp | 375 | ||||
-rw-r--r-- | src/Bindings/PluginLua.h | 22 | ||||
-rw-r--r-- | src/Bindings/PluginManager.cpp | 435 | ||||
-rw-r--r-- | src/Bindings/PluginManager.h | 171 | ||||
-rw-r--r-- | src/Bindings/WebPlugin.cpp | 110 | ||||
-rw-r--r-- | src/Bindings/WebPlugin.h | 61 | ||||
-rw-r--r-- | src/Bindings/virtual_method_hooks.lua | 518 |
23 files changed, 2989 insertions, 2634 deletions
diff --git a/src/Bindings/.gitignore b/src/Bindings/.gitignore index 0d00dd578..711ae9c3a 100644 --- a/src/Bindings/.gitignore +++ b/src/Bindings/.gitignore @@ -1,2 +1,4 @@ lua51.dll -LuaState_Call.inc +LuaState_Declaration.inc +LuaState_Implementation.cpp +LuaState_Typedefs.inc diff --git a/src/Bindings/AllToLua.bat b/src/Bindings/AllToLua.bat index f085af9e9..44675a886 100644 --- a/src/Bindings/AllToLua.bat +++ b/src/Bindings/AllToLua.bat @@ -12,7 +12,7 @@ :: Regenerate the files: echo Regenerating LUA bindings . . . -"tolua++.exe" -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg +"tolua++.exe" -L BindingsProcessor.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg diff --git a/src/Bindings/AllToLua.sh b/src/Bindings/AllToLua.sh index 887c2490c..625ae4300 100644 --- a/src/Bindings/AllToLua.sh +++ b/src/Bindings/AllToLua.sh @@ -1,2 +1,2 @@ #!/bin/bash -/usr/bin/tolua++ -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg +/usr/bin/tolua++ -L BindingsProcessor.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg diff --git a/src/Bindings/AllToLua_lua.bat b/src/Bindings/AllToLua_lua.bat index 81c738f32..2d52c022d 100644 --- a/src/Bindings/AllToLua_lua.bat +++ b/src/Bindings/AllToLua_lua.bat @@ -13,7 +13,7 @@ :: Regenerate the files: echo Regenerating LUA bindings . . . -lua ..\..\lib\tolua++\src\bin\lua\_driver.lua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg +lua ..\..\lib\tolua++\src\bin\lua\_driver.lua -L BindingsProcessor.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg diff --git a/src/Bindings/BindingsProcessor.lua b/src/Bindings/BindingsProcessor.lua new file mode 100644 index 000000000..f86be6c6d --- /dev/null +++ b/src/Bindings/BindingsProcessor.lua @@ -0,0 +1,161 @@ + +-- BindingsProcessor.lua + +-- Implements additional processing that is done while generating the Lua bindings + + + + + +local access = {public = 0, protected = 1, private = 2} + + + + + +--- Defines classes that have a custom manual Push() implementation and should not generate the automatic one +-- Map of classname -> true +local g_HasCustomPushImplementation = +{ + cEntity = true +} + + + + + +function parser_hook(s) + local container = classContainer.curr -- get the current container + + -- process access-specifying labels (public, private, etc) + do + local b, e, label = string.find(s, "^%s*(%w*)%s*:[^:]") -- we need to check for [^:], otherwise it would match 'namespace::type' + if b then + + -- found a label, get the new access value from the global 'access' table + if access[label] then + container.curr_member_access = access[label] + end -- else ? + + return strsub(s, e) -- normally we would use 'e+1', but we need to preserve the [^:] + end + end +end + + + + + +--- Outputs the helper files supplementing the cLuaState class +-- Writes: +-- LuaState_Declaration.inc +-- LuaState_Implementation.cpp +-- LuaState_Typedefs.inc +local function OutputLuaStateHelpers(a_Package) + -- Collect all class types from ToLua: + local types = {} + for idx, item in ipairs(a_Package) do + local mt = getmetatable(item) or {} + if (mt.classtype == "class") then + table.insert(types, {name = item.name, lname = item.lname}) + end + end + table.sort(types, + function(a_Item1, a_Item2) + return (a_Item1.name:lower() < a_Item2.name:lower()) + end + ) + + -- Output the typedefs: + do + local f = assert(io.open("LuaState_Typedefs.inc", "w")) + f:write("\n// LuaState_Typedefs.inc\n\n// This file is generated along with the Lua bindings by ToLua. Do not edit manually, do not commit to repo.\n") + f:write("// Provides a forward declaration and a typedef for a pointer to each class exported to the Lua API.\n") + f:write("\n\n\n\n\n") + for _, item in ipairs(types) do + if not(item.name:match(".*<.*")) then -- Skip templates altogether + -- Classes start with a "c", everything else is a struct: + if (item.name:sub(1, 1) == "c") then + f:write("class " .. item.name .. ";\n") + else + f:write("struct " .. item.name .. ";\n") + end + end + end + f:write("\n\n\n\n\n") + for _, item in ipairs(types) do + f:write("typedef " .. item.name .. " * Ptr" .. item.lname .. ";\n") + end + f:write("\n\n\n\n\n") + f:close() + end + + -- Output the Push() and GetStackValue() function declarations: + do + local f = assert(io.open("LuaState_Declaration.inc", "w")) + f:write("\n// LuaState_Declaration.inc\n\n// This file is generated along with the Lua bindings by ToLua. Do not edit manually, do not commit to repo.\n") + f:write("// Implements a Push() and GetStackValue() function for each class exported to the Lua API.\n") + f:write("// This file expects to be included form inside the cLuaState class definition\n") + f:write("\n\n\n\n\n") + for _, item in ipairs(types) do + f:write("void Push(" .. item.name .. " * a_Value);\n") + end + for _, item in ipairs(types) do + f:write("void GetStackValue(int a_StackPos, Ptr" .. item.lname .. " & a_ReturnedVal);\n") + end + f:write("\n\n\n\n\n") + f:close() + end + + -- Output the Push() and GetStackValue() function implementations: + do + local f = assert(io.open("LuaState_Implementation.cpp", "w")) + f:write("\n// LuaState_Implementation.cpp\n\n// This file is generated along with the Lua bindings by ToLua. Do not edit manually, do not commit to repo.\n") + f:write("// Implements a Push() and GetStackValue() function for each class exported to the Lua API.\n") + f:write("// This file expects to be compiled as a separate translation unit\n") + f:write("\n\n\n\n\n") + f:write("#include \"Globals.h\"\n#include \"LuaState.h\"\n#include \"tolua++/include/tolua++.h\"\n") + f:write("\n\n\n\n\n") + for _, item in ipairs(types) do + if not(g_HasCustomPushImplementation[item.name]) then + f:write("void cLuaState::Push(" .. item.name .. " * a_Value)\n{\n\tASSERT(IsValid());\n") + f:write("\ttolua_pushusertype(m_LuaState, a_Value, \"" .. item.name .. "\");\n"); + f:write("\tm_NumCurrentFunctionArgs += 1;\n") + f:write("}\n\n\n\n\n\n") + end + end + for _, item in ipairs(types) do + f:write("void cLuaState::GetStackValue(int a_StackPos, Ptr" .. item.lname .. " & a_ReturnedVal)\n{\n\tASSERT(IsValid());\n") + f:write("\tif (lua_isnil(m_LuaState, a_StackPos))\n\t{\n") + f:write("\t a_ReturnedVal = nullptr;\n") + f:write("\t return;\n\t}\n") + f:write("\ttolua_Error err;\n") + f:write("\tif (tolua_isusertype(m_LuaState, a_StackPos, \"" .. item.name .. "\", false, &err))\n") + f:write("\t{\n") + f:write("\t a_ReturnedVal = *(reinterpret_cast<" .. item.name .. " **>(lua_touserdata(m_LuaState, a_StackPos)));\n") + f:write("\t}\n") + f:write("}\n\n\n\n\n\n") + end + f:close() + end +end + + + + + +function pre_output_hook(a_Package) + OutputLuaStateHelpers(a_Package) +end + + + + + +function post_output_hook() + print("Bindings have been generated.") +end + + + + diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt index 4cc73b350..133c2224d 100644 --- a/src/Bindings/CMakeLists.txt +++ b/src/Bindings/CMakeLists.txt @@ -11,12 +11,14 @@ SET (SRCS LuaNameLookup.cpp LuaServerHandle.cpp LuaState.cpp + LuaState_Implementation.cpp LuaTCPLink.cpp LuaUDPEndpoint.cpp LuaWindow.cpp ManualBindings.cpp ManualBindings_Network.cpp ManualBindings_RankManager.cpp + ManualBindings_World.cpp Plugin.cpp PluginLua.cpp PluginManager.cpp @@ -31,6 +33,8 @@ SET (HDRS LuaNameLookup.h LuaServerHandle.h LuaState.h + LuaState_Declaration.inc + LuaState_Typedefs.inc LuaTCPLink.h LuaUDPEndpoint.h LuaWindow.h @@ -46,12 +50,15 @@ SET (HDRS set (BINDING_OUTPUTS ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Bindings.h + ${CMAKE_CURRENT_SOURCE_DIR}/LuaState_Declaration.inc + ${CMAKE_CURRENT_SOURCE_DIR}/LuaState_Implementation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/LuaState_Typedefs.inc ) set(BINDING_DEPENDENCIES tolua - ../Bindings/virtual_method_hooks.lua ../Bindings/AllToLua.pkg + ../Bindings/BindingsProcessor.lua ../Bindings/LuaFunctions.h ../Bindings/LuaWindow.h ../Bindings/Plugin.h @@ -126,7 +133,7 @@ if (NOT MSVC) OUTPUT ${BINDING_OUTPUTS} # Regenerate bindings: - COMMAND tolua -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg + COMMAND tolua -L BindingsProcessor.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} # add any new generation dependencies here @@ -134,13 +141,12 @@ if (NOT MSVC) ) endif () -set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.cpp PROPERTIES GENERATED TRUE) -set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.h PROPERTIES GENERATED TRUE) +set_source_files_properties(${BINDING_OUTPUTS} PROPERTIES GENERATED TRUE) set_source_files_properties(${CMAKE_SOURCE_DIR}/src/Bindings/Bindings.cpp PROPERTIES COMPILE_FLAGS -Wno-error) if(NOT MSVC) add_library(Bindings ${SRCS} ${HDRS}) - target_link_libraries(Bindings lua sqlite tolualib polarssl) + target_link_libraries(Bindings lua sqlite tolualib mbedtls) endif() diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 25c77a652..08c7e19d7 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -19,13 +19,13 @@ extern "C" #include "../Entities/Entity.h" #include "../BlockEntities/BlockEntity.h" -// fwd: SQLite/lsqlite3.c +// fwd: "SQLite/lsqlite3.c" extern "C" { int luaopen_lsqlite3(lua_State * L); } -// fwd: LuaExpat/lxplib.c: +// fwd: "LuaExpat/lxplib.c": extern "C" { int luaopen_lxp(lua_State * L); @@ -107,7 +107,7 @@ void cLuaState::Create(void) void cLuaState::RegisterAPILibs(void) { tolua_AllToLua_open(m_LuaState); - ManualBindings::Bind(m_LuaState); + cManualBindings::Bind(m_LuaState); DeprecatedBindings::Bind(m_LuaState); luaopen_lsqlite3(m_LuaState); luaopen_lxp(m_LuaState); @@ -530,42 +530,6 @@ void cLuaState::Push(bool a_Value) -void cLuaState::Push(cBlockEntity * a_BlockEntity) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_BlockEntity, (a_BlockEntity == nullptr) ? "cBlockEntity" : a_BlockEntity->GetClass()); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cChunkDesc * a_ChunkDesc) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_ChunkDesc, "cChunkDesc"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cClientHandle * a_Client) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Client, "cClientHandle"); - m_NumCurrentFunctionArgs += 1; -} - - - - - void cLuaState::Push(cEntity * a_Entity) { ASSERT(IsValid()); @@ -632,42 +596,6 @@ void cLuaState::Push(cEntity * a_Entity) -void cLuaState::Push(cHopperEntity * a_Hopper) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Hopper, "cHopperEntity"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cItem * a_Item) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Item, "cItem"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cItems * a_Items) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Items, "cItems"); - m_NumCurrentFunctionArgs += 1; -} - - - - - void cLuaState::Push(cLuaServerHandle * a_ServerHandle) { ASSERT(IsValid()); @@ -704,114 +632,6 @@ void cLuaState::Push(cLuaUDPEndpoint * a_UDPEndpoint) -void cLuaState::Push(cMonster * a_Monster) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Monster, "cMonster"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cPickup * a_Pickup) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Pickup, "cPickup"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cPlayer * a_Player) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cPluginLua * a_Plugin) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Plugin, "cPluginLua"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cProjectileEntity * a_ProjectileEntity) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_ProjectileEntity, "cProjectileEntity"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cTNTEntity * a_TNTEntity) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_TNTEntity, "cTNTEntity"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cWebAdmin * a_WebAdmin) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_WebAdmin, "cWebAdmin"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cWindow * a_Window) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Window, "cWindow"); - m_NumCurrentFunctionArgs += 1; -} - - - - - -void cLuaState::Push(cWorld * a_World) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - m_NumCurrentFunctionArgs += 1; -} - - - - - void cLuaState::Push(double a_Value) { ASSERT(IsValid()); @@ -836,11 +656,18 @@ void cLuaState::Push(int a_Value) -void cLuaState::Push(TakeDamageInfo * a_TDI) +void cLuaState::Push(void * a_Ptr) { + UNUSED(a_Ptr); ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_TDI, "TakeDamageInfo"); + // Investigate the cause of this - what is the callstack? + // One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them + LOGWARNING("Lua engine: attempting to push a plain pointer, pushing nil instead."); + LOGWARNING("This indicates an unimplemented part of MCS bindings"); + LogStackTrace(); + + lua_pushnil(m_LuaState); m_NumCurrentFunctionArgs += 1; } @@ -848,11 +675,11 @@ void cLuaState::Push(TakeDamageInfo * a_TDI) -void cLuaState::Push(Vector3d * a_Vector) +void cLuaState::Push(std::chrono::milliseconds a_Value) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_Vector, "Vector3<double>"); + tolua_pushnumber(m_LuaState, static_cast<lua_Number>(a_Value.count())); m_NumCurrentFunctionArgs += 1; } @@ -860,51 +687,40 @@ void cLuaState::Push(Vector3d * a_Vector) -void cLuaState::Push(Vector3i * a_Vector) +/* +void cLuaState::PushUserType(void * a_Object, const char * a_Type) { ASSERT(IsValid()); - tolua_pushusertype(m_LuaState, a_Vector, "Vector3<int>"); + tolua_pushusertype(m_LuaState, a_Object, a_Type); m_NumCurrentFunctionArgs += 1; } +*/ -void cLuaState::Push(void * a_Ptr) -{ - UNUSED(a_Ptr); - ASSERT(IsValid()); - - // Investigate the cause of this - what is the callstack? - // One code path leading here is the OnHookExploding / OnHookExploded with exotic parameters. Need to decide what to do with them - LOGWARNING("Lua engine: attempting to push a plain pointer, pushing nil instead."); - LOGWARNING("This indicates an unimplemented part of MCS bindings"); - LogStackTrace(); - - lua_pushnil(m_LuaState); - m_NumCurrentFunctionArgs += 1; -} - -void cLuaState::Push(std::chrono::milliseconds a_Value) +void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) { - ASSERT(IsValid()); - - tolua_pushnumber(m_LuaState, static_cast<lua_Number>(a_Value.count())); - m_NumCurrentFunctionArgs += 1; + size_t len = 0; + const char * data = lua_tolstring(m_LuaState, a_StackPos, &len); + if (data != nullptr) + { + a_Value.assign(data, len); + } } -void cLuaState::PushUserType(void * a_Object, const char * a_Type) +void cLuaState::GetStackValue(int a_StackPos, BLOCKTYPE & a_ReturnedVal) { - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Object, a_Type); - m_NumCurrentFunctionArgs += 1; + if (lua_isnumber(m_LuaState, a_StackPos)) + { + a_ReturnedVal = static_cast<BLOCKTYPE>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)); + } } @@ -920,13 +736,11 @@ void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) +void cLuaState::GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result) { - size_t len = 0; - const char * data = lua_tolstring(m_LuaState, a_StackPos, &len); - if (data != nullptr) + if (lua_isnumber(m_LuaState, a_StackPos)) { - a_Value.assign(data, len); + a_Result = static_cast<cPluginManager::CommandResult>(static_cast<int>((tolua_tonumber(m_LuaState, a_StackPos, a_Result)))); } } @@ -934,12 +748,9 @@ void cLuaState::GetStackValue(int a_StackPos, AString & a_Value) -void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) { - if (lua_isnumber(m_LuaState, a_StackPos)) - { - a_ReturnedVal = (int)tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal); - } + a_Ref.RefStack(*this, a_StackPos); } @@ -958,11 +769,11 @@ void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, float & 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<float>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)); } } @@ -970,35 +781,27 @@ void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, pBoundingBox & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal) { - if (lua_isnil(m_LuaState, a_StackPos)) + if (!lua_isnumber(m_LuaState, a_StackPos)) { - a_ReturnedVal = nullptr; return; } - tolua_Error err; - if (tolua_isusertype(m_LuaState, a_StackPos, "cBoundingBox", false, &err)) - { - a_ReturnedVal = *((cBoundingBox **)lua_touserdata(m_LuaState, a_StackPos)); - } + a_ReturnedVal = static_cast<eWeather>(Clamp( + static_cast<int>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)), + static_cast<int>(wSunny), static_cast<int>(wThunderstorm)) + ); } -void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, int & 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)) + if (lua_isnumber(m_LuaState, a_StackPos)) { - a_ReturnedVal = *((cWorld **)lua_touserdata(m_LuaState, a_StackPos)); + a_ReturnedVal = static_cast<int>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)); } } @@ -1006,15 +809,6 @@ void cLuaState::GetStackValue(int a_StackPos, pWorld & a_ReturnedVal) -void cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) -{ - a_Ref.RefStack(*this, a_StackPos); -} - - - - - bool cLuaState::CallFunction(int a_NumResults) { ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first @@ -1133,6 +927,9 @@ bool cLuaState::CheckParamTable(int a_StartParam, int a_EndParam) VERIFY(lua_getstack(m_LuaState, 0, &entry)); VERIFY(lua_getinfo (m_LuaState, "n", &entry)); AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?"); + + BreakIntoDebugger(m_LuaState); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); return false; } // for i - Param @@ -1280,7 +1077,7 @@ bool cLuaState::CheckParamFunctionOrNil(int a_StartParam, int a_EndParam) bool cLuaState::CheckParamEnd(int a_Param) { tolua_Error tolua_err; - if (tolua_isnoobj(m_LuaState, a_Param, &tolua_err)) + if (tolua_isnoobj(m_LuaState, a_Param, &tolua_err) == 1) { return true; } @@ -1297,6 +1094,30 @@ bool cLuaState::CheckParamEnd(int a_Param) +bool cLuaState::IsParamUserType(int a_Param, AString a_UserType) +{ + ASSERT(IsValid()); + + tolua_Error tolua_err; + return (tolua_isusertype(m_LuaState, a_Param, a_UserType.c_str(), 0, &tolua_err) == 1); +} + + + + + +bool cLuaState::IsParamNumber(int a_Param) +{ + ASSERT(IsValid()); + + tolua_Error tolua_err; + return (tolua_isnumber(m_LuaState, a_Param, 0, &tolua_err) == 1); +} + + + + + bool cLuaState::ReportErrors(int a_Status) { return ReportErrors(m_LuaState, a_Status); @@ -1376,7 +1197,7 @@ int cLuaState::CallFunctionWithForeignParams( if (!PushFunction(a_FunctionName.c_str())) { LOGWARNING("Function '%s' not found", a_FunctionName.c_str()); - lua_pop(m_LuaState, 2); + lua_settop(m_LuaState, OldTop); return -1; } @@ -1384,7 +1205,7 @@ int cLuaState::CallFunctionWithForeignParams( if (CopyStackFrom(a_SrcLuaState, a_SrcParamStart, a_SrcParamEnd) < 0) { // Something went wrong, fix the stack and exit - lua_pop(m_LuaState, 2); + lua_settop(m_LuaState, OldTop); m_NumCurrentFunctionArgs = -1; m_CurrentFunctionName.clear(); return -1; @@ -1395,13 +1216,8 @@ int cLuaState::CallFunctionWithForeignParams( if (ReportErrors(s)) { LOGWARN("Error while calling function '%s' in '%s'", a_FunctionName.c_str(), m_SubsystemName.c_str()); - // Fix the stack. - // We don't know how many values have been pushed, so just get rid of any that weren't there initially - int CurTop = lua_gettop(m_LuaState); - if (CurTop > OldTop) - { - lua_pop(m_LuaState, CurTop - OldTop); - } + // Reset the stack: + lua_settop(m_LuaState, OldTop); // Reset the internal checking mechanisms: m_NumCurrentFunctionArgs = -1; @@ -1553,6 +1369,7 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) { LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); LogStackTrace(a_LuaState, 1); + BreakIntoDebugger(a_LuaState); return 1; // We left the error message on the stack as the return value } @@ -1560,6 +1377,28 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) +int cLuaState::BreakIntoDebugger(lua_State * a_LuaState) +{ + // Call the BreakIntoDebugger function, if available: + lua_getglobal(a_LuaState, "BreakIntoDebugger"); + if (!lua_isfunction(a_LuaState, -1)) + { + LOGD("LUA: BreakIntoDebugger() not found / not a function"); + lua_pop(a_LuaState, 1); + return 1; + } + lua_insert(a_LuaState, -2); // Copy the string that has been passed to us + LOGD("Calling BreakIntoDebugger()..."); + lua_call(a_LuaState, 1, 0); + LOGD("Returned from BreakIntoDebugger()."); + + return 0; +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cLuaState::cRef: diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 159483634..5b4ec3ae4 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -32,40 +32,14 @@ extern "C" #include "../Vector3.h" #include "../Defines.h" +#include "PluginManager.h" +#include "LuaState_Typedefs.inc" - - - - -class cWorld; -class cPlayer; -class cEntity; -class cProjectileEntity; -class cMonster; -class cItem; -class cItems; -class cClientHandle; -class cPickup; -class cChunkDesc; -class cCraftingGrid; -class cCraftingRecipe; -struct TakeDamageInfo; -class cWindow; -class cPluginLua; -struct HTTPRequest; -class cWebAdmin; -struct HTTPTemplateRequest; -class cTNTEntity; -class cHopperEntity; -class cBlockEntity; -class cBoundingBox; -class cLuaTCPLink; +// fwd: class cLuaServerHandle; +class cLuaTCPLink; class cLuaUDPEndpoint; -typedef cBoundingBox * pBoundingBox; -typedef cWorld * pWorld; - @@ -202,59 +176,30 @@ public: void Push(const Vector3i & a_Vector); void Push(const Vector3i * a_Vector); - // Push a value onto the stack (keep alpha-sorted): + // Push a simple value onto the stack (keep alpha-sorted): void Push(bool a_Value); - void Push(cBlockEntity * a_BlockEntity); - void Push(cChunkDesc * a_ChunkDesc); - void Push(cClientHandle * a_ClientHandle); - void Push(cEntity * a_Entity); - void Push(cHopperEntity * a_Hopper); - void Push(cItem * a_Item); - void Push(cItems * a_Items); - void Push(cLuaServerHandle * a_ServerHandle); - void Push(cLuaTCPLink * a_TCPLink); - void Push(cLuaUDPEndpoint * a_UDPEndpoint); - void Push(cMonster * a_Monster); - void Push(cPickup * a_Pickup); - void Push(cPlayer * a_Player); - void Push(cPluginLua * a_Plugin); - void Push(cProjectileEntity * a_ProjectileEntity); - void Push(cTNTEntity * a_TNTEntity); - void Push(cWebAdmin * a_WebAdmin); - void Push(cWindow * a_Window); - void Push(cWorld * a_World); void Push(double a_Value); void Push(int a_Value); - void Push(TakeDamageInfo * a_TDI); - void Push(Vector3d * a_Vector); - void Push(Vector3i * a_Vector); void Push(void * a_Ptr); void Push(std::chrono::milliseconds a_time); + void Push(cLuaServerHandle * a_ServerHandle); + void Push(cLuaTCPLink * a_TCPLink); + void Push(cLuaUDPEndpoint * a_UDPEndpoint); - /** 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, BLOCKTYPE & a_Value); + void GetStackValue(int a_StackPos, bool & a_Value); + void GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result); + 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); + void GetStackValue(int a_StackPos, float & a_ReturnedVal); + void GetStackValue(int a_StackPos, int & 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, 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, pWorld & a_Value); - - /** Store the value at a_StackPos as a reference. */ - void GetStackValue(int a_StackPos, cRef & a_Ref); + // Include the auto-generated Push and GetStackValue() functions: + #include "LuaState_Declaration.inc" /** Call the specified Lua function. Returns true if call succeeded, false if there was an error. @@ -303,6 +248,10 @@ public: /** Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) */ bool CheckParamEnd(int a_Param); + bool IsParamUserType(int a_Param, AString a_UserType); + + bool IsParamNumber(int a_Param); + /** If the status is nonzero, prints the text on the top of Lua stack and returns true */ bool ReportErrors(int status); @@ -429,7 +378,7 @@ protected: bool PushFunction(const cTableRef & a_TableRef); /** Pushes a usertype of the specified class type onto the stack */ - void PushUserType(void * a_Object, const char * a_Type); + // void PushUserType(void * a_Object, const char * a_Type); /** Calls the function that has been pushed onto the stack by PushFunction(), @@ -440,6 +389,9 @@ protected: /** Used as the error reporting function for function calls */ static int ReportFnCallErrors(lua_State * a_LuaState); + + /** Tries to break into the MobDebug debugger, if it is installed. */ + static int BreakIntoDebugger(lua_State * a_LuaState); } ; diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp index d4014059b..5f7832ef5 100644 --- a/src/Bindings/LuaWindow.cpp +++ b/src/Bindings/LuaWindow.cpp @@ -159,7 +159,7 @@ void cLuaWindow::Destroy(void) m_Plugin->Unreference(m_LuaRef); } - // Lua will take care of this object, it will garbage-collect it, so we *must not* delete it! + // Lua will take care of this object, it will garbage-collect it, so we must not delete it! m_IsDestroyed = false; } @@ -167,10 +167,10 @@ void cLuaWindow::Destroy(void) -void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer& a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) +void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) { cSlotAreas Areas; - for (auto Area : m_SlotAreas) + for (auto && Area : m_SlotAreas) { if (Area != a_ClickedArea) { diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 6e579b364..ff904d74a 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -5,6 +5,7 @@ #undef TOLUA_TEMPLATE_BIND #include <sstream> #include <iomanip> +#include <array> #include "tolua++/include/tolua++.h" #include "polarssl/md5.h" #include "polarssl/sha1.h" @@ -32,13 +33,14 @@ #include "../WorldStorage/SchematicFileSerializer.h" #include "../CompositeChat.h" #include "../StringCompression.h" +#include "../CommandOutput.h" // Better error reporting for Lua -static int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError) +int cManualBindings::tolua_do_error(lua_State * L, const char * a_pMsg, tolua_Error * a_pToLuaError) { // Retrieve current function name lua_Debug entry; @@ -58,7 +60,7 @@ static int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pTo -static int lua_do_error(lua_State* L, const char * a_pFormat, ...) +int cManualBindings::lua_do_error(lua_State * L, const char * a_pFormat, ...) { // Retrieve current function name lua_Debug entry; @@ -67,7 +69,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; @@ -90,12 +92,12 @@ static int tolua_Clamp(lua_State * tolua_S) int NumArgs = lua_gettop(LuaState); if (NumArgs != 3) { - return lua_do_error(LuaState, "Error in function call '#funcname#': Requires 3 arguments, got %i", NumArgs); + return cManualBindings::lua_do_error(LuaState, "Error in function call '#funcname#': Requires 3 arguments, got %i", NumArgs); } if (!lua_isnumber(LuaState, 1) || !lua_isnumber(LuaState, 2) || !lua_isnumber(LuaState, 3)) { - return lua_do_error(LuaState, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); + return cManualBindings::lua_do_error(LuaState, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); } lua_Number Number = tolua_tonumber(LuaState, 1, 0); @@ -253,12 +255,13 @@ static int tolua_InflateString(lua_State * tolua_S) static int tolua_StringSplit(lua_State * tolua_S) { + // Get the params: cLuaState LuaState(tolua_S); - std::string str = (std::string)tolua_tocppstring(LuaState, 1, 0); - std::string delim = (std::string)tolua_tocppstring(LuaState, 2, 0); + AString str, delim; + LuaState.GetStackValues(1, str, delim); - AStringVector Split = StringSplit(str, delim); - LuaState.Push(Split); + // Execute and push the result: + LuaState.Push(StringSplit(str, delim)); return 1; } @@ -286,12 +289,20 @@ static int tolua_StringSplitWithQuotes(lua_State * tolua_S) static int tolua_StringSplitAndTrim(lua_State * tolua_S) { - cLuaState LuaState(tolua_S); - std::string str = (std::string)tolua_tocppstring(LuaState, 1, 0); - std::string delim = (std::string)tolua_tocppstring(LuaState, 2, 0); + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamString(1, 2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } - AStringVector Split = StringSplitAndTrim(str, delim); - LuaState.Push(Split); + // Process: + AString str, delim; + L.GetStackValues(1, str, delim); + L.Push(StringSplitAndTrim(str, delim)); return 1; } @@ -450,7 +461,7 @@ static int tolua_Base64Decode(lua_State * tolua_S) -cPluginLua * GetLuaPlugin(lua_State * L) +cPluginLua * cManualBindings::GetLuaPlugin(lua_State * L) { // Get the plugin identification out of LuaState: lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME); @@ -472,6 +483,7 @@ cPluginLua * GetLuaPlugin(lua_State * L) static int tolua_cFile_GetFolderContents(lua_State * tolua_S) { + // Check params: cLuaState LuaState(tolua_S); if ( !LuaState.CheckParamUserTable(1, "cFile") || @@ -482,10 +494,12 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) return 0; } - AString Folder = (AString)tolua_tocppstring(LuaState, 2, 0); + // Get params: + AString Folder; + LuaState.GetStackValues(2, Folder); - AStringVector Contents = cFile::GetFolderContents(Folder); - LuaState.Push(Contents); + // Execute and push result: + LuaState.Push(cFile::GetFolderContents(Folder)); return 1; } @@ -493,447 +507,25 @@ static int tolua_cFile_GetFolderContents(lua_State * tolua_S) -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, nullptr); - - const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); - if ((ItemName == nullptr) || (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); - 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 */ - } - 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; -} - - - - - -template < - class Ty1, - class Ty2, - bool (Ty1::*Func1)(UInt32, cItemCallback<Ty2> &) -> -static int tolua_DoWithID(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, nullptr); - - int ItemID = (int)tolua_tonumber(tolua_S, 2, 0); - 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 to call - tolua_pushusertype(LuaState, a_Item, a_Item->GetClass()); // Push the item - if (TableRef != LUA_REFNIL) - { - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param - } - - 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 */ - } - lua_State * LuaState; - int FuncRef; - int TableRef; - } Callback(tolua_S, FuncRef, TableRef); - - - bool bRetVal = (self->*Func1)(ItemID, 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, nullptr); - 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)); - 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); - 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 */ - } - 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; -} - - - - - -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, nullptr); - 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 (cLuaState::ReportErrors(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; -} - - - - - -template < - class Ty1, - class Ty2, - bool (Ty1::*Func1)(const cBoundingBox &, cItemCallback<Ty2> &) -> -static int tolua_ForEachInBox(lua_State * tolua_S) +static int tolua_cFile_ReadWholeFile(lua_State * tolua_S) { // Check params: - cLuaState L(tolua_S); + cLuaState LuaState(tolua_S); if ( - !L.CheckParamUserType(1, "cWorld") || - !L.CheckParamUserType(2, "cBoundingBox") || - !L.CheckParamFunction(3) || - !L.CheckParamEnd(4) + !LuaState.CheckParamUserTable(1, "cFile") || + !LuaState.CheckParamString (2) || + !LuaState.CheckParamEnd (3) ) { return 0; } - - // Get the params: - Ty1 * Self = nullptr; - cBoundingBox * Box = nullptr; - L.GetStackValues(1, Self, Box); - if ((Self == nullptr) || (Box == nullptr)) - { - LOGWARNING("Invalid world (%p) or boundingbox (%p)", Self, Box); - L.LogStackTrace(); - return 0; - } - // Create a reference for the function: - cLuaState::cRef FnRef(L, 3); + // Get params: + AString FileName; + LuaState.GetStackValues(2, FileName); - // Callback wrapper for the Lua function: - class cLuaCallback : public cItemCallback<Ty2> - { - public: - cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FuncRef) : - m_LuaState(a_LuaState), - m_FnRef(a_FuncRef) - {} - - private: - // cItemCallback<Ty2> overrides: - virtual bool Item(Ty2 * a_Item) override - { - bool res = false; - if (!m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res)) - { - LOGWARNING("Failed to call Lua callback"); - m_LuaState.LogStackTrace(); - return true; // Abort enumeration - } - - return res; - } - cLuaState & m_LuaState; - cLuaState::cRef & m_FnRef; - } Callback(L, FnRef); - - bool bRetVal = (Self->*Func1)(*Box, Callback); - - FnRef.UnRef(); - - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Execute and push result: + LuaState.Push(cFile::ReadWholeFile(FileName)); return 1; } @@ -941,535 +533,30 @@ static int tolua_ForEachInBox(lua_State * tolua_S) -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, nullptr); - if (self == nullptr) - { - 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 (cLuaState::ReportErrors(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)(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; -} - - - - - -static int tolua_cWorld_GetBlockInfo(lua_State * tolua_S) -{ - // Exported manually, because tolua would generate useless additional parameters (a_BlockType .. a_BlockSkyLight) - // Function signature: GetBlockInfo(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta, BlockSkyLight, BlockBlockLight] - #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || - !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 4, 0, &tolua_err) || - !tolua_isnoobj (tolua_S, 5, &tolua_err) - ) - goto tolua_lerror; - else - #endif - { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); - int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); - int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); - int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); - #ifndef TOLUA_RELEASE - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'GetBlockInfo'", nullptr); - } - #endif - { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta, BlockSkyLight, BlockBlockLight; - bool res = self->GetBlockInfo(BlockX, BlockY, BlockZ, BlockType, BlockMeta, BlockSkyLight, BlockBlockLight); - tolua_pushboolean(tolua_S, res ? 1 : 0); - if (res) - { - tolua_pushnumber(tolua_S, BlockType); - tolua_pushnumber(tolua_S, BlockMeta); - tolua_pushnumber(tolua_S, BlockSkyLight); - tolua_pushnumber(tolua_S, BlockBlockLight); - return 5; - } - } - } - return 1; - - #ifndef TOLUA_RELEASE -tolua_lerror: - tolua_error(tolua_S, "#ferror in function 'GetBlockInfo'.", &tolua_err); - return 0; - #endif -} - - - - - -static int tolua_cWorld_GetBlockTypeMeta(lua_State * tolua_S) -{ - // Exported manually, because tolua would generate useless additional parameters (a_BlockType, a_BlockMeta) - // Function signature: GetBlockTypeMeta(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta] - #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || - !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 4, 0, &tolua_err) || - !tolua_isnoobj (tolua_S, 5, &tolua_err) - ) - goto tolua_lerror; - else - #endif - { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); - int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); - int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); - int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); - #ifndef TOLUA_RELEASE - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'GetBlockTypeMeta'", nullptr); - } - #endif - { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - bool res = self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta); - tolua_pushboolean(tolua_S, res ? 1 : 0); - if (res) - { - tolua_pushnumber(tolua_S, BlockType); - tolua_pushnumber(tolua_S, BlockMeta); - return 3; - } - } - } - return 1; - - #ifndef TOLUA_RELEASE -tolua_lerror: - tolua_error(tolua_S, "#ferror in function 'GetBlockTypeMeta'.", &tolua_err); - return 0; - #endif -} - - - - - -static int tolua_cWorld_GetSignLines(lua_State * tolua_S) -{ - // Exported manually, because tolua would generate useless additional parameters (a_Line1 .. a_Line4) - #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || - !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 4, 0, &tolua_err) || - !tolua_isnoobj (tolua_S, 10, &tolua_err) - ) - goto tolua_lerror; - else - #endif - { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); - int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); - int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); - int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); - #ifndef TOLUA_RELEASE - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'GetSignLines'", nullptr); - } - #endif - { - AString Line1, Line2, Line3, Line4; - bool res = self->GetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); - tolua_pushboolean(tolua_S, res ? 1 : 0); - if (res) - { - tolua_pushstring(tolua_S, Line1.c_str()); - tolua_pushstring(tolua_S, Line2.c_str()); - tolua_pushstring(tolua_S, Line3.c_str()); - tolua_pushstring(tolua_S, Line4.c_str()); - return 5; - } - } - } - return 1; - - #ifndef TOLUA_RELEASE -tolua_lerror: - tolua_error(tolua_S, "#ferror in function 'GetSignLines'.", &tolua_err); - return 0; - #endif -} - - - - - -static int tolua_cWorld_SetSignLines(lua_State * tolua_S) +static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) { - // Exported manually, because tolua would generate useless additional return values (a_Line1 .. a_Line4) - #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || - !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 4, 0, &tolua_err) || - !tolua_iscppstring(tolua_S, 5, 0, &tolua_err) || - !tolua_iscppstring(tolua_S, 6, 0, &tolua_err) || - !tolua_iscppstring(tolua_S, 7, 0, &tolua_err) || - !tolua_iscppstring(tolua_S, 8, 0, &tolua_err) || - !tolua_isusertype (tolua_S, 9, "cPlayer", 1, &tolua_err) || - !tolua_isnoobj (tolua_S, 10, &tolua_err) - ) - goto tolua_lerror; - else - #endif - { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); - int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); - int BlockY = (int) tolua_tonumber (tolua_S, 3, 0); - int BlockZ = (int) tolua_tonumber (tolua_S, 4, 0); - const AString Line1 = tolua_tocppstring(tolua_S, 5, 0); - const AString Line2 = tolua_tocppstring(tolua_S, 6, 0); - const AString Line3 = tolua_tocppstring(tolua_S, 7, 0); - const AString Line4 = tolua_tocppstring(tolua_S, 8, 0); - cPlayer * Player = (cPlayer *)tolua_tousertype (tolua_S, 9, nullptr); - #ifndef TOLUA_RELEASE - if (self == nullptr) - { - tolua_error(tolua_S, "invalid 'self' in function 'SetSignLines'", nullptr); - } - #endif - { - bool res = self->SetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4, Player); - tolua_pushboolean(tolua_S, res ? 1 : 0); - } - } - return 1; - - #ifndef TOLUA_RELEASE -tolua_lerror: - tolua_error(tolua_S, "#ferror in function 'SetSignLines'.", &tolua_err); - return 0; - #endif -} - - - + // API function no longer available: + LOGWARNING("cPluginManager:GetAllPlugins() is no longer available, use cPluginManager:ForEachPlugin() instead"); + cLuaState::LogStackTrace(tolua_S); -static int tolua_cWorld_TryGetHeight(lua_State * tolua_S) -{ - // Exported manually, because tolua would require the out-only param a_Height to be used when calling - // Takes a_World, a_BlockX, a_BlockZ - // Returns Height, IsValid - #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype (tolua_S, 1, "cWorld", 0, &tolua_err) || - !tolua_isnumber (tolua_S, 2, 0, &tolua_err) || - !tolua_isnumber (tolua_S, 3, 0, &tolua_err) || - !tolua_isnoobj (tolua_S, 4, &tolua_err) - ) - goto tolua_lerror; - else - #endif - { - cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, nullptr); - int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); - int BlockZ = (int) tolua_tonumber (tolua_S, 3, 0); - #ifndef TOLUA_RELEASE - if (self == nullptr) - { - tolua_error(tolua_S, "Invalid 'self' in function 'TryGetHeight'", nullptr); - } - #endif - { - int Height = 0; - bool res = self->TryGetHeight(BlockX, BlockZ, Height); - tolua_pushboolean(tolua_S, res ? 1 : 0); - if (res) - { - tolua_pushnumber(tolua_S, Height); - return 2; - } - } - } + // Return an empty table: + lua_newtable(tolua_S); return 1; - - #ifndef TOLUA_RELEASE -tolua_lerror: - tolua_error(tolua_S, "#ferror in function 'TryGetHeight'.", &tolua_err); - return 0; - #endif } -class cLuaWorldTask : - public cWorld::cTask, - public cPluginLua::cResettable -{ -public: - cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) : - cPluginLua::cResettable(a_Plugin), - m_FnRef(a_FnRef) - { - } - -protected: - int m_FnRef; - - // cWorld::cTask overrides: - virtual void Run(cWorld & a_World) override - { - cCSLock Lock(m_CSPlugin); - if (m_Plugin != nullptr) - { - m_Plugin->Call(m_FnRef, &a_World); - } - } -} ; - - - - - -static int tolua_cWorld_QueueTask(lua_State * tolua_S) -{ - // Binding for cWorld::QueueTask - // Params: function - - // Retrieve the cPlugin from the LuaState: - cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == nullptr) - { - // An error message has been already printed in GetLuaPlugin() - return 0; - } - - // Retrieve the args: - cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); - if (self == nullptr) - { - 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"); - } - - // Create a reference to the function: - int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FnRef == LUA_REFNIL) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); - } - - auto task = std::make_shared<cLuaWorldTask>(*Plugin, FnRef); - Plugin->AddResettable(task); - self->QueueTask(task); - return 0; -} - - - - - -class cLuaScheduledWorldTask : - public cWorld::cTask, - public cPluginLua::cResettable -{ -public: - cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : - cPluginLua::cResettable(a_Plugin), - m_FnRef(a_FnRef) - { - } - -protected: - int m_FnRef; - - // cWorld::cTask overrides: - virtual void Run(cWorld & a_World) override - { - cCSLock Lock(m_CSPlugin); - if (m_Plugin != nullptr) - { - m_Plugin->Call(m_FnRef, &a_World); - } - } -}; - - - - - -static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) +static int tolua_cPluginManager_GetCurrentPlugin(lua_State * S) { - // Binding for cWorld::ScheduleTask - // Params: function, Ticks - - // Retrieve the cPlugin from the LuaState: - cPluginLua * Plugin = GetLuaPlugin(tolua_S); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(S); if (Plugin == nullptr) { - // An error message has been already printed in GetLuaPlugin() - return 0; - } - - // Retrieve the args: - cLuaState L(tolua_S); - if ( - !L.CheckParamUserType(1, "cWorld") || - !L.CheckParamNumber (2) || - !L.CheckParamFunction(3) - ) - { + // An error message has already been printed in GetLuaPlugin() return 0; } - cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); - if (World == nullptr) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); - } - - // Create a reference to the function: - int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FnRef == LUA_REFNIL) - { - return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); - } - - int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0); - - auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef); - Plugin->AddResettable(task); - World->ScheduleTask(DelayTicks, task); - return 0; -} - - - - - -static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) -{ - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); - - const cPluginManager::PluginMap & AllPlugins = self->GetAllPlugins(); - - lua_newtable(tolua_S); - int index = 1; - cPluginManager::PluginMap::const_iterator iter = AllPlugins.begin(); - while (iter != AllPlugins.end()) - { - const cPlugin* Plugin = iter->second; - tolua_pushstring(tolua_S, iter->first.c_str()); - if (Plugin != nullptr) - { - tolua_pushusertype(tolua_S, (void *)Plugin, "const cPlugin"); - } - else - { - tolua_pushboolean(tolua_S, 0); - } - lua_rawset(tolua_S, -3); - ++iter; - ++index; - } + tolua_pushusertype(S, Plugin, "cPluginLua"); return 1; } @@ -1477,16 +564,12 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) -static int tolua_cPluginManager_GetCurrentPlugin(lua_State * S) +static int tolua_cPluginManager_GetPlugin(lua_State * tolua_S) { - cPluginLua * Plugin = GetLuaPlugin(S); - if (Plugin == nullptr) - { - // An error message has already been printed in GetLuaPlugin() - return 0; - } - tolua_pushusertype(S, Plugin, "cPluginLua"); - return 1; + // API function no longer available: + LOGWARNING("cPluginManager:GetPlugin() is no longer available. Use cPluginManager:DoWithPlugin() or cPluginManager:CallPlugin() instead."); + cLuaState::LogStackTrace(tolua_S); + return 0; } @@ -1510,7 +593,7 @@ static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager, // The arg types have already been checked // Retrieve the cPlugin from the LuaState: - cPluginLua * Plugin = GetLuaPlugin(S); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(S); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() @@ -1557,7 +640,7 @@ static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager, S.LogStackTrace(); return 0; } - if (Plugin != GetLuaPlugin(S)) + if (Plugin != cManualBindings::GetLuaPlugin(S)) { // The plugin parameter passed to us is not our stored plugin. Disallow this! LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, cannot add hook to foreign plugins. Hook not added."); @@ -1664,74 +747,55 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S) static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if (NumArgs != 1) - { - LOGWARN("Error in function call 'ForEachCommand': Requires 1 argument, got %i", NumArgs); - return 0; - } - - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); - if (self == nullptr) - { - LOGWARN("Error in function call 'ForEachCommand': Not called on an object instance"); - return 0; - } + /* + Function signature: + cPluginManager:Get():ForEachCommand(a_CallbackFn) -> bool + */ - if (!lua_isfunction(tolua_S, 2)) + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cPluginManager") || + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) { - LOGWARN("Error in function call 'ForEachCommand': Expected a function for parameter #1"); return 0; } - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) + // Get the params: + cLuaState::cRef FnRef; + L.GetStackValues(2, FnRef); + if (!FnRef.IsValid()) { LOGWARN("Error in function call 'ForEachCommand': Could not get function reference of parameter #1"); return 0; } + // Callback for enumerating all commands: class cLuaCallback : public cPluginManager::cCommandEnumCallback { public: - cLuaCallback(lua_State * a_LuaState, int a_FuncRef) - : LuaState( a_LuaState) - , FuncRef( a_FuncRef) - {} + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } private: virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override { UNUSED(a_Plugin); - - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ - tolua_pushcppstring(LuaState, a_Command); - tolua_pushcppstring(LuaState, a_Permission); - tolua_pushcppstring(LuaState, a_HelpString); - - int s = lua_pcall(LuaState, 3, 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_Command, a_Permission, a_HelpString, cLuaState::Return, ret); + return ret; } - lua_State * LuaState; - int FuncRef; - } Callback(tolua_S, FuncRef); - - bool bRetVal = self->ForEachCommand(Callback); - - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Execute and push the returned value: + L.Push(cPluginManager::Get()->ForEachCommand(Callback)); return 1; } @@ -1741,74 +805,56 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if (NumArgs != 1) - { - LOGWARN("Error in function call 'ForEachConsoleCommand': Requires 1 argument, got %i", NumArgs); - return 0; - } - - cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr); - if (self == nullptr) - { - LOGWARN("Error in function call 'ForEachConsoleCommand': Not called on an object instance"); - return 0; - } + /* + Function signature: + cPluginManager:Get():ForEachConsoleCommand(a_CallbackFn) -> bool + */ - if (!lua_isfunction(tolua_S, 2)) + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cPluginManager") || + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) { - LOGWARN("Error in function call 'ForEachConsoleCommand': Expected a function for parameter #1"); return 0; } - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) + // Get the params: + cLuaState::cRef FnRef; + L.GetStackValues(2, FnRef); + if (!FnRef.IsValid()) { LOGWARN("Error in function call 'ForEachConsoleCommand': Could not get function reference of parameter #1"); return 0; } + // Callback for enumerating all commands: class cLuaCallback : public cPluginManager::cCommandEnumCallback { public: - cLuaCallback(lua_State * a_LuaState, int a_FuncRef) - : LuaState( a_LuaState) - , FuncRef( a_FuncRef) - {} + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } private: virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override { UNUSED(a_Plugin); UNUSED(a_Permission); - - lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ - tolua_pushcppstring(LuaState, a_Command); - tolua_pushcppstring(LuaState, a_HelpString); - - int s = lua_pcall(LuaState, 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_Command, a_HelpString, cLuaState::Return, ret); + return ret; } - lua_State * LuaState; - int FuncRef; - } Callback(tolua_S, FuncRef); - - bool bRetVal = self->ForEachConsoleCommand(Callback); - - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + } Callback(L, FnRef); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal); + // Execute and push the returned value: + L.Push(cPluginManager::Get()->ForEachConsoleCommand(Callback)); return 1; } @@ -1822,7 +868,7 @@ static int tolua_cPluginManager_BindCommand(lua_State * L) cPluginManager:BindCommand(Command, Permission, Function, HelpString) cPluginManager.BindCommand(Command, Permission, Function, HelpString) -- without the "self" param */ - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { return 0; @@ -1892,7 +938,7 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L) */ // Get the plugin identification out of LuaState: - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { return 0; @@ -1980,7 +1026,7 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S) } // If requesting calling the current plugin, refuse: - cPluginLua * ThisPlugin = GetLuaPlugin(L); + cPluginLua * ThisPlugin = cManualBindings::GetLuaPlugin(L); if (ThisPlugin == nullptr) { return 0; @@ -2011,7 +1057,11 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S) virtual bool Item(cPlugin * a_Plugin) override { - m_NumReturns = ((cPluginLua *)a_Plugin)->CallFunctionFromForeignState( + if (!a_Plugin->IsLoaded()) + { + return false; + } + m_NumReturns = static_cast<cPluginLua *>(a_Plugin)->CallFunctionFromForeignState( m_FunctionName, m_SrcLuaState, 4, lua_gettop(m_SrcLuaState) ); return true; @@ -2019,9 +1069,11 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S) } Callback(FunctionName, L); if (!cPluginManager::Get()->DoWithPlugin(PluginName, Callback)) { - // TODO 2014_01_20 _X: This might be too much logging, plugins cannot know if other plugins are loaded (async) - LOGWARNING("cPluginManager::CallPlugin: No such plugin name (\"%s\")", PluginName.c_str()); - L.LogStackTrace(); + return 0; + } + if (Callback.m_NumReturns < 0) + { + // The call has failed, there are zero return values. Do NOT return negative number (Lua considers that a "yield") return 0; } return Callback.m_NumReturns; @@ -2031,48 +1083,48 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S) -static int tolua_cWorld_ChunkStay(lua_State * tolua_S) +static int tolua_cPluginManager_ExecuteConsoleCommand(lua_State * tolua_S) { - /* Function signature: - World:ChunkStay(ChunkCoordTable, OnChunkAvailable, OnAllChunksAvailable) - ChunkCoordTable == { {Chunk1x, Chunk1z}, {Chunk2x, Chunk2z}, ... } + /* + Function signature: + cPluginManager:ExecuteConsoleCommand(EntireCommandStr) -> OutputString */ - + + // Check params: cLuaState L(tolua_S); if ( - !L.CheckParamUserType (1, "cWorld") || - !L.CheckParamTable (2) || - !L.CheckParamFunctionOrNil(3, 4) + !L.CheckParamUserTable(1, "cPluginManager") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) ) { return 0; } - - cPluginLua * Plugin = GetLuaPlugin(tolua_S); - if (Plugin == nullptr) - { - return 0; - } - - // Read the params: - cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); - if (World == nullptr) - { - LOGWARNING("World:ChunkStay(): invalid world parameter"); - L.LogStackTrace(); - return 0; - } - cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); + // Get the params: + AString Command; + L.GetStackValues(2, Command); + auto Split = StringSplit(Command, " "); + + // Store the command output in a string: + cStringAccumCommandOutputCallback CommandOutput; + L.Push(cPluginManager::Get()->ExecuteConsoleCommand(Split, CommandOutput, Command)); + L.Push(CommandOutput.GetAccum()); + return 2; +} - if (!ChunkStay->AddChunks(2)) - { - delete ChunkStay; - ChunkStay = nullptr; - return 0; - } - ChunkStay->Enable(*World->GetChunkMap(), 3, 4); + + + +static int tolua_cPluginManager_FindPlugins(lua_State * tolua_S) +{ + // API function no longer exists: + LOGWARNING("cPluginManager:FindPlugins() is obsolete, use cPluginManager:RefreshPluginList() instead!"); + cLuaState::LogStackTrace(tolua_S); + + // Still, do the actual work performed by the API function when it existed: + cPluginManager::Get()->RefreshPluginList(); return 0; } @@ -2080,75 +1132,40 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) -static int tolua_cWorld_PrepareChunk(lua_State * tolua_S) +static int tolua_cPlayer_GetPermissions(lua_State * tolua_S) { - /* Function signature: - World:PrepareChunk(ChunkX, ChunkZ, Callback) - */ - - // Check the param types: + // Function signature: cPlayer:GetPermissions() -> {permissions-array} + + // Check the params: cLuaState L(tolua_S); if ( - !L.CheckParamUserType (1, "cWorld") || - !L.CheckParamNumber (2, 3) || - !L.CheckParamFunctionOrNil(4) + !L.CheckParamUserType(1, "cPlayer") || + !L.CheckParamEnd (2) ) { return 0; } - - // Read the params: - cWorld * world = nullptr; - int chunkX = 0, chunkZ = 0; - L.GetStackValues(1, world, chunkX, chunkZ); - if (world == nullptr) + + // Get the params: + cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) { - LOGWARNING("World:PrepareChunk(): invalid world parameter"); - L.LogStackTrace(); + LOGWARNING("%s: invalid self (%p)", __FUNCTION__, self); return 0; } - - // Wrap the Lua callback inside a C++ callback class: - class cCallback: - public cChunkCoordCallback - { - public: - cCallback(lua_State * a_LuaState): - m_LuaState(a_LuaState), - m_Callback(m_LuaState, 4) - { - } - - // cChunkCoordCallback override: - virtual void Call(int a_CBChunkX, int a_CBChunkZ) override - { - if (m_Callback.IsValid()) - { - m_LuaState.Call(m_Callback, a_CBChunkX, a_CBChunkZ); - } - - // This is the last reference of this object, we must delete it so that it doesn't leak: - delete this; - } - - protected: - cLuaState m_LuaState; - cLuaState::cRef m_Callback; - }; - cCallback * callback = new cCallback(tolua_S); - - // Call the chunk preparation: - world->PrepareChunk(chunkX, chunkZ, callback); - return 0; + + // Push the permissions: + L.Push(self->GetPermissions()); + return 1; } -static int tolua_cPlayer_GetPermissions(lua_State * tolua_S) +static int tolua_cPlayer_GetRestrictions(lua_State * tolua_S) { - // Function signature: cPlayer:GetPermissions() -> {permissions-array} + // Function signature: cPlayer:GetRestrictions() -> {restrictions-array} // Check the params: cLuaState L(tolua_S); @@ -2169,7 +1186,7 @@ static int tolua_cPlayer_GetPermissions(lua_State * tolua_S) } // Push the permissions: - L.Push(self->GetPermissions()); + L.Push(self->GetRestrictions()); return 1; } @@ -2182,7 +1199,7 @@ static int tolua_cPlayer_OpenWindow(lua_State * tolua_S) // Function signature: cPlayer:OpenWindow(Window) // Retrieve the plugin instance from the Lua state - cPluginLua * Plugin = GetLuaPlugin(tolua_S); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); if (Plugin == nullptr) { return 0; @@ -2263,7 +1280,7 @@ static int tolua_SetObjectCallback(lua_State * tolua_S) // Function signature: OBJTYPE:SetWhateverCallback(CallbackFunction) // Retrieve the plugin instance from the Lua state - cPluginLua * Plugin = GetLuaPlugin(tolua_S); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); if (Plugin == nullptr) { // Warning message has already been printed by GetLuaPlugin(), bail out silently @@ -2315,7 +1332,7 @@ static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S) } else { - return tolua_do_error(tolua_S, "#ferror calling function '#funcname#'", &tolua_err); + return cManualBindings::tolua_do_error(tolua_S, "#ferror calling function '#funcname#'", &tolua_err); } if (Reference != LUA_REFNIL) @@ -2337,40 +1354,40 @@ static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S) -static int tolua_cPluginLua_AddTab(lua_State* tolua_S) +static int tolua_cPlugin_GetDirectory(lua_State * tolua_S) { - cPluginLua * self = (cPluginLua *) tolua_tousertype(tolua_S, 1, nullptr); - LOGWARN("WARNING: Using deprecated function AddTab()! Use AddWebTab() instead. (plugin \"%s\" in folder \"%s\")", - self->GetName().c_str(), self->GetDirectory().c_str() - ); - return tolua_cPluginLua_AddWebTab( tolua_S); + cLuaState L(tolua_S); + + // Log the obsoletion warning: + LOGWARNING("cPlugin:GetDirectory() is obsolete, use cPlugin:GetFolderName() instead."); + L.LogStackTrace(); + + // Retrieve the params: + cPlugin * Plugin = static_cast<cPluginLua *>(tolua_tousertype(tolua_S, 1, nullptr)); + + // Get the folder name: + L.Push(Plugin->GetFolderName()); + return 1; } -static int tolua_cPlugin_Call(lua_State * tolua_S) +static int tolua_cPlugin_GetLocalDirectory(lua_State * tolua_S) { cLuaState L(tolua_S); // Log the obsoletion warning: - LOGWARNING("cPlugin:Call() is obsolete and unsafe, use cPluginManager:CallPlugin() instead."); + LOGWARNING("cPlugin:GetLocalDirectory() is obsolete, use cPlugin:GetLocalFolder() instead."); L.LogStackTrace(); - // Retrieve the params: plugin and the function name to call - cPluginLua * TargetPlugin = (cPluginLua *) tolua_tousertype(tolua_S, 1, nullptr); - AString FunctionName = tolua_tostring(tolua_S, 2, ""); + // Retrieve the params: + cPlugin * Plugin = static_cast<cPluginLua *>(tolua_tousertype(tolua_S, 1, nullptr)); - // Call the function: - int NumReturns = TargetPlugin->CallFunctionFromForeignState(FunctionName, L, 3, lua_gettop(L)); - if (NumReturns < 0) - { - LOGWARNING("cPlugin::Call() failed to call destination function"); - L.LogStackTrace(); - return 0; - } - return NumReturns; + // Get the folder: + L.Push(Plugin->GetLocalFolder()); + return 1; } @@ -2488,8 +1505,8 @@ static int tolua_push_StringStringMap(lua_State* tolua_S, std::map< std::string, for (std::map<std::string, std::string>::iterator it = a_StringStringMap.begin(); it != a_StringStringMap.end(); ++it) { - const char* key = it->first.c_str(); - const char* value = it->second.c_str(); + const char * key = it->first.c_str(); + const char * value = it->second.c_str(); lua_pushstring(tolua_S, key); lua_pushstring(tolua_S, value); lua_settable(tolua_S, top); @@ -2504,7 +1521,7 @@ static int tolua_push_StringStringMap(lua_State* tolua_S, std::map< std::string, static int tolua_get_HTTPRequest_Params(lua_State* tolua_S) { - HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, nullptr); + HTTPRequest * self = reinterpret_cast<HTTPRequest *>(tolua_tousertype(tolua_S, 1, nullptr)); return tolua_push_StringStringMap(tolua_S, self->Params); } @@ -2514,7 +1531,7 @@ static int tolua_get_HTTPRequest_Params(lua_State* tolua_S) static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S) { - HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, nullptr); + HTTPRequest * self = reinterpret_cast<HTTPRequest *>(tolua_tousertype(tolua_S, 1, nullptr)); return tolua_push_StringStringMap(tolua_S, self->PostParams); } @@ -2524,8 +1541,8 @@ static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S) static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S) { - HTTPRequest* self = (HTTPRequest*) tolua_tousertype(tolua_S, 1, nullptr); - std::map< std::string, HTTPFormData >& FormData = self->FormData; + HTTPRequest * self = reinterpret_cast<HTTPRequest *>(tolua_tousertype(tolua_S, 1, nullptr)); + std::map<std::string, HTTPFormData> & FormData = self->FormData; lua_newtable(tolua_S); int top = lua_gettop(tolua_S); @@ -2628,22 +1645,16 @@ static int tolua_AllToLua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S) static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) { - cWebPlugin* self = (cWebPlugin*) tolua_tousertype(tolua_S, 1, nullptr); - - const cWebPlugin::TabNameList & TabNames = self->GetTabNames(); - + // Returns a map of (SafeTitle -> Title) for the plugin's web tabs. + auto self = reinterpret_cast<cWebPlugin *>(tolua_tousertype(tolua_S, 1, nullptr)); + auto TabNames = self->GetTabNames(); lua_newtable(tolua_S); int index = 1; - cWebPlugin::TabNameList::const_iterator iter = TabNames.begin(); - while (iter != TabNames.end()) - { - const AString & FancyName = iter->first; - const AString & WebName = iter->second; - tolua_pushstring( tolua_S, WebName.c_str()); // Because the WebName is supposed to be unique, use it as key - tolua_pushstring( tolua_S, FancyName.c_str()); - // + for (auto itr = TabNames.cbegin(), end = TabNames.cend(); itr != end; ++itr) + { + tolua_pushstring(tolua_S, itr->second.c_str()); // Because the SafeTitle is supposed to be unique, use it as key + tolua_pushstring(tolua_S, itr->first.c_str()); lua_rawset(tolua_S, -3); - ++iter; ++index; } return 1; @@ -3214,6 +2225,44 @@ static int tolua_cBlockArea_GetOrigin(lua_State * tolua_S) +static int tolua_cBlockArea_GetNonAirCropRelCoords(lua_State * tolua_S) +{ + // function cBlockArea::GetNonAirCropRelCoords() + // Exported manually because tolua would generate extra input params for the outputs + + cLuaState L(tolua_S); + if (!L.CheckParamUserType(1, "cBlockArea")) + { + return 0; + } + + cBlockArea * self = nullptr; + BLOCKTYPE IgnoreBlockType = E_BLOCK_AIR; + L.GetStackValues(1, self, IgnoreBlockType); + if (self == nullptr) + { + tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetNonAirCropRelCoords'", nullptr); + return 0; + } + + // Calculate the crop coords: + int MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ; + self->GetNonAirCropRelCoords(MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ, IgnoreBlockType); + + // Push the six crop coords: + L.Push(MinRelX); + L.Push(MinRelY); + L.Push(MinRelZ); + L.Push(MaxRelX); + L.Push(MaxRelY); + L.Push(MaxRelZ); + return 6; +} + + + + + static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * tolua_S) { // function cBlockArea::GetRelBlockTypeMeta() @@ -3680,17 +2729,17 @@ static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S) -void ManualBindings::Bind(lua_State * tolua_S) +void cManualBindings::Bind(lua_State * tolua_S) { tolua_beginmodule(tolua_S, nullptr); // Create the new classes: tolua_usertype(tolua_S, "cCryptoHash"); - tolua_cclass(tolua_S, "cCryptoHash", "cCryptoHash", "", nullptr); + tolua_usertype(tolua_S, "cLineBlockTracer"); tolua_usertype(tolua_S, "cStringCompression"); + tolua_cclass(tolua_S, "cCryptoHash", "cCryptoHash", "", nullptr); + tolua_cclass(tolua_S, "cLineBlockTracer", "cLineBlockTracer", "", nullptr); tolua_cclass(tolua_S, "cStringCompression", "cStringCompression", "", nullptr); - tolua_usertype(tolua_S, "cLineBlockTracer"); - tolua_cclass(tolua_S, "cLineBlockTracer", "cLineBlockTracer", "", nullptr); // Globals: tolua_function(tolua_S, "Clamp", tolua_Clamp); @@ -3705,15 +2754,12 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode); tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode); tolua_function(tolua_S, "md5", tolua_md5_obsolete); // OBSOLETE, use cCryptoHash.md5() instead - - tolua_beginmodule(tolua_S, "cFile"); - tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); - tolua_endmodule(tolua_S); - + tolua_beginmodule(tolua_S, "cBlockArea"); tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta); tolua_function(tolua_S, "GetCoordRange", tolua_cBlockArea_GetCoordRange); tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin); + tolua_function(tolua_S, "GetNonAirCropRelCoords", tolua_cBlockArea_GetNonAirCropRelCoords); tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta); tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize); tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile); @@ -3721,7 +2767,13 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile); tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString); tolua_endmodule(tolua_S); - + + tolua_beginmodule(tolua_S, "cClientHandle"); + tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); + tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); + tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cCompositeChat"); tolua_function(tolua_S, "AddRunCommandPart", tolua_cCompositeChat_AddRunCommandPart); tolua_function(tolua_S, "AddSuggestCommandPart", tolua_cCompositeChat_AddSuggestCommandPart); @@ -3731,105 +2783,105 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "SetMessageType", tolua_cCompositeChat_SetMessageType); tolua_function(tolua_S, "UnderlineUrls", tolua_cCompositeChat_UnderlineUrls); tolua_endmodule(tolua_S); - + + tolua_beginmodule(tolua_S, "cCryptoHash"); + tolua_function(tolua_S, "md5", tolua_md5); + tolua_function(tolua_S, "md5HexString", tolua_md5HexString); + tolua_function(tolua_S, "sha1", tolua_sha1); + tolua_function(tolua_S, "sha1HexString", tolua_sha1HexString); + tolua_endmodule(tolua_S); + + tolua_beginmodule(tolua_S, "cEntity"); + tolua_constant(tolua_S, "INVALID_ID", cEntity::INVALID_ID); + tolua_endmodule(tolua_S); + + tolua_beginmodule(tolua_S, "cFile"); + tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); + tolua_function(tolua_S, "ReadWholeFile", tolua_cFile_ReadWholeFile); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cHopperEntity"); tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos); tolua_endmodule(tolua_S); - + + tolua_beginmodule(tolua_S, "cItemGrid"); + tolua_function(tolua_S, "GetSlotCoords", Lua_ItemGrid_GetSlotCoords); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cLineBlockTracer"); tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace); tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cRoot"); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>); - tolua_function(tolua_S, "DoWithPlayerByUUID", tolua_DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>); - tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>); - tolua_function(tolua_S, "ForEachWorld", tolua_ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); - tolua_function(tolua_S, "GetFurnaceRecipe", tolua_cRoot_GetFurnaceRecipe); - tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); - tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); - tolua_function(tolua_S, "DoWithBeaconAt", tolua_DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>); - tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); - tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); - tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); - tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); - tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); - tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); - tolua_function(tolua_S, "DoWithMobHeadAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>); - tolua_function(tolua_S, "DoWithFlowerPotAt", tolua_DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>); - 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, "DoWithPlayerByUUID", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>); - tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); - tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); - tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); - tolua_function(tolua_S, "ForEachEntityInBox", tolua_ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>); - tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); - tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); - tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); - tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); - tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); - tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); - tolua_function(tolua_S, "PrepareChunk", tolua_cWorld_PrepareChunk); - tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); - tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask); - tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); - tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); + + tolua_beginmodule(tolua_S, "cLuaWindow"); + tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>); + tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>); tolua_endmodule(tolua_S); - + tolua_beginmodule(tolua_S, "cMapManager"); - tolua_function(tolua_S, "DoWithMap", tolua_DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>); + tolua_function(tolua_S, "DoWithMap", DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S, "cScoreboard"); - tolua_function(tolua_S, "ForEachObjective", tolua_ForEach<cScoreboard, cObjective, &cScoreboard::ForEachObjective>); - tolua_function(tolua_S, "ForEachTeam", tolua_ForEach<cScoreboard, cTeam, &cScoreboard::ForEachTeam>); + tolua_beginmodule(tolua_S, "cMojangAPI"); + tolua_function(tolua_S, "AddPlayerNameToUUIDMapping", tolua_cMojangAPI_AddPlayerNameToUUIDMapping); + tolua_function(tolua_S, "GetPlayerNameFromUUID", tolua_cMojangAPI_GetPlayerNameFromUUID); + tolua_function(tolua_S, "GetUUIDFromPlayerName", tolua_cMojangAPI_GetUUIDFromPlayerName); + tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cMojangAPI_GetUUIDsFromPlayerNames); + tolua_function(tolua_S, "MakeUUIDDashed", tolua_cMojangAPI_MakeUUIDDashed); + tolua_function(tolua_S, "MakeUUIDShort", tolua_cMojangAPI_MakeUUIDShort); tolua_endmodule(tolua_S); - + + tolua_beginmodule(tolua_S, "cPlayer"); + tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions); + tolua_function(tolua_S, "GetRestrictions", tolua_cPlayer_GetRestrictions); + tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow); + tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cPlugin"); - tolua_function(tolua_S, "Call", tolua_cPlugin_Call); + tolua_function(tolua_S, "GetDirectory", tolua_cPlugin_GetDirectory); + tolua_function(tolua_S, "GetLocalDirectory", tolua_cPlugin_GetLocalDirectory); tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cPluginLua"); + tolua_function(tolua_S, "AddWebTab", tolua_cPluginLua_AddWebTab); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cPluginManager"); tolua_function(tolua_S, "AddHook", tolua_cPluginManager_AddHook); 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", StaticDoWith<cPluginManager, cPlugin, &cPluginManager::DoWithPlugin>); + tolua_function(tolua_S, "ExecuteConsoleCommand", tolua_cPluginManager_ExecuteConsoleCommand); + 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", StaticForEach<cPluginManager, cPlugin, &cPluginManager::ForEachPlugin>); tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); tolua_function(tolua_S, "GetCurrentPlugin", tolua_cPluginManager_GetCurrentPlugin); + tolua_function(tolua_S, "GetPlugin", tolua_cPluginManager_GetPlugin); tolua_function(tolua_S, "LogStackTrace", tolua_cPluginManager_LogStackTrace); tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cPlayer"); - tolua_function(tolua_S, "GetPermissions", tolua_cPlayer_GetPermissions); - tolua_function(tolua_S, "OpenWindow", tolua_cPlayer_OpenWindow); - tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches); - tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cLuaWindow"); - tolua_function(tolua_S, "SetOnClosing", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>); - tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>); + + tolua_beginmodule(tolua_S, "cRoot"); + tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>); + tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>); + tolua_function(tolua_S, "ForEachPlayer", ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>); + tolua_function(tolua_S, "ForEachWorld", ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); + tolua_function(tolua_S, "GetFurnaceRecipe", tolua_cRoot_GetFurnaceRecipe); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S, "cPluginLua"); - tolua_function(tolua_S, "AddTab", tolua_cPluginLua_AddTab); - tolua_function(tolua_S, "AddWebTab", tolua_cPluginLua_AddWebTab); + tolua_beginmodule(tolua_S, "cScoreboard"); + tolua_function(tolua_S, "ForEachObjective", ForEach<cScoreboard, cObjective, &cScoreboard::ForEachObjective>); + tolua_function(tolua_S, "ForEachTeam", ForEach<cScoreboard, cTeam, &cScoreboard::ForEachTeam>); tolua_endmodule(tolua_S); - tolua_cclass(tolua_S, "HTTPRequest", "HTTPRequest", "", nullptr); - tolua_beginmodule(tolua_S, "HTTPRequest"); - // tolua_variable(tolua_S, "Method", tolua_get_HTTPRequest_Method, tolua_set_HTTPRequest_Method); - // tolua_variable(tolua_S, "Path", tolua_get_HTTPRequest_Path, tolua_set_HTTPRequest_Path); - tolua_variable(tolua_S, "FormData", tolua_get_HTTPRequest_FormData, 0); - tolua_variable(tolua_S, "Params", tolua_get_HTTPRequest_Params, 0); - tolua_variable(tolua_S, "PostParams", tolua_get_HTTPRequest_PostParams, 0); + tolua_beginmodule(tolua_S, "cStringCompression"); + tolua_function(tolua_S, "CompressStringZLIB", tolua_CompressStringZLIB); + tolua_function(tolua_S, "UncompressStringZLIB", tolua_UncompressStringZLIB); + tolua_function(tolua_S, "CompressStringGZIP", tolua_CompressStringGZIP); + tolua_function(tolua_S, "UncompressStringGZIP", tolua_UncompressStringGZIP); + tolua_function(tolua_S, "InflateString", tolua_InflateString); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWebAdmin"); @@ -3841,47 +2893,16 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_beginmodule(tolua_S, "cWebPlugin"); tolua_function(tolua_S, "GetTabNames", tolua_cWebPlugin_GetTabNames); tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cClientHandle"); - tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); - tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); - tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); - tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S, "cMojangAPI"); - tolua_function(tolua_S, "AddPlayerNameToUUIDMapping", tolua_cMojangAPI_AddPlayerNameToUUIDMapping); - tolua_function(tolua_S, "GetPlayerNameFromUUID", tolua_cMojangAPI_GetPlayerNameFromUUID); - tolua_function(tolua_S, "GetUUIDFromPlayerName", tolua_cMojangAPI_GetUUIDFromPlayerName); - tolua_function(tolua_S, "GetUUIDsFromPlayerNames", tolua_cMojangAPI_GetUUIDsFromPlayerNames); - tolua_function(tolua_S, "MakeUUIDDashed", tolua_cMojangAPI_MakeUUIDDashed); - tolua_function(tolua_S, "MakeUUIDShort", tolua_cMojangAPI_MakeUUIDShort); - tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cItemGrid"); - tolua_function(tolua_S, "GetSlotCoords", Lua_ItemGrid_GetSlotCoords); + tolua_beginmodule(tolua_S, "HTTPRequest"); + tolua_variable(tolua_S, "FormData", tolua_get_HTTPRequest_FormData, nullptr); + tolua_variable(tolua_S, "Params", tolua_get_HTTPRequest_Params, nullptr); + tolua_variable(tolua_S, "PostParams", tolua_get_HTTPRequest_PostParams, nullptr); tolua_endmodule(tolua_S); - tolua_beginmodule(tolua_S, "cCryptoHash"); - tolua_function(tolua_S, "md5", tolua_md5); - tolua_function(tolua_S, "md5HexString", tolua_md5HexString); - tolua_function(tolua_S, "sha1", tolua_sha1); - tolua_function(tolua_S, "sha1HexString", tolua_sha1HexString); - tolua_endmodule(tolua_S); - - tolua_beginmodule(tolua_S, "cStringCompression"); - tolua_function(tolua_S, "CompressStringZLIB", tolua_CompressStringZLIB); - tolua_function(tolua_S, "UncompressStringZLIB", tolua_UncompressStringZLIB); - tolua_function(tolua_S, "CompressStringGZIP", tolua_CompressStringGZIP); - tolua_function(tolua_S, "UncompressStringGZIP", tolua_UncompressStringGZIP); - tolua_function(tolua_S, "InflateString", tolua_InflateString); - tolua_endmodule(tolua_S); - - BindRankManager(tolua_S); BindNetwork(tolua_S); - - tolua_beginmodule(tolua_S, "cEntity"); - tolua_constant(tolua_S, "INVALID_ID", cEntity::INVALID_ID); - tolua_endmodule(tolua_S); + BindRankManager(tolua_S); + BindWorld(tolua_S); tolua_endmodule(tolua_S); } diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index 74d24d5f5..e7a576588 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -1,33 +1,566 @@ + +// ManualBindings.h + +// Declares the cManualBindings class used as a namespace for functions exported to the Lua API manually + + + + + #pragma once -struct lua_State; -class cPluginLua; +#include "LuaState.h" + + + + +// fwd: +struct tolua_Error; /** Provides namespace for the bindings. */ -class ManualBindings +class cManualBindings { public: /** Binds all the manually implemented functions to tolua_S. */ static void Bind(lua_State * tolua_S); protected: + /** Binds the manually implemented cNetwork-related API to tolua_S. + Implemented in ManualBindings_Network.cpp. */ + static void BindNetwork(lua_State * tolua_S); + /** Binds the manually implemented cRankManager glue code to tolua_S. Implemented in ManualBindings_RankManager.cpp. */ static void BindRankManager(lua_State * tolua_S); - /** Binds the manually implemented cNetwork-related API to tolua_S. - Implemented in ManualBindings_Network.cpp. */ - static void BindNetwork(lua_State * tolua_S); -}; + /** Binds the manually implemented cWorld API functions to tolua_S. + Implemented in ManualBindings_World.cpp. */ + static void BindWorld(lua_State * tolua_S); + + +public: + // Helper functions: + static cPluginLua * GetLuaPlugin(lua_State * L); + static int tolua_do_error(lua_State * L, const char * a_pMsg, tolua_Error * a_pToLuaError); + static int lua_do_error(lua_State * L, const char * a_pFormat, ...); + + + /** Binds the DoWith(ItemName) functions of regular classes. */ + template < + class Ty1, + class Ty2, + bool (Ty1::*DoWithFn)(const AString &, cItemCallback<Ty2> &) + > + static int DoWith(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamString(2) || + !L.CheckParamFunction(3) + ) + { + return 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#': Invalid 'self'"); + } + if (ItemName.empty() || (ItemName[0] == 0)) + { + 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<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } + + 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<Ty2> &) + > + static int StaticDoWith(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamString(2) || + !L.CheckParamFunction(3) + ) + { + return 0; + } + + // 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#': 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<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } + + 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 = (Ty1::Get()->*DoWithFn)(ItemName, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; + } + + + + + + template < + class Ty1, + class Ty2, + bool (Ty1::*DoWithFn)(UInt32, cItemCallback<Ty2> &) + > + static int DoWithID(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamNumber(2) || + !L.CheckParamFunction(3) + ) + { + return 0; + } + + // Get parameters: + Ty1 * Self = nullptr; + int ItemID; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, ItemID, FnRef); + if (Self == nullptr) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + 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<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } + + 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)(ItemID, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; + } + -extern cPluginLua * GetLuaPlugin(lua_State * L); + template < + class Ty1, + class Ty2, + bool (Ty1::*DoWithFn)(int, int, int, cItemCallback<Ty2> &) + > + static int DoWithXYZ(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamNumber(2, 5) || + !L.CheckParamFunction(6) + ) + { + return 0; + } + + // Get parameters: + Ty1 * Self = nullptr; + int BlockX, BlockY, BlockZ; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, FnRef); + if (Self == nullptr) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #5"); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } + + 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)(BlockX, BlockY, BlockZ, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; + } + + + + + + template < + class Ty1, + class Ty2, + bool (Ty1::*ForEachFn)(int, int, cItemCallback<Ty2> &) + > + static int ForEachInChunk(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamNumber(2, 4) || + !L.CheckParamFunction(5) + ) + { + return 0; + } + + // Get parameters: + Ty1 * Self = nullptr; + int ChunkX, ChunkZ; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, ChunkX, ChunkZ, FnRef); + if (Self == nullptr) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #4"); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef): + m_LuaState(a_LuaState), + m_FnRef(a_FnRef) + { + } + + 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->*ForEachFn)(ChunkX, ChunkZ, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; + } + + + + + + template < + class Ty1, + class Ty2, + bool (Ty1::*ForEachFn)(const cBoundingBox &, cItemCallback<Ty2> &) + > + static int ForEachInBox(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamUserType(2, "cBoundingBox") || + !L.CheckParamFunction(3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + Ty1 * Self = nullptr; + cBoundingBox * Box = nullptr; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, Box, FnRef); + if ((Self == nullptr) || (Box == nullptr)) + { + LOGWARNING("Invalid world (%p) or boundingbox (%p)", Self, Box); + L.LogStackTrace(); + return 0; + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); + } + + // Callback wrapper for the Lua function: + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FuncRef) : + m_LuaState(a_LuaState), + m_FnRef(a_FuncRef) + { + } + + private: + cLuaState & m_LuaState; + cLuaState::cRef & m_FnRef; + + // cItemCallback<Ty2> overrides: + virtual bool Item(Ty2 * a_Item) override + { + bool res = false; + if (!m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res)) + { + LOGWARNING("Failed to call Lua callback"); + m_LuaState.LogStackTrace(); + return true; // Abort enumeration + } + + return res; + } + } Callback(L, FnRef); + + bool res = (Self->*ForEachFn)(*Box, Callback); + + // Push the result as the return value: + L.Push(res); + return 1; + } + + + + + + template < + class Ty1, + class Ty2, + bool (Ty1::*ForEachFn)(cItemCallback<Ty2> &) + > + static int ForEach(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + Ty1 * Self = nullptr; + cLuaState::cRef FnRef; + L.GetStackValues(1, Self, FnRef); + if (Self == nullptr) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'."); + } + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #1"); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + 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 + { + bool res = false; // By default continue the enumeration + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res); + return res; + } + } Callback(L, FnRef); + + // Call the enumeration: + bool res = (Self->*ForEachFn)(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::*ForEachFn)(cItemCallback<Ty2> &) + > + static int StaticForEach(lua_State * tolua_S) + { + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamFunction(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + cLuaState::cRef FnRef(L, 2); + if (!FnRef.IsValid()) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #1"); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + 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 + { + bool res = false; // By default continue the enumeration + m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res); + return res; + } + } Callback(L, FnRef); + + // Call the enumeration: + bool res = (Ty1::Get()->*ForEachFn)(Callback); + + // Push the return value: + L.Push(res); + return 1; + } +}; diff --git a/src/Bindings/ManualBindings_Network.cpp b/src/Bindings/ManualBindings_Network.cpp index 628cda7f0..df97d60b3 100644 --- a/src/Bindings/ManualBindings_Network.cpp +++ b/src/Bindings/ManualBindings_Network.cpp @@ -39,7 +39,7 @@ static int tolua_cNetwork_Connect(lua_State * L) } // Get the plugin instance: - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() @@ -92,7 +92,7 @@ static int tolua_cNetwork_CreateUDPEndpoint(lua_State * L) } // Get the plugin instance: - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() @@ -171,7 +171,7 @@ static int tolua_cNetwork_HostnameToIP(lua_State * L) } // Get the plugin instance: - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() @@ -212,7 +212,7 @@ static int tolua_cNetwork_IPToHostname(lua_State * L) } // Get the plugin instance: - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() @@ -253,7 +253,7 @@ static int tolua_cNetwork_Listen(lua_State * L) } // Get the plugin instance: - cPluginLua * Plugin = GetLuaPlugin(L); + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L); if (Plugin == nullptr) { // An error message has been already printed in GetLuaPlugin() @@ -913,17 +913,17 @@ static int tolua_cUDPEndpoint_Send(lua_State * L) //////////////////////////////////////////////////////////////////////////////// // Register the bindings: -void ManualBindings::BindNetwork(lua_State * tolua_S) +void cManualBindings::BindNetwork(lua_State * tolua_S) { // Create the cNetwork API classes: tolua_usertype(tolua_S, "cNetwork"); - tolua_cclass(tolua_S, "cNetwork", "cNetwork", "", nullptr); - tolua_usertype(tolua_S, "cTCPLink"); - tolua_cclass(tolua_S, "cTCPLink", "cTCPLink", "", nullptr); tolua_usertype(tolua_S, "cServerHandle"); - tolua_cclass(tolua_S, "cServerHandle", "cServerHandle", "", tolua_collect_cServerHandle); + tolua_usertype(tolua_S, "cTCPLink"); tolua_usertype(tolua_S, "cUDPEndpoint"); - tolua_cclass(tolua_S, "cUDPEndpoint", "cUDPEndpoint", "", tolua_collect_cUDPEndpoint); + tolua_cclass(tolua_S, "cNetwork", "cNetwork", "", nullptr); + tolua_cclass(tolua_S, "cServerHandle", "cServerHandle", "", tolua_collect_cServerHandle); + tolua_cclass(tolua_S, "cTCPLink", "cTCPLink", "", nullptr); + tolua_cclass(tolua_S, "cUDPEndpoint", "cUDPEndpoint", "", tolua_collect_cUDPEndpoint); // Fill in the functions (alpha-sorted): tolua_beginmodule(tolua_S, "cNetwork"); diff --git a/src/Bindings/ManualBindings_RankManager.cpp b/src/Bindings/ManualBindings_RankManager.cpp index fa1b88b6a..7797d1887 100644 --- a/src/Bindings/ManualBindings_RankManager.cpp +++ b/src/Bindings/ManualBindings_RankManager.cpp @@ -100,6 +100,35 @@ static int tolua_cRankManager_AddPermissionToGroup(lua_State * L) +/** Binds cRankManager::AddRestrictionToGroup */ +static int tolua_cRankManager_AddRestrictionToGroup(lua_State * L) +{ + // Function signature: + // cRankManager:AddRestrictionToGroup(Permission, GroupName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Read the params: + AString GroupName, Permission; + S.GetStackValues(2, Permission, GroupName); + + // Add the group to the rank: + S.Push(cRoot::Get()->GetRankManager()->AddRestrictionToGroup(Permission, GroupName)); + return 1; +} + + + + + /** Binds cRankManager::AddRank */ static int tolua_cRankManager_AddRank(lua_State * L) { @@ -204,6 +233,60 @@ static int tolua_cRankManager_GetAllPermissions(lua_State * L) +/** Binds cRankManager::GetAllPermissions */ +static int tolua_cRankManager_GetAllRestrictions(lua_State * L) +{ + // Function signature: + // cRankManager:GetAllRestrictions() -> arraytable of Permissions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Get the permissions: + AStringVector Permissions = cRoot::Get()->GetRankManager()->GetAllRestrictions(); + + // Push the results: + S.Push(Permissions); + return 1; +} + + + + + +/** Binds cRankManager::GetAllPermissionsRestrictions */ +static int tolua_cRankManager_GetAllPermissionsRestrictions(lua_State * L) +{ + // Function signature: + // cRankManager:GetAllPermissionsRestrictions() -> arraytable of Permissions and Restrictions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamEnd(2) + ) + { + return 0; + } + + // Get the permissions: + AStringVector Permissions = cRoot::Get()->GetRankManager()->GetAllPermissionsRestrictions(); + + // Push the results: + S.Push(Permissions); + return 1; +} + + + + + /** Binds cRankManager::GetAllPlayerUUIDs */ static int tolua_cRankManager_GetAllPlayerUUIDs(lua_State * L) { @@ -314,6 +397,38 @@ static int tolua_cRankManager_GetGroupPermissions(lua_State * L) +/** Binds cRankManager::GetGroupRestrictions */ +static int tolua_cRankManager_GetGroupRestrictions(lua_State * L) +{ + // Function signature: + // cRankManager:GetGroupRestrictions(GroupName) -> arraytable of restrictions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString GroupName; + S.GetStackValue(2, GroupName); + + // Get the restrictions: + AStringVector Restrictions = cRoot::Get()->GetRankManager()->GetGroupRestrictions(GroupName); + + // Push the results: + S.Push(Restrictions); + return 1; +} + + + + + /** Binds cRankManager::GetPlayerGroups */ static int tolua_cRankManager_GetPlayerGroups(lua_State * L) { @@ -416,6 +531,38 @@ static int tolua_cRankManager_GetPlayerPermissions(lua_State * L) +/** Binds cRankManager::GetPlayerRestrictions */ +static int tolua_cRankManager_GetPlayerRestrictions(lua_State * L) +{ + // Function signature: + // cRankManager:GetPlayerRestrictions(PlayerUUID) -> arraytable of restrictions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString PlayerUUID; + S.GetStackValue(2, PlayerUUID); + + // Get the permissions: + AStringVector Restrictions = cRoot::Get()->GetRankManager()->GetPlayerRestrictions(PlayerUUID); + + // Push the results: + S.Push(Restrictions); + return 1; +} + + + + + /** Binds cRankManager::GetPlayerRankName */ static int tolua_cRankManager_GetPlayerRankName(lua_State * L) { @@ -544,6 +691,38 @@ static int tolua_cRankManager_GetRankPermissions(lua_State * L) +/** Binds cRankManager::GetRankRestrictions */ +static int tolua_cRankManager_GetRankRestrictions(lua_State * L) +{ + // Function signature: + // cRankManager:GetRankRestrictions(RankName) -> arraytable of restrictions + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2) || + !S.CheckParamEnd(3) + ) + { + return 0; + } + + // Get the params: + AString RankName; + S.GetStackValue(2, RankName); + + // Get the permissions: + AStringVector Restrictions = cRoot::Get()->GetRankManager()->GetRankRestrictions(RankName); + + // Push the results: + S.Push(Restrictions); + return 1; +} + + + + + /** Binds cRankManager::GetRankVisuals */ static int tolua_cRankManager_GetRankVisuals(lua_State * L) { @@ -679,6 +858,38 @@ static int tolua_cRankManager_IsPermissionInGroup(lua_State * L) +/** Binds cRankManager::IsRestrictionInGroup */ +static int tolua_cRankManager_IsRestrictionInGroup(lua_State * L) +{ + // Function signature: + // cRankManager:IsRestrictionInGroup(Restriction, GroupName) -> bool + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString GroupName, Restriction; + S.GetStackValues(2, Restriction, GroupName); + + // Get the response: + bool res = cRoot::Get()->GetRankManager()->IsRestrictionInGroup(Restriction, GroupName); + + // Push the result: + S.Push(res); + return 1; +} + + + + + /** Binds cRankManager::IsPlayerRankSet */ static int tolua_cRankManager_IsPlayerRankSet(lua_State * L) { @@ -821,7 +1032,7 @@ static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) AString GroupName, Permission; S.GetStackValues(2, Permission, GroupName); - // Remove the group: + // Remove the permission: cRoot::Get()->GetRankManager()->RemovePermissionFromGroup(Permission, GroupName); return 0; } @@ -830,6 +1041,35 @@ static int tolua_cRankManager_RemovePermissionFromGroup(lua_State * L) +/** Binds cRankManager::RemoveRestrictionFromGroup */ +static int tolua_cRankManager_RemoveRestrictionFromGroup(lua_State * L) +{ + // Function signature: + // cRankManager:RemoveRestrictionFromGroup(Restriction, GroupName) + + cLuaState S(L); + if ( + !S.CheckParamUserTable(1, "cRankManager") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + + // Get the params: + AString GroupName, Restriction; + S.GetStackValues(2, Restriction, GroupName); + + // Remove the restriction: + cRoot::Get()->GetRankManager()->RemoveRestrictionFromGroup(Restriction, GroupName); + return 0; +} + + + + + /** Binds cRankManager::RemovePlayerRank */ static int tolua_cRankManager_RemovePlayerRank(lua_State * L) { @@ -1040,7 +1280,7 @@ static int tolua_cRankManager_SetRankVisuals(lua_State * L) -void ManualBindings::BindRankManager(lua_State * tolua_S) +void cManualBindings::BindRankManager(lua_State * tolua_S) { // Create the cRankManager class in the API: tolua_usertype(tolua_S, "cRankManager"); @@ -1048,40 +1288,48 @@ void ManualBindings::BindRankManager(lua_State * tolua_S) // Fill in the functions (alpha-sorted): tolua_beginmodule(tolua_S, "cRankManager"); - tolua_function(tolua_S, "AddGroup", tolua_cRankManager_AddGroup); - tolua_function(tolua_S, "AddGroupToRank", tolua_cRankManager_AddGroupToRank); - tolua_function(tolua_S, "AddPermissionToGroup", tolua_cRankManager_AddPermissionToGroup); - tolua_function(tolua_S, "AddRank", tolua_cRankManager_AddRank); - tolua_function(tolua_S, "ClearPlayerRanks", tolua_cRankManager_ClearPlayerRanks); - tolua_function(tolua_S, "GetAllGroups", tolua_cRankManager_GetAllGroups); - tolua_function(tolua_S, "GetAllPermissions", tolua_cRankManager_GetAllPermissions); - tolua_function(tolua_S, "GetAllPlayerUUIDs", tolua_cRankManager_GetAllPlayerUUIDs); - tolua_function(tolua_S, "GetAllRanks", tolua_cRankManager_GetAllRanks); - tolua_function(tolua_S, "GetDefaultRank", tolua_cRankManager_GetDefaultRank); - tolua_function(tolua_S, "GetGroupPermissions", tolua_cRankManager_GetGroupPermissions); - tolua_function(tolua_S, "GetPlayerGroups", tolua_cRankManager_GetPlayerGroups); - tolua_function(tolua_S, "GetPlayerMsgVisuals", tolua_cRankManager_GetPlayerMsgVisuals); - tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerPermissions); - tolua_function(tolua_S, "GetPlayerRankName", tolua_cRankManager_GetPlayerRankName); - tolua_function(tolua_S, "GetPlayerName", tolua_cRankManager_GetPlayerName); - tolua_function(tolua_S, "GetRankGroups", tolua_cRankManager_GetRankGroups); - tolua_function(tolua_S, "GetRankPermissions", tolua_cRankManager_GetRankPermissions); - tolua_function(tolua_S, "GetRankVisuals", tolua_cRankManager_GetRankVisuals); - tolua_function(tolua_S, "GroupExists", tolua_cRankManager_GroupExists); - tolua_function(tolua_S, "IsGroupInRank", tolua_cRankManager_IsGroupInRank); - tolua_function(tolua_S, "IsPermissionInGroup", tolua_cRankManager_IsPermissionInGroup); - tolua_function(tolua_S, "IsPlayerRankSet", tolua_cRankManager_IsPlayerRankSet); - tolua_function(tolua_S, "RankExists", tolua_cRankManager_RankExists); - tolua_function(tolua_S, "RemoveGroup", tolua_cRankManager_RemoveGroup); - tolua_function(tolua_S, "RemoveGroupFromRank", tolua_cRankManager_RemoveGroupFromRank); - tolua_function(tolua_S, "RemovePermissionFromGroup", tolua_cRankManager_RemovePermissionFromGroup); - tolua_function(tolua_S, "RemovePlayerRank", tolua_cRankManager_RemovePlayerRank); - tolua_function(tolua_S, "RemoveRank", tolua_cRankManager_RemoveRank); - tolua_function(tolua_S, "RenameGroup", tolua_cRankManager_RenameGroup); - tolua_function(tolua_S, "RenameRank", tolua_cRankManager_RenameRank); - tolua_function(tolua_S, "SetDefaultRank", tolua_cRankManager_SetDefaultRank); - tolua_function(tolua_S, "SetPlayerRank", tolua_cRankManager_SetPlayerRank); - tolua_function(tolua_S, "SetRankVisuals", tolua_cRankManager_SetRankVisuals); + tolua_function(tolua_S, "AddGroup", tolua_cRankManager_AddGroup); + tolua_function(tolua_S, "AddGroupToRank", tolua_cRankManager_AddGroupToRank); + tolua_function(tolua_S, "AddPermissionToGroup", tolua_cRankManager_AddPermissionToGroup); + tolua_function(tolua_S, "AddRestrictionToGroup", tolua_cRankManager_AddRestrictionToGroup); + tolua_function(tolua_S, "AddRank", tolua_cRankManager_AddRank); + tolua_function(tolua_S, "ClearPlayerRanks", tolua_cRankManager_ClearPlayerRanks); + tolua_function(tolua_S, "GetAllGroups", tolua_cRankManager_GetAllGroups); + tolua_function(tolua_S, "GetAllPermissions", tolua_cRankManager_GetAllPermissions); + tolua_function(tolua_S, "GetAllRestrictions", tolua_cRankManager_GetAllRestrictions); + tolua_function(tolua_S, "GetAllPermissionsRestrictions", tolua_cRankManager_GetAllPermissionsRestrictions); + tolua_function(tolua_S, "GetAllPlayerUUIDs", tolua_cRankManager_GetAllPlayerUUIDs); + tolua_function(tolua_S, "GetAllRanks", tolua_cRankManager_GetAllRanks); + tolua_function(tolua_S, "GetDefaultRank", tolua_cRankManager_GetDefaultRank); + tolua_function(tolua_S, "GetGroupPermissions", tolua_cRankManager_GetGroupPermissions); + tolua_function(tolua_S, "GetGroupRestrictions", tolua_cRankManager_GetGroupRestrictions); + tolua_function(tolua_S, "GetPlayerGroups", tolua_cRankManager_GetPlayerGroups); + tolua_function(tolua_S, "GetPlayerMsgVisuals", tolua_cRankManager_GetPlayerMsgVisuals); + tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerPermissions); + tolua_function(tolua_S, "GetPlayerPermissions", tolua_cRankManager_GetPlayerRestrictions); + tolua_function(tolua_S, "GetPlayerRankName", tolua_cRankManager_GetPlayerRankName); + tolua_function(tolua_S, "GetPlayerName", tolua_cRankManager_GetPlayerName); + tolua_function(tolua_S, "GetRankGroups", tolua_cRankManager_GetRankGroups); + tolua_function(tolua_S, "GetRankPermissions", tolua_cRankManager_GetRankPermissions); + tolua_function(tolua_S, "GetRankRestrictions", tolua_cRankManager_GetRankRestrictions); + tolua_function(tolua_S, "GetRankVisuals", tolua_cRankManager_GetRankVisuals); + tolua_function(tolua_S, "GroupExists", tolua_cRankManager_GroupExists); + tolua_function(tolua_S, "IsGroupInRank", tolua_cRankManager_IsGroupInRank); + tolua_function(tolua_S, "IsPermissionInGroup", tolua_cRankManager_IsPermissionInGroup); + tolua_function(tolua_S, "IsRestrictionInGroup", tolua_cRankManager_IsRestrictionInGroup); + tolua_function(tolua_S, "IsPlayerRankSet", tolua_cRankManager_IsPlayerRankSet); + tolua_function(tolua_S, "RankExists", tolua_cRankManager_RankExists); + tolua_function(tolua_S, "RemoveGroup", tolua_cRankManager_RemoveGroup); + tolua_function(tolua_S, "RemoveGroupFromRank", tolua_cRankManager_RemoveGroupFromRank); + tolua_function(tolua_S, "RemovePermissionFromGroup", tolua_cRankManager_RemovePermissionFromGroup); + tolua_function(tolua_S, "RemoveRestrictionFromGroup", tolua_cRankManager_RemoveRestrictionFromGroup); + tolua_function(tolua_S, "RemovePlayerRank", tolua_cRankManager_RemovePlayerRank); + tolua_function(tolua_S, "RemoveRank", tolua_cRankManager_RemoveRank); + tolua_function(tolua_S, "RenameGroup", tolua_cRankManager_RenameGroup); + tolua_function(tolua_S, "RenameRank", tolua_cRankManager_RenameRank); + tolua_function(tolua_S, "SetDefaultRank", tolua_cRankManager_SetDefaultRank); + tolua_function(tolua_S, "SetPlayerRank", tolua_cRankManager_SetPlayerRank); + tolua_function(tolua_S, "SetRankVisuals", tolua_cRankManager_SetRankVisuals); tolua_endmodule(tolua_S); } diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp new file mode 100644 index 000000000..5becbba92 --- /dev/null +++ b/src/Bindings/ManualBindings_World.cpp @@ -0,0 +1,588 @@ + +// ManualBindings_World.cpp + +// Implements the manual Lua API bindings for the cWorld class + +#include "Globals.h" +#include "tolua++/include/tolua++.h" +#include "../World.h" +#include "../Broadcaster.h" +#include "ManualBindings.h" +#include "LuaState.h" +#include "PluginLua.h" +#include "LuaChunkStay.h" + + + + + +static int tolua_cWorld_BroadcastParticleEffect(lua_State * tolua_S) +{ + /* Function signature: + World:BroadcastParticleEffect("Name", PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmount, [ExcludeClient], [OptionalParam1], [OptionalParam2] + */ + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamString (2) || + !L.CheckParamNumber (3, 10) + ) + { + return 0; + } + + // Read the params: + cWorld * World = nullptr; + AString Name; + float PosX, PosY, PosZ, OffX, OffY, OffZ; + float ParticleData; + int ParticleAmmount; + cClientHandle * ExcludeClient = nullptr; + L.GetStackValues(1, World, Name, PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmmount, ExcludeClient); + if (World == nullptr) + { + LOGWARNING("World:BroadcastParticleEffect(): invalid world parameter"); + L.LogStackTrace(); + return 0; + } + + // Read up to 2 more optional data params: + std::array<int, 2> data; + for (int i = 0; (i < 2) && L.IsParamNumber(11 + i); i++) + { + L.GetStackValue(11 + i, data[i]); + } + + World->GetBroadcaster().BroadcastParticleEffect(Name, Vector3f(PosX, PosY, PosZ), Vector3f(OffX, OffY, OffZ), ParticleData, ParticleAmmount, ExcludeClient); + + return 0; +} + + + + + +static int tolua_cWorld_ChunkStay(lua_State * tolua_S) +{ + /* Function signature: + World:ChunkStay(ChunkCoordTable, OnChunkAvailable, OnAllChunksAvailable) + ChunkCoordTable == { {Chunk1x, Chunk1z}, {Chunk2x, Chunk2z}, ... } + */ + + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType (1, "cWorld") || + !L.CheckParamTable (2) || + !L.CheckParamFunctionOrNil(3, 4) + ) + { + return 0; + } + + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); + if (Plugin == nullptr) + { + return 0; + } + + // Read the params: + cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); + if (World == nullptr) + { + LOGWARNING("World:ChunkStay(): invalid world parameter"); + L.LogStackTrace(); + return 0; + } + + cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); + + if (!ChunkStay->AddChunks(2)) + { + delete ChunkStay; + ChunkStay = nullptr; + return 0; + } + + ChunkStay->Enable(*World->GetChunkMap(), 3, 4); + return 0; +} + + + + + +static int tolua_cWorld_GetBlockInfo(lua_State * tolua_S) +{ + // Exported manually, because tolua would generate useless additional parameters (a_BlockType .. a_BlockSkyLight) + // Function signature: GetBlockInfo(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta, BlockSkyLight, BlockBlockLight] + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber(2, 4) || + !L.CheckParamEnd(5) + ) + { + return 0; + } + + // Get params: + cWorld * Self = nullptr; + int BlockX, BlockY, BlockZ; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ); + if (Self == nullptr) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + + // Call the function: + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta, BlockSkyLight, BlockBlockLight; + bool res = Self->GetBlockInfo(BlockX, BlockY, BlockZ, BlockType, BlockMeta, BlockSkyLight, BlockBlockLight); + + // Push the returned values: + L.Push(res); + if (res) + { + L.Push(BlockType); + L.Push(BlockMeta); + L.Push(BlockSkyLight); + L.Push(BlockBlockLight); + return 5; + } + return 1; +} + + + + + +static int tolua_cWorld_GetBlockTypeMeta(lua_State * tolua_S) +{ + // Exported manually, because tolua would generate useless additional parameters (a_BlockType, a_BlockMeta) + // Function signature: GetBlockTypeMeta(BlockX, BlockY, BlockZ) -> BlockValid, [BlockType, BlockMeta] + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber(2, 4) || + !L.CheckParamEnd(5) + ) + { + return 0; + } + + // Get params: + cWorld * Self = nullptr; + int BlockX, BlockY, BlockZ; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ); + if (Self == nullptr) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + + // Call the function: + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + bool res = Self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta); + + // Push the returned values: + L.Push(res); + if (res) + { + L.Push(BlockType); + L.Push(BlockMeta); + return 3; + } + return 1; +} + + + + + +static int tolua_cWorld_GetSignLines(lua_State * tolua_S) +{ + // Exported manually, because tolua would generate useless additional parameters (a_Line1 .. a_Line4) + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber(2, 4) || + !L.CheckParamEnd(5) + ) + { + return 0; + } + + // Get params: + cWorld * Self = nullptr; + int BlockX, BlockY, BlockZ; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ); + if (Self == nullptr) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + + // Call the function: + AString Line1, Line2, Line3, Line4; + bool res = Self->GetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); + + // Push the returned values: + L.Push(res); + if (res) + { + L.Push(Line1); + L.Push(Line2); + L.Push(Line3); + L.Push(Line4); + return 5; + } + return 1; +} + + + + + +static int tolua_cWorld_PrepareChunk(lua_State * tolua_S) +{ + /* Function signature: + World:PrepareChunk(ChunkX, ChunkZ, Callback) + */ + + // Check the param types: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType (1, "cWorld") || + !L.CheckParamNumber (2, 3) || + !L.CheckParamFunctionOrNil(4) + ) + { + return 0; + } + + // Read the params: + cWorld * world = nullptr; + int chunkX = 0, chunkZ = 0; + L.GetStackValues(1, world, chunkX, chunkZ); + if (world == nullptr) + { + LOGWARNING("World:PrepareChunk(): invalid world parameter"); + L.LogStackTrace(); + return 0; + } + + // Wrap the Lua callback inside a C++ callback class: + class cCallback: + public cChunkCoordCallback + { + public: + cCallback(lua_State * a_LuaState): + m_LuaState(a_LuaState), + m_Callback(m_LuaState, 4) + { + } + + // cChunkCoordCallback override: + virtual void Call(int a_CBChunkX, int a_CBChunkZ) override + { + if (m_Callback.IsValid()) + { + m_LuaState.Call(m_Callback, a_CBChunkX, a_CBChunkZ); + } + + // This is the last reference of this object, we must delete it so that it doesn't leak: + delete this; + } + + protected: + cLuaState m_LuaState; + cLuaState::cRef m_Callback; + }; + cCallback * callback = new cCallback(tolua_S); + + // Call the chunk preparation: + world->PrepareChunk(chunkX, chunkZ, callback); + return 0; +} + + + + + +class cLuaWorldTask : + public cWorld::cTask, + public cPluginLua::cResettable +{ +public: + cLuaWorldTask(cPluginLua & a_Plugin, int a_FnRef) : + cPluginLua::cResettable(a_Plugin), + m_FnRef(a_FnRef) + { + } + +protected: + int m_FnRef; + + // cWorld::cTask overrides: + virtual void Run(cWorld & a_World) override + { + cCSLock Lock(m_CSPlugin); + if (m_Plugin != nullptr) + { + m_Plugin->Call(m_FnRef, &a_World); + } + } +} ; + + + + + +static int tolua_cWorld_QueueTask(lua_State * tolua_S) +{ + // Binding for cWorld::QueueTask + // Params: function + + // Retrieve the cPlugin from the LuaState: + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); + if (Plugin == nullptr) + { + // An error message has been already printed in GetLuaPlugin() + return 0; + } + + // Retrieve the args: + cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); + if (self == nullptr) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); + } + if (!lua_isfunction(tolua_S, 2)) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); + } + + // Create a reference to the function: + int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FnRef == LUA_REFNIL) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); + } + + auto task = std::make_shared<cLuaWorldTask>(*Plugin, FnRef); + Plugin->AddResettable(task); + self->QueueTask(task); + return 0; +} + + + + + +static int tolua_cWorld_SetSignLines(lua_State * tolua_S) +{ + // Exported manually, because tolua would generate useless additional return values (a_Line1 .. a_Line4) + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber(2, 4) || + !L.CheckParamString(5, 8) || + !L.CheckParamEnd(9) + ) + { + return 0; + } + + // Get params: + cWorld * Self = nullptr; + int BlockX, BlockY, BlockZ; + AString Line1, Line2, Line3, Line4; + L.GetStackValues(1, Self, BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); + if (Self == nullptr) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Invalid 'self'"); + } + + // Call the function: + bool res = Self->SetSignLines(BlockX, BlockY, BlockZ, Line1, Line2, Line3, Line4); + + // Push the returned values: + L.Push(res); + return 1; +} + + + + + +class cLuaScheduledWorldTask : + public cWorld::cTask, + public cPluginLua::cResettable +{ +public: + cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : + cPluginLua::cResettable(a_Plugin), + m_FnRef(a_FnRef) + { + } + +protected: + int m_FnRef; + + // cWorld::cTask overrides: + virtual void Run(cWorld & a_World) override + { + cCSLock Lock(m_CSPlugin); + if (m_Plugin != nullptr) + { + m_Plugin->Call(m_FnRef, &a_World); + } + } +}; + + + + + +static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) +{ + // Binding for cWorld::ScheduleTask + // Params: function, Ticks + + // Retrieve the cPlugin from the LuaState: + cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S); + if (Plugin == nullptr) + { + // An error message has been already printed in GetLuaPlugin() + return 0; + } + + // Retrieve the args: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber (2) || + !L.CheckParamFunction(3) + ) + { + return 0; + } + cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, nullptr); + if (World == nullptr) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); + } + + // Create a reference to the function: + int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FnRef == LUA_REFNIL) + { + return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); + } + + int DelayTicks = (int)tolua_tonumber(tolua_S, 2, 0); + + auto task = std::make_shared<cLuaScheduledWorldTask>(*Plugin, FnRef); + Plugin->AddResettable(task); + World->ScheduleTask(DelayTicks, task); + return 0; +} + + + + + + +static int tolua_cWorld_TryGetHeight(lua_State * tolua_S) +{ + /* Exported manually, because tolua would require the out-only param a_Height to be used when calling + Function signature: world:TryGetHeight(a_World, a_BlockX, a_BlockZ) -> IsValid, Height + */ + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamNumber(2, 3) || + !L.CheckParamEnd(4) + ) + { + return 0; + } + + // Get params: + cWorld * self = nullptr; + int BlockX, BlockZ; + L.GetStackValues(1, self, BlockX, BlockZ); + if (self == nullptr) + { + tolua_error(tolua_S, "Invalid 'self' in function 'TryGetHeight'", nullptr); + return 0; + } + + // Call the implementation: + int Height = 0; + bool res = self->TryGetHeight(BlockX, BlockZ, Height); + L.Push(res); + if (res) + { + L.Push(Height); + return 2; + } + return 1; +} + + + + + +void cManualBindings::BindWorld(lua_State * tolua_S) +{ + tolua_beginmodule(tolua_S, nullptr); + tolua_beginmodule(tolua_S, "cWorld"); + tolua_function(tolua_S, "BroadcastParticleEffect", tolua_cWorld_BroadcastParticleEffect); + tolua_function(tolua_S, "ChunkStay", tolua_cWorld_ChunkStay); + tolua_function(tolua_S, "DoWithBlockEntityAt", DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); + tolua_function(tolua_S, "DoWithBeaconAt", DoWithXYZ<cWorld, cBeaconEntity, &cWorld::DoWithBeaconAt>); + tolua_function(tolua_S, "DoWithChestAt", DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); + tolua_function(tolua_S, "DoWithDispenserAt", DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); + tolua_function(tolua_S, "DoWithDropSpenserAt", DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); + tolua_function(tolua_S, "DoWithDropperAt", DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); + tolua_function(tolua_S, "DoWithEntityByID", DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFurnaceAt", DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); + tolua_function(tolua_S, "DoWithNoteBlockAt", DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); + tolua_function(tolua_S, "DoWithCommandBlockAt", DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); + tolua_function(tolua_S, "DoWithMobHeadAt", DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>); + tolua_function(tolua_S, "DoWithFlowerPotAt", DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>); + tolua_function(tolua_S, "DoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "DoWithPlayerByUUID", DoWith< cWorld, cPlayer, &cWorld::DoWithPlayerByUUID>); + tolua_function(tolua_S, "ForEachBlockEntityInChunk", ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); + tolua_function(tolua_S, "ForEachChestInChunk", ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); + tolua_function(tolua_S, "ForEachEntity", ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInBox", ForEachInBox< cWorld, cEntity, &cWorld::ForEachEntityInBox>); + tolua_function(tolua_S, "ForEachEntityInChunk", ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); + tolua_function(tolua_S, "ForEachFurnaceInChunk", ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); + tolua_function(tolua_S, "ForEachPlayer", ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); + tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); + tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); + tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); + tolua_function(tolua_S, "PrepareChunk", tolua_cWorld_PrepareChunk); + tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); + tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask); + tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); + tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); + tolua_endmodule(tolua_S); + tolua_endmodule(tolua_S); +} + + + + diff --git a/src/Bindings/Plugin.cpp b/src/Bindings/Plugin.cpp index 98ccfb88c..2f2771e38 100644 --- a/src/Bindings/Plugin.cpp +++ b/src/Bindings/Plugin.cpp @@ -7,11 +7,11 @@ -cPlugin::cPlugin(const AString & a_PluginDirectory) : - m_Language(E_CPP), - m_Name(a_PluginDirectory), +cPlugin::cPlugin(const AString & a_FolderName) : + m_Status(cPluginManager::psDisabled), + m_Name(a_FolderName), m_Version(0), - m_Directory(a_PluginDirectory) + m_FolderName(a_FolderName) { } @@ -28,9 +28,33 @@ cPlugin::~cPlugin() +void cPlugin::Unload(void) +{ + auto pm = cPluginManager::Get(); + pm->RemovePluginCommands(this); + pm->RemovePluginConsoleCommands(this); + pm->RemoveHooks(this); + OnDisable(); + m_Status = cPluginManager::psUnloaded; + m_LoadError.clear(); +} + + + + + AString cPlugin::GetLocalFolder(void) const { - return std::string("Plugins/") + m_Directory; + return std::string("Plugins/") + m_FolderName; +} + + + + +void cPlugin::SetLoadError(const AString & a_LoadError) +{ + m_Status = cPluginManager::psError; + m_LoadError = a_LoadError; } diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 3f9fa7655..1330bca0d 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -1,30 +1,16 @@ -#pragma once - -#include "Defines.h" +// Plugin.h -class cCommandOutputCallback; -class cItems; -class cHopperEntity; +// Declares the cPlugin class representing an interface that a plugin implementation needs to expose, with some helping functions -class cBlockEntityWithItems; -class cClientHandle; -class cPickup; -class cPlayer; -class cProjectileEntity; -class cEntity; -class cMonster; -class cWorld; -class cChunkDesc; -struct TakeDamageInfo; -// fwd: CraftingRecipes.h -class cCraftingGrid; -class cCraftingRecipe; +#pragma once +#include "Defines.h" +#include "PluginManager.h" @@ -35,11 +21,23 @@ class cPlugin public: // tolua_end - cPlugin( const AString & a_PluginDirectory); + /** Creates a new instance. + a_FolderName is the name of the folder (in the Plugins folder) from which the plugin is loaded. + The plugin's name defaults to the folder name. */ + cPlugin(const AString & a_FolderName); + virtual ~cPlugin(); + /** Called as the last call into the plugin before it is unloaded. */ virtual void OnDisable(void) {} - virtual bool Initialize(void) = 0; + + /** Loads and initializes the plugin. Sets m_Status to psLoaded or psError accordingly. + Returns true if the initialization succeeded, false otherwise. */ + virtual bool Load(void) = 0; + + /** Unloads the plugin. Sets m_Status to psDisabled. + The default implementation removes the plugin's associations with cPluginManager, descendants should call it as well. */ + virtual void Unload(void); // Called each tick virtual void Tick(float a_Dt) = 0; @@ -58,7 +56,9 @@ public: virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0; virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) = 0; virtual bool OnEntityTeleport (cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; - virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0; + virtual bool OnEntityChangingWorld (cEntity & a_Entity, cWorld & a_World) = 0; + virtual bool OnEntityChangedWorld (cEntity & a_Entity, cWorld & a_World) = 0; + virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) = 0; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; virtual bool OnHandshake (cClientHandle & a_Client, const AString & a_Username) = 0; @@ -109,19 +109,17 @@ public: /** Handles the command split into a_Split, issued by player a_Player. Command permissions have already been checked. - Returns true if command handled successfully - */ + Returns true if command handled successfully. */ virtual bool HandleCommand(const AStringVector & a_Split, cPlayer & a_Player, const AString & a_FullCommand) = 0; /** Handles the console command split into a_Split. - Returns true if command handled successfully. Output is to be sent to the a_Output callback. - */ + Returns true if command handled successfully. Output is to be sent to the a_Output callback. */ virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_FullCommand) = 0; - /// All bound commands are to be removed, do any language-dependent cleanup here + /** All bound commands are to be removed, do any language-dependent cleanup here */ virtual void ClearCommands(void) {} - /// All bound console commands are to be removed, do any language-dependent cleanup here + /** All bound console commands are to be removed, do any language-dependent cleanup here */ virtual void ClearConsoleCommands(void) {} // tolua_begin @@ -131,28 +129,43 @@ public: int GetVersion(void) const { return m_Version; } void SetVersion(int a_Version) { m_Version = a_Version; } - const AString & GetDirectory(void) const {return m_Directory; } - AString GetLocalDirectory(void) const {return GetLocalFolder(); } // OBSOLETE, use GetLocalFolder() instead + /** Returns the name of the folder (in the Plugins folder) from which the plugin is loaded. */ + const AString & GetFolderName(void) const {return m_FolderName; } + + /** Returns the folder relative to the MCS Executable, from which the plugin is loaded. */ AString GetLocalFolder(void) const; + + /** Returns the error encountered while loading the plugin. Only valid if m_Status == psError. */ + const AString & GetLoadError(void) const { return m_LoadError; } + + cPluginManager::ePluginStatus GetStatus(void) const { return m_Status; } + + bool IsLoaded(void) const { return (m_Status == cPluginManager::psLoaded); } // tolua_end + // Needed for ManualBindings' tolua_ForEach<> + static const char * GetClassStatic(void) { return "cPlugin"; } + +protected: + friend class cPluginManager; + + cPluginManager::ePluginStatus m_Status; - /* This should not be exposed to scripting languages */ - enum PluginLanguage - { - E_CPP, - E_LUA, - E_SQUIRREL, // OBSOLETE, but kept in place to remind us of the horrors lurking in the history - }; - PluginLanguage GetLanguage() { return m_Language; } - void SetLanguage( PluginLanguage a_Language) { m_Language = a_Language; } - -private: - PluginLanguage m_Language; + /** The name of the plugin, used to identify the plugin in the system and for inter-plugin calls. */ AString m_Name; + int m_Version; - AString m_Directory; + /** Name of the folder (in the Plugins folder) from which the plugin is loaded. */ + AString m_FolderName; + + /** The error encountered while loading the plugin. + Only valid if m_Status == psError. */ + AString m_LoadError; + + + /** Sets m_LoadError to the specified string and m_Status to psError. */ + void SetLoadError(const AString & a_LoadError); }; // tolua_export diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 0a2a8411d..234bf579b 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -63,6 +63,11 @@ void cPluginLua::Close(void) return; } + // Remove the command bindings and web tabs: + ClearCommands(); + ClearConsoleCommands(); + ClearTabs(); + // Notify and remove all m_Resettables (unlock the m_CriticalSection while resetting them): cResettablePtrs resettables; std::swap(m_Resettables, resettables); @@ -93,7 +98,7 @@ void cPluginLua::Close(void) -bool cPluginLua::Initialize(void) +bool cPluginLua::Load(void) { cCSLock Lock(m_CriticalSection); if (!m_LuaState.IsValid()) @@ -144,6 +149,7 @@ bool cPluginLua::Initialize(void) // Warn if there are no Lua files in the plugin folder: if (LuaFiles.empty()) { + SetLoadError("No lua files found, plugin is probably missing."); LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str()); Close(); return false; @@ -155,6 +161,7 @@ bool cPluginLua::Initialize(void) AString Path = PluginPath + *itr; if (!m_LuaState.LoadFile(Path)) { + SetLoadError(Printf("Failed to load file %s.", itr->c_str())); Close(); return false; } @@ -164,6 +171,8 @@ bool cPluginLua::Initialize(void) AString Path = PluginPath + "Info.lua"; if (!m_LuaState.LoadFile(Path)) { + SetLoadError("Failed to load file Info.lua."); + m_Status = cPluginManager::psError; Close(); return false; } @@ -173,17 +182,20 @@ bool cPluginLua::Initialize(void) bool res = false; if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res)) { + SetLoadError("Cannot call the Initialize() function."); LOGWARNING("Error in plugin %s: Cannot call the Initialize() function. Plugin is temporarily disabled.", GetName().c_str()); Close(); return false; } if (!res) { + SetLoadError("The Initialize() function failed."); LOGINFO("Plugin %s: Initialize() call failed, plugin is temporarily disabled.", GetName().c_str()); Close(); return false; } + m_Status = cPluginManager::psLoaded; return true; } @@ -191,6 +203,17 @@ bool cPluginLua::Initialize(void) +void cPluginLua::Unload(void) +{ + ClearTabs(); + super::Unload(); + Close(); +} + + + + + void cPluginLua::OnDisable(void) { cCSLock Lock(m_CriticalSection); @@ -208,6 +231,10 @@ void cPluginLua::OnDisable(void) void cPluginLua::Tick(float a_Dt) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return; + } cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -222,6 +249,10 @@ void cPluginLua::Tick(float a_Dt) bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -242,6 +273,10 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -262,6 +297,10 @@ bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_Bl bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -282,6 +321,10 @@ bool cPluginLua::OnChat(cPlayer & a_Player, AString & a_Message) bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -302,6 +345,10 @@ bool cPluginLua::OnChunkAvailable(cWorld & a_World, int a_ChunkX, int a_ChunkZ) bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -322,6 +369,10 @@ bool cPluginLua::OnChunkGenerated(cWorld & a_World, int a_ChunkX, int a_ChunkZ, bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -342,6 +393,10 @@ bool cPluginLua::OnChunkGenerating(cWorld & a_World, int a_ChunkX, int a_ChunkZ, bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -362,6 +417,10 @@ bool cPluginLua::OnChunkUnloaded(cWorld & a_World, int a_ChunkX, int a_ChunkZ) bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -382,6 +441,10 @@ bool cPluginLua::OnChunkUnloading(cWorld & a_World, int a_ChunkX, int a_ChunkZ) bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -402,6 +465,10 @@ bool cPluginLua::OnCollectingPickup(cPlayer & a_Player, cPickup & a_Pickup) bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -422,6 +489,10 @@ bool cPluginLua::OnCraftingNoRecipe(cPlayer & a_Player, cCraftingGrid & a_Grid, bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -442,6 +513,10 @@ bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_ADD_EFFECT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -459,14 +534,66 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E -bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +bool cPluginLua::OnEntityChangingWorld(cEntity & a_Entity, cWorld & a_World) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGING_WORLD]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Entity, &a_World, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; +} + + + + + +bool cPluginLua::OnEntityChangedWorld(cEntity & a_Entity, cWorld & a_World) +{ + cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGED_WORLD]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Entity, &a_World, res); + if (res) + { + return true; + } + } + return false; +} + + + + + +bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) +{ + cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Split, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), a_Player, a_Split, a_EntireCommand, cLuaState::Return, res, a_Result); if (res) { return true; @@ -482,6 +609,10 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -519,6 +650,10 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -556,6 +691,10 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Username) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -576,8 +715,11 @@ bool cPluginLua::OnHandshake(cClientHandle & a_Client, const AString & a_Usernam bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_DstSlotNum, cBlockEntityWithItems & a_SrcEntity, int a_SrcSlotNum) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; - cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -597,6 +739,10 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, int a_SrcSlotNum, cBlockEntityWithItems & a_DstEntity, int a_DstSlotNum) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -617,6 +763,10 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInfo & a_TDI) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -637,6 +787,10 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer, TakeDamageInf bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const AString & a_Username) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -657,6 +811,10 @@ bool cPluginLua::OnLogin(cClientHandle & a_Client, int a_ProtocolVersion, const bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -677,6 +835,10 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation) bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -697,6 +859,10 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -717,6 +883,10 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_DESTROYED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -737,6 +907,10 @@ bool cPluginLua::OnPlayerDestroyed(cPlayer & a_Player) bool cPluginLua::OnPlayerEating(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -757,6 +931,10 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player) bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FOOD_LEVEL_CHANGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -777,6 +955,10 @@ bool cPluginLua::OnPlayerFoodLevelChange(cPlayer & a_Player, int a_NewFoodLevel) bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -797,6 +979,10 @@ bool cPluginLua::OnPlayerFished(cPlayer & a_Player, const cItems & a_Reward) bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_FISHING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -817,6 +1003,10 @@ bool cPluginLua::OnPlayerFishing(cPlayer & a_Player, cItems & a_Reward) bool cPluginLua::OnPlayerJoined(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -837,6 +1027,10 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player) bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -857,6 +1051,10 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -877,6 +1075,10 @@ bool cPluginLua::OnPlayerMoving(cPlayer & a_Player, const Vector3d & a_OldPositi bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_TELEPORT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -897,6 +1099,10 @@ bool cPluginLua::OnEntityTeleport(cEntity & a_Entity, const Vector3d & a_OldPosi bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -922,6 +1128,10 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, const sSetBlock & a_Blo bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_BlockChange) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -947,6 +1157,10 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, const sSetBlock & a_Bl bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -967,6 +1181,10 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -987,6 +1205,10 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent bool cPluginLua::OnPlayerShooting(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1007,6 +1229,10 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player) bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1027,6 +1253,10 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player) bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1047,6 +1277,10 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player) bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1067,6 +1301,10 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1087,6 +1325,10 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1107,6 +1349,10 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1127,6 +1373,10 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Channel, const AString & a_Message) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1147,6 +1397,10 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha bool cPluginLua::OnPluginsLoaded(void) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1165,6 +1419,10 @@ bool cPluginLua::OnPluginsLoaded(void) bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1185,6 +1443,10 @@ bool cPluginLua::OnPostCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCra bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1205,6 +1467,10 @@ bool cPluginLua::OnPreCrafting(cPlayer & a_Player, cCraftingGrid & a_Grid, cCraf bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Face, const Vector3d & a_BlockHitPos) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1225,6 +1491,10 @@ bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile, int a_Bl bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1245,6 +1515,10 @@ bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_ServerDescription, int & a_OnlinePlayersCount, int & a_MaxPlayersCount, AString & a_Favicon) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SERVER_PING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1265,6 +1539,10 @@ bool cPluginLua::OnServerPing(cClientHandle & a_ClientHandle, AString & a_Server bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1285,6 +1563,10 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1305,6 +1587,10 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1325,6 +1611,10 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1345,6 +1635,10 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1370,6 +1664,10 @@ bool cPluginLua::OnUpdatedSign( ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1395,6 +1693,10 @@ bool cPluginLua::OnUpdatingSign( ) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1415,6 +1717,10 @@ bool cPluginLua::OnUpdatingSign( bool cPluginLua::OnWeatherChanged(cWorld & a_World) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1435,6 +1741,10 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World) bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) @@ -1455,6 +1765,10 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) bool cPluginLua::OnWorldStarted(cWorld & a_World) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_STARTED]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -1470,6 +1784,10 @@ bool cPluginLua::OnWorldStarted(cWorld & a_World) bool cPluginLua::OnWorldTick(cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec) { cCSLock Lock(m_CriticalSection); + if (!m_LuaState.IsValid()) + { + return false; + } cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { @@ -1614,6 +1932,8 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_DISCONNECT: return "OnDisconnect"; case cPluginManager::HOOK_PLAYER_ANIMATION: return "OnPlayerAnimation"; case cPluginManager::HOOK_ENTITY_ADD_EFFECT: return "OnEntityAddEffect"; + case cPluginManager::HOOK_ENTITY_CHANGING_WORLD: return "OnEntityChangingWorld"; + case cPluginManager::HOOK_ENTITY_CHANGED_WORLD: return "OnEntityChangedWorld"; case cPluginManager::HOOK_ENTITY_TELEPORT: return "OnEntityTeleport"; case cPluginManager::HOOK_EXECUTE_COMMAND: return "OnExecuteCommand"; case cPluginManager::HOOK_HANDSHAKE: return "OnHandshake"; @@ -1736,40 +2056,29 @@ void cPluginLua::AddResettable(cPluginLua::cResettablePtr a_Resettable) -AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request) +AString cPluginLua::HandleWebRequest(const HTTPRequest & a_Request) { - cCSLock Lock(m_CriticalSection); - std::string RetVal = ""; - - std::pair< std::string, std::string > TabName = GetTabNameForRequest(a_Request); - std::string SafeTabName = TabName.second; - if (SafeTabName.empty()) + // Find the tab to use for the request: + auto TabName = GetTabNameForRequest(a_Request); + AString SafeTabTitle = TabName.second; + if (SafeTabTitle.empty()) { return ""; } - - sWebPluginTab * Tab = 0; - for (TabList::iterator itr = GetTabs().begin(); itr != GetTabs().end(); ++itr) + auto Tab = GetTabBySafeTitle(SafeTabTitle); + if (Tab == nullptr) { - if ((*itr)->SafeTitle.compare(SafeTabName) == 0) // This is the one! Rawr - { - Tab = *itr; - break; - } + return ""; } - if (Tab != nullptr) + // Get the page content from the plugin: + cCSLock Lock(m_CriticalSection); + AString Contents = Printf("WARNING: WebPlugin tab '%s' did not return a string!", Tab->m_Title.c_str()); + if (!m_LuaState.Call(Tab->m_UserData, &a_Request, cLuaState::Return, Contents)) { - AString Contents = Printf("WARNING: WebPlugin tab '%s' did not return a string!", Tab->Title.c_str()); - if (!m_LuaState.Call(Tab->UserData, a_Request, cLuaState::Return, Contents)) - { - return "Lua encountered error while processing the page request"; - } - - RetVal += Contents; + return "Lua encountered error while processing the page request"; } - - return RetVal; + return Contents; } @@ -1784,13 +2093,7 @@ bool cPluginLua::AddWebTab(const AString & a_Title, lua_State * a_LuaState, int LOGERROR("Only allowed to add a tab to a WebPlugin of your own Plugin!"); return false; } - sWebPluginTab * Tab = new sWebPluginTab(); - Tab->Title = a_Title; - Tab->SafeTitle = SafeString(a_Title); - - Tab->UserData = a_FunctionReference; - - GetTabs().push_back(Tab); + AddNewWebTab(a_Title, a_FunctionReference); return true; } diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index c14b02687..a763cdfdf 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -20,7 +20,7 @@ -// fwd: UI/Window.h +// fwd: "UI/Window.h" class cWindow; @@ -32,6 +32,8 @@ class cPluginLua : public cPlugin, public cWebPlugin { + typedef cPlugin super; + public: // tolua_end @@ -96,7 +98,8 @@ public: ~cPluginLua(); virtual void OnDisable(void) override; - virtual bool Initialize(void) override; + virtual bool Load(void) override; + virtual void Unload(void) override; virtual void Tick(float a_Dt) override; @@ -112,7 +115,9 @@ public: virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override; virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override; virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) override; - virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override; + virtual bool OnEntityChangingWorld (cEntity & a_Entity, cWorld & a_World) override; + virtual bool OnEntityChangedWorld (cEntity & a_Entity, cWorld & a_World) override; + virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) override; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; virtual bool OnHandshake (cClientHandle & a_Client, const AString & a_Username) override; @@ -173,12 +178,13 @@ public: /** Returns true if the plugin contains the function for the specified hook type, using the old-style registration (#121) */ bool CanAddOldStyleHook(int a_HookType); - // cWebPlugin override - virtual const AString GetWebTitle(void) const {return GetName(); } + // cWebPlugin overrides + virtual const AString GetWebTitle(void) const override {return GetName(); } + virtual AString HandleWebRequest(const HTTPRequest & a_Request) override; - // cWebPlugin and WebAdmin stuff - virtual AString HandleWebRequest(const HTTPRequest * a_Request) override; - bool AddWebTab(const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference); // >> EXPORTED IN MANUALBINDINGS << + /** Adds a new web tab to webadmin. + Displaying the tab calls the referenced function. */ + bool AddWebTab(const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference); // Exported in ManualBindings.cpp /** Binds the command to call the function specified by a Lua function reference. Simply adds to CommandMap. */ void BindCommand(const AString & a_Command, int a_FnRef); diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 8935f7dd3..5b6bec728 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -59,39 +59,48 @@ void cPluginManager::ReloadPlugins(void) -void cPluginManager::FindPlugins(void) +void cPluginManager::RefreshPluginList(void) { + // Get a list of currently available folders: AString PluginsPath = GetPluginsPath() + "/"; - - // First get a clean list of only the currently running plugins, we don't want to mess those up - for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) + AStringVector Contents = cFile::GetFolderContents(PluginsPath.c_str()); + AStringVector Folders; + for (auto & item: Contents) { - if (itr->second == nullptr) + if ((item == ".") || (item == "..") || (!cFile::IsFolder(PluginsPath + item))) { - PluginMap::iterator thiz = itr; - ++thiz; - m_Plugins.erase( itr); - itr = thiz; + // We only want folders, and don't want "." or ".." continue; } - ++itr; - } + Folders.push_back(item); + } // for item - Contents[] - AStringVector Files = cFile::GetFolderContents(PluginsPath.c_str()); - for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) + // Set all plugins with invalid folders as psNotFound: + for (auto & plugin: m_Plugins) { - if ((*itr == ".") || (*itr == "..") || (!cFile::IsFolder(PluginsPath + *itr))) + if (std::find(Folders.cbegin(), Folders.cend(), plugin->GetFolderName()) == Folders.end()) { - // We only want folders, and don't want "." or ".." - continue; + plugin->m_Status = psNotFound; } + } // for plugin - m_Plugins[] - // Add plugin name/directory to the list - if (m_Plugins.find(*itr) == m_Plugins.end()) + // Add all newly discovered plugins: + for (auto & folder: Folders) + { + bool hasFound = false; + for (auto & plugin: m_Plugins) { - m_Plugins[*itr] = nullptr; + if (plugin->GetFolderName() == folder) + { + hasFound = true; + break; + } + } // for plugin - m_Plugins[] + if (!hasFound) + { + m_Plugins.push_back(std::make_shared<cPluginLua>(folder)); } - } + } // for folder - Folders[] } @@ -109,60 +118,26 @@ void cPluginManager::ReloadPluginsNow(void) -void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) +void cPluginManager::ReloadPluginsNow(cSettingsRepositoryInterface & a_Settings) { LOG("-- Loading Plugins --"); + + // Unload any existing plugins: m_bReloadPlugins = false; UnloadPluginsNow(); - FindPlugins(); - - cServer::BindBuiltInConsoleCommands(); - - // Check if the Plugins section exists. - int KeyNum = a_SettingsIni.FindKey("Plugins"); - - if (KeyNum == -1) - { - InsertDefaultPlugins(a_SettingsIni); - KeyNum = a_SettingsIni.FindKey("Plugins"); - } - - // How many plugins are there? - int NumPlugins = a_SettingsIni.GetNumValues(KeyNum); - - for (int i = 0; i < NumPlugins; i++) - { - AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); - if (ValueName.compare("Plugin") == 0) - { - AString PluginFile = a_SettingsIni.GetValue(KeyNum, i); - if (!PluginFile.empty()) - { - if (m_Plugins.find(PluginFile) != m_Plugins.end()) - { - LoadPlugin(PluginFile); - } - } - } - } - + // Refresh the list of plugins to load new ones from disk / remove the deleted ones: + RefreshPluginList(); - // Remove invalid plugins from the PluginMap. - for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) + // Load the plugins: + AStringVector ToLoad = GetFoldersToLoad(a_Settings); + for (auto & pluginFolder: ToLoad) { - if (itr->second == nullptr) - { - PluginMap::iterator thiz = itr; - ++thiz; - m_Plugins.erase(itr); - itr = thiz; - continue; - } - ++itr; - } + LoadPlugin(pluginFolder); + } // for pluginFolder - ToLoad[] - size_t NumLoadedPlugins = GetNumPlugins(); + // Log a report of the loading process + size_t NumLoadedPlugins = GetNumLoadedPlugins(); if (NumLoadedPlugins == 0) { LOG("-- No Plugins Loaded --"); @@ -173,7 +148,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) } else { - LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins); + LOG("-- Loaded %u Plugins --", static_cast<unsigned>(NumLoadedPlugins)); } CallHookPluginsLoaded(); } @@ -182,16 +157,16 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) -void cPluginManager::InsertDefaultPlugins(cIniFile & a_SettingsIni) +void cPluginManager::InsertDefaultPlugins(cSettingsRepositoryInterface & a_Settings) { - a_SettingsIni.AddKeyName("Plugins"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=Debuggers"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=HookNotify"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=ChunkWorx"); - a_SettingsIni.AddKeyComment("Plugins", " Plugin=APIDump"); - a_SettingsIni.AddValue("Plugins", "Plugin", "Core"); - a_SettingsIni.AddValue("Plugins", "Plugin", "TransAPI"); - a_SettingsIni.AddValue("Plugins", "Plugin", "ChatLog"); + a_Settings.AddKeyName("Plugins"); + a_Settings.AddKeyComment("Plugins", " Plugin=Debuggers"); + a_Settings.AddKeyComment("Plugins", " Plugin=HookNotify"); + a_Settings.AddKeyComment("Plugins", " Plugin=ChunkWorx"); + a_Settings.AddKeyComment("Plugins", " Plugin=APIDump"); + a_Settings.AddValue("Plugins", "Plugin", "Core"); + a_Settings.AddValue("Plugins", "Plugin", "TransAPI"); + a_Settings.AddValue("Plugins", "Plugin", "ChatLog"); } @@ -200,12 +175,39 @@ void cPluginManager::InsertDefaultPlugins(cIniFile & a_SettingsIni) void cPluginManager::Tick(float a_Dt) { - while (!m_DisablePluginList.empty()) + // Unload plugins that have been scheduled for unloading: + AStringVector PluginsToUnload; { - RemovePlugin(m_DisablePluginList.front()); - m_DisablePluginList.pop_front(); + cCSLock Lock(m_CSPluginsToUnload); + std::swap(m_PluginsToUnload, PluginsToUnload); } + for (auto & folder: PluginsToUnload) + { + bool HasUnloaded = false; + bool HasFound = false; + for (auto & plugin: m_Plugins) + { + if (plugin->GetFolderName() == folder) + { + HasFound = true; + if (plugin->IsLoaded()) + { + plugin->Unload(); + HasUnloaded = true; + } + } + } + if (!HasFound) + { + LOG("Cannot unload plugin in folder \"%s\", there's no such plugin folder", folder.c_str()); + } + else if (!HasUnloaded) + { + LOG("Cannot unload plugin in folder \"%s\", it has not been loaded.", folder.c_str()); + } + } // for plugin - m_Plugins[] + // If a plugin reload has been scheduled, reload now: if (m_bReloadPlugins) { ReloadPluginsNow(); @@ -523,14 +525,50 @@ bool cPluginManager::CallHookEntityTeleport(cEntity & a_Entity, const Vector3d & -bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +bool cPluginManager::CallHookEntityChangingWorld(cEntity & a_Entity, cWorld & a_World) +{ + FIND_HOOK(HOOK_ENTITY_CHANGING_WORLD); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnEntityChangingWorld(a_Entity, a_World)) + { + return true; + } + } + return false; +} + + + + +bool cPluginManager::CallHookEntityChangedWorld(cEntity & a_Entity, cWorld & a_World) +{ + FIND_HOOK(HOOK_ENTITY_CHANGED_WORLD); + VERIFY_HOOK; + + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnEntityChangedWorld(a_Entity, a_World)) + { + return true; + } + } + return false; +} + + + + +bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, CommandResult & a_Result) { FIND_HOOK(HOOK_EXECUTE_COMMAND); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnExecuteCommand(a_Player, a_Split)) + if ((*itr)->OnExecuteCommand(a_Player, a_Split, a_EntireCommand, a_Result)) { return true; } @@ -1443,14 +1481,25 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player, if (cmd == m_Commands.end()) { // Command not found + // If it started with a slash, ask the plugins if they still want to handle it: + if (!a_Command.empty() && (a_Command[0] == '/')) + { + CommandResult Result = crUnknownCommand; + CallHookExecuteCommand(&a_Player, Split, a_Command, Result); + return Result; + } return crUnknownCommand; } // Ask plugins first if a command is okay to execute the command: - if (CallHookExecuteCommand(&a_Player, Split)) + CommandResult Result = crBlocked; + if (CallHookExecuteCommand(&a_Player, Split, a_Command, Result)) { - LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player.GetName().c_str(), Split[0].c_str()); - return crBlocked; + if (Result == crBlocked) + { + LOGINFO("Player %s tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player.GetName().c_str(), Split[0].c_str()); + } + return Result; } if ( @@ -1477,68 +1526,56 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player, -cPlugin * cPluginManager::GetPlugin(const AString & a_Plugin) const +void cPluginManager::UnloadPluginsNow() { - for (PluginMap::const_iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr) - { - if (itr->second == nullptr) - { - // The plugin is currently unloaded - continue; - } + // Remove all bindings: + m_Hooks.clear(); + m_Commands.clear(); + m_ConsoleCommands.clear(); - if (itr->second->GetName().compare(a_Plugin) == 0) + // Re-bind built-in console commands: + cServer::BindBuiltInConsoleCommands(); + + // Unload all loaded plugins: + for (auto & plugin: m_Plugins) + { + if (plugin->IsLoaded()) { - return itr->second; + plugin->Unload(); } } - return 0; } -const cPluginManager::PluginMap & cPluginManager::GetAllPlugins() const +void cPluginManager::UnloadPlugin(const AString & a_PluginFolder) { - return m_Plugins; + cCSLock Lock(m_CSPluginsToUnload); + m_PluginsToUnload.push_back(a_PluginFolder); } -void cPluginManager::UnloadPluginsNow() +bool cPluginManager::LoadPlugin(const AString & a_FolderName) { - m_Hooks.clear(); - - while (!m_Plugins.empty()) + for (auto & plugin: m_Plugins) { - RemovePlugin(m_Plugins.begin()->second); - } - - m_Commands.clear(); - m_ConsoleCommands.clear(); -} - - - - - -bool cPluginManager::DisablePlugin(const AString & a_PluginName) -{ - PluginMap::iterator itr = m_Plugins.find(a_PluginName); - if (itr == m_Plugins.end()) - { - return false; - } + if (plugin->GetFolderName() == a_FolderName) + { + if (!plugin->IsLoaded()) + { + return plugin->Load(); + } + return true; + } + } // for plugin - m_Plugins[] - if (itr->first.compare(a_PluginName) == 0) // _X 2013_02_01: wtf? Isn't this supposed to be what find() does? - { - m_DisablePluginList.push_back(itr->second); - itr->second = nullptr; // Get rid of this thing right away - return true; - } + // Plugin not found + LOG("Cannot load plugin, folder \"%s\" not found.", a_FolderName.c_str()); return false; } @@ -1546,15 +1583,6 @@ bool cPluginManager::DisablePlugin(const AString & a_PluginName) -bool cPluginManager::LoadPlugin(const AString & a_PluginName) -{ - return AddPlugin(new cPluginLua(a_PluginName.c_str())); -} - - - - - void cPluginManager::RemoveHooks(cPlugin * a_Plugin) { for (HookMap::iterator itr = m_Hooks.begin(), end = m_Hooks.end(); itr != end; ++itr) @@ -1567,32 +1595,6 @@ void cPluginManager::RemoveHooks(cPlugin * a_Plugin) -void cPluginManager::RemovePlugin(cPlugin * a_Plugin) -{ - for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr) - { - if (itr->second == a_Plugin) - { - m_Plugins.erase(itr); - break; - } - } - - RemovePluginCommands(a_Plugin); - RemovePluginConsoleCommands(a_Plugin); - RemoveHooks(a_Plugin); - if (a_Plugin != nullptr) - { - a_Plugin->OnDisable(); - } - delete a_Plugin; - a_Plugin = nullptr; -} - - - - - void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin) { if (a_Plugin != nullptr) @@ -1619,6 +1621,22 @@ void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin) +bool cPluginManager::IsPluginLoaded(const AString & a_PluginName) +{ + for (auto & plugin: m_Plugins) + { + if (plugin->GetName() == a_PluginName) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::BindCommand(const AString & a_Command, cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) { CommandMap::iterator cmd = m_Commands.find(a_Command); @@ -1779,7 +1797,10 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma if (cmd == m_ConsoleCommands.end()) { // Command not found - return false; + // Still notify the plugins (so that plugins such as Aliases can intercept unknown commands). + CommandResult res = crBlocked; + CallHookExecuteCommand(nullptr, a_Split, a_Command, res); + return (res == crExecuted); } if (cmd->second.m_Plugin == nullptr) @@ -1789,10 +1810,10 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma } // Ask plugins first if a command is okay to execute the console command: - if (CallHookExecuteCommand(nullptr, a_Split)) + CommandResult res = crBlocked; + if (CallHookExecuteCommand(nullptr, a_Split, a_Command, res)) { - a_Output.Out("Command \"%s\" was stopped by the HOOK_EXECUTE_COMMAND hook", a_Split[0].c_str()); - return false; + return (res == crExecuted); } return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output, a_Command); @@ -1836,31 +1857,31 @@ bool cPluginManager::IsValidHookType(int a_HookType) bool cPluginManager::DoWithPlugin(const AString & a_PluginName, cPluginCallback & a_Callback) { // TODO: Implement locking for plugins - PluginMap::iterator itr = m_Plugins.find(a_PluginName); - if ((itr == m_Plugins.end()) || (itr->second == nullptr)) + for (auto & plugin: m_Plugins) { - return false; + if (plugin->GetName() == a_PluginName) + { + return a_Callback.Item(plugin.get()); + } } - return a_Callback.Item(itr->second); + return false; } -bool cPluginManager::AddPlugin(cPlugin * a_Plugin) +bool cPluginManager::ForEachPlugin(cPluginCallback & a_Callback) { - m_Plugins[a_Plugin->GetDirectory()] = a_Plugin; - - if (a_Plugin->Initialize()) + // TODO: Implement locking for plugins + for (auto & plugin: m_Plugins) { - // Initialization OK - return true; + if (a_Callback.Item(plugin.get())) + { + return false; + } } - - // Initialization failed - RemovePlugin(a_Plugin); // Also undoes any registrations that Initialize() might have made - return false; + return true; } @@ -1869,21 +1890,23 @@ bool cPluginManager::AddPlugin(cPlugin * a_Plugin) void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) { - if (!a_Plugin) + if (a_Plugin == nullptr) { LOGWARN("Called cPluginManager::AddHook() with a_Plugin == nullptr"); return; } PluginList & Plugins = m_Hooks[a_Hook]; - Plugins.remove(a_Plugin); - Plugins.push_back(a_Plugin); + if (std::find(Plugins.cbegin(), Plugins.cend(), a_Plugin) == Plugins.cend()) + { + Plugins.push_back(a_Plugin); + } } -size_t cPluginManager::GetNumPlugins() const +size_t cPluginManager::GetNumPlugins(void) const { return m_Plugins.size(); } @@ -1891,3 +1914,51 @@ size_t cPluginManager::GetNumPlugins() const + +size_t cPluginManager::GetNumLoadedPlugins(void) const +{ + size_t res = 0; + for (auto & plugin: m_Plugins) + { + if (plugin->IsLoaded()) + { + res += 1; + } + } + return res; +} + + + + + +AStringVector cPluginManager::GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings) +{ + // Check if the Plugins section exists. + if (!a_Settings.KeyExists("Plugins")) + { + InsertDefaultPlugins(a_Settings); + } + + // Get the list of plugins to load: + AStringVector res; + auto Values = a_Settings.GetValues("Plugins"); + for (auto NameValue : Values) + { + AString ValueName = NameValue.first; + if (ValueName.compare("Plugin") == 0) + { + AString PluginFile = NameValue.second; + if (!PluginFile.empty()) + { + res.push_back(PluginFile); + } + } + } // for i - ini values + + return res; +} + + + + diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 4efcbb6f3..6bcef87bf 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -6,48 +6,31 @@ -class cPlugin; -// fwd: World.h -class cWorld; -// fwd: ChunkDesc.h +// fwd: +class cBlockEntityWithItems; class cChunkDesc; - -// fwd: Entities/Entity.h -class cEntity; - -// fwd: Entities/ProjectileEntity.h -class cProjectileEntity; - -// fwd: Mobs/Monster.h -class cMonster; - -// fwd: Player.h -class cPlayer; - -// fwd: CraftingRecipes.h +class cClientHandle; +class cCommandOutputCallback; class cCraftingGrid; class cCraftingRecipe; - -// fwd: Pickup.h +class cEntity; +class cHopperEntity; +class cItems; +class cMonster; class cPickup; - -// fwd: Pawn.h +class cPlayer; +class cPlugin; +class cProjectileEntity; +class cWorld; +class cSettingsRepositoryInterface; struct TakeDamageInfo; -// fwd: CommandOutput.h -class cCommandOutputCallback; - -// fwd: BlockEntities/HopperEntity.h -class cHopperEntity; - -// fwd: BlockEntities/BlockEntityWithItems.h -class cBlockEntityWithItems; - +typedef SharedPtr<cPlugin> cPluginPtr; +typedef std::vector<cPluginPtr> cPluginPtrs; -class cItems; @@ -55,12 +38,7 @@ class cItems; class cPluginManager { public: - // tolua_end - - // Called each tick - virtual void Tick(float a_Dt); - - // tolua_begin + enum CommandResult { crExecuted, @@ -70,6 +48,29 @@ public: crNoPermission, } ; + + /** Defines the status of a single plugin - whether it is loaded, disabled or errored. */ + enum ePluginStatus + { + /** The plugin has been loaded successfully. */ + psLoaded, + + /** The plugin is disabled in settings.ini. */ + psDisabled, + + /** The plugin is enabled in settings.ini but has been unloaded (by a command). */ + psUnloaded, + + /** The plugin is enabled in settings.ini but has failed to load. + m_LoadError is the description of the error. */ + psError, + + /** The plugin has been loaded before, but after a folder refresh it is no longer present. + The plugin will be unloaded in the next call to ReloadPlugins(). */ + psNotFound, + }; + + enum PluginHook { HOOK_BLOCK_SPREAD, @@ -85,6 +86,8 @@ public: HOOK_DISCONNECT, HOOK_PLAYER_ANIMATION, HOOK_ENTITY_ADD_EFFECT, + HOOK_ENTITY_CHANGING_WORLD, + HOOK_ENTITY_CHANGED_WORLD, HOOK_EXECUTE_COMMAND, HOOK_EXPLODED, HOOK_EXPLODING, @@ -134,6 +137,8 @@ public: HOOK_WEATHER_CHANGING, HOOK_WORLD_STARTED, HOOK_WORLD_TICK, + + // tolua_end // Note that if a hook type is added, it may need processing in cPlugin::CanAddHook() descendants, // and it definitely needs adding in cPluginLua::GetHookFnName() ! @@ -141,8 +146,7 @@ public: // Keep these two as the last items, they are used for validity checking and get their values automagically HOOK_NUM_HOOKS, HOOK_MAX = HOOK_NUM_HOOKS - 1, - } ; - // tolua_end + } ; // tolua_export /** Used as a callback for enumerating bound commands */ class cCommandEnumCallback @@ -159,24 +163,31 @@ public: /** The interface used for enumerating and extern-calling plugins */ typedef cItemCallback<cPlugin> cPluginCallback; + typedef std::list<cPlugin *> PluginList; + + + /** Called each tick, calls the plugins' OnTick hook, as well as processes plugin events (addition, removal) */ + void Tick(float a_Dt); /** Returns the instance of the Plugin Manager (there is only ever one) */ static cPluginManager * Get(void); // tolua_export - typedef std::map< AString, cPlugin * > PluginMap; - typedef std::list< cPlugin * > PluginList; - cPlugin * GetPlugin( const AString & a_Plugin) const; // tolua_export - const PluginMap & GetAllPlugins() const; // >> EXPORTED IN MANUALBINDINGS << + /** Refreshes the m_Plugins list based on the current contents of the Plugins folder. + If an active plugin's folder is not found anymore, the plugin is set as psNotFound, but not yet unloaded. */ + void RefreshPluginList(); // tolua_export - // tolua_begin - void FindPlugins(); - void ReloadPlugins(); - // tolua_end + /** Schedules a reload of the plugins to happen within the next call to Tick(). */ + void ReloadPlugins(); // tolua_export - /** Adds the plugin to the list of plugins called for the specified hook type. Handles multiple adds as a single add */ + /** Adds the plugin to the list of plugins called for the specified hook type. + If a plugin adds multiple handlers for a single hook, it is added only once (ignore-duplicates). */ void AddHook(cPlugin * a_Plugin, int a_HookType); + /** Returns the number of all plugins in m_Plugins (includes disabled, unloaded and errored plugins). */ size_t GetNumPlugins() const; // tolua_export + + /** Returns the number of plugins that are psLoaded. */ + size_t GetNumLoadedPlugins(void) const; // tolua_export // Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort bool CallHookBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source); @@ -192,7 +203,9 @@ public: bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason); bool CallHookEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier); bool CallHookEntityTeleport (cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition); - bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == nullptr, it is a console cmd + bool CallHookEntityChangingWorld (cEntity & a_Entity, cWorld & a_World); + bool CallHookEntityChangedWorld (cEntity & a_Entity, cWorld & a_World); + bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, CommandResult & a_Result); // If a_Player == nullptr, it is a console cmd bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); bool CallHookHandshake (cClientHandle & a_ClientHandle, const AString & a_Username); @@ -241,18 +254,26 @@ public: bool CallHookWorldStarted (cWorld & a_World); bool CallHookWorldTick (cWorld & a_World, std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec); - bool DisablePlugin(const AString & a_PluginName); // tolua_export - bool LoadPlugin (const AString & a_PluginName); // tolua_export + /** Queues the specified plugin to be unloaded in the next call to Tick(). + Note that this function returns before the plugin is unloaded, to avoid deadlocks. */ + void UnloadPlugin(const AString & a_PluginFolder); // tolua_export + + /** Loads the plugin from the specified plugin folder. + Returns true if the plugin was loaded successfully or was already loaded before, false otherwise. */ + bool LoadPlugin(const AString & a_PluginFolder); // tolua_export /** Removes all hooks the specified plugin has registered */ void RemoveHooks(cPlugin * a_Plugin); - /** Removes the plugin from the internal structures and deletes its object. */ - void RemovePlugin(cPlugin * a_Plugin); + /** Removes the plugin of the specified name from the internal structures and deletes its object. */ + void RemovePlugin(const AString & a_PluginName); /** Removes all command bindings that the specified plugin has made */ void RemovePluginCommands(cPlugin * a_Plugin); - + + /** Returns true if the specified plugin is loaded. */ + bool IsPluginLoaded(const AString & a_PluginName); // tolua_export + /** Binds a command to the specified plugin. Returns true if successful, false if command already bound. */ bool BindCommand(const AString & a_Command, cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString); // Exported in ManualBindings.cpp, without the a_Plugin param @@ -283,7 +304,9 @@ public: /** Returns true if the console command is in the command map */ bool IsConsoleCommandBound(const AString & a_Command); // tolua_export - /** Executes the command split into a_Split, as if it was given on the console. Returns true if executed. Output is sent to the a_Output callback */ + /** Executes the command split into a_Split, as if it was given on the console. + Returns true if executed. Output is sent to the a_Output callback + Exported in ManualBindings.cpp with a different signature. */ bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output, const AString & a_Command); /** Appends all commands beginning with a_Text (case-insensitive) into a_Results. @@ -295,8 +318,12 @@ public: static bool IsValidHookType(int a_HookType); /** Calls the specified callback with the plugin object of the specified plugin. - Returns false if plugin not found, and the value that the callback has returned otherwise. */ + Returns false if plugin not found, otherwise returns the value that the callback has returned. */ bool DoWithPlugin(const AString & a_PluginName, cPluginCallback & a_Callback); + + /** Calls the specified callback for each plugin in m_Plugins. + Returns true if all plugins have been reported, false if the callback has aborted the enumeration by returning true. */ + bool ForEachPlugin(cPluginCallback & a_Callback); /** Returns the path where individual plugins' folders are expected. The path doesn't end in a slash. */ @@ -316,34 +343,46 @@ private: typedef std::map<int, cPluginManager::PluginList> HookMap; typedef std::map<AString, cCommandReg> CommandMap; - PluginList m_DisablePluginList; - PluginMap m_Plugins; + + /** FolderNames of plugins that should be unloaded. + The plugins will be unloaded within the next call to Tick(), to avoid multithreading issues. + Protected against multithreaded access by m_CSPluginsToUnload. */ + AStringVector m_PluginsToUnload; + + /** Protects m_PluginsToUnload against multithreaded access. */ + mutable cCriticalSection m_CSPluginsToUnload; + + /** All plugins that have been found in the Plugins folder. */ + cPluginPtrs m_Plugins; + HookMap m_Hooks; CommandMap m_Commands; CommandMap m_ConsoleCommands; + /** If set to true, all the plugins will be reloaded within the next call to Tick(). */ bool m_bReloadPlugins; + cPluginManager(); virtual ~cPluginManager(); /** Reloads all plugins, defaulting to settings.ini for settings location */ void ReloadPluginsNow(void); - /** Reloads all plugins with a cIniFile object expected to be initialised to settings.ini */ - void ReloadPluginsNow(cIniFile & a_SettingsIni); + /** Reloads all plugins with a settings repo expected to be initialised to settings.ini */ + void ReloadPluginsNow(cSettingsRepositoryInterface & a_Settings); /** Unloads all plugins */ void UnloadPluginsNow(void); - /** Handles writing default plugins if 'Plugins' key not found using a cIniFile object expected to be intialised to settings.ini */ - void InsertDefaultPlugins(cIniFile & a_SettingsIni); - - /** Adds the plugin into the internal list of plugins and initializes it. If initialization fails, the plugin is removed again. */ - bool AddPlugin(cPlugin * a_Plugin); + /** Handles writing default plugins if 'Plugins' key not found using a settings repo expected to be intialised to settings.ini */ + void InsertDefaultPlugins(cSettingsRepositoryInterface & a_Settings); /** Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns crExecuted if the command is executed. */ CommandResult HandleCommand(cPlayer & a_Player, const AString & a_Command, bool a_ShouldCheckPermissions); + + /** Returns the folders that are specified in the settings ini to load plugins from. */ + AStringVector GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings); } ; // tolua_export diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp index 5759b20e7..1eca7de93 100644 --- a/src/Bindings/WebPlugin.cpp +++ b/src/Bindings/WebPlugin.cpp @@ -24,75 +24,82 @@ cWebPlugin::cWebPlugin() cWebPlugin::~cWebPlugin() { + ASSERT(m_Tabs.empty()); // Has ClearTabs() been called? + + // Remove from WebAdmin: cWebAdmin * WebAdmin = cRoot::Get()->GetWebAdmin(); if (WebAdmin != nullptr) { WebAdmin->RemovePlugin(this); } +} + + + - for (TabList::iterator itr = m_Tabs.begin(); itr != m_Tabs.end(); ++itr) + +cWebPlugin::cTabNames cWebPlugin::GetTabNames(void) const +{ + std::list< std::pair<AString, AString>> NameList; + for (auto itr = m_Tabs.cbegin(), end = m_Tabs.cend(); itr != end; ++itr) { - delete *itr; + NameList.push_back(std::make_pair((*itr)->m_Title, (*itr)->m_SafeTitle)); } - m_Tabs.clear(); + return NameList; } -std::list<std::pair<AString, AString> > cWebPlugin::GetTabNames(void) +cWebPlugin::cTabPtr cWebPlugin::GetTabBySafeTitle(const AString & a_SafeTitle) const { - std::list< std::pair< AString, AString > > NameList; - for (TabList::iterator itr = GetTabs().begin(); itr != GetTabs().end(); ++itr) + cCSLock Lock(m_CSTabs); + for (auto itr = m_Tabs.cbegin(), end = m_Tabs.cend(); itr != end; ++itr) { - std::pair< AString, AString > StringPair; - StringPair.first = (*itr)->Title; - StringPair.second = (*itr)->SafeTitle; - NameList.push_back( StringPair); + if ((*itr)->m_SafeTitle == a_SafeTitle) + { + return *itr; + } } - return NameList; + return nullptr; } -std::pair< AString, AString > cWebPlugin::GetTabNameForRequest(const HTTPRequest * a_Request) +std::pair<AString, AString> cWebPlugin::GetTabNameForRequest(const HTTPRequest & a_Request) { - std::pair< AString, AString > Names; - AStringVector Split = StringSplit(a_Request->Path, "/"); + AStringVector Split = StringSplit(a_Request.Path, "/"); + if (Split.empty()) + { + return std::make_pair(AString(), AString()); + } - if (Split.size() > 1) + cCSLock Lock(m_CSTabs); + cTabPtr Tab; + if (Split.size() > 2) // If we got the tab name, show that page { - sWebPluginTab * Tab = nullptr; - if (Split.size() > 2) // If we got the tab name, show that page + for (auto itr = m_Tabs.cbegin(), end = m_Tabs.cend(); itr != end; ++itr) { - for (TabList::iterator itr = GetTabs().begin(); itr != GetTabs().end(); ++itr) + if ((*itr)->m_SafeTitle.compare(Split[2]) == 0) // This is the one! { - if ((*itr)->SafeTitle.compare(Split[2]) == 0) // This is the one! - { - Tab = *itr; - break; - } - } - } - else // Otherwise show the first tab - { - if (GetTabs().size() > 0) - { - Tab = *GetTabs().begin(); + return std::make_pair((*itr)->m_Title, (*itr)->m_SafeTitle); } } + // Tab name not found, display an "empty" page: + return std::make_pair(AString(), AString()); + } - if (Tab != nullptr) - { - Names.first = Tab->Title; - Names.second = Tab->SafeTitle; - } + // Show the first tab: + if (!m_Tabs.empty()) + { + return std::make_pair(m_Tabs.front()->m_SafeTitle, m_Tabs.front()->m_SafeTitle); } - return Names; + // No tabs at all: + return std::make_pair(AString(), AString()); } @@ -101,14 +108,16 @@ std::pair< AString, AString > cWebPlugin::GetTabNameForRequest(const HTTPRequest AString cWebPlugin::SafeString(const AString & a_String) { AString RetVal; - for (unsigned int i = 0; i < a_String.size(); ++i) + auto len = a_String.size(); + RetVal.reserve(len); + for (size_t i = 0; i < len; ++i) { char c = a_String[i]; if (c == ' ') { c = '_'; } - RetVal.push_back( c); + RetVal.push_back(c); } return RetVal; } @@ -116,3 +125,28 @@ AString cWebPlugin::SafeString(const AString & a_String) + +void cWebPlugin::AddNewWebTab(const AString & a_Title, int a_UserData) +{ + auto Tab = std::make_shared<cTab>(a_Title, a_UserData); + cCSLock Lock(m_CSTabs); + m_Tabs.push_back(Tab); +} + + + + + +void cWebPlugin::ClearTabs(void) +{ + // Remove the webadmin tabs: + cTabPtrs Tabs; + { + cCSLock Lock(m_CSTabs); + std::swap(Tabs, m_Tabs); + } +} + + + + diff --git a/src/Bindings/WebPlugin.h b/src/Bindings/WebPlugin.h index 9b825b918..ade4f4359 100644 --- a/src/Bindings/WebPlugin.h +++ b/src/Bindings/WebPlugin.h @@ -12,34 +12,67 @@ class cWebPlugin { public: // tolua_end + + struct cTab + { + AString m_Title; + AString m_SafeTitle; + int m_UserData; + + cTab(const AString & a_Title, int a_UserData): + m_Title(a_Title), + m_SafeTitle(cWebPlugin::SafeString(a_Title)), + m_UserData(a_UserData) + { + } + }; + + typedef SharedPtr<cTab> cTabPtr; + typedef std::list<cTabPtr> cTabPtrs; + typedef std::list<std::pair<AString, AString>> cTabNames; + + cWebPlugin(); + virtual ~cWebPlugin(); // tolua_begin + + /** Returns the title of the plugin, as it should be presented in the webadmin's pages tree. */ virtual const AString GetWebTitle(void) const = 0; - virtual AString HandleWebRequest(const HTTPRequest * a_Request) = 0; + /** Sanitizes the input string, replacing spaces with underscores. */ + static AString SafeString(const AString & a_String); - static AString SafeString( const AString & a_String); // tolua_end - struct sWebPluginTab - { - std::string Title; - std::string SafeTitle; + virtual AString HandleWebRequest(const HTTPRequest & a_Request) = 0; - int UserData; - }; + /** Adds a new web tab with the specified contents. */ + void AddNewWebTab(const AString & a_Title, int a_UserData); + + /** Removes all the tabs. */ + void ClearTabs(void); - typedef std::list< sWebPluginTab* > TabList; - TabList & GetTabs() { return m_Tabs; } + /** Returns all the tabs that this plugin has registered. */ + const cTabPtrs & GetTabs(void) const { return m_Tabs; } - typedef std::list< std::pair<AString, AString> > TabNameList; - TabNameList GetTabNames(); // >> EXPORTED IN MANUALBINDINGS << - std::pair< AString, AString > GetTabNameForRequest(const HTTPRequest* a_Request); + /** Returns all of the tabs that this plugin has registered. */ + cTabNames GetTabNames(void) const; // Exported in ManualBindings.cpp + + /** Returns the tab that has the specified SafeTitle. + Returns nullptr if no such tab. */ + cTabPtr GetTabBySafeTitle(const AString & a_SafeTitle) const; + + std::pair<AString, AString> GetTabNameForRequest(const HTTPRequest & a_Request); private: - TabList m_Tabs; + /** All tabs that this plugin has registered. + Protected against multithreaded access by m_CSTabs. */ + cTabPtrs m_Tabs; + + /** Protects m_Tabs against multithreaded access. */ + mutable cCriticalSection m_CSTabs; }; // tolua_export diff --git a/src/Bindings/virtual_method_hooks.lua b/src/Bindings/virtual_method_hooks.lua deleted file mode 100644 index a52728ff8..000000000 --- a/src/Bindings/virtual_method_hooks.lua +++ /dev/null @@ -1,518 +0,0 @@ --- flags -local disable_virtual_hooks = true -local enable_pure_virtual = true -local default_private_access = false - - - - - -local access = {public = 0, protected = 1, private = 2} - -function preparse_hook(p) - - if default_private_access then - -- we need to make all structs 'public' by default - p.code = string.gsub(p.code, "(struct[^;]*{)", "%1\npublic:\n") - end -end - - -function parser_hook(s) - - local container = classContainer.curr -- get the current container - - if default_private_access then - if not container.curr_member_access and container.classtype == 'class' then - -- default access for classes is private - container.curr_member_access = access.private - end - end - - -- try labels (public, private, etc) - do - local b,e,label = string.find(s, "^%s*(%w*)%s*:[^:]") -- we need to check for [^:], otherwise it would match 'namespace::type' - if b then - - -- found a label, get the new access value from the global 'access' table - if access[label] then - container.curr_member_access = access[label] - end -- else ? - - return strsub(s, e) -- normally we would use 'e+1', but we need to preserve the [^:] - end - end - - - local ret = nil - - if disable_virtual_hooks then - - return ret - end - - local b,e,decl,arg = string.find(s, "^%s*virtual%s+([^%({~]+)(%b())") - local const - if b then - local ret = string.sub(s, e+1) - if string.find(ret, "^%s*const") then - const = "const" - ret = string.gsub(ret, "^%s*const", "") - end - local purev = false - if string.find(ret, "^%s*=%s*0") then - purev = true - ret = string.gsub(ret, "^%s*=%s*0", "") - end - ret = string.gsub(ret, "^%s*%b{}", "") - - local func = Function(decl, arg, const) - func.pure_virtual = purev - --func.access = access - func.original_sig = decl - - local curflags = classContainer.curr.flags - if not curflags.virtual_class then - - curflags.virtual_class = VirtualClass() - end - curflags.virtual_class:add(func) - curflags.pure_virtual = curflags.pure_virtual or purev - - return ret - end - - return ret -end - - --- class VirtualClass -classVirtualClass = { - classtype = 'class', - name = '', - base = '', - type = '', - btype = '', - ctype = '', -} -classVirtualClass.__index = classVirtualClass -setmetatable(classVirtualClass,classClass) - -function classVirtualClass:add(f) - - local parent = classContainer.curr - pop() - - table.insert(self.methods, {f=f}) - - local name,sig - - -- doble negative means positive - if f.name == 'new' and ((not self.flags.parent_object.flags.pure_virtual) or (enable_pure_virtual)) then - - name = self.original_name - elseif f.name == 'delete' then - name = '~'..self.original_name - else - if f.access ~= 2 and (not f.pure_virtual) and f.name ~= 'new' and f.name ~= 'delete' then - name = f.mod.." "..f.type..f.ptr.." "..self.flags.parent_object.lname.."__"..f.name - end - end - - if name then - sig = name..self:get_arg_list(f, true)..";\n" - push(self) - sig = preprocess(sig) - self:parse(sig) - pop() - end - - push(parent) -end - -function preprocess(sig) - - sig = gsub(sig,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*' - sig = gsub(sig,"([^%w_])void%s*%*","%1_userdata ") -- substitute 'void*' - sig = gsub(sig,"([^%w_])char%s*%*","%1_cstring ") -- substitute 'char*' - sig = gsub(sig,"([^%w_])lua_State%s*%*","%1_lstate ") -- substitute 'lua_State*' - - return sig -end - -function classVirtualClass:get_arg_list(f, decl) - - local ret = "" - local sep = "" - local i=1 - while f.args[i] do - - local arg = f.args[i] - if decl then - local ptr - if arg.ret ~= '' then - ptr = arg.ret - else - ptr = arg.ptr - end - local def = "" - if arg.def and arg.def ~= "" then - - def = " = "..arg.def - end - ret = ret..sep..arg.mod.." "..arg.type..ptr.." "..arg.name..def - else - ret = ret..sep..arg.name - end - - sep = "," - i = i+1 - end - - return "("..ret..")" -end - -function classVirtualClass:add_parent_virtual_methods(parent) - - parent = parent or _global_classes[self.flags.parent_object.btype] - - if not parent then return end - - if parent.flags.virtual_class then - - local vclass = parent.flags.virtual_class - for k,v in ipairs(vclass.methods) do - if v.f.name ~= 'new' and v.f.name ~= 'delete' and (not self:has_method(v.f)) then - table.insert(self.methods, {f=v.f}) - end - end - end - - parent = _global_classes[parent.btype] - if parent then - self:add_parent_virtual_methods(parent) - end -end - -function classVirtualClass:has_method(f) - - for k,v in pairs(self.methods) do - -- just match name for now - if v.f.name == f.name then - return true - end - end - - return false -end - -function classVirtualClass:add_constructors() - - local i=1 - while self.flags.parent_object[i] do - - local v = self.flags.parent_object[i] - if getmetatable(v) == classFunction and (v.name == 'new' or v.name == 'delete') then - - self:add(v) - end - - i = i+1 - end - -end - ---[[ -function classVirtualClass:requirecollection(t) - - self:add_constructors() - local req = classClass.requirecollection(self, t) - if req then - output('class ',self.name,";") - end - return req -end ---]] - -function classVirtualClass:supcode() - - -- pure virtual classes can have no default constructors on gcc 4 - - if self.flags.parent_object.flags.pure_virtual and not enable_pure_virtual then - output('#if (__GNUC__ == 4) || (__GNUC__ > 4 ) // I hope this works on Microsoft Visual studio .net server 2003 XP Compiler\n') - end - - local ns - if self.prox.classtype == 'namespace' then - output('namespace ',self.prox.name, " {") - ns = true - end - - output("class "..self.original_name.." : public "..self.btype..", public ToluaBase {") - - output("public:\n") - - self:add_parent_virtual_methods() - - self:output_methods(self.btype) - self:output_parent_methods() - - self:add_constructors() - - -- no constructor for pure virtual classes - if (not self.flags.parent_object.flags.pure_virtual) or enable_pure_virtual then - - self:output_constructors() - end - - output("};\n\n") - - if ns then - output("};") - end - - classClass.supcode(self) - - if self.flags.parent_object.flags.pure_virtual and not enable_pure_virtual then - output('#endif // __GNUC__ >= 4\n') - end - - -- output collector for custom class if required - if self:requirecollection(_collect) and _collect[self.type] then - - output('\n') - output('/* function to release collected object via destructor */') - output('#ifdef __cplusplus\n') - --for i,v in pairs(collect) do - i,v = self.type, _collect[self.type] - output('\nstatic int '..v..' (lua_State* tolua_S)') - output('{') - output(' '..i..'* self = ('..i..'*) tolua_tousertype(tolua_S,1,0);') - output(' delete self;') - output(' return 0;') - output('}') - --end - output('#endif\n\n') - end - -end - -function classVirtualClass:register(pre) - - -- pure virtual classes can have no default constructors on gcc 4 - if self.flags.parent_object.flags.pure_virtual and not enable_pure_virtual then - output('#if (__GNUC__ == 4) || (__GNUC__ > 4 )\n') - end - - classClass.register(self, pre) - - if self.flags.parent_object.flags.pure_virtual and not enable_pure_virtual then - output('#endif // __GNUC__ >= 4\n') - end -end - - ---function classVirtualClass:requirecollection(_c) --- if self.flags.parent_object.flags.pure_virtual then --- return false --- end --- return classClass.requirecollection(self, _c) ---end - -function classVirtualClass:output_parent_methods() - - for k,v in ipairs(self.methods) do - - if v.f.access ~= 2 and (not v.f.pure_virtual) and v.f.name ~= 'new' and v.f.name ~= 'delete' then - - local rettype = v.f.mod.." "..v.f.type..v.f.ptr.." " - local parent_name = rettype..self.btype.."__"..v.f.name - - local par_list = self:get_arg_list(v.f, true) - local var_list = self:get_arg_list(v.f, false) - - -- the parent's virtual function - output("\t"..parent_name..par_list.." {") - - output("\t\treturn (",rettype,")"..self.btype.."::"..v.f.name..var_list..";") - output("\t};") - end - end -end - -function classVirtualClass:output_methods(btype) - - for k,v in ipairs(self.methods) do - - if v.f.name ~= 'new' and v.f.name ~= 'delete' then - - self:output_method(v.f, btype) - end - end - output("\n") -end - -function classVirtualClass:output_constructors() - - for k,v in ipairs(self.methods) do - - if v.f.name == 'new' then - - local par_list = self:get_arg_list(v.f, true) - local var_list = self:get_arg_list(v.f, false) - - output("\t",self.original_name,par_list,":",self.btype,var_list,"{};") - end - end -end - -function classVirtualClass:output_method(f, btype) - - if f.access == 2 then -- private - return - end - - local ptr - if f.ret ~= '' then - ptr = f.ret - else - ptr = f.ptr - end - - local rettype = f.mod.." "..f.type..f.ptr.." " - local par_list = self:get_arg_list(f, true) - local var_list = self:get_arg_list(f, false) - - if string.find(rettype, "%s*LuaQtGenericFlags%s*") then - - _,_,rettype = string.find(f.original_sig, "^%s*([^%s]+)%s+") - end - - -- the caller of the lua method - output("\t"..rettype.." "..f.name..par_list..f.const.." {") - local fn = f.cname - if f.access == 1 then - fn = "NULL" - end - output('\t\tif (push_method("',f.lname,'", ',fn,')) {') - - --if f.type ~= 'void' then - -- output("\t\t\tint top = lua_gettop(lua_state)-1;") - --end - - -- push the parameters - local argn = 0 - for i,arg in ipairs(f.args) do - if arg.type ~= 'void' then - local t,ct = isbasic(arg.type) - if t and t ~= '' then - if arg.ret == "*" then - t = 'userdata' - ct = 'void*' - end - output("\t\t\ttolua_push"..t.."(lua_state, ("..ct..")"..arg.name..");"); - else - local m = arg.ptr - if m and m~= "" then - if m == "*" then m = "" end - output("\t\t\ttolua_pushusertype(lua_state, (void*)"..m..arg.name..", \""..arg.type.."\");") - else - output("\t\t\tvoid* tolua_obj" .. argn .." = (void*)new "..arg.type.."("..arg.name..");\n") - output('\t\t\ttolua_pushusertype_and_takeownership(lua_state, tolua_obj' .. argn .. ', "'..arg.type..'");\n') - end - end - argn = argn+1 - end - end - - -- call the function - output("\t\t\tToluaBase::dbcall(lua_state, ",argn+1,", ") - - -- return value - if f.type ~= 'void' then - output("1);") - - local t,ct = isbasic(f.type) - if t and t ~= '' then - --output("\t\t\treturn ("..rettype..")tolua_to"..t.."(lua_state, top, 0);") - output("\t\t\t",rettype,"tolua_ret = ("..rettype..")tolua_to"..t.."(lua_state, -1, 0);") - else - - local mod = "" - if f.ptr ~= "*" then - mod = "*("..f.type.."*)" - end - - --output("\t\t\treturn ("..rettype..")"..mod.."tolua_tousertype(lua_state, top, 0);") - output("\t\t\t",rettype,"tolua_ret = ("..rettype..")"..mod.."tolua_tousertype(lua_state, -1, 0);") - end - output("\t\t\tlua_pop(lua_state, 1);") - output("\t\t\treturn tolua_ret;") - else - output("0);") - end - - -- handle non-implemeted function - output("\t\t} else {") - - if f.pure_virtual then - - output('\t\t\tif (lua_state)') - --output('\t\t\t\ttolua_error(lua_state, "pure-virtual method '..btype.."::"..f.name..' not implemented.", NULL);') - output('\t\t\t\tLOG("pure-virtual method '..btype.."::"..f.name..' not implemented.");') - output('\t\t\telse {') - output('\t\t\t\tLOG("pure-virtual method '..btype.."::"..f.name..' called with no lua_state. Aborting");') - output('\t\t\t\t::abort();') - output('\t\t\t};') - if( rettype == " std::string " ) then - output('\t\t\treturn "";') - else - output('\t\t\treturn (',rettype,')0;') - end - else - - output('\t\t\treturn (',rettype,')',btype,'::',f.name,var_list,';') - end - - output("\t\t};") - - output("\t};") -end - -function VirtualClass() - - local parent = classContainer.curr - pop() - - local name = "Lua__"..parent.original_name - - local c = _Class(_Container{name=name, base=parent.name, extra_bases=nil}) - setmetatable(c, classVirtualClass) - - local ft = getnamespace(c.parent)..c.original_name - append_global_type(ft, c) - - push(parent) - - c.flags.parent_object = parent - c.methods = {} - - push(c) - c:parse("\nvoid tolua__set_instance(_lstate L, lua_Object lo);\n") - pop() - - return c -end - - - - - - -function post_output_hook() - print("Bindings have been generated.") -end - - - - |