From 99876ea4bae68af856e1b7a231b180cdb1ffef32 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Thu, 21 Feb 2013 13:47:01 +0000 Subject: [PATCH] Added HOOK_EXECUTE_COMMAND for intercepting executed commands and console commands. Note that built-in console commands are exempt to this hook - they are always performed and the hook is not called. Also note that, for reasons unknown, the HookNotify plugin doesn't list the callback arguments. git-svn-id: http://mc-server.googlecode.com/svn/trunk@1221 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- MCServer/Plugins/HookNotify/HookNotify.lua | 16 +++++++ source/Bindings.cpp | 4 +- source/Bindings.h | 2 +- source/Plugin.cpp | 11 +++++ source/Plugin.h | 1 + source/PluginManager.cpp | 35 ++++++++++++++ source/PluginManager.h | 2 + source/Plugin_NewLua.cpp | 56 +++++++++++++++++----- source/Plugin_NewLua.h | 1 + 9 files changed, 114 insertions(+), 14 deletions(-) diff --git a/MCServer/Plugins/HookNotify/HookNotify.lua b/MCServer/Plugins/HookNotify/HookNotify.lua index 92cc2e059..ed463c5ca 100644 --- a/MCServer/Plugins/HookNotify/HookNotify.lua +++ b/MCServer/Plugins/HookNotify/HookNotify.lua @@ -23,6 +23,7 @@ function Initialize(Plugin) PluginManager:AddHook(Plugin, cPluginManager.HOOK_COLLECTING_PICKUP); PluginManager:AddHook(Plugin, cPluginManager.HOOK_CRAFTING_NO_RECIPE); PluginManager:AddHook(Plugin, cPluginManager.HOOK_DISCONNECT); + PluginManager:AddHook(Plugin, cPluginManager.HOOK_EXECUTE_COMMAND); PluginManager:AddHook(Plugin, cPluginManager.HOOK_HANDSHAKE); PluginManager:AddHook(Plugin, cPluginManager.HOOK_KILLING); PluginManager:AddHook(Plugin, cPluginManager.HOOK_LOGIN); @@ -174,6 +175,21 @@ end +function OnExecuteCommand(...) + LogHook("OnExecuteCommand", unpack(arg)); + + -- For some reason logging doesn't work for this callback, so list some stuff manually to verify: + LOG("arg1 type: " .. type(arg[1])); + if (arg[1] ~= nil) then + LOG("Player name: " .. arg[1]:GetName()); + end + LOG("Command: " .. arg[2][1]); +end + + + + + function OnHandshake(...) LogHook("OnHandshake", unpack(arg)); end diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 8abc8af0a..e8a277fb0 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 02/16/13 12:08:29. +** Generated automatically by tolua++-1.0.92 on 02/21/13 14:08:40. */ #ifndef __cplusplus @@ -21948,6 +21948,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"etPickup",cEntity::etPickup); tolua_constant(tolua_S,"etMob",cEntity::etMob); tolua_constant(tolua_S,"etFallingBlock",cEntity::etFallingBlock); + tolua_constant(tolua_S,"etMinecart",cEntity::etMinecart); tolua_constant(tolua_S,"eEntityType_Entity",cEntity::eEntityType_Entity); tolua_constant(tolua_S,"eEntityType_Player",cEntity::eEntityType_Player); tolua_constant(tolua_S,"eEntityType_Pickup",cEntity::eEntityType_Pickup); @@ -22146,6 +22147,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"HOOK_COLLECTING_PICKUP",cPluginManager::HOOK_COLLECTING_PICKUP); tolua_constant(tolua_S,"HOOK_CRAFTING_NO_RECIPE",cPluginManager::HOOK_CRAFTING_NO_RECIPE); tolua_constant(tolua_S,"HOOK_DISCONNECT",cPluginManager::HOOK_DISCONNECT); + tolua_constant(tolua_S,"HOOK_EXECUTE_COMMAND",cPluginManager::HOOK_EXECUTE_COMMAND); tolua_constant(tolua_S,"HOOK_HANDSHAKE",cPluginManager::HOOK_HANDSHAKE); tolua_constant(tolua_S,"HOOK_KILLING",cPluginManager::HOOK_KILLING); tolua_constant(tolua_S,"HOOK_LOGIN",cPluginManager::HOOK_LOGIN); diff --git a/source/Bindings.h b/source/Bindings.h index b073923f0..9e0cdbb93 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 02/16/13 12:08:29. +** Generated automatically by tolua++-1.0.92 on 02/21/13 14:08:41. */ /* Exported function */ diff --git a/source/Plugin.cpp b/source/Plugin.cpp index 3c2502617..879a1a3d6 100644 --- a/source/Plugin.cpp +++ b/source/Plugin.cpp @@ -164,6 +164,17 @@ bool cPlugin::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPlugin::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +{ + UNUSED(a_Player); + UNUSED(a_Split); + return false; +} + + + + + bool cPlugin::OnHandshake(cClientHandle * a_Client, const AString & a_Username) { UNUSED(a_Client); diff --git a/source/Plugin.h b/source/Plugin.h index de7113c22..74447d888 100644 --- a/source/Plugin.h +++ b/source/Plugin.h @@ -58,6 +58,7 @@ public: virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup); virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason); + virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); virtual bool OnHandshake (cClientHandle * a_Client, const AString & a_Username); virtual bool OnKilling (cPawn & a_Victim, cEntity * a_Killer); virtual bool OnLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username); diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index 014cf719f..dc724b966 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -403,6 +403,27 @@ bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Re +bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_EXECUTE_COMMAND); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnExecuteCommand(a_Player, a_Split)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookHandshake(cClientHandle * a_ClientHandle, const AString & a_Username) { HookMap::iterator Plugins = m_Hooks.find(HOOK_HANDSHAKE); @@ -966,6 +987,13 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command return false; } + // Ask plugins first if a command is okay to execute the command: + if (CallHookExecuteCommand(a_Player, Split)) + { + 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 false; + } + if ( a_ShouldCheckPermissions && !cmd->second.m_Permission.empty() && @@ -1282,6 +1310,13 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split) return false; } + // Ask plugins first if a command is okay to execute the console command: + if (CallHookExecuteCommand(NULL, a_Split)) + { + LOGINFO("Command \"%s\" was stopped by the HOOK_EXECUTE_COMMAND hook", a_Split[0].c_str()); + return false; + } + return cmd->second.m_Plugin->HandleConsoleCommand(a_Split); } diff --git a/source/PluginManager.h b/source/PluginManager.h index d070bfabd..d930a0c8b 100644 --- a/source/PluginManager.h +++ b/source/PluginManager.h @@ -49,6 +49,7 @@ public: // tolua_export HOOK_COLLECTING_PICKUP, HOOK_CRAFTING_NO_RECIPE, HOOK_DISCONNECT, + HOOK_EXECUTE_COMMAND, HOOK_HANDSHAKE, HOOK_KILLING, HOOK_LOGIN, @@ -116,6 +117,7 @@ public: // tolua_export bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup); bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookDisconnect (cPlayer * a_Player, const AString & a_Reason); + bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd bool CallHookHandshake (cClientHandle * a_ClientHandle, const AString & a_Username); bool CallHookKilling (cPawn & a_Victim, cEntity * a_Killer); bool CallHookLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username); diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp index 2b233579a..6b5e233f6 100644 --- a/source/Plugin_NewLua.cpp +++ b/source/Plugin_NewLua.cpp @@ -461,6 +461,45 @@ bool cPlugin_NewLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPlugin_NewLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +{ + cCSLock Lock(m_CriticalSection); + const char * FnName = GetHookFnName(cPluginManager::HOOK_EXECUTE_COMMAND); + ASSERT(FnName != NULL); + if (!PushFunction(FnName)) + { + return false; + } + + tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); + + // Push the split: + 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; + } + + if (!CallFunction(2, 1, FnName)) + { + return false; + } + + bool bRetVal = (tolua_toboolean(m_LuaState, -1, 0) > 0); + lua_pop(m_LuaState, 1); + return bRetVal; +} + + + + + bool cPlugin_NewLua::OnHandshake(cClientHandle * a_Client, const AString & a_Username) { cCSLock Lock(m_CriticalSection); @@ -1280,11 +1319,9 @@ bool cPlugin_NewLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Pl 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; @@ -1296,24 +1333,21 @@ bool cPlugin_NewLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Pl ++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)); + LOGERROR("LUA error in %s. Stack size: %i", __FUNCTION__, 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; } @@ -1335,11 +1369,9 @@ bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split) 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; @@ -1351,10 +1383,8 @@ bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split) ++iter; ++index; } - LOGD("3. Stack size: %i", lua_gettop(m_LuaState)); // Call function: - LOGD("Calling bound function! :D"); int s = lua_pcall(m_LuaState, 1, 1, 0); if (report_errors(m_LuaState, s)) { @@ -1365,7 +1395,6 @@ bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split) // 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; } @@ -1471,6 +1500,7 @@ const char * cPlugin_NewLua::GetHookFnName(cPluginManager::PluginHook a_Hook) case cPluginManager::HOOK_COLLECTING_PICKUP: return "OnCollectingPickup"; case cPluginManager::HOOK_CRAFTING_NO_RECIPE: return "OnCraftingNoRecipe"; case cPluginManager::HOOK_DISCONNECT: return "OnDisconnect"; + case cPluginManager::HOOK_EXECUTE_COMMAND: return "OnExecuteCommand"; case cPluginManager::HOOK_HANDSHAKE: return "OnHandshake"; case cPluginManager::HOOK_KILLING: return "OnKilling"; case cPluginManager::HOOK_LOGIN: return "OnLogin"; @@ -1633,8 +1663,10 @@ bool cPlugin_NewLua::PushFunction(const char * a_FunctionName, bool a_bLogError -bool cPlugin_NewLua::CallFunction( int a_NumArgs, int a_NumResults, const char* a_FunctionName ) +bool cPlugin_NewLua::CallFunction( int a_NumArgs, int a_NumResults, const char * a_FunctionName) { + ASSERT(lua_isfunction(m_LuaState, -a_NumArgs - 1)); + int s = lua_pcall(m_LuaState, a_NumArgs, a_NumResults, 0); if (report_errors(m_LuaState, s)) { diff --git a/source/Plugin_NewLua.h b/source/Plugin_NewLua.h index ab1907a41..8ba22477a 100644 --- a/source/Plugin_NewLua.h +++ b/source/Plugin_NewLua.h @@ -43,6 +43,7 @@ public: virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override; virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) override; + virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override; virtual bool OnHandshake (cClientHandle * a_Client, const AString & a_Username) override; virtual bool OnKilling (cPawn & a_Victim, cEntity * a_Killer) override; virtual bool OnLogin (cClientHandle * a_Client, int a_ProtocolVersion, const AString & a_Username) override;