From 019c8b5bc71708e2d895a95757643406f75b4149 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Fri, 1 Feb 2013 19:55:42 +0000 Subject: Moved command API into cPluginManager. As specified in http://forum.mc-server.org/showthread.php?tid=765 , commands are now bound using a single function, cPluginManager:BindCommand(). git-svn-id: http://mc-server.googlecode.com/svn/trunk@1183 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- MCServer/Plugins/Core/help.lua | 76 +++---- MCServer/Plugins/Core/main.lua | 75 +++---- MCServer/Plugins/Core/regeneratechunk.lua | 24 +-- VC2008/MCServer.vcproj | 8 - source/Bindings.cpp | 204 +++++++----------- source/Bindings.h | 2 +- source/LuaCommandBinder.cpp | 154 -------------- source/LuaCommandBinder.h | 42 ---- source/ManualBindings.cpp | 142 +++++++++++-- source/Plugin.cpp | 37 ++-- source/Plugin.h | 24 +-- source/PluginManager.cpp | 332 ++++++++++++++++++------------ source/PluginManager.h | 97 +++++---- source/Plugin_NewLua.cpp | 117 ++++++++++- source/Plugin_NewLua.h | 22 +- 15 files changed, 677 insertions(+), 679 deletions(-) delete mode 100644 source/LuaCommandBinder.cpp delete mode 100644 source/LuaCommandBinder.h diff --git a/MCServer/Plugins/Core/help.lua b/MCServer/Plugins/Core/help.lua index 800a65924..68cdeca66 100644 --- a/MCServer/Plugins/Core/help.lua +++ b/MCServer/Plugins/Core/help.lua @@ -1,56 +1,40 @@ -function HandleHelpCommand( Split, Player ) +function HandleHelpCommand(Split, Player) local PluginManager = cRoot:Get():GetPluginManager() - local LinesPerPage = 9 - local CurrentPage = 1 - local CurrentLine = 0 + local LinesPerPage = 9; + local CurrentPage = 1; + local CurrentLine = 0; + local PageRequested = 1; + local Output = {}; - if( #Split == 2 ) then - CurrentPage = tonumber(Split[2]) + if (#Split == 2) then + PageRequested = tonumber(Split[2]); end - local Pages = {} + local Process = function(Command, Permission, HelpString) + if not(Player:HasPermission(Permission)) then + return false; + end; + if (HelpString == "") then + return false; + end; - local PluginList = PluginManager:GetAllPlugins() - for k, Plugin in pairs(PluginList) do - if( Plugin ) then - local Commands = Plugin:GetCommands() - for i, v in ipairs( Commands ) do - if( Player:HasPermission( v.Permission ) ) then - local PageNum = math.floor( CurrentLine/LinesPerPage )+1 - if( Pages[ PageNum ] == nil ) then Pages[ PageNum ] = {} end -- Create page - - if( Pages[ PageNum ].ShownName ~= Plugin:GetName() and SHOW_PLUGIN_NAMES == true ) then - if( CurrentLine == LinesPerPage * PageNum -1 ) then -- Don't add if it's the last line of the page, it looks silly - -- Add it to the next page instead - CurrentLine = CurrentLine+1 - PageNum = math.floor( CurrentLine/LinesPerPage )+1 - - if( Pages[ PageNum ] == nil ) then Pages[ PageNum ] = {} end -- Create page - table.insert( Pages[ PageNum ], cChatColor.Gold .. Plugin:GetName() ) - else - Pages[ PageNum ].ShownName = Plugin:GetName() - table.insert( Pages[ PageNum ], cChatColor.Gold .. Plugin:GetName() ) - end - CurrentLine = CurrentLine+1 - PageNum = math.floor( CurrentLine/LinesPerPage )+1 - if( Pages[ PageNum ] == nil ) then Pages[ PageNum ] = {} end -- Create page - end - local Message = cChatColor.Blue .. v.Command .. v.Description; - table.insert( Pages[ PageNum ], Message ) - CurrentLine = CurrentLine+1 - end - end - end - end - - Player:SendMessage( cChatColor.Purple .. "- All commands - " .. cChatColor.Gold .. "[Page " .. (CurrentPage) .."/"..#Pages.."]" ) - - if( Pages[CurrentPage] ~= nil ) then - for i, v in ipairs(Pages[CurrentPage]) do - Player:SendMessage( v ) - end + CurrentLine = CurrentLine + 1; + CurrentPage = math.floor(CurrentLine / LinesPerPage) + 1; + if (CurrentPage ~= PageRequested) then + return false; + end; + table.insert(Output, cChatColor.Blue .. Command .. HelpString); end + + PluginManager:ForEachCommand(Process); + + -- CurrentPage now contains the total number of pages, and Output has the individual help lines to be sent + + Player:SendMessage(cChatColor.Purple .. "- All commands - " .. cChatColor.Gold .. "[Page " .. PageRequested .. " / " .. CurrentPage .. "]"); + for idx, msg in ipairs(Output) do + Player:SendMessage(msg); + end; return true end \ No newline at end of file diff --git a/MCServer/Plugins/Core/main.lua b/MCServer/Plugins/Core/main.lua index 2dfbfb407..4682333fd 100644 --- a/MCServer/Plugins/Core/main.lua +++ b/MCServer/Plugins/Core/main.lua @@ -8,11 +8,15 @@ PLUGIN = {} -- Reference to own plugin object BannedPlayersIni = {} WhiteListIni = {} -function Initialize( Plugin ) + + + + +function Initialize(Plugin) PLUGIN = Plugin - Plugin:SetName( "Core" ) - Plugin:SetVersion(9) + Plugin:SetName("Core") + Plugin:SetVersion(10) PluginManager = cRoot:Get():GetPluginManager() PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_JOINED) @@ -22,50 +26,29 @@ function Initialize( Plugin ) PluginManager:AddHook(Plugin, cPluginManager.HOOK_KILLING) PluginManager:AddHook(Plugin, cPluginManager.HOOK_CRAFTING_NO_RECIPE) PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHAT) -- used in web_chat.lua - - Plugin:AddCommand("/help", " - [Page] Show this message", "core.help") - Plugin:AddCommand("/pluginlist", " - Show list of plugins", "core.pluginlist") - Plugin:AddCommand("/tp", " - [Player] - Teleport yourself to a player", "core.teleport") - Plugin:AddCommand("/item", " - [ItemType/Name] - Give yourself an item", "core.item") - Plugin:AddCommand("/list", " - Shows list of connected players", "core.playerlist") - Plugin:AddCommand("/motd", " - Show message of the day", "core.motd") - Plugin:AddCommand("/reload", " - Reload all plugins", "core.reload") - Plugin:AddCommand("/stop", " - Stops the server", "core.stop") - Plugin:AddCommand("/time", " - [Day/Night] - Sets the time of day", "core.time") - Plugin:AddCommand("/spawn", " - Return to the spawn", "core.spawn") - Plugin:AddCommand("/kick", " - [Player] - Kick a player", "core.kick") - Plugin:AddCommand("/ban", " - [Player] - Ban a player", "core.ban") - Plugin:AddCommand("/unban", " - [Player] - Unban a player", "core.unban") - Plugin:AddCommand("/top", " - Teleport yourself to the top most block", "core.top") - Plugin:AddCommand("/gm", " - [Gamemode (0|1)] - Change your gamemode", "core.changegm") - Plugin:AddCommand("/gotoworld", " - Move to a different world!", "core.gotoworld") - Plugin:AddCommand("/coords", " - Show your current server coordinates", "core.coords") - Plugin:AddCommand("/viewdistance", " - [".. cClientHandle.MIN_VIEW_DISTANCE .."-".. cClientHandle.MAX_VIEW_DISTANCE .."] - Change your view distance", "core.viewdistance") - Plugin:AddCommand("/regeneratechunk", " - - Regenerates a chunk", "core.regeneratechunk") - - Plugin:BindCommand( "/help", "core.help", HandleHelpCommand ) - Plugin:BindCommand( "/pluginlist", "core.pluginlist", HandlePluginListCommand ) - Plugin:BindCommand( "/tp", "core.teleport", HandleTPCommand ) - Plugin:BindCommand( "/item", "core.item", HandleItemCommand ) - Plugin:BindCommand( "/i", "core.item", HandleItemCommand ) - Plugin:BindCommand( "/list", "core.playerlist", HandlePlayerListCommand ) - Plugin:BindCommand( "/who", "core.playerlist", HandlePlayerListCommand ) - Plugin:BindCommand( "/playerlist", "core.playerlist", HandlePlayerListCommand ) - Plugin:BindCommand( "/motd", "core.motd", HandleMOTDCommand ) - Plugin:BindCommand( "/reload", "core.reload", HandleReloadCommand ) - Plugin:BindCommand( "/stop", "core.stop", HandleStopCommand ) - Plugin:BindCommand( "/time", "core.time", HandleTimeCommand ) - Plugin:BindCommand( "/spawn", "core.spawn", HandleSpawnCommand ) - Plugin:BindCommand( "/kick", "core.kick", HandleKickCommand ) - Plugin:BindCommand( "/ban", "core.ban", HandleBanCommand ) - Plugin:BindCommand( "/unban", "core.unban", HandleUnbanCommand ) - Plugin:BindCommand( "/top", "core.top", HandleTopCommand ) - Plugin:BindCommand( "/gm", "core.changegm", HandleChangeGMCommand ) - Plugin:BindCommand( "/gotoworld", "core.gotoworld", HandleGotoWorldCommand ) - Plugin:BindCommand( "/coords", "core.coords", HandleCoordsCommand ) - Plugin:BindCommand( "/viewdistance", "core.viewdistance", HandleViewDistanceCommand ) - Plugin:BindCommand( "/regeneratechunk", "core.regeneratechunk", HandleRegenerateChunkCommand ) + PluginManager:BindCommand("/help", "core.help", HandleHelpCommand, " [Page] - Show available commands"); + PluginManager:BindCommand("/pluginlist", "core.pluginlist", HandlePluginListCommand, " - Show list of plugins"); + PluginManager:BindCommand("/tp", "core.teleport", HandleTPCommand, " [Player] - Teleport yourself to a player"); + PluginManager:BindCommand("/item", "core.item", HandleItemCommand, " [ItemType/Name] - Give yourself an item"); + PluginManager:BindCommand("/list", "core.playerlist", HandlePlayerListCommand, " - Shows list of connected players"); + PluginManager:BindCommand("/who", "core.playerlist", HandlePlayerListCommand, " - Shows list of connected players"); + PluginManager:BindCommand("/playerlist", "core.playerlist", HandlePlayerListCommand, " - Shows list of connected players"); + PluginManager:BindCommand("/motd", "core.motd", HandleMOTDCommand, " - Show message of the day"); + PluginManager:BindCommand("/reload", "core.reload", HandleReloadCommand, " - Reload all plugins"); + PluginManager:BindCommand("/stop", "core.stop", HandleStopCommand, " - Stops the server"); + PluginManager:BindCommand("/time", "core.time", HandleTimeCommand, " [Day/Night] - Sets the time of day"); + PluginManager:BindCommand("/spawn", "core.spawn", HandleSpawnCommand, " - Return to the spawn"); + PluginManager:BindCommand("/kick", "core.kick", HandleKickCommand, " [Player] - Kick a player"); + PluginManager:BindCommand("/ban", "core.ban", HandleBanCommand, " [Player] - Ban a player"); + PluginManager:BindCommand("/unban", "core.unban", HandleUnbanCommand, " [Player] - Unban a player"); + PluginManager:BindCommand("/top", "core.top", HandleTopCommand, " - Teleport yourself to the top most block"); + PluginManager:BindCommand("/gm", "core.changegm", HandleChangeGMCommand, " [0|1] - Change your gamemode"); + PluginManager:BindCommand("/gotoworld", "core.gotoworld", HandleGotoWorldCommand, " [WorldName] - Move to a different world!"); + PluginManager:BindCommand("/coords", "core.coords", HandleCoordsCommand, " - Show your current server coordinates"); + PluginManager:BindCommand("/regeneratechunk", "core.regeneratechunk", HandleRegenerateChunkCommand, " <[X] [Z]> - Regenerates a chunk, current or specified"); + PluginManager:BindCommand("/viewdistance", "core.viewdistance", HandleViewDistanceCommand, " [".. cClientHandle.MIN_VIEW_DISTANCE .."-".. cClientHandle.MAX_VIEW_DISTANCE .."] - Change your view distance") + local IniFile = cIniFile("settings.ini") if ( IniFile:ReadFile() == true ) then SHOW_PLUGIN_NAMES = IniFile:GetValueB("HelpPlugin", "ShowPluginNames", true ) diff --git a/MCServer/Plugins/Core/regeneratechunk.lua b/MCServer/Plugins/Core/regeneratechunk.lua index b4b2874fc..7f91f48c1 100644 --- a/MCServer/Plugins/Core/regeneratechunk.lua +++ b/MCServer/Plugins/Core/regeneratechunk.lua @@ -1,18 +1,18 @@ -function HandleRegenerateChunkCommand( Split, Player ) - if( (#Split == 2) or (#Split > 3) ) then - Player:SendMessage( cChatColor.Green .. "Usage: /regeneratechunk " ) - return true +function HandleRegenerateChunkCommand(Split, Player) + if ((#Split == 2) or (#Split > 3)) then + Player:SendMessage( cChatColor.Green .. "Usage: '/regeneratechunk' or '/regeneratechunk [X] [Z]'"); + return true; end - local X = Player:GetChunkX() - local Z = Player:GetChunkZ() + local X = Player:GetChunkX(); + local Z = Player:GetChunkZ(); - if( #Split == 3 ) then - X = Split[2] - Z = Split[3] + if (#Split == 3) then + X = Split[2]; + Z = Split[3]; end - Player:SendMessage(cChatColor.Green .. "Regenerating chunk ["..X..", "..Z.."]") - Player:GetWorld():RegenerateChunk(X, Z) - return true + Player:SendMessage(cChatColor.Green .. "Regenerating chunk ["..X..", "..Z.."]"); + Player:GetWorld():RegenerateChunk(X, Z); + return true; end \ No newline at end of file diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 318f80646..b9d671d0e 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1455,14 +1455,6 @@ RelativePath="..\source\Bindings.h" > - - - - diff --git a/source/Bindings.cpp b/source/Bindings.cpp index c1cba495c..264c036a5 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 01/28/13 17:46:12. +** Generated automatically by tolua++-1.0.92 on 02/01/13 20:11:44. */ #ifndef __cplusplus @@ -154,7 +154,6 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cInventory"); tolua_usertype(tolua_S,"cRoot"); tolua_usertype(tolua_S,"cCraftingGrid"); - tolua_usertype(tolua_S,"cPlugin::CommandStruct"); tolua_usertype(tolua_S,"cPickup"); tolua_usertype(tolua_S,"cItems"); tolua_usertype(tolua_S,"cGroup"); @@ -167,7 +166,7 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"Vector3i"); tolua_usertype(tolua_S,"Lua__cWebPlugin"); tolua_usertype(tolua_S,"Lua__cPawn"); - tolua_usertype(tolua_S,"cStairs"); + tolua_usertype(tolua_S,"cPawn"); tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"Vector3f"); tolua_usertype(tolua_S,"Lua__cTCPLink"); @@ -179,13 +178,13 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cGroupManager"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"Lua__cPickup"); - tolua_usertype(tolua_S,"cWebPlugin"); + tolua_usertype(tolua_S,"Lua__cEntity"); tolua_usertype(tolua_S,"cPluginManager"); - tolua_usertype(tolua_S,"cPlugin"); - tolua_usertype(tolua_S,"HTTPFormData"); + tolua_usertype(tolua_S,"cWebPlugin"); + tolua_usertype(tolua_S,"cServer"); tolua_usertype(tolua_S,"cLadder"); tolua_usertype(tolua_S,"MTRand"); - tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"HTTPFormData"); tolua_usertype(tolua_S,"cIniFile"); tolua_usertype(tolua_S,"cEntity"); tolua_usertype(tolua_S,"HTTPRequest"); @@ -193,10 +192,10 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cPlayer"); tolua_usertype(tolua_S,"cTorch"); tolua_usertype(tolua_S,"cBlockEntityWindowOwner"); - tolua_usertype(tolua_S,"cServer"); + tolua_usertype(tolua_S,"cPlugin"); tolua_usertype(tolua_S,"Lua__cChestEntity"); - tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"Lua__cEntity"); + tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"cStairs"); tolua_usertype(tolua_S,"Vector3d"); } @@ -8782,9 +8781,9 @@ static int tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: GetPluginManager of class cPluginManager */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_GetPluginManager00 -static int tolua_AllToLua_cPluginManager_GetPluginManager00(lua_State* tolua_S) +/* method: Get of class cPluginManager */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_Get00 +static int tolua_AllToLua_cPluginManager_Get00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -8797,14 +8796,14 @@ static int tolua_AllToLua_cPluginManager_GetPluginManager00(lua_State* tolua_S) #endif { { - cPluginManager* tolua_ret = (cPluginManager*) cPluginManager::GetPluginManager(); + cPluginManager* tolua_ret = (cPluginManager*) cPluginManager::Get(); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPluginManager"); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetPluginManager'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'Get'.",&tolua_err); return 0; #endif } @@ -8990,7 +8989,7 @@ static int tolua_AllToLua_cPluginManager_DisablePlugin00(lua_State* tolua_S) #endif { cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0); - AString a_PluginName = ((AString) tolua_tocppstring(tolua_S,2,0)); + const AString a_PluginName = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DisablePlugin'", NULL); #endif @@ -9025,7 +9024,7 @@ static int tolua_AllToLua_cPluginManager_LoadPlugin00(lua_State* tolua_S) #endif { cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0); - AString a_PluginName = ((AString) tolua_tocppstring(tolua_S,2,0)); + const AString a_PluginName = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'LoadPlugin'", NULL); #endif @@ -9044,93 +9043,73 @@ static int tolua_AllToLua_cPluginManager_LoadPlugin00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* get function: Command of class CommandStruct */ -#ifndef TOLUA_DISABLE_tolua_get_cPlugin__CommandStruct_Command -static int tolua_get_cPlugin__CommandStruct_Command(lua_State* tolua_S) +/* method: IsCommandBound of class cPluginManager */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_IsCommandBound00 +static int tolua_AllToLua_cPluginManager_IsCommandBound00(lua_State* tolua_S) { - cPlugin::CommandStruct* self = (cPlugin::CommandStruct*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'Command'",NULL); + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else #endif - tolua_pushcppstring(tolua_S,(const char*)self->Command); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - -/* set function: Command of class CommandStruct */ -#ifndef TOLUA_DISABLE_tolua_set_cPlugin__CommandStruct_Command -static int tolua_set_cPlugin__CommandStruct_Command(lua_State* tolua_S) -{ - cPlugin::CommandStruct* self = (cPlugin::CommandStruct*) tolua_tousertype(tolua_S,1,0); + { + cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0); + const AString a_Command = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'Command'",NULL); - if (!tolua_iscppstring(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in variable assignment.",&tolua_err); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsCommandBound'", NULL); #endif - self->Command = ((AString) tolua_tocppstring(tolua_S,2,0)) -; - return 0; -} -#endif //#ifndef TOLUA_DISABLE - -/* get function: Description of class CommandStruct */ -#ifndef TOLUA_DISABLE_tolua_get_cPlugin__CommandStruct_Description -static int tolua_get_cPlugin__CommandStruct_Description(lua_State* tolua_S) -{ - cPlugin::CommandStruct* self = (cPlugin::CommandStruct*) tolua_tousertype(tolua_S,1,0); + { + bool tolua_ret = (bool) self->IsCommandBound(a_Command); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_Command); + } + } + return 2; #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'Description'",NULL); + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsCommandBound'.",&tolua_err); + return 0; #endif - tolua_pushcppstring(tolua_S,(const char*)self->Description); - return 1; } #endif //#ifndef TOLUA_DISABLE -/* set function: Description of class CommandStruct */ -#ifndef TOLUA_DISABLE_tolua_set_cPlugin__CommandStruct_Description -static int tolua_set_cPlugin__CommandStruct_Description(lua_State* tolua_S) +/* method: GetCommandPermission of class cPluginManager */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_GetCommandPermission00 +static int tolua_AllToLua_cPluginManager_GetCommandPermission00(lua_State* tolua_S) { - cPlugin::CommandStruct* self = (cPlugin::CommandStruct*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'Description'",NULL); - if (!tolua_iscppstring(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in variable assignment.",&tolua_err); + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else #endif - self->Description = ((AString) tolua_tocppstring(tolua_S,2,0)) -; - return 0; -} -#endif //#ifndef TOLUA_DISABLE - -/* get function: Permission of class CommandStruct */ -#ifndef TOLUA_DISABLE_tolua_get_cPlugin__CommandStruct_Permission -static int tolua_get_cPlugin__CommandStruct_Permission(lua_State* tolua_S) -{ - cPlugin::CommandStruct* self = (cPlugin::CommandStruct*) tolua_tousertype(tolua_S,1,0); + { + cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0); + const AString a_Command = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'Permission'",NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetCommandPermission'", NULL); #endif - tolua_pushcppstring(tolua_S,(const char*)self->Permission); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - -/* set function: Permission of class CommandStruct */ -#ifndef TOLUA_DISABLE_tolua_set_cPlugin__CommandStruct_Permission -static int tolua_set_cPlugin__CommandStruct_Permission(lua_State* tolua_S) -{ - cPlugin::CommandStruct* self = (cPlugin::CommandStruct*) tolua_tousertype(tolua_S,1,0); + { + AString tolua_ret = (AString) self->GetCommandPermission(a_Command); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_Command); + } + } + return 2; #ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'Permission'",NULL); - if (!tolua_iscppstring(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in variable assignment.",&tolua_err); -#endif - self->Permission = ((AString) tolua_tocppstring(tolua_S,2,0)) -; + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetCommandPermission'.",&tolua_err); return 0; +#endif } #endif //#ifndef TOLUA_DISABLE @@ -9329,46 +9308,6 @@ static int tolua_AllToLua_cPlugin_GetLocalDirectory00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: AddCommand of class cPlugin */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlugin_AddCommand00 -static int tolua_AllToLua_cPlugin_AddCommand00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cPlugin",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_iscppstring(tolua_S,3,0,&tolua_err) || - !tolua_iscppstring(tolua_S,4,0,&tolua_err) || - !tolua_isnoobj(tolua_S,5,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0); - const AString a_Command = ((const AString) tolua_tocppstring(tolua_S,2,0)); - const AString a_Description = ((const AString) tolua_tocppstring(tolua_S,3,0)); - const AString a_Permission = ((const AString) tolua_tocppstring(tolua_S,4,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddCommand'", NULL); -#endif - { - self->AddCommand(a_Command,a_Description,a_Permission); - tolua_pushcppstring(tolua_S,(const char*)a_Command); - tolua_pushcppstring(tolua_S,(const char*)a_Description); - tolua_pushcppstring(tolua_S,(const char*)a_Permission); - } - } - return 3; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'AddCommand'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* get function: __cWebPlugin__ of class cPlugin_NewLua */ #ifndef TOLUA_DISABLE_tolua_get_cPlugin_NewLua___cWebPlugin__ static int tolua_get_cPlugin_NewLua___cWebPlugin__(lua_State* tolua_S) @@ -21285,7 +21224,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"HOOK_UPDATED_SIGN",cPluginManager::HOOK_UPDATED_SIGN); tolua_constant(tolua_S,"HOOK_UPDATING_SIGN",cPluginManager::HOOK_UPDATING_SIGN); tolua_constant(tolua_S,"HOOK_WEATHER_CHANGED",cPluginManager::HOOK_WEATHER_CHANGED); - tolua_function(tolua_S,"GetPluginManager",tolua_AllToLua_cPluginManager_GetPluginManager00); + tolua_function(tolua_S,"Get",tolua_AllToLua_cPluginManager_Get00); tolua_function(tolua_S,"GetPlugin",tolua_AllToLua_cPluginManager_GetPlugin00); tolua_function(tolua_S,"FindPlugins",tolua_AllToLua_cPluginManager_FindPlugins00); tolua_function(tolua_S,"ReloadPlugins",tolua_AllToLua_cPluginManager_ReloadPlugins00); @@ -21293,22 +21232,17 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetNumPlugins",tolua_AllToLua_cPluginManager_GetNumPlugins00); tolua_function(tolua_S,"DisablePlugin",tolua_AllToLua_cPluginManager_DisablePlugin00); tolua_function(tolua_S,"LoadPlugin",tolua_AllToLua_cPluginManager_LoadPlugin00); + tolua_function(tolua_S,"IsCommandBound",tolua_AllToLua_cPluginManager_IsCommandBound00); + tolua_function(tolua_S,"GetCommandPermission",tolua_AllToLua_cPluginManager_GetCommandPermission00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cPlugin","cPlugin","",NULL); tolua_beginmodule(tolua_S,"cPlugin"); - tolua_cclass(tolua_S,"CommandStruct","cPlugin::CommandStruct","",NULL); - tolua_beginmodule(tolua_S,"CommandStruct"); - tolua_variable(tolua_S,"Command",tolua_get_cPlugin__CommandStruct_Command,tolua_set_cPlugin__CommandStruct_Command); - tolua_variable(tolua_S,"Description",tolua_get_cPlugin__CommandStruct_Description,tolua_set_cPlugin__CommandStruct_Description); - tolua_variable(tolua_S,"Permission",tolua_get_cPlugin__CommandStruct_Permission,tolua_set_cPlugin__CommandStruct_Permission); - tolua_endmodule(tolua_S); tolua_function(tolua_S,"GetName",tolua_AllToLua_cPlugin_GetName00); tolua_function(tolua_S,"SetName",tolua_AllToLua_cPlugin_SetName00); tolua_function(tolua_S,"GetVersion",tolua_AllToLua_cPlugin_GetVersion00); tolua_function(tolua_S,"SetVersion",tolua_AllToLua_cPlugin_SetVersion00); tolua_function(tolua_S,"GetDirectory",tolua_AllToLua_cPlugin_GetDirectory00); tolua_function(tolua_S,"GetLocalDirectory",tolua_AllToLua_cPlugin_GetLocalDirectory00); - tolua_function(tolua_S,"AddCommand",tolua_AllToLua_cPlugin_AddCommand00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cPlugin_NewLua","cPlugin_NewLua","cPlugin",NULL); tolua_beginmodule(tolua_S,"cPlugin_NewLua"); diff --git a/source/Bindings.h b/source/Bindings.h index 3d4cb5c5a..88b970a76 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 01/28/13 17:46:13. +** Generated automatically by tolua++-1.0.92 on 02/01/13 20:11:44. */ /* Exported function */ diff --git a/source/LuaCommandBinder.cpp b/source/LuaCommandBinder.cpp deleted file mode 100644 index 84a379c74..000000000 --- a/source/LuaCommandBinder.cpp +++ /dev/null @@ -1,154 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "LuaCommandBinder.h" -#include "Player.h" -#include "Plugin.h" - -#include "tolua++.h" - - - - - -bool report_errors(lua_State * lua, int status) -{ - if (status == 0) - { - // No error to report - return false; - } - - LOGERROR("LUA: %s", lua_tostring(lua, -1)); - lua_pop(lua, 1); - return true; -} - - - - - -cLuaCommandBinder::cLuaCommandBinder() -{ -} - - - - - -cLuaCommandBinder::~cLuaCommandBinder() -{ -} - - - - - -void cLuaCommandBinder::ClearBindings() -{ - m_BoundCommands.clear(); -} - - - - - -void cLuaCommandBinder::RemoveBindingsForPlugin( cPlugin* a_Plugin ) -{ - for( CommandMap::iterator itr = m_BoundCommands.begin(); itr != m_BoundCommands.end(); ) - { - if( itr->second.Plugin == a_Plugin ) - { - LOGINFO("Unbinding %s ", itr->first.c_str( ) ); - luaL_unref( itr->second.LuaState, LUA_REGISTRYINDEX, itr->second.Reference ); // unreference - CommandMap::iterator eraseme = itr; - ++itr; - m_BoundCommands.erase( eraseme ); - continue; - } - ++itr; - } -} - - - - - -bool cLuaCommandBinder::BindCommand( const std::string & a_Command, const std::string & a_Permission, cPlugin* a_Plugin, lua_State * a_LuaState, int a_FunctionReference ) -{ - if( !a_Plugin->CanBindCommands() ) - { - LOGERROR("ERROR: Trying to bind command \"%s\" to a plugin that is not initialized.", a_Command.c_str() ); - return false; - } - if( m_BoundCommands.find( a_Command ) != m_BoundCommands.end() ) - { - LOGERROR("ERROR: Trying to bind command \"%s\" that has already been bound.", a_Command.c_str() ); - return false; - } - LOGINFO("Binding %s (%s)", a_Command.c_str(), a_Permission.c_str() ); - m_BoundCommands[ a_Command ] = BoundFunction( a_Plugin, a_LuaState, a_FunctionReference, a_Permission ); - return true; -} - - - - - -bool cLuaCommandBinder::HandleCommand( const std::string & a_Command, cPlayer* a_Player ) -{ - AStringVector Split = StringSplit(a_Command, " "); - if (Split.size() == 0) - { - return false; - } - - CommandMap::iterator FoundCommand = m_BoundCommands.find( Split[0] ); - if( FoundCommand != m_BoundCommands.end() ) - { - const BoundFunction & func = FoundCommand->second; - if( func.Permission.size() > 0 ) - { - if( !a_Player->HasPermission( func.Permission.c_str() ) ) - { - return false; - } - } - - - LOGD("1. Stack size: %i", lua_gettop(func.LuaState) ); - lua_rawgeti( func.LuaState, LUA_REGISTRYINDEX, func.Reference); // same as lua_getref() - - // Push the split - LOGD("2. Stack size: %i", lua_gettop(func.LuaState) ); - lua_createtable(func.LuaState, Split.size(), 0); - int newTable = lua_gettop(func.LuaState); - int index = 1; - std::vector::const_iterator iter = Split.begin(); - while(iter != Split.end()) { - tolua_pushstring( func.LuaState, (*iter).c_str() ); - lua_rawseti(func.LuaState, newTable, index); - ++iter; - ++index; - } - LOGD("3. Stack size: %i", lua_gettop(func.LuaState) ); - // Push player - tolua_pushusertype( func.LuaState, a_Player, "cPlayer" ); - LOGD("Calling bound function! :D"); - int s = lua_pcall(func.LuaState, 2, 1, 0); - if( report_errors( func.LuaState, s ) ) - { - LOGERROR("error. Stack size: %i", lua_gettop(func.LuaState) ); - return false; - } - bool RetVal = (tolua_toboolean(func.LuaState, -1, 0) > 0); - lua_pop(func.LuaState, 1); // Pop return value - LOGD("ok. Stack size: %i", lua_gettop(func.LuaState) ); - return RetVal; - } - return false; -} - - - - diff --git a/source/LuaCommandBinder.h b/source/LuaCommandBinder.h deleted file mode 100644 index 768d097f8..000000000 --- a/source/LuaCommandBinder.h +++ /dev/null @@ -1,42 +0,0 @@ - -#pragma once - -struct lua_State; -class cPlugin; -class cPlayer; - - - - - -class cLuaCommandBinder -{ -public: - cLuaCommandBinder(); - ~cLuaCommandBinder(); - - bool HandleCommand( const std::string & a_Command, cPlayer* a_Player ); - - bool BindCommand( const std::string & a_Command, const std::string & a_Permission, cPlugin* a_Plugin, lua_State * a_LuaState, int a_FunctionReference ); - - void ClearBindings(); - void RemoveBindingsForPlugin( cPlugin* a_Plugin ); -private: - struct BoundFunction - { - BoundFunction() : Plugin( 0 ), LuaState( 0 ), Reference( 0 ) {} - BoundFunction( cPlugin* a_Plugin, lua_State * a_LuaState, int a_Reference, const std::string & a_Permission ) : Plugin( a_Plugin ), LuaState( a_LuaState ), Reference( a_Reference ), Permission( a_Permission ) {} - cPlugin* Plugin; - lua_State* LuaState; - int Reference; - std::string Permission; - }; - - typedef std::map< std::string, BoundFunction > CommandMap; - CommandMap m_BoundCommands; -}; - - - - - diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index be4a1cb66..8dc55a54c 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -9,7 +9,6 @@ #include "Plugin.h" #include "Plugin_NewLua.h" #include "PluginManager.h" -#include "LuaCommandBinder.h" #include "Player.h" #include "WebAdmin.h" #include "StringMap.h" @@ -488,24 +487,74 @@ DEFINE_LUA_FOREACHINCHUNK(cWorld, cFurnaceEntity, ForEachFurnaceInChunk, tolua_c -static int tolua_cPlugin_GetCommands(lua_State * tolua_S) +static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) { - cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0); + 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; + } - const std::vector< cPlugin::CommandStruct > & AllCommands = self->GetCommands(); + cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, 0); + if (self == NULL) + { + LOGWARN("Error in function call 'ForEachCommand': Not called on an object instance"); + return 0; + } - lua_createtable(tolua_S, AllCommands.size(), 0); - int newTable = lua_gettop(tolua_S); - int index = 1; - std::vector< cPlugin::CommandStruct >::const_iterator iter = AllCommands.begin(); - while(iter != AllCommands.end()) + if (!lua_isfunction(tolua_S, 2)) { - const cPlugin::CommandStruct & CS = *iter; - tolua_pushusertype( tolua_S, (void*)&CS, "const cPlugin::CommandStruct" ); - lua_rawseti(tolua_S, newTable, index); - ++iter; - ++index; + 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) + { + LOGWARN("Error in function call 'ForEachCommand': Could not get function reference of parameter #1"); + return 0; + } + + class cLuaCallback : public cPluginManager::cCommandEnumCallback + { + public: + cLuaCallback(lua_State * a_LuaState, int a_FuncRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + {} + + private: + virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override + { + 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 (report_errors(LuaState, s)) + { + return true; /* Abort enumeration */ + } + + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean( LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + } 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); + + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal); return 1; } @@ -547,6 +596,64 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State* tolua_S) +static int tolua_cPluginManager_BindCommand(lua_State * L) +{ + // Function signature: cPluginManager:BindCommand(Command, Permission, Function, HelpString) + + // Get the plugin identification out of LuaState: + lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME); + if (!lua_islightuserdata(L, -1)) + { + LOGERROR("cPluginManager:BindCommand() cannot get plugin instance, what have you done to my Lua state? Command-binding aborted."); + } + cPlugin_NewLua * Plugin = (cPlugin_NewLua *)lua_topointer(L, -1); + lua_pop(L, 1); + + // Read the arguments to this API call: + tolua_Error tolua_err; + if ( + !tolua_isusertype (L, 1, "cPluginManager", 0, &tolua_err) || + !tolua_iscppstring(L, 2, 0, &tolua_err) || + !tolua_iscppstring(L, 3, 0, &tolua_err) || + !tolua_iscppstring(L, 5, 0, &tolua_err) || + !tolua_isnoobj (L, 6, &tolua_err) + ) + { + tolua_error(L, "#ferror in function 'BindCommand'.", &tolua_err); + return 0; + } + if (!lua_isfunction(L, 4)) + { + luaL_error(L, "\"BindCommand\" function expects a function as its 3rd parameter. Command-binding aborted."); + return 0; + } + cPluginManager * self = (cPluginManager *)tolua_tousertype(L, 1, 0); + AString Command (tolua_tocppstring(L, 2, "")); + AString Permission(tolua_tocppstring(L, 3, "")); + AString HelpString(tolua_tocppstring(L, 5, "")); + + // Store the function reference: + lua_pop(L, 1); // Pop the help string off the stack + int FnRef = luaL_ref(L, LUA_REGISTRYINDEX); // Store function reference + if (FnRef == LUA_REFNIL) + { + LOGERROR("\"BindCommand\": Cannot create a function reference. Command \"%s\" not bound.", Command); + return 0; + } + + if (!self->BindCommand(Command, Plugin, Permission, HelpString)) + { + // Refused. Possibly already bound. Error message has been given, bail out silently. + return 0; + } + + Plugin->BindCommand(Command, FnRef); + return 0; +} + + + + static int tolua_cPlayer_GetGroups(lua_State* tolua_S) { @@ -598,6 +705,8 @@ static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S) +/* +// TODO: rewrite this for the new API static int tolua_cPlugin_BindCommand(lua_State* tolua_S) { cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0); @@ -651,6 +760,7 @@ static int tolua_cPlugin_BindCommand(lua_State* tolua_S) return 0; } +*/ @@ -927,13 +1037,13 @@ void ManualBindings::Bind( lua_State* tolua_S ) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlugin"); - tolua_function(tolua_S, "GetCommands", tolua_cPlugin_GetCommands); - tolua_function(tolua_S, "BindCommand", tolua_cPlugin_BindCommand); tolua_function(tolua_S, "Call", tolua_cPlugin_Call); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPluginManager"); tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); + tolua_function(tolua_S, "BindCommand", tolua_cPluginManager_BindCommand); + tolua_function(tolua_S, "ForEachCommand", tolua_cPluginManager_ForEachCommand); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlayer"); diff --git a/source/Plugin.cpp b/source/Plugin.cpp index 2b26ae2cb..491acaa5b 100644 --- a/source/Plugin.cpp +++ b/source/Plugin.cpp @@ -10,10 +10,9 @@ cPlugin::cPlugin( const AString & a_PluginDirectory ) - : m_Version( 0 ) - , m_Language( E_CPP ) - , m_bCanBindCommands( false ) - , m_Directory( a_PluginDirectory ) + : m_Version(0) + , m_Language(E_CPP) + , m_Directory(a_PluginDirectory) { } @@ -126,6 +125,17 @@ bool cPlugin::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPlugin::OnHandshake(cClientHandle * a_Client, const AString & a_Username) +{ + UNUSED(a_Client); + UNUSED(a_Username); + return false; +} + + + + + bool cPlugin::OnKilling(cPawn & a_Victim, cEntity * a_Killer) { UNUSED(a_Victim); @@ -464,10 +474,10 @@ bool cPlugin::OnWeatherChanged(cWorld * a_World) -bool cPlugin::OnHandshake(cClientHandle * a_Client, const AString & a_Username) +bool cPlugin::HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) { - UNUSED(a_Client); - UNUSED(a_Username); + UNUSED(a_Split); + UNUSED(a_Player); return false; } @@ -475,19 +485,6 @@ bool cPlugin::OnHandshake(cClientHandle * a_Client, const AString & a_Username) -void cPlugin::AddCommand(const AString & a_Command, const AString & a_Description, const AString & a_Permission) -{ - CommandStruct Command; - Command.Command = a_Command; - Command.Description = a_Description; - Command.Permission = a_Permission; - m_Commands.push_back( Command ); -} - - - - - AString cPlugin::GetLocalDirectory(void) const { return std::string("Plugins/") + m_Directory; diff --git a/source/Plugin.h b/source/Plugin.h index 44d8d29a5..51cdeab68 100644 --- a/source/Plugin.h +++ b/source/Plugin.h @@ -81,6 +81,12 @@ public: virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player); virtual bool OnWeatherChanged (cWorld * a_World); + /// Handles the command split into a_Split, issued by player a_Player. Command permissions have already been checked. + virtual bool HandleCommand(const AStringVector & a_Split, cPlayer * a_Player); + + /// All bound commands are to be removed, do any language-dependent cleanup here + virtual void ClearCommands(void) {} ; + /** Called from cPluginManager::AddHook() to check if the hook can be added. Plugin API providers may check if the plugin is written correctly (has the hook handler function) Returns true if the hook can be added (handler exists) @@ -89,13 +95,6 @@ public: virtual bool CanAddHook(cPluginManager::PluginHook a_Hook) { return false; } // tolua_begin - struct CommandStruct - { - AString Command; - AString Description; - AString Permission; - }; - const AString & GetName(void) const { return m_Name; } void SetName(const AString & a_Name) { m_Name = a_Name; } @@ -104,14 +103,8 @@ public: const AString & GetDirectory(void) const {return m_Directory; } AString GetLocalDirectory(void) const; - - void AddCommand(const AString & a_Command, const AString & a_Description, const AString & a_Permission); // tolua_end - typedef bool (FuncCommandHandler)( AString & a_Command, std::vector< std::string > & a_Split ); - void BindCommand( FuncCommandHandler* a_Function, AString & a_Command ); // >> EXPORTED IN MANUALBINDINGS << - const std::vector< CommandStruct > & GetCommands() const { return m_Commands; } // >> EXPORTED IN MANUALBINDINGS << - /* This should not be exposed to scripting languages */ enum PluginLanguage @@ -123,13 +116,8 @@ public: PluginLanguage GetLanguage() { return m_Language; } void SetLanguage( PluginLanguage a_Language ) { m_Language = a_Language; } - bool CanBindCommands() { return m_bCanBindCommands; } private: - friend class cPluginManager; - bool m_bCanBindCommands; // Only changed by cPluginManager - PluginLanguage m_Language; - std::vector< CommandStruct > m_Commands; AString m_Name; int m_Version; diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index 921955ba4..ef7c9f3b3 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "PluginManager.h" @@ -6,32 +7,17 @@ #include "WebAdmin.h" #include "Item.h" #include "Root.h" -#include "LuaCommandBinder.h" - -#ifdef USE_SQUIRREL - #include "Plugin_Squirrel.h" - #include "SquirrelCommandBinder.h" -#endif #include "../iniFile/iniFile.h" #include "tolua++.h" #include "Player.h" -#ifdef USE_SQUIRREL - #include "squirrelbindings/SquirrelBindings.h" - #include "squirrelbindings/SquirrelFunctions.h" - #pragma warning(disable:4100;disable:4127;disable:4510;disable:4610;disable:4244;disable:4512) // Getting A LOT of these warnings from SqPlus - - #pragma warning(default:4100;default:4127;default:4510;default:4610;default:4244;default:4512) -#endif - -cPluginManager* cPluginManager::GetPluginManager() +cPluginManager * cPluginManager::Get(void) { - LOGWARN("WARNING: Using deprecated function cPluginManager::GetPluginManager() use cRoot::Get()->GetPluginManager() instead!"); return cRoot::Get()->GetPluginManager(); } @@ -39,12 +25,8 @@ cPluginManager* cPluginManager::GetPluginManager() -cPluginManager::cPluginManager() - : m_LuaCommandBinder( new cLuaCommandBinder() ) -#ifdef USE_SQUIRREL - , m_SquirrelCommandBinder( new cSquirrelCommandBinder() ) -#endif - , m_bReloadPlugins(false) +cPluginManager::cPluginManager(void) : + m_bReloadPlugins(false) { } @@ -55,18 +37,13 @@ cPluginManager::cPluginManager() cPluginManager::~cPluginManager() { UnloadPluginsNow(); - - delete m_LuaCommandBinder; -#ifdef USE_SQUIRREL - delete m_SquirrelCommandBinder; -#endif } -void cPluginManager::ReloadPlugins() +void cPluginManager::ReloadPlugins(void) { m_bReloadPlugins = true; } @@ -75,12 +52,12 @@ void cPluginManager::ReloadPlugins() -void cPluginManager::FindPlugins() +void cPluginManager::FindPlugins(void) { AString PluginsPath = FILE_IO_PREFIX + AString( "Plugins/" ); // 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(); ) + for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) { if( itr->second == NULL ) { @@ -103,7 +80,7 @@ void cPluginManager::FindPlugins() } // Add plugin name/directory to the list - if( m_Plugins.find( *itr ) == m_Plugins.end() ) + if (m_Plugins.find( *itr ) == m_Plugins.end()) { m_Plugins[ *itr ] = NULL; } @@ -114,71 +91,51 @@ void cPluginManager::FindPlugins() -void cPluginManager::ReloadPluginsNow() +void cPluginManager::ReloadPluginsNow(void) { LOG("Loading plugins"); m_bReloadPlugins = false; UnloadPluginsNow(); - #ifdef USE_SQUIRREL - CloseSquirrelVM(); - OpenSquirrelVM(); - #endif // USE_SQUIRREL - FindPlugins(); cIniFile IniFile("settings.ini"); - if (!IniFile.ReadFile() ) + if (!IniFile.ReadFile()) { LOGWARNING("cPluginManager: Can't find settings.ini, so can't load any plugins."); } unsigned int KeyNum = IniFile.FindKey("Plugins"); - unsigned int NumPlugins = IniFile.GetNumValues( KeyNum ); - if( NumPlugins > 0 ) + unsigned int NumPlugins = IniFile.GetNumValues(KeyNum); + if (NumPlugins > 0) { for(unsigned int i = 0; i < NumPlugins; i++) { AString ValueName = IniFile.GetValueName(KeyNum, i ); - if( (ValueName.compare("NewPlugin") == 0) || (ValueName.compare("Plugin") == 0) ) // New plugin style + if ( + (ValueName.compare("NewPlugin") == 0) || + (ValueName.compare("Plugin") == 0) + ) { - AString PluginFile = IniFile.GetValue(KeyNum, i ); - if( !PluginFile.empty() ) + AString PluginFile = IniFile.GetValue(KeyNum, i); + if (!PluginFile.empty()) { - if( m_Plugins.find( PluginFile ) != m_Plugins.end() ) + if (m_Plugins.find(PluginFile) != m_Plugins.end()) { LoadPlugin( PluginFile ); } } } - - #ifdef USE_SQUIRREL - else if( ValueName.compare("Squirrel") == 0 ) // Squirrel plugin - { - AString PluginFile = IniFile.GetValue(KeyNum, i ); - if( !PluginFile.empty() ) - { - LOGINFO("Loading Squirrel plugin: %s", PluginFile.c_str() ); - - cPlugin_Squirrel *Plugin = new cPlugin_Squirrel(PluginFile.c_str()); - - if( !AddPlugin( Plugin ) ) - { - delete Plugin; - } - } - } - #endif // USE_SQUIRREL } } - if( GetNumPlugins() == 0 ) + if (GetNumPlugins() == 0) { LOG("No plugins loaded"); } else { - LOG("Loaded %i plugin(s)", GetNumPlugins() ); + LOG("Loaded %i plugin(s)", GetNumPlugins()); } } @@ -188,23 +145,23 @@ void cPluginManager::ReloadPluginsNow() void cPluginManager::Tick(float a_Dt) { - while( m_DisablePluginList.size() > 0 ) + while (!m_DisablePluginList.empty()) { - RemovePlugin( m_DisablePluginList.front(), true ); + RemovePlugin(m_DisablePluginList.front()); m_DisablePluginList.pop_front(); } - if( m_bReloadPlugins ) + if (m_bReloadPlugins) { ReloadPluginsNow(); } HookMap::iterator Plugins = m_Hooks.find(HOOK_TICK); - if( Plugins != m_Hooks.end() ) + if (Plugins != m_Hooks.end()) { - for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr ) + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - (*itr)->Tick( a_Dt ); + (*itr)->Tick(a_Dt); } } } @@ -240,22 +197,17 @@ bool cPluginManager::CallHookBlockToPickups( bool cPluginManager::CallHookChat(cPlayer * a_Player, const AString & a_Message) { - #ifdef USE_SQUIRREL - if (m_SquirrelCommandBinder->HandleCommand(a_Message, a_Player)) - { - return true; - } - #endif // USE_SQUIRREL - - if (m_LuaCommandBinder->HandleCommand(a_Message, a_Player)) + if (ExecuteCommand(a_Player, a_Message)) { return true; } // Check if it was a standard command (starts with a slash) - if (a_Message[0] == '/') + if (!a_Message.empty() && (a_Message[0] == '/')) { - a_Player->SendMessage("Unknown Command"); + AStringVector Split(StringSplit(a_Message, " ")); + ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long + a_Player->SendMessage(Printf("Unknown Command: \"%s\"", Split[0].c_str())); LOGINFO("Player \"%s\" issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str()); return true; // Cancel sending } @@ -911,7 +863,43 @@ bool cPluginManager::CallHookWeatherChanged(cWorld * a_World) -cPlugin* cPluginManager::GetPlugin( const AString & a_Plugin ) const +bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) +{ + ASSERT(a_Player != NULL); + + AStringVector Split(StringSplit(a_Command, " ")); + if (Split.empty()) + { + return false; + } + + CommandMap::iterator cmd = m_Commands.find(Split[0]); + if (cmd == m_Commands.end()) + { + // Command not found + return false; + } + + if ( + a_ShouldCheckPermissions && + !cmd->second.m_Permission.empty() && + !a_Player->HasPermission(cmd->second.m_Permission) + ) + { + LOGINFO("Player \"%s\" tried to execute forbidden command \"%s\".", a_Player->GetName().c_str(), Split[0].c_str()); + return false; + } + + ASSERT(cmd->second.m_Plugin != NULL); + + return cmd->second.m_Plugin->HandleCommand(Split, a_Player); +} + + + + + +cPlugin * cPluginManager::GetPlugin( const AString & a_Plugin ) const { for( PluginMap::const_iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr ) { @@ -941,9 +929,9 @@ void cPluginManager::UnloadPluginsNow() { m_Hooks.clear(); - while( m_Plugins.size() > 0 ) + while (!m_Plugins.empty()) { - RemovePlugin( m_Plugins.begin()->second, true ); + RemovePlugin(m_Plugins.begin()->second); } //SquirrelVM::Shutdown(); // This breaks shit @@ -953,17 +941,19 @@ void cPluginManager::UnloadPluginsNow() -bool cPluginManager::DisablePlugin( AString & a_PluginName ) +bool cPluginManager::DisablePlugin(const AString & a_PluginName) { - PluginMap::iterator itr = m_Plugins.find( a_PluginName ); - if (itr != m_Plugins.end()) + PluginMap::iterator itr = m_Plugins.find(a_PluginName); + if (itr == m_Plugins.end()) { - if (itr->first.compare( a_PluginName ) == 0) - { - m_DisablePluginList.push_back( itr->second ); - itr->second = NULL; // Get rid of this thing right away - return true; - } + return false; + } + + 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 = NULL; // Get rid of this thing right away + return true; } return false; } @@ -972,15 +962,9 @@ bool cPluginManager::DisablePlugin( AString & a_PluginName ) -bool cPluginManager::LoadPlugin( AString & a_PluginName ) +bool cPluginManager::LoadPlugin(const AString & a_PluginName) { - cPlugin_NewLua* Plugin = new cPlugin_NewLua( a_PluginName.c_str() ); - if (!AddPlugin(Plugin)) - { - delete Plugin; - return false; - } - return true; + return AddPlugin(new cPlugin_NewLua(a_PluginName.c_str())); } @@ -999,47 +983,137 @@ void cPluginManager::RemoveHooks(cPlugin * a_Plugin) -void cPluginManager::RemovePlugin( cPlugin * a_Plugin, bool a_bDelete /* = false */ ) +void cPluginManager::RemovePlugin(cPlugin * a_Plugin) { - if( a_bDelete ) + 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); + RemoveHooks(a_Plugin); + if (a_Plugin != NULL) { - m_LuaCommandBinder->RemoveBindingsForPlugin( a_Plugin ); -#ifdef USE_SQUIRREL - m_SquirrelCommandBinder->RemoveBindingsForPlugin( a_Plugin ); -#endif + a_Plugin->OnDisable(); + } + delete a_Plugin; +} - for( PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr ) + + + + +void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin) +{ + if (a_Plugin != NULL) + { + a_Plugin->ClearCommands(); + } + + for (CommandMap::iterator itr = m_Commands.begin(); itr != m_Commands.end();) + { + if (itr->second.m_Plugin == a_Plugin) { - if( itr->second == a_Plugin ) - { - m_Plugins.erase( itr ); - break; - } + itr = m_Commands.erase(itr); } - if( a_Plugin != NULL ) + else { - RemoveHooks( a_Plugin ); - a_Plugin->OnDisable(); - delete a_Plugin; + ++itr; } + } // for itr - m_Commands[] +} + + + + + +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); + if (cmd != m_Commands.end()) + { + LOGWARNING("Command \"%s\" is already bound to plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str()); + return false; } + + m_Commands[a_Command].m_Plugin = a_Plugin; + m_Commands[a_Command].m_Permission = a_Permission; + m_Commands[a_Command].m_HelpString = a_HelpString; + return true; } -bool cPluginManager::AddPlugin( cPlugin* a_Plugin ) +bool cPluginManager::ForEachCommand(cCommandEnumCallback & a_Callback) { - a_Plugin->m_bCanBindCommands = true; - if( a_Plugin->Initialize() ) + for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) { - m_Plugins[ a_Plugin->GetDirectory() ] = a_Plugin; + if (a_Callback.Command(itr->first, itr->second.m_Plugin, itr->second.m_Permission, itr->second.m_HelpString)) + { + return false; + } + } // for itr - m_Commands[] + return true; +} + + + + + +bool cPluginManager::IsCommandBound(const AString & a_Command) +{ + return (m_Commands.find(a_Command) != m_Commands.end()); +} + + + + + +AString cPluginManager::GetCommandPermission(const AString & a_Command) +{ + CommandMap::iterator cmd = m_Commands.find(a_Command); + return (cmd == m_Commands.end()) ? "" : cmd->second.m_Permission; +} + + + + + +bool cPluginManager::ExecuteCommand(cPlayer * a_Player, const AString & a_Command) +{ + return HandleCommand(a_Player, a_Command, true); +} + + + + + +bool cPluginManager::ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command) +{ + return HandleCommand(a_Player, a_Command, false); +} + + + + + +bool cPluginManager::AddPlugin(cPlugin * a_Plugin) +{ + m_Plugins[a_Plugin->GetDirectory()] = a_Plugin; + if (a_Plugin->Initialize()) + { + // Initialization OK return true; } - a_Plugin->m_bCanBindCommands = false; - RemoveHooks( a_Plugin ); // Undo any damage the Initialize() might have done + // Initialization failed + RemovePlugin(a_Plugin); // Also undoes any registrations that Initialize() might have made return false; } @@ -1075,17 +1149,3 @@ unsigned int cPluginManager::GetNumPlugins() const - -bool cPluginManager::HasPlugin( cPlugin* a_Plugin ) const -{ - for( PluginMap::const_iterator itr = m_Plugins.begin(); itr != m_Plugins.end(); ++itr ) - { - if( itr->second == a_Plugin ) - return true; - } - return false; -} - - - - diff --git a/source/PluginManager.h b/source/PluginManager.h index 9a7d36f91..7a52b0fc6 100644 --- a/source/PluginManager.h +++ b/source/PluginManager.h @@ -3,13 +3,6 @@ #include "Item.h" -struct lua_State; -class cLuaCommandBinder; - -#ifdef USE_SQUIRREL - class cSquirrelCommandBinder; -#endif // USE_SQUIRREL - class cPlugin; // fwd: World.h @@ -84,7 +77,16 @@ public: // tolua_export } ; // tolua_end - static cPluginManager * GetPluginManager(); // tolua_export + /// Used as a callback for enumerating bound commands + class cCommandEnumCallback + { + public: + /// Called for each command; return true to abort enumeration + virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) = 0; + } ; + + /// 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; @@ -93,7 +95,6 @@ public: // tolua_export void FindPlugins(); // tolua_export void ReloadPlugins(); // tolua_export - bool AddPlugin( cPlugin* a_Plugin ); void AddHook( cPlugin* a_Plugin, PluginHook a_Hook ); // tolua_export unsigned int GetNumPlugins() const; // tolua_export @@ -130,46 +131,70 @@ public: // tolua_export bool CallHookUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player); bool CallHookUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player); bool CallHookWeatherChanged (cWorld * a_World); + + bool DisablePlugin(const AString & a_PluginName); // tolua_export + bool LoadPlugin (const AString & a_PluginName); // tolua_export - bool DisablePlugin( AString & a_PluginName ); // tolua_export - bool LoadPlugin( AString & a_PluginName ); // tolua_export - - void RemoveHooks( cPlugin * a_Plugin ); - void RemovePlugin( cPlugin * a_Plugin, bool a_bDelete = false ); + /// Removes all hooks the specified plugin has registered + void RemoveHooks(cPlugin * a_Plugin); - cLuaCommandBinder* GetLuaCommandBinder() const { return m_LuaCommandBinder; } + /// Removes the plugin from the internal structures and deletes its object. + void RemovePlugin(cPlugin * a_Plugin); - #ifdef USE_SQUIRREL - cSquirrelCommandBinder * GetSquirrelCommandBinder() { return m_SquirrelCommandBinder; } - #endif // USE_SQUIRREL - - bool HasPlugin( cPlugin* a_Plugin ) const; + /// Removes all command bindings that the specified plugin has made + void RemovePluginCommands(cPlugin * a_Plugin); -private: + /// 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 + + /// Calls a_Callback for each bound command, returns true if all commands were enumerated + bool ForEachCommand(cCommandEnumCallback & a_Callback); // Exported in ManualBindings.cpp + + /// Returns true if the command is in the command map + bool IsCommandBound(const AString & a_Command); // tolua_export + + /// Returns the permission needed for the specified command; empty string if command not found + AString GetCommandPermission(const AString & a_Command); // tolua_export + + /// Executes the command, as if it was requested by a_Player. Checks permissions first. Returns true if executed. + bool ExecuteCommand(cPlayer * a_Player, const AString & a_Command); + + /// Executes the command, as if it was requested by a_Player. Permisssions are not checked. Returns true if executed (false if not found) + bool ForceExecuteCommand(cPlayer * a_Player, const AString & a_Command); +private: friend class cRoot; - cPluginManager(); - ~cPluginManager(); - + class cCommandReg + { + public: + cPlugin * m_Plugin; + AString m_Permission; + AString m_HelpString; + } ; + typedef std::map< cPluginManager::PluginHook, cPluginManager::PluginList > HookMap; + typedef std::map CommandMap; PluginList m_DisablePluginList; + PluginMap m_Plugins; + HookMap m_Hooks; + CommandMap m_Commands; + + bool m_bReloadPlugins; - PluginMap m_Plugins; - HookMap m_Hooks; + cPluginManager(); + ~cPluginManager(); - void ReloadPluginsNow(); - void UnloadPluginsNow(); - - cLuaCommandBinder * m_LuaCommandBinder; - - #ifdef USE_SQUIRREL - cSquirrelCommandBinder * m_SquirrelCommandBinder; - #endif // USE_SQUIRREL + void ReloadPluginsNow(void); + void UnloadPluginsNow(void); - bool m_bReloadPlugins; -}; // tolua_export + /// 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); + + /// Tries to match a_Command to the internal table of commands, if a match is found, the corresponding plugin is called. Returns true if the command is handled. + bool HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions); +} ; // tolua_export diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp index ed497e1a9..ed66f1d28 100644 --- a/source/Plugin_NewLua.cpp +++ b/source/Plugin_NewLua.cpp @@ -18,7 +18,18 @@ extern "C" -extern bool report_errors(lua_State * lua, int status); +bool report_errors(lua_State * lua, int status) +{ + if (status == 0) + { + // No error to report + return false; + } + + LOGERROR("LUA: %s", lua_tostring(lua, -1)); + lua_pop(lua, 1); + return true; +} @@ -53,15 +64,21 @@ cPlugin_NewLua::~cPlugin_NewLua() -bool cPlugin_NewLua::Initialize() +bool cPlugin_NewLua::Initialize(void) { cCSLock Lock(m_CriticalSection); - if( !m_LuaState ) + if (m_LuaState == NULL) { m_LuaState = lua_open(); - luaL_openlibs( m_LuaState ); + luaL_openlibs(m_LuaState); tolua_AllToLua_open(m_LuaState); - ManualBindings::Bind( m_LuaState ); + ManualBindings::Bind(m_LuaState); + + // Inject the identification global variables into the state: + lua_pushlightuserdata(m_LuaState, this); + lua_setglobal(m_LuaState, LUA_PLUGIN_INSTANCE_VAR_NAME); + lua_pushstring(m_LuaState, GetName().c_str()); + lua_setglobal(m_LuaState, LUA_PLUGIN_NAME_VAR_NAME); } std::string PluginPath = FILE_IO_PREFIX + GetLocalDirectory() + "/"; @@ -1134,6 +1151,80 @@ bool cPlugin_NewLua::OnWeatherChanged(cWorld * a_World) +bool cPlugin_NewLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) +{ + ASSERT(!a_Split.empty()); + CommandMap::iterator cmd = m_Commands.find(a_Split[0]); + if (cmd == m_Commands.end()) + { + LOGWARNING("Command handler registered in cPluginManager but not in cPlugin, wtf? Command \"%s\".", a_Split[0].c_str()); + return false; + } + + cCSLock Lock(m_CriticalSection); + + // Push the function to be called: + LOGD("1. Stack size: %i", lua_gettop(m_LuaState)); + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, cmd->second); // same as lua_getref() + + // Push the split: + LOGD("2. Stack size: %i", lua_gettop(m_LuaState)); + lua_createtable(m_LuaState, a_Split.size(), 0); + int newTable = lua_gettop(m_LuaState); + int index = 1; + std::vector::const_iterator iter = a_Split.begin(), end = a_Split.end(); + while(iter != end) + { + tolua_pushstring(m_LuaState, (*iter).c_str()); + lua_rawseti(m_LuaState, newTable, index); + ++iter; + ++index; + } + LOGD("3. Stack size: %i", lua_gettop(m_LuaState)); + + // Push player: + tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); + + // Call function: + LOGD("Calling bound function! :D"); + int s = lua_pcall(m_LuaState, 2, 1, 0); + if (report_errors(m_LuaState, s)) + { + LOGERROR("error. Stack size: %i", lua_gettop(m_LuaState)); + return false; + } + + // Handle return value: + bool RetVal = (tolua_toboolean(m_LuaState, -1, 0) > 0); + lua_pop(m_LuaState, 1); // Pop return value + LOGD("ok. Stack size: %i", lua_gettop(m_LuaState)); + + return RetVal; +} + + + + + +void cPlugin_NewLua::ClearCommands(void) +{ + cCSLock Lock(m_CriticalSection); + + // Unreference the bound functions so that Lua can GC them + if (m_LuaState != NULL) + { + for (CommandMap::iterator itr = m_Commands.begin(), end = m_Commands.end(); itr != end; ++itr) + { + luaL_unref(m_LuaState, LUA_REGISTRYINDEX, itr->second); + } + } + m_Commands.clear(); +} + + + + + bool cPlugin_NewLua::CanAddHook(cPluginManager::PluginHook a_Hook) { const char * FnName = GetHookFnName(a_Hook); @@ -1305,9 +1396,25 @@ bool cPlugin_NewLua::AddWebTab( const AString & a_Title, lua_State * a_LuaState, +void cPlugin_NewLua::BindCommand(const AString & a_Command, int a_FnRef) +{ + ASSERT(m_Commands.find(a_Command) == m_Commands.end()); + m_Commands[a_Command] = a_FnRef; +} + + + + + // Helper functions bool cPlugin_NewLua::PushFunction(const char * a_FunctionName, bool a_bLogError /* = true */) { + if (m_LuaState == NULL) + { + // This happens if Initialize() fails with an error + return false; + } + lua_getglobal(m_LuaState, a_FunctionName); if (!lua_isfunction(m_LuaState, -1)) { diff --git a/source/Plugin_NewLua.h b/source/Plugin_NewLua.h index 87b30b26d..604bcde93 100644 --- a/source/Plugin_NewLua.h +++ b/source/Plugin_NewLua.h @@ -4,6 +4,9 @@ #include "Plugin.h" #include "WebPlugin.h" +// Names for the global variables through which the plugin is identified in its LuaState +#define LUA_PLUGIN_NAME_VAR_NAME "_MCServerInternal_PluginName" +#define LUA_PLUGIN_INSTANCE_VAR_NAME "_MCServerInternal_PluginInstance" @@ -63,6 +66,10 @@ public: virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) override; virtual bool OnWeatherChanged (cWorld * a_World) override; + virtual bool HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) override; + + virtual void ClearCommands(void) override; + virtual bool CanAddHook(cPluginManager::PluginHook a_Hook) override; // cWebPlugin override @@ -71,21 +78,28 @@ public: // cWebPlugin and WebAdmin stuff virtual AString HandleWebRequest( HTTPRequest * a_Request ) override; bool AddWebTab(const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference); // >> EXPORTED IN MANUALBINDINGS << + + /// 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); lua_State* GetLuaState() { return m_LuaState; } cCriticalSection & GetCriticalSection() { return m_CriticalSection; } protected: + cCriticalSection m_CriticalSection; + lua_State * m_LuaState; + + /// Maps command name into Lua function reference + typedef std::map CommandMap; + + CommandMap m_Commands; + bool PushFunction(const char * a_FunctionName, bool a_bLogError = true); bool CallFunction(int a_NumArgs, int a_NumResults, const char * a_FunctionName ); // a_FunctionName is only used for error messages, nothing else /// Returns the name of Lua function that should handle the specified hook const char * GetHookFnName(cPluginManager::PluginHook a_Hook); - - cCriticalSection m_CriticalSection; - - lua_State * m_LuaState; } ; // tolua_export -- cgit v1.2.3