summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source/Bindings.cpp84
-rw-r--r--source/Bindings.h2
-rw-r--r--source/CommandOutput.cpp71
-rw-r--r--source/CommandOutput.h82
-rw-r--r--source/Plugin.cpp4
-rw-r--r--source/Plugin.h6
-rw-r--r--source/PluginManager.cpp7
-rw-r--r--source/PluginManager.h7
-rw-r--r--source/Plugin_NewLua.cpp21
-rw-r--r--source/Plugin_NewLua.h2
-rw-r--r--source/RCONServer.cpp45
-rw-r--r--source/RCONServer.h3
-rw-r--r--source/Root.cpp94
-rw-r--r--source/Root.h52
-rw-r--r--source/Server.cpp12
-rw-r--r--source/Server.h6
-rw-r--r--source/StringUtils.cpp23
17 files changed, 375 insertions, 146 deletions
diff --git a/source/Bindings.cpp b/source/Bindings.cpp
index 386ec2e41..ec164b764 100644
--- a/source/Bindings.cpp
+++ b/source/Bindings.cpp
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 06/22/13 19:31:23.
+** Generated automatically by tolua++-1.0.92 on 06/29/13 17:21:35.
*/
#ifndef __cplusplus
@@ -195,7 +195,7 @@ static void tolua_reg_types (lua_State* tolua_S)
{
tolua_usertype(tolua_S,"TakeDamageInfo");
tolua_usertype(tolua_S,"cCraftingRecipe");
- tolua_usertype(tolua_S,"cEntity");
+ tolua_usertype(tolua_S,"cPlugin_NewLua");
tolua_usertype(tolua_S,"cStringMap");
tolua_usertype(tolua_S,"cItemGrid");
tolua_usertype(tolua_S,"cBlockArea");
@@ -205,48 +205,47 @@ static void tolua_reg_types (lua_State* tolua_S)
tolua_usertype(tolua_S,"cRoot");
tolua_usertype(tolua_S,"cWindow");
tolua_usertype(tolua_S,"cCraftingGrid");
- tolua_usertype(tolua_S,"cTracer");
tolua_usertype(tolua_S,"cPickup");
tolua_usertype(tolua_S,"cItems");
tolua_usertype(tolua_S,"cGroup");
tolua_usertype(tolua_S,"cClientHandle");
tolua_usertype(tolua_S,"cChunkDesc");
tolua_usertype(tolua_S,"cFurnaceRecipe");
- tolua_usertype(tolua_S,"cCuboid");
+ tolua_usertype(tolua_S,"cTracer");
tolua_usertype(tolua_S,"cChatColor");
+ tolua_usertype(tolua_S,"cCuboid");
tolua_usertype(tolua_S,"Vector3i");
- tolua_usertype(tolua_S,"cPlugin_NewLua");
tolua_usertype(tolua_S,"Lua__cWebPlugin");
tolua_usertype(tolua_S,"Lua__cPawn");
- tolua_usertype(tolua_S,"cWebAdmin");
+ tolua_usertype(tolua_S,"cEntity");
tolua_usertype(tolua_S,"cItem");
tolua_usertype(tolua_S,"Vector3f");
- tolua_usertype(tolua_S,"cCraftingRecipes");
+ tolua_usertype(tolua_S,"cWebAdmin");
tolua_usertype(tolua_S,"cDropSpenserEntity");
tolua_usertype(tolua_S,"Lua__cPlayer");
- tolua_usertype(tolua_S,"cItemGrid::cListener");
+ tolua_usertype(tolua_S,"cCraftingRecipes");
tolua_usertype(tolua_S,"cChestEntity");
tolua_usertype(tolua_S,"cDispenserEntity");
- tolua_usertype(tolua_S,"Lua__cPickup");
+ tolua_usertype(tolua_S,"cPlugin");
tolua_usertype(tolua_S,"cBlockEntity");
tolua_usertype(tolua_S,"cCriticalSection");
+ tolua_usertype(tolua_S,"Lua__cPickup");
tolua_usertype(tolua_S,"cWebPlugin");
tolua_usertype(tolua_S,"HTTPRequest");
tolua_usertype(tolua_S,"HTTPFormData");
tolua_usertype(tolua_S,"cFurnaceEntity");
- tolua_usertype(tolua_S,"cDropperEntity");
tolua_usertype(tolua_S,"cPluginManager");
- tolua_usertype(tolua_S,"cWorld");
+ tolua_usertype(tolua_S,"cDropperEntity");
tolua_usertype(tolua_S,"cIniFile");
- tolua_usertype(tolua_S,"cPlugin");
- tolua_usertype(tolua_S,"AStringVector");
+ tolua_usertype(tolua_S,"cWorld");
+ tolua_usertype(tolua_S,"cListeners");
tolua_usertype(tolua_S,"cPawn");
tolua_usertype(tolua_S,"cPlayer");
tolua_usertype(tolua_S,"cGroupManager");
tolua_usertype(tolua_S,"cBlockEntityWindowOwner");
- tolua_usertype(tolua_S,"cBlockEntityWithItems");
+ tolua_usertype(tolua_S,"cItemGrid::cListener");
tolua_usertype(tolua_S,"cServer");
- tolua_usertype(tolua_S,"cListeners");
+ tolua_usertype(tolua_S,"cBlockEntityWithItems");
tolua_usertype(tolua_S,"Lua__cEntity");
tolua_usertype(tolua_S,"Vector3d");
}
@@ -5878,18 +5877,20 @@ static int tolua_AllToLua_cEntity_Destroy00(lua_State* tolua_S)
tolua_Error tolua_err;
if (
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,2,&tolua_err)
+ !tolua_isboolean(tolua_S,2,1,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
)
goto tolua_lerror;
else
#endif
{
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
+ bool a_ShouldBroadcast = ((bool) tolua_toboolean(tolua_S,2,true));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Destroy'", NULL);
#endif
{
- self->Destroy();
+ self->Destroy(a_ShouldBroadcast);
}
}
return 0;
@@ -10169,40 +10170,6 @@ static int tolua_AllToLua_cPluginManager_IsConsoleCommandBound00(lua_State* tolu
}
#endif //#ifndef TOLUA_DISABLE
-/* method: ExecuteConsoleCommand of class cPluginManager */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_ExecuteConsoleCommand00
-static int tolua_AllToLua_cPluginManager_ExecuteConsoleCommand00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) ||
- (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const AStringVector",0,&tolua_err)) ||
- !tolua_isnoobj(tolua_S,3,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0);
- const AStringVector* a_Split = ((const AStringVector*) tolua_tousertype(tolua_S,2,0));
-#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'ExecuteConsoleCommand'", NULL);
-#endif
- {
- bool tolua_ret = (bool) self->ExecuteConsoleCommand(*a_Split);
- tolua_pushboolean(tolua_S,(bool)tolua_ret);
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'ExecuteConsoleCommand'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
/* method: GetName of class cPlugin */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlugin_GetName00
static int tolua_AllToLua_cPlugin_GetName00(lua_State* tolua_S)
@@ -18771,9 +18738,9 @@ static int tolua_AllToLua_cRoot_GetPluginManager00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
-/* method: ExecuteConsoleCommand of class cRoot */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_ExecuteConsoleCommand00
-static int tolua_AllToLua_cRoot_ExecuteConsoleCommand00(lua_State* tolua_S)
+/* method: QueueExecuteConsoleCommand of class cRoot */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_QueueExecuteConsoleCommand00
+static int tolua_AllToLua_cRoot_QueueExecuteConsoleCommand00(lua_State* tolua_S)
{
#ifndef TOLUA_RELEASE
tolua_Error tolua_err;
@@ -18789,17 +18756,17 @@ static int tolua_AllToLua_cRoot_ExecuteConsoleCommand00(lua_State* tolua_S)
cRoot* self = (cRoot*) tolua_tousertype(tolua_S,1,0);
const AString a_Cmd = ((const AString) tolua_tocppstring(tolua_S,2,0));
#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'ExecuteConsoleCommand'", NULL);
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'QueueExecuteConsoleCommand'", NULL);
#endif
{
- self->ExecuteConsoleCommand(a_Cmd);
+ self->QueueExecuteConsoleCommand(a_Cmd);
tolua_pushcppstring(tolua_S,(const char*)a_Cmd);
}
}
return 1;
#ifndef TOLUA_RELEASE
tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'ExecuteConsoleCommand'.",&tolua_err);
+ tolua_error(tolua_S,"#ferror in function 'QueueExecuteConsoleCommand'.",&tolua_err);
return 0;
#endif
}
@@ -28187,7 +28154,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"ExecuteCommand",tolua_AllToLua_cPluginManager_ExecuteCommand00);
tolua_function(tolua_S,"ForceExecuteCommand",tolua_AllToLua_cPluginManager_ForceExecuteCommand00);
tolua_function(tolua_S,"IsConsoleCommandBound",tolua_AllToLua_cPluginManager_IsConsoleCommandBound00);
- tolua_function(tolua_S,"ExecuteConsoleCommand",tolua_AllToLua_cPluginManager_ExecuteConsoleCommand00);
tolua_endmodule(tolua_S);
tolua_cclass(tolua_S,"cPlugin","cPlugin","",NULL);
tolua_beginmodule(tolua_S,"cPlugin");
@@ -28599,7 +28565,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GetFurnaceRecipe",tolua_AllToLua_cRoot_GetFurnaceRecipe00);
tolua_function(tolua_S,"GetWebAdmin",tolua_AllToLua_cRoot_GetWebAdmin00);
tolua_function(tolua_S,"GetPluginManager",tolua_AllToLua_cRoot_GetPluginManager00);
- tolua_function(tolua_S,"ExecuteConsoleCommand",tolua_AllToLua_cRoot_ExecuteConsoleCommand00);
+ tolua_function(tolua_S,"QueueExecuteConsoleCommand",tolua_AllToLua_cRoot_QueueExecuteConsoleCommand00);
tolua_function(tolua_S,"GetTotalChunkCount",tolua_AllToLua_cRoot_GetTotalChunkCount00);
tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cRoot_SaveAllChunks00);
tolua_function(tolua_S,"GetProtocolVersionTextFromInt",tolua_AllToLua_cRoot_GetProtocolVersionTextFromInt00);
diff --git a/source/Bindings.h b/source/Bindings.h
index df29c6201..c13cf32bd 100644
--- a/source/Bindings.h
+++ b/source/Bindings.h
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 06/22/13 19:31:24.
+** Generated automatically by tolua++-1.0.92 on 06/29/13 17:21:36.
*/
/* Exported function */
diff --git a/source/CommandOutput.cpp b/source/CommandOutput.cpp
new file mode 100644
index 000000000..49102b38c
--- /dev/null
+++ b/source/CommandOutput.cpp
@@ -0,0 +1,71 @@
+
+// CommandOutput.cpp
+
+// Implements the various classes that process command output
+
+#include "Globals.h"
+#include "CommandOutput.h"
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cCommandOutputCallback:
+
+void cCommandOutputCallback::Out(const char * a_Fmt, ...)
+{
+ AString Output;
+ va_list args;
+ va_start(args, a_Fmt);
+ AppendVPrintf(Output, a_Fmt, args);
+ va_end(args);
+ Output.append("\n");
+ Out(Output);
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cLogCommandOutputCallback:
+
+void cLogCommandOutputCallback::Out(const AString & a_Text)
+{
+ m_Buffer.append(a_Text);
+}
+
+
+
+
+
+void cLogCommandOutputCallback::Finished(void)
+{
+ // Log each line separately:
+ size_t len = m_Buffer.length();
+ size_t last = 0;
+ for (size_t i = 0; i < len; i++)
+ {
+ switch (m_Buffer[i])
+ {
+ case '\n':
+ {
+ LOG(m_Buffer.substr(last, i - last).c_str());
+ last = i + 1;
+ break;
+ }
+ }
+ } // for i - m_Buffer[]
+ if (last < len)
+ {
+ LOG(m_Buffer.substr(last).c_str());
+ }
+
+ // Clear the buffer for the next command output:
+ m_Buffer.clear();
+}
+
+
+
+
diff --git a/source/CommandOutput.h b/source/CommandOutput.h
new file mode 100644
index 000000000..68217dbb4
--- /dev/null
+++ b/source/CommandOutput.h
@@ -0,0 +1,82 @@
+
+// CommandOutput.h
+
+// Declares various classes that process command output
+
+
+
+
+
+/** Interface for a callback that receives command output
+The Out() function is called for any output the command has produced.
+Descendants override that function to provide specific processing of the output.
+*/
+class cCommandOutputCallback
+{
+public:
+ virtual ~cCommandOutputCallback() {}; // Force a virtual destructor in subclasses
+
+ /// Syntax sugar function, calls Out() with Printf()-ed parameters; appends a "\n"
+ void Out(const char * a_Fmt, ...);
+
+ /// Called when the command wants to output anything; may be called multiple times
+ virtual void Out(const AString & a_Text) = 0;
+
+ /// Called when the command processing has been finished
+ virtual void Finished(void) {};
+} ;
+
+
+
+
+
+/// Class that discards all command output
+class cNullCommandOutputCallback :
+ public cCommandOutputCallback
+{
+ // cCommandOutputCallback overrides:
+ virtual void Out(const AString & a_Text) override
+ {
+ // Do nothing
+ }
+} ;
+
+
+
+
+
+
+/// Sends all command output to a log, line by line, when the command finishes processing
+class cLogCommandOutputCallback :
+ public cCommandOutputCallback
+{
+public:
+ // cCommandOutputCallback overrides:
+ virtual void Out(const AString & a_Text) override;
+ virtual void Finished(void) override;
+
+protected:
+ /// Output is stored here until the command finishes processing
+ AString m_Buffer;
+} ;
+
+
+
+
+
+/// Sends all command output to a log, line by line; deletes self when command finishes processing
+class cLogCommandDeleteSelfOutputCallback :
+ public cLogCommandOutputCallback
+{
+ typedef cLogCommandOutputCallback super;
+
+ virtual void Finished(void) override
+ {
+ super::Finished();
+ delete this;
+ }
+} ;
+
+
+
+
diff --git a/source/Plugin.cpp b/source/Plugin.cpp
index 389ef15e4..daf1d33c8 100644
--- a/source/Plugin.cpp
+++ b/source/Plugin.cpp
@@ -5,6 +5,7 @@
#include "Pawn.h"
#include "Player.h"
#include "World.h"
+#include "CommandOutput.h"
@@ -546,9 +547,10 @@ bool cPlugin::HandleCommand(const AStringVector & a_Split, cPlayer * a_Player)
-bool cPlugin::HandleConsoleCommand(const AStringVector & a_Split)
+bool cPlugin::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output)
{
UNUSED(a_Split);
+ UNUSED(a_Output);
return false;
}
diff --git a/source/Plugin.h b/source/Plugin.h
index 9107cce6f..91f5f5286 100644
--- a/source/Plugin.h
+++ b/source/Plugin.h
@@ -92,8 +92,10 @@ public:
*/
virtual bool HandleCommand(const AStringVector & a_Split, cPlayer * a_Player);
- /// Handles the console command split into a_Split. Returns true if command handled successfully.
- virtual bool HandleConsoleCommand(const AStringVector & a_Split);
+ /** Handles the console command split into a_Split.
+ Returns true if command handled successfully. Output is to be sent to the a_Output callback.
+ */
+ virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
/// All bound commands are to be removed, do any language-dependent cleanup here
virtual void ClearCommands(void) {} ;
diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp
index a180f5618..32f2a2a99 100644
--- a/source/PluginManager.cpp
+++ b/source/PluginManager.cpp
@@ -8,6 +8,7 @@
#include "Item.h"
#include "Root.h"
#include "Server.h"
+#include "CommandOutput.h"
#include "../iniFile/iniFile.h"
#include "tolua++.h"
@@ -1300,7 +1301,7 @@ bool cPluginManager::IsConsoleCommandBound(const AString & a_Command)
-bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split)
+bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output)
{
if (a_Split.empty())
{
@@ -1323,11 +1324,11 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split)
// 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());
+ a_Output.Out("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);
+ return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output);
}
diff --git a/source/PluginManager.h b/source/PluginManager.h
index 655081568..9268fe66d 100644
--- a/source/PluginManager.h
+++ b/source/PluginManager.h
@@ -29,6 +29,9 @@ class cPickup;
struct TakeDamageInfo;
class cPawn;
+// fwd: CommandOutput.h
+class cCommandOutputCallback;
+
@@ -191,8 +194,8 @@ public: // tolua_export
/// 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.
- bool ExecuteConsoleCommand(const AStringVector & a_Split); // 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
+ bool ExecuteConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
private:
friend class cRoot;
diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp
index 335ac000a..1e4a6a94a 100644
--- a/source/Plugin_NewLua.cpp
+++ b/source/Plugin_NewLua.cpp
@@ -3,7 +3,7 @@
#define LUA_USE_POSIX
#include "Plugin_NewLua.h"
-#include "MCLogger.h"
+#include "CommandOutput.h"
extern "C"
{
@@ -1378,13 +1378,15 @@ bool cPlugin_NewLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Pl
-bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split)
+bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output)
{
ASSERT(!a_Split.empty());
CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]);
if (cmd == m_ConsoleCommands.end())
{
- LOGWARNING("Console command handler is registered in cPluginManager but not in cPlugin, wtf? Console command \"%s\".", a_Split[0].c_str());
+ LOGWARNING("Console command handler is registered in cPluginManager but not in cPlugin, wtf? Console command \"%s\", plugin \"%s\".",
+ a_Split[0].c_str(), GetName().c_str()
+ );
return false;
}
@@ -1407,16 +1409,21 @@ bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split)
}
// Call function:
- int s = lua_pcall(m_LuaState, 1, 1, 0);
+ int s = lua_pcall(m_LuaState, 1, 2, 0);
if (report_errors(m_LuaState, s))
{
LOGERROR("Lua 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
+ // Handle return values:
+ if (lua_isstring(m_LuaState, -1))
+ {
+ AString str = tolua_tocppstring(m_LuaState, -1, "");
+ a_Output.Out(str);
+ }
+ bool RetVal = (tolua_toboolean(m_LuaState, -2, 0) > 0);
+ lua_pop(m_LuaState, 2); // Pop return values
return RetVal;
}
diff --git a/source/Plugin_NewLua.h b/source/Plugin_NewLua.h
index 086568f76..7abd0f9fe 100644
--- a/source/Plugin_NewLua.h
+++ b/source/Plugin_NewLua.h
@@ -77,7 +77,7 @@ public:
virtual bool HandleCommand(const AStringVector & a_Split, cPlayer * a_Player) override;
- virtual bool HandleConsoleCommand(const AStringVector & a_Split) override;
+ virtual bool HandleConsoleCommand(const AStringVector & a_Split, cCommandOutputCallback & a_Output) override;
virtual void ClearCommands(void) override;
diff --git a/source/RCONServer.cpp b/source/RCONServer.cpp
index 9558512eb..cf6ed8b0c 100644
--- a/source/RCONServer.cpp
+++ b/source/RCONServer.cpp
@@ -8,6 +8,7 @@
#include "RCONServer.h"
#include "Server.h"
#include "Root.h"
+#include "CommandOutput.h"
@@ -38,6 +39,41 @@ enum
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cRCONCommandOutput:
+
+class cRCONCommandOutput :
+ public cCommandOutputCallback
+{
+public:
+ cRCONCommandOutput(cRCONServer::cConnection & a_Connection, int a_RequestID) :
+ m_Connection(a_Connection),
+ m_RequestID(a_RequestID)
+ {
+ }
+
+ // cCommandOutputCallback overrides:
+ virtual void Out(const AString & a_Text) override
+ {
+ m_Buffer.append(a_Text);
+ }
+
+ virtual void Finished(void) override
+ {
+ m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, m_Buffer.size(), m_Buffer.c_str());
+ delete this;
+ }
+
+protected:
+ cRCONServer::cConnection & m_Connection;
+ int m_RequestID;
+ AString m_Buffer;
+} ;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cRCONServer:
cRCONServer::cRCONServer(cServer & a_Server) :
@@ -218,9 +254,16 @@ bool cRCONServer::cConnection::ProcessPacket(int a_RequestID, int a_PacketType,
case RCON_PACKET_COMMAND:
{
+ if (!m_IsAuthenticated)
+ {
+ char AuthNeeded[] = "You need to authenticate first!";
+ SendResponse(a_RequestID, RCON_PACKET_RESPONSE, sizeof(AuthNeeded), AuthNeeded);
+ return false;
+ }
+
AString cmd(a_Payload, a_PayloadLength);
LOGD("RCON command from %s: \"%s\"", m_IPAddress.c_str(), cmd.c_str());
- cRoot::Get()->ExecuteConsoleCommand(cmd);
+ cRoot::Get()->ExecuteConsoleCommand(cmd, *(new cRCONCommandOutput(*this, a_RequestID)));
// Send an empty response:
SendResponse(a_RequestID, RCON_PACKET_RESPONSE, 0, NULL);
diff --git a/source/RCONServer.h b/source/RCONServer.h
index 95122ba5f..a4a0d20fe 100644
--- a/source/RCONServer.h
+++ b/source/RCONServer.h
@@ -34,6 +34,8 @@ public:
void Initialize(cIniFile & a_IniFile);
protected:
+ friend class cRCONCommandOutput;
+
class cConnection :
public cSocketThreads::cCallback
{
@@ -41,6 +43,7 @@ protected:
cConnection(cRCONServer & a_RCONServer, cSocket & a_Socket);
protected:
+ friend class cRCONCommandOutput;
/// Set to true if the client has successfully authenticated
bool m_IsAuthenticated;
diff --git a/source/Root.cpp b/source/Root.cpp
index c7be00c20..771986003 100644
--- a/source/Root.cpp
+++ b/source/Root.cpp
@@ -15,6 +15,7 @@
#include "Items/ItemHandler.h"
#include "Chunk.h"
#include "Protocol/ProtocolRecognizer.h" // for protocol version constants
+#include "CommandOutput.h"
#ifdef USE_SQUIRREL
#include "squirrelbindings/SquirrelFunctions.h"
@@ -69,11 +70,13 @@ void cRoot::InputThread(void * a_Params)
{
cRoot & self = *(cRoot*)a_Params;
+ cLogCommandOutputCallback Output;
+
while (!(self.m_bStop || self.m_bRestart))
{
std::string Command;
std::getline(std::cin, Command);
- self.ExecuteConsoleCommand(Command);
+ self.ExecuteConsoleCommand(Command, Output);
}
}
@@ -350,14 +353,14 @@ bool cRoot::ForEachWorld(cWorldListCallback & a_Callback)
void cRoot::TickWorlds(float a_Dt)
{
// Execute any pending commands:
- AStringVector PendingCommands;
+ cCommandQueue PendingCommands;
{
cCSLock Lock(m_CSPendingCommands);
std::swap(PendingCommands, m_PendingCommands);
}
- for (AStringVector::iterator itr = PendingCommands.begin(), end = PendingCommands.end(); itr != end; ++itr)
+ for (cCommandQueue::iterator itr = PendingCommands.begin(), end = PendingCommands.end(); itr != end; ++itr)
{
- DoExecuteConsoleCommand(*itr);
+ ExecuteConsoleCommand(itr->m_Command, *(itr->m_Output));
}
// Tick the worlds:
@@ -371,7 +374,28 @@ void cRoot::TickWorlds(float a_Dt)
-void cRoot::ExecuteConsoleCommand(const AString & a_Cmd)
+void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
+{
+ // Some commands are built-in:
+ if (a_Cmd == "stop")
+ {
+ m_bStop = true;
+ }
+ else if (a_Cmd == "restart")
+ {
+ m_bRestart = true;
+ }
+
+ // Put the command into a queue (Alleviates FS #363):
+ cCSLock Lock(m_CSPendingCommands);
+ m_PendingCommands.push_back(cCommand(a_Cmd, &a_Output));
+}
+
+
+
+
+
+void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
{
// Some commands are built-in:
if (a_Cmd == "stop")
@@ -385,17 +409,27 @@ void cRoot::ExecuteConsoleCommand(const AString & a_Cmd)
// Put the command into a queue (Alleviates FS #363):
cCSLock Lock(m_CSPendingCommands);
- m_PendingCommands.push_back(a_Cmd);
+ m_PendingCommands.push_back(cCommand(a_Cmd, new cLogCommandDeleteSelfOutputCallback));
}
-void cRoot::DoExecuteConsoleCommand(const AString & a_Cmd)
+void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
{
+ // Some commands are built-in:
+ if (a_Cmd == "stop")
+ {
+ m_bStop = true;
+ }
+ else if (a_Cmd == "restart")
+ {
+ m_bRestart = true;
+ }
+
LOG("Executing console command: \"%s\"", a_Cmd.c_str());
- m_Server->ExecuteConsoleCommand(a_Cmd);
+ m_Server->ExecuteConsoleCommand(a_Cmd, a_Output);
}
@@ -524,7 +558,7 @@ AString cRoot::GetProtocolVersionTextFromInt(int a_ProtocolVersion)
-void cRoot::LogChunkStats(void)
+void cRoot::LogChunkStats(cCommandOutputCallback & a_Output)
{
int SumNumValid = 0;
int SumNumDirty = 0;
@@ -541,35 +575,35 @@ void cRoot::LogChunkStats(void)
int NumDirty = 0;
int NumInLighting = 0;
World->GetChunkStats(NumValid, NumDirty, NumInLighting);
- LOG("World %s:", World->GetName().c_str());
- LOG(" Num loaded chunks: %d", NumValid);
- LOG(" Num dirty chunks: %d", NumDirty);
- LOG(" Num chunks in lighting queue: %d", NumInLighting);
- LOG(" Num chunks in generator queue: %d", NumInGenerator);
- LOG(" Num chunks in storage load queue: %d", NumInLoadQueue);
- LOG(" Num chunks in storage save queue: %d", NumInSaveQueue);
+ a_Output.Out("World %s:", World->GetName().c_str());
+ a_Output.Out(" Num loaded chunks: %d", NumValid);
+ a_Output.Out(" Num dirty chunks: %d", NumDirty);
+ a_Output.Out(" Num chunks in lighting queue: %d", NumInLighting);
+ a_Output.Out(" Num chunks in generator queue: %d", NumInGenerator);
+ a_Output.Out(" Num chunks in storage load queue: %d", NumInLoadQueue);
+ a_Output.Out(" Num chunks in storage save queue: %d", NumInSaveQueue);
int Mem = NumValid * sizeof(cChunk);
- LOG(" Memory used by chunks: %d KiB (%d MiB)", (Mem + 1023) / 1024, (Mem + 1024 * 1024 - 1) / (1024 * 1024));
- LOG(" Per-chunk memory size breakdown:");
- LOG(" block types: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
- LOG(" block metadata: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
- LOG(" block lighting: %6d bytes (%3d KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
- LOG(" heightmap: %6d bytes (%3d KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
- LOG(" biomemap: %6d bytes (%3d KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
+ a_Output.Out(" Memory used by chunks: %d KiB (%d MiB)", (Mem + 1023) / 1024, (Mem + 1024 * 1024 - 1) / (1024 * 1024));
+ a_Output.Out(" Per-chunk memory size breakdown:");
+ a_Output.Out(" block types: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
+ a_Output.Out(" block metadata: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
+ a_Output.Out(" block lighting: %6d bytes (%3d KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
+ a_Output.Out(" heightmap: %6d bytes (%3d KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
+ a_Output.Out(" biomemap: %6d bytes (%3d KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
int Rest = sizeof(cChunk) - sizeof(cChunkDef::BlockTypes) - 3 * sizeof(cChunkDef::BlockNibbles) - sizeof(cChunkDef::HeightMap) - sizeof(cChunkDef::BiomeMap);
- LOG(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024);
+ a_Output.Out(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024);
SumNumValid += NumValid;
SumNumDirty += NumDirty;
SumNumInLighting += NumInLighting;
SumNumInGenerator += NumInGenerator;
SumMem += Mem;
}
- LOG("Totals:");
- LOG(" Num loaded chunks: %d", SumNumValid);
- LOG(" Num dirty chunks: %d", SumNumDirty);
- LOG(" Num chunks in lighting queue: %d", SumNumInLighting);
- LOG(" Num chunks in generator queue: %d", SumNumInGenerator);
- LOG(" Memory used by chunks: %d KiB (%d MiB)", (SumMem + 1023) / 1024, (SumMem + 1024 * 1024 - 1) / (1024 * 1024));
+ a_Output.Out("Totals:");
+ a_Output.Out(" Num loaded chunks: %d", SumNumValid);
+ a_Output.Out(" Num dirty chunks: %d", SumNumDirty);
+ a_Output.Out(" Num chunks in lighting queue: %d", SumNumInLighting);
+ a_Output.Out(" Num chunks in generator queue: %d", SumNumInGenerator);
+ a_Output.Out(" Memory used by chunks: %d KiB (%d MiB)", (SumMem + 1023) / 1024, (SumMem + 1024 * 1024 - 1) / (1024 * 1024));
}
diff --git a/source/Root.h b/source/Root.h
index 9f94c4df3..1e2befcd4 100644
--- a/source/Root.h
+++ b/source/Root.h
@@ -1,15 +1,13 @@
#pragma once
-
-
-
#include "Authenticator.h"
+// fwd:
class cThread;
class cMonsterConfig;
class cGroupManager;
@@ -20,6 +18,8 @@ class cPluginManager;
class cServer;
class cWorld;
class cPlayer;
+class cCommandOutputCallback ;
+
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cWorld> cWorldListCallback;
@@ -27,6 +27,7 @@ typedef cItemCallback<cWorld> cWorldListCallback;
+/// The root of the object hierarchy
class cRoot // tolua_export
{ // tolua_export
public:
@@ -47,8 +48,8 @@ public:
/// Calls the callback for each world; returns true if the callback didn't abort (return true)
bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings <<
- /// Logs chunkstats for each world and totals
- void LogChunkStats(void);
+ /// Writes chunkstats, for each world and totals, to the output callback
+ void LogChunkStats(cCommandOutputCallback & a_Output);
int GetPrimaryServerVersion(void) const { return m_PrimaryServerVersion; } // tolua_export
void SetPrimaryServerVersion(int a_Version) { m_PrimaryServerVersion = a_Version; } // tolua_export
@@ -62,8 +63,22 @@ public:
cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export
cAuthenticator & GetAuthenticator (void) { return m_Authenticator; }
- /// Queues a console command for execution through the cServer class; does special handling for "stop" and "restart".
- void ExecuteConsoleCommand(const AString & a_Cmd); // tolua_export
+ /** Queues a console command for execution through the cServer class.
+ The command will be executed in the tick thread
+ The command's output will be written to the a_Output callback
+ "stop" and "restart" commands have special handling.
+ */
+ void QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
+
+ /** Queues a console command for execution through the cServer class.
+ The command will be executed in the tick thread
+ The command's output will be sent to console
+ "stop" and "restart" commands have special handling.
+ */
+ void QueueExecuteConsoleCommand(const AString & a_Cmd); // tolua_export
+
+ /// Executes a console command through the cServer class; does special handling for "stop" and "restart".
+ void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
/// Kicks the user, no matter in what world they are. Used from cAuthenticator
void KickUser(int a_ClientID, const AString & a_Reason);
@@ -89,12 +104,27 @@ public:
static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum); // tolua_export
private:
- typedef std::map< AString, cWorld* > WorldMap;
- cWorld* m_pDefaultWorld;
+ class cCommand
+ {
+ public:
+ cCommand(const AString & a_Command, cCommandOutputCallback * a_Output) :
+ m_Command(a_Command),
+ m_Output(a_Output)
+ {
+ }
+
+ AString m_Command;
+ cCommandOutputCallback * m_Output;
+ } ;
+
+ typedef std::map<AString, cWorld *> WorldMap;
+ typedef std::vector<cCommand> cCommandQueue;
+
+ cWorld * m_pDefaultWorld;
WorldMap m_WorldsByName;
cCriticalSection m_CSPendingCommands;
- AStringVector m_PendingCommands;
+ cCommandQueue m_PendingCommands;
cThread * m_InputThread;
@@ -131,7 +161,7 @@ private:
void DoExecuteConsoleCommand(const AString & a_Cmd);
static void InputThread(void* a_Params);
-
+
static cRoot* s_Root;
}; // tolua_export
diff --git a/source/Server.cpp b/source/Server.cpp
index 7dac3ea18..67a02f626 100644
--- a/source/Server.cpp
+++ b/source/Server.cpp
@@ -21,6 +21,7 @@
#include "Tracer.h"
#include "WebAdmin.h"
#include "Protocol/ProtocolRecognizer.h"
+#include "CommandOutput.h"
#include "MersenneTwister.h"
@@ -425,7 +426,7 @@ bool cServer::Command(cClientHandle & a_Client, AString & a_Cmd)
-void cServer::ExecuteConsoleCommand(const AString & a_Cmd)
+void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
{
AStringVector split = StringSplit(a_Cmd, " ");
if (split.empty())
@@ -442,7 +443,8 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd)
// There is currently no way a plugin can do these (and probably won't ever be):
if (split[0].compare("chunkstats") == 0)
{
- cRoot::Get()->LogChunkStats();
+ cRoot::Get()->LogChunkStats(a_Output);
+ a_Output.Finished();
return;
}
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
@@ -462,12 +464,14 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd)
}
#endif
- if (cPluginManager::Get()->ExecuteConsoleCommand(split))
+ if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output))
{
+ a_Output.Finished();
return;
}
- LOG("Unknown command, type 'help' for all commands.\n");
+ a_Output.Out("Unknown command, type 'help' for all commands.");
+ a_Output.Finished();
}
diff --git a/source/Server.h b/source/Server.h
index 3f7a24699..542673b49 100644
--- a/source/Server.h
+++ b/source/Server.h
@@ -19,9 +19,11 @@
+// fwd:
class cPlayer;
class cClientHandle;
class cIniFile;
+class cCommandOutputCallback ;
typedef std::list<cClientHandle *> cClientHandleList;
@@ -44,7 +46,9 @@ public: // tolua_export
bool Start(void);
bool Command(cClientHandle & a_Client, AString & a_Cmd);
- void ExecuteConsoleCommand(const AString & a_Cmd);
+
+ /// Executes the console command, sends output through the specified callback
+ void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
/// Binds the built-in console commands with the plugin manager
static void BindBuiltInConsoleCommands(void);
diff --git a/source/StringUtils.cpp b/source/StringUtils.cpp
index da809c5a4..b55ce51e6 100644
--- a/source/StringUtils.cpp
+++ b/source/StringUtils.cpp
@@ -569,26 +569,3 @@ AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_
-
-AString Trim(const AString & a_Text)
-{
- if (a_Text.empty())
- {
- return "";
- }
- size_t Beginning = a_Text.find_first_not_of(" \r\n\t");
- if (Beginning == AString::npos)
- {
- Beginning = 0;
- }
- size_t End = a_Text.find_last_not_of(" \r\n\t");
- if (End == AString::npos)
- {
- End = a_Text.length();
- }
- return a_Text.substr(Beginning, End - Beginning + 1);
-}
-
-
-
-