summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/LuaState.cpp12
-rw-r--r--src/Bindings/LuaState.h3
-rw-r--r--src/Bindings/ManualBindings.cpp39
-rw-r--r--src/Bindings/Plugin.h2
-rw-r--r--src/Bindings/PluginLua.cpp4
-rw-r--r--src/Bindings/PluginLua.h2
-rw-r--r--src/Bindings/PluginManager.cpp25
-rw-r--r--src/Bindings/PluginManager.h6
-rw-r--r--src/CommandOutput.cpp19
-rw-r--r--src/CommandOutput.h30
-rw-r--r--src/StringUtils.cpp7
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() == '\''))
{