From 2271469d1bfe1b4f4c53645c0ec8c216a6662479 Mon Sep 17 00:00:00 2001 From: Asher Baker Date: Mon, 18 Jul 2011 03:23:03 +0100 Subject: [PATCH] Added ServerCommandEx native to get the response when running a command (bug 3873, r=ds). --- AMBuildScript | 1 + core/smn_console.cpp | 112 ++++++++++++++++++++++++++++++++++++ plugins/include/console.inc | 17 ++++++ 3 files changed, 130 insertions(+) diff --git a/AMBuildScript b/AMBuildScript index f605acc0..b2fc3950 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -97,6 +97,7 @@ class SM: self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor') self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual') self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H') + self.compiler.AddToListVar('CDEFINES', 'GNUC') if self.vendor == 'gcc': self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse') elif isinstance(cxx, Cpp.MSVC): diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 307fcbcb..288b9e02 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "Logger.h" #include "ConsoleDetours.h" #include "ConCommandBaseIterator.h" @@ -901,6 +902,116 @@ static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params) return 1; } +char *g_ServerCommandBuffer = NULL; +cell_t g_ServerCommandBufferLength; + +bool g_ShouldCatchSpew = false; + +#if SOURCE_ENGINE < SE_LEFT4DEAD2 +SpewOutputFunc_t g_OriginalSpewOutputFunc = NULL; + +SpewRetval_t SourcemodSpewOutputFunc(SpewType_t spewType, tchar const *pMsg) +{ + if (g_ServerCommandBuffer) + { + V_strcat(g_ServerCommandBuffer, pMsg, g_ServerCommandBufferLength); + } + + if (g_OriginalSpewOutputFunc) + { + return g_OriginalSpewOutputFunc(spewType, pMsg); + } else { + return SPEW_CONTINUE; + } +} +#else +class CSourcemodLoggingListener: public ILoggingListener +{ +public: + void Log(const LoggingContext_t *pContext, const tchar *pMessage) + { + if (g_ServerCommandBuffer) + { + V_strcat(g_ServerCommandBuffer, pMessage, g_ServerCommandBufferLength); + } + } +} g_SourcemodLoggingListener; +#endif + +CON_COMMAND(sm_conhook_start, "") +{ + if (!g_ShouldCatchSpew) + { + Warning("You shouldn't run this command!\n"); + return; + } + +#if SOURCE_ENGINE < SE_LEFT4DEAD2 + g_OriginalSpewOutputFunc = GetSpewOutputFunc(); + SpewOutputFunc(SourcemodSpewOutputFunc); +#else +#if SOURCE_ENGINE < SE_ALIENSWARM + LoggingSystem_PushLoggingState(false); +#else + LoggingSystem_PushLoggingState(false, false); +#endif + LoggingSystem_RegisterLoggingListener(&g_SourcemodLoggingListener); +#endif +} + +CON_COMMAND(sm_conhook_stop, "") +{ + if (!g_ShouldCatchSpew) + { + Warning("You shouldn't run this command!\n"); + return; + } + +#if SOURCE_ENGINE < SE_LEFT4DEAD2 + SpewOutputFunc(g_OriginalSpewOutputFunc); +#else + LoggingSystem_PopLoggingState(false); +#endif + + g_ShouldCatchSpew = false; +} + +static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params) +{ + g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); + + char buffer[1024]; + size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 3); + + if (pContext->GetLastNativeError() != SP_ERROR_NONE) + { + return 0; + } + + /* One byte for null terminator, one for newline */ + buffer[len++] = '\n'; + buffer[len] = '\0'; + + pContext->LocalToString(params[1], &g_ServerCommandBuffer); + g_ServerCommandBufferLength = params[2]; + + engine->ServerExecute(); + + g_ShouldCatchSpew = true; + engine->ServerCommand("sm_conhook_start\n"); + engine->ServerCommand(buffer); + engine->ServerCommand("sm_conhook_stop\n"); + + engine->ServerExecute(); + + g_ServerCommandBuffer[g_ServerCommandBufferLength-1] = '\0'; + + g_ServerCommandBuffer = NULL; + g_ServerCommandBufferLength = 0; + + return 1; +} + static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params) { g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); @@ -1399,6 +1510,7 @@ REGISTER_NATIVES(consoleNatives) {"PrintToConsole", sm_PrintToConsole}, {"RegAdminCmd", sm_RegAdminCmd}, {"ServerCommand", sm_ServerCommand}, + {"ServerCommandEx", sm_ServerCommandEx}, {"InsertServerCommand", sm_InsertServerCommand}, {"ServerExecute", sm_ServerExecute}, {"ClientCommand", sm_ClientCommand}, diff --git a/plugins/include/console.inc b/plugins/include/console.inc index ee40dc77..96d64806 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -121,6 +121,23 @@ enum ConVarQueryResult */ native ServerCommand(const String:format[], any:...); +/** + * Executes a server command as if it were on the server console (or RCON) + * and stores the printed text into buffer. + * + * Warning: This calls ServerExecute internally and may have issues if + * certain commands are in the buffer, only use when you really need + * the response. + * Also, on L4D2 this will not print the command output to the server console. + * + * @param buffer String to store command result into. + * @param maxlen Length of buffer. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native ServerCommandEx(String:buffer[], maxlen, const String:format[], any:...); + /** * Inserts a server command at the beginning of the server command buffer. *