diff options
Diffstat (limited to '')
-rw-r--r-- | src/Bindings/LuaState.cpp | 12 | ||||
-rw-r--r-- | src/Bindings/LuaState.h | 3 | ||||
-rw-r--r-- | src/Bindings/ManualBindings.cpp | 39 | ||||
-rw-r--r-- | src/Bindings/Plugin.h | 2 | ||||
-rw-r--r-- | src/Bindings/PluginLua.cpp | 4 | ||||
-rw-r--r-- | src/Bindings/PluginLua.h | 2 | ||||
-rw-r--r-- | src/Bindings/PluginManager.cpp | 25 | ||||
-rw-r--r-- | src/Bindings/PluginManager.h | 6 | ||||
-rw-r--r-- | src/CommandOutput.cpp | 19 | ||||
-rw-r--r-- | src/CommandOutput.h | 30 | ||||
-rw-r--r-- | src/StringUtils.cpp | 7 |
11 files changed, 118 insertions, 31 deletions
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index c96ab083a..fb02569c9 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -958,6 +958,18 @@ void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal) +void cLuaState::GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result) +{ + if (lua_isnumber(m_LuaState, a_StackPos)) + { + a_Result = static_cast<cPluginManager::CommandResult>(static_cast<int>((tolua_tonumber(m_LuaState, a_StackPos, a_Result)))); + } +} + + + + + void cLuaState::GetStackValue(int a_StackPos, cRef & a_Ref) { a_Ref.RefStack(*this, a_StackPos); diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 4377ed5d0..959a62bb8 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -32,6 +32,7 @@ extern "C" #include "../Vector3.h" #include "../Defines.h" +#include "PluginManager.h" @@ -57,7 +58,6 @@ class cPickup; class cPlayer; class cPlugin; class cPluginLua; -class cPluginManager; class cProjectileEntity; class cRoot; class cScoreboard; @@ -249,6 +249,7 @@ public: void GetStackValue(int a_StackPos, AString & a_Value); 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); void GetStackValue(int a_StackPos, float & a_ReturnedVal); diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 9b3c1555d..bfe280f51 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" @@ -33,9 +34,10 @@ #include "../CompositeChat.h" #include "../StringCompression.h" #include "../Broadcaster.h" +#include "../CommandOutput.h" + -#include <array> // Better error reporting for Lua @@ -2000,6 +2002,40 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S) +static int tolua_cPluginManager_ExecuteConsoleCommand(lua_State * tolua_S) +{ + /* + Function signature: + cPluginManager:ExecuteConsoleCommand(EntireCommandStr) -> OutputString + */ + + // Check params: + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cPluginManager") || + !L.CheckParamString(2) || + !L.CheckParamEnd(3) + ) + { + return 0; + } + + // 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; +} + + + + + static int tolua_cPluginManager_FindPlugins(lua_State * tolua_S) { // API function no longer exists: @@ -3906,6 +3942,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "BindConsoleCommand", tolua_cPluginManager_BindConsoleCommand); tolua_function(tolua_S, "CallPlugin", tolua_cPluginManager_CallPlugin); tolua_function(tolua_S, "DoWithPlugin", tolua_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); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 5c43f9042..d0c2bcefa 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -56,7 +56,7 @@ 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 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; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 4c98b8d26..76d3557a4 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -534,7 +534,7 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E -bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +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()) @@ -545,7 +545,7 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp 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; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index bedb3d83b..524c249b0 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -115,7 +115,7 @@ 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 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; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 003996802..15bea22bd 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -525,14 +525,14 @@ bool cPluginManager::CallHookEntityTeleport(cEntity & a_Entity, const Vector3d & -bool cPluginManager::CallHookExecuteCommand(cPlayer * a_Player, const AStringVector & a_Split) +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; } @@ -1449,10 +1449,14 @@ cPluginManager::CommandResult cPluginManager::HandleCommand(cPlayer & a_Player, } // 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 ( @@ -1750,7 +1754,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) @@ -1760,10 +1767,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); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 994f19943..d8c886b62 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -200,7 +200,7 @@ 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 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); @@ -299,7 +299,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. diff --git a/src/CommandOutput.cpp b/src/CommandOutput.cpp index 510461d81..255ec3e9b 100644 --- a/src/CommandOutput.cpp +++ b/src/CommandOutput.cpp @@ -29,29 +29,32 @@ void cCommandOutputCallback::Out(const char * a_Fmt, ...) //////////////////////////////////////////////////////////////////////////////// -// cLogCommandOutputCallback: +// cStringAccumCommandOutputCallback: -void cLogCommandOutputCallback::Out(const AString & a_Text) +void cStringAccumCommandOutputCallback::Out(const AString & a_Text) { - m_Buffer.append(a_Text); + m_Accum.append(a_Text); } +//////////////////////////////////////////////////////////////////////////////// +// cLogCommandOutputCallback: + void cLogCommandOutputCallback::Finished(void) { // Log each line separately: - size_t len = m_Buffer.length(); + size_t len = m_Accum.length(); size_t last = 0; for (size_t i = 0; i < len; i++) { - switch (m_Buffer[i]) + switch (m_Accum[i]) { case '\n': { - LOG("%s", m_Buffer.substr(last, i - last).c_str()); + LOG("%s", m_Accum.substr(last, i - last).c_str()); last = i + 1; break; } @@ -59,11 +62,11 @@ void cLogCommandOutputCallback::Finished(void) } // for i - m_Buffer[] if (last < len) { - LOG("%s", m_Buffer.substr(last).c_str()); + LOG("%s", m_Accum.substr(last).c_str()); } // Clear the buffer for the next command output: - m_Buffer.clear(); + m_Accum.clear(); } diff --git a/src/CommandOutput.h b/src/CommandOutput.h index daa9430c0..6265b74ea 100644 --- a/src/CommandOutput.h +++ b/src/CommandOutput.h @@ -47,18 +47,36 @@ class cNullCommandOutputCallback : -/// Sends all command output to a log, line by line, when the command finishes processing -class cLogCommandOutputCallback : +/** Accumulates all command output into a string. */ +class cStringAccumCommandOutputCallback: public cCommandOutputCallback { + typedef cCommandOutputCallback super; + public: // cCommandOutputCallback overrides: virtual void Out(const AString & a_Text) override; - virtual void Finished(void) override; - + virtual void Finished(void) override {} + + /** Returns the accumulated command output in a string. */ + const AString & GetAccum(void) const { return m_Accum; } + protected: - /// Output is stored here until the command finishes processing - AString m_Buffer; + /** Output is stored here until the command finishes processing */ + AString m_Accum; +} ; + + + + + +/// Sends all command output to a log, line by line, when the command finishes processing +class cLogCommandOutputCallback : + public cStringAccumCommandOutputCallback +{ +public: + // cStringAccumCommandOutputCallback overrides: + virtual void Finished(void) override; } ; diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index 4adc6a0a0..12bd3ada1 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -150,6 +150,13 @@ AStringVector StringSplitWithQuotes(const AString & str, const AString & delim) while ((cutAt = str.find_first_of(delim, Prev)) != str.npos) { + if (cutAt == Prev) + { + // Empty string due to multiple whitespace / whitespace at the beginning of the input + // Just skip it + Prev = Prev + 1; + continue; + } AString current = str.substr(Prev, cutAt - Prev); if ((current.front() == '"') || (current.front() == '\'')) { |