diff -r 000000000000 -r b7aa2b626807 core/smn_console.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/smn_console.cpp Sun Mar 30 07:00:22 2008 +0000
@@ -0,0 +1,1307 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#include "sm_globals.h"
+#include "HalfLife2.h"
+#include "sourcemm_api.h"
+#include "HandleSys.h"
+#include "ConVarManager.h"
+#include "ConCmdManager.h"
+#include "PluginSys.h"
+#include "sm_stringutil.h"
+#include "PlayerManager.h"
+#include "ChatTriggers.h"
+#include "AdminCache.h"
+#include
+#include
+#include
+
+#define NET_SETCONVAR 5
+
+enum ConVarBounds
+{
+ ConVarBound_Upper = 0,
+ ConVarBound_Lower
+};
+
+HandleType_t hCmdIterType = 0;
+HandleType_t htConCmdIter = 0;
+
+struct GlobCmdIter
+{
+ bool started;
+ List::iterator iter;
+};
+
+struct ConCmdIter
+{
+ const ConCommandBase *pLast;
+};
+
+class ConsoleHelpers :
+ public SMGlobalClass,
+ public IHandleTypeDispatch
+{
+public:
+ virtual void OnSourceModAllInitialized()
+ {
+ HandleAccess access;
+
+ g_HandleSys.InitAccessDefaults(NULL, &access);
+
+ htConCmdIter = g_HandleSys.CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
+
+ access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
+
+ hCmdIterType = g_HandleSys.CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
+ }
+ virtual void OnHandleDestroy(HandleType_t type, void *object)
+ {
+ if (type == hCmdIterType)
+ {
+ GlobCmdIter *iter = (GlobCmdIter *)object;
+ delete iter;
+ }
+ else if (type == htConCmdIter)
+ {
+ ConCmdIter *iter = (ConCmdIter * )object;
+ delete iter;
+ }
+ }
+ virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
+ {
+ if (type == htConCmdIter)
+ {
+ *pSize = sizeof(ConCmdIter);
+ return true;
+ }
+ else if (type == hCmdIterType)
+ {
+ *pSize = sizeof(GlobCmdIter);
+ return true;
+ }
+ return false;
+ }
+} s_ConsoleHelpers;
+
+class CommandFlagsHelper : public IConCommandTracker
+{
+public:
+ void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
+ {
+ m_CmdFlags.remove(name);
+ }
+ bool GetFlags(const char *name, int *flags)
+ {
+ ConCommandBase **ppCmd;
+ ConCommandBase *pCmd;
+ if ((ppCmd=m_CmdFlags.retrieve(name)))
+ {
+ TrackConCommandBase((*ppCmd), this);
+ *flags = (*ppCmd)->GetFlags();
+ return true;
+ }
+ else if ((pCmd=FindConCommandBase(name)))
+ {
+ m_CmdFlags.insert(name, pCmd);
+ TrackConCommandBase(pCmd, this);
+ *flags = pCmd->GetFlags();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ bool SetFlags(const char *name, int flags)
+ {
+ ConCommandBase **ppCmd;
+ ConCommandBase *pCmd;
+ if ((ppCmd=m_CmdFlags.retrieve(name)))
+ {
+ (*ppCmd)->SetFlags(flags);
+ TrackConCommandBase((*ppCmd), this);
+ return true;
+ }
+ else if ((pCmd=FindConCommandBase(name)))
+ {
+ m_CmdFlags.insert(name, pCmd);
+ pCmd->SetFlags(flags);
+ TrackConCommandBase(pCmd, this);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+private:
+ KTrie m_CmdFlags;
+} s_CommandFlagsHelper;
+
+static void ReplicateConVar(ConVar *pConVar)
+{
+ int maxClients = g_Players.GetMaxClients();
+
+ char data[256];
+ bf_write buffer(data, sizeof(data));
+
+ buffer.WriteUBitLong(NET_SETCONVAR, 5);
+ buffer.WriteByte(1);
+ buffer.WriteString(pConVar->GetName());
+ buffer.WriteString(pConVar->GetString());
+
+ for (int i = 1; i <= maxClients; i++)
+ {
+ CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
+
+ if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
+ {
+ INetChannel *netchan = static_cast(engine->GetPlayerNetInfo(i));
+ netchan->SendData(buffer);
+ }
+ }
+}
+
+static void NotifyConVar(ConVar *pConVar)
+{
+ IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
+ pEvent->SetString("cvarname", pConVar->GetName());
+ if (IsFlagSet(pConVar, FCVAR_PROTECTED))
+ {
+ pEvent->SetString("cvarvalue", "***PROTECTED***");
+ }
+ else
+ {
+ pEvent->SetString("cvarvalue", pConVar->GetString());
+ }
+
+ gameevents->FireEvent(pEvent);
+}
+
+static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
+{
+ char *name, *defaultVal, *helpText;
+
+ pContext->LocalToString(params[1], &name);
+
+ // While the engine seems to accept a blank convar name, it causes a crash upon server quit
+ if (name == NULL || strcmp(name, "") == 0)
+ {
+ return pContext->ThrowNativeError("Convar with blank name is not permitted");
+ }
+
+ pContext->LocalToString(params[2], &defaultVal);
+ pContext->LocalToString(params[3], &helpText);
+
+ bool hasMin = params[5] ? true : false;
+ bool hasMax = params[7] ? true : false;
+ float min = sp_ctof(params[6]);
+ float max = sp_ctof(params[8]);
+
+ Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
+
+ if (hndl == BAD_HANDLE)
+ {
+ return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
+ }
+
+ return hndl;
+}
+
+static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
+{
+ char *name;
+
+ pContext->LocalToString(params[1], &name);
+
+ return g_ConVarManager.FindConVar(name);
+}
+
+static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
+
+ if (!pFunction)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ g_ConVarManager.HookConVarChange(pConVar, pFunction);
+
+ return 1;
+}
+
+static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
+
+ if (!pFunction)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
+
+ return 1;
+}
+
+static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ return pConVar->GetBool();
+}
+
+static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ return pConVar->GetInt();
+}
+
+/* This handles both SetConVarBool() and SetConVarInt() */
+static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ pConVar->SetValue(params[2]);
+
+ /* Should we replicate it? */
+ if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
+ {
+ ReplicateConVar(pConVar);
+ }
+
+ /* Should we notify clients? */
+ if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
+ {
+ NotifyConVar(pConVar);
+ }
+
+ return 1;
+}
+
+static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ float value = pConVar->GetFloat();
+
+ return sp_ftoc(value);
+}
+
+static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ float value = sp_ctof(params[2]);
+ pConVar->SetValue(value);
+
+ /* Should we replicate it? */
+ if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
+ {
+ ReplicateConVar(pConVar);
+ }
+
+ /* Should we notify clients? */
+ if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
+ {
+ NotifyConVar(pConVar);
+ }
+
+ return 1;
+}
+
+static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
+
+ return 1;
+}
+
+static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ char *value;
+ pContext->LocalToString(params[2], &value);
+
+ pConVar->SetValue(value);
+
+ /* Should we replicate it? */
+ if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
+ {
+ ReplicateConVar(pConVar);
+ }
+
+ /* Should we notify clients? */
+ if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
+ {
+ NotifyConVar(pConVar);
+ }
+
+ return 1;
+}
+
+static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ pConVar->Revert();
+
+ /* Should we replicate it? */
+ if (params[2] && IsFlagSet(pConVar, FCVAR_REPLICATED))
+ {
+ ReplicateConVar(pConVar);
+ }
+
+ /* Should we notify clients? */
+ if (params[3] && IsFlagSet(pConVar, FCVAR_NOTIFY))
+ {
+ NotifyConVar(pConVar);
+ }
+
+ return 1;
+}
+
+static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ return pConVar->GetFlags();
+}
+
+static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ pConVar->SetFlags(params[2]);
+
+ return 1;
+}
+
+static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ cell_t *addr;
+ bool hasBound;
+ float bound;
+
+ switch (params[2])
+ {
+ case ConVarBound_Upper:
+ hasBound = pConVar->GetMax(bound);
+ break;
+ case ConVarBound_Lower:
+ hasBound = pConVar->GetMin(bound);
+ break;
+ default:
+ return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
+ }
+
+ pContext->LocalToPhysAddr(params[3], &addr);
+ *addr = sp_ftoc(bound);
+
+ return hasBound;
+}
+
+static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ switch (params[2])
+ {
+ case ConVarBound_Upper:
+ pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
+ break;
+ case ConVarBound_Lower:
+ pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
+ break;
+ default:
+ return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
+ }
+
+ return 1;
+}
+
+static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[1]);
+ HandleError err;
+ ConVar *pConVar;
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
+
+ return 1;
+}
+
+static bool s_QueryAlreadyWarned = false;
+
+static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
+{
+ CPlayer *pPlayer;
+ char *name;
+ IPluginFunction *pCallback;
+
+ if (!g_ConVarManager.IsQueryingSupported())
+ {
+ if (!s_QueryAlreadyWarned)
+ {
+ s_QueryAlreadyWarned = true;
+ return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
+ }
+
+ return 0;
+ }
+
+ pPlayer = g_Players.GetPlayerByIndex(params[1]);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
+ }
+
+ if (!pPlayer->IsConnected())
+ {
+ return pContext->ThrowNativeError("Client %d is not connected", params[1]);
+ }
+
+ /* Trying a query on a bot results in callback not be fired, so don't bother */
+ if (pPlayer->IsFakeClient())
+ {
+ return 0;
+ }
+
+ pContext->LocalToString(params[2], &name);
+ pCallback = pContext->GetFunctionById(params[3]);
+
+ if (!pCallback)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
+ }
+
+ return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
+}
+
+static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
+{
+ char *name,*help;
+ IPluginFunction *pFunction;
+
+ pContext->LocalToString(params[1], &name);
+ pContext->LocalToString(params[3], &help);
+ pFunction = pContext->GetFunctionById(params[2]);
+
+ if (!pFunction)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
+ {
+ return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
+ }
+
+ return 1;
+}
+
+static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
+{
+ char *name,*help;
+ IPluginFunction *pFunction;
+
+ pContext->LocalToString(params[1], &name);
+ pContext->LocalToString(params[3], &help);
+ pFunction = pContext->GetFunctionById(params[2]);
+
+ if (!pFunction)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
+ {
+ return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
+ }
+
+ return 1;
+}
+
+static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
+{
+ char *name,*help;
+ const char *group;
+ IPluginFunction *pFunction;
+ FlagBits flags = params[3];
+ int cmdflags = params[6];
+
+ pContext->LocalToString(params[1], &name);
+ pContext->LocalToString(params[4], &help);
+ pContext->LocalToString(params[5], (char **)&group);
+ pFunction = pContext->GetFunctionById(params[2]);
+
+ if (group[0] == '\0')
+ {
+ CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
+ group = pPlugin->GetFilename();
+ }
+
+ if (!pFunction)
+ {
+ return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
+ }
+
+ if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
+ {
+ return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
+ }
+
+ return 1;
+}
+
+static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
+{
+ const CCommand *pCmd = g_HL2.PeekCommandStack();
+
+ if (!pCmd)
+ {
+ return pContext->ThrowNativeError("No command callback available");
+ }
+
+ return pCmd->ArgC() - 1;
+}
+
+static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
+{
+ const CCommand *pCmd = g_HL2.PeekCommandStack();
+
+ if (!pCmd)
+ {
+ return pContext->ThrowNativeError("No command callback available");
+ }
+
+ size_t length;
+
+ const char *arg = pCmd->Arg(params[1]);
+
+ pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
+
+ return (cell_t)length;
+}
+
+static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
+{
+ const CCommand *pCmd = g_HL2.PeekCommandStack();
+
+ if (!pCmd)
+ {
+ return pContext->ThrowNativeError("No command callback available");
+ }
+
+ const char *args = pCmd->ArgS();
+ size_t length;
+
+ if (!args)
+ {
+ args = "";
+ }
+
+ pContext->StringToLocalUTF8(params[1], params[2], args, &length);
+
+ return (cell_t)length;
+}
+
+static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
+{
+ char buffer[1024];
+ char *fmt;
+ int arg = 2;
+
+ pCtx->LocalToString(params[1], &fmt);
+ size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
+
+ buffer[res++] = '\n';
+ buffer[res] = '\0';
+
+ META_CONPRINT(buffer);
+
+ return 1;
+}
+
+static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
+{
+ int index = params[1];
+ if ((index < 0) || (index > g_Players.GetMaxClients()))
+ {
+ return pCtx->ThrowNativeError("Client index %d is invalid", index);
+ }
+
+ CPlayer *pPlayer = NULL;
+ if (index != 0)
+ {
+ pPlayer = g_Players.GetPlayerByIndex(index);
+ if (!pPlayer->IsInGame())
+ {
+ return pCtx->ThrowNativeError("Client %d is not in game", index);
+ }
+
+ /* Silent fail on bots, engine will crash */
+ if (pPlayer->IsFakeClient())
+ {
+ return 0;
+ }
+ }
+
+ char buffer[1024];
+ char *fmt;
+ int arg = 3;
+
+ pCtx->LocalToString(params[2], &fmt);
+ size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
+
+ buffer[res++] = '\n';
+ buffer[res] = '\0';
+
+ if (index != 0)
+ {
+ engine->ClientPrintf(pPlayer->GetEdict(), buffer);
+ } else {
+ META_CONPRINT(buffer);
+ }
+
+ return 1;
+}
+
+static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
+{
+ g_SourceMod.SetGlobalTarget(LANG_SERVER);
+
+ char buffer[1024];
+ size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
+
+ if (pContext->GetContext()->n_err != SP_ERROR_NONE)
+ {
+ return 0;
+ }
+
+ /* One byte for null terminator, one for newline */
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+
+ engine->ServerCommand(buffer);
+
+ return 1;
+}
+
+static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
+{
+ g_SourceMod.SetGlobalTarget(LANG_SERVER);
+
+ char buffer[1024];
+ size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
+
+ if (pContext->GetContext()->n_err != SP_ERROR_NONE)
+ {
+ return 0;
+ }
+
+ /* One byte for null terminator, one for newline */
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+
+ InsertServerCommand(buffer);
+
+ return 1;
+}
+
+static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
+{
+ engine->ServerExecute();
+
+ return 1;
+}
+
+static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
+{
+ CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
+ }
+
+ if (!pPlayer->IsConnected())
+ {
+ return pContext->ThrowNativeError("Client %d is not connected", params[1]);
+ }
+
+ g_SourceMod.SetGlobalTarget(params[1]);
+
+ char buffer[256];
+ g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
+
+ if (pContext->GetContext()->n_err != SP_ERROR_NONE)
+ {
+ return 0;
+ }
+
+ engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
+
+ return 1;
+}
+
+static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
+{
+ CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
+ }
+
+ if (!pPlayer->IsConnected())
+ {
+ return pContext->ThrowNativeError("Client %d is not connected", params[1]);
+ }
+
+ char buffer[256];
+ g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
+
+ if (pContext->GetContext()->n_err != SP_ERROR_NONE)
+ {
+ return 0;
+ }
+
+ serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
+
+ return 1;
+}
+
+static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
+{
+ CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
+ }
+
+ if (!pPlayer->IsConnected())
+ {
+ return pContext->ThrowNativeError("Client %d is not connected", params[1]);
+ }
+
+ char buffer[256];
+ g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
+
+ if (pContext->GetContext()->n_err != SP_ERROR_NONE)
+ {
+ return 0;
+ }
+
+ g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
+
+ return 1;
+}
+
+static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
+{
+ g_SourceMod.SetGlobalTarget(params[1]);
+
+ /* Build the format string */
+ char buffer[1024];
+ size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
+
+ if (pContext->GetContext()->n_err != SP_ERROR_NONE)
+ {
+ return 0;
+ }
+
+ /* If we're printing to the server, shortcut out */
+ if (params[1] == 0)
+ {
+ /* Print */
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+ META_CONPRINT(buffer);
+ return 1;
+ }
+
+ CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
+ }
+
+ if (!pPlayer->IsConnected())
+ {
+ return pContext->ThrowNativeError("Client %d is not connected", params[1]);
+ }
+
+ g_SourceMod.SetGlobalTarget(params[1]);
+
+ unsigned int replyto = g_ChatTriggers.GetReplyTo();
+ if (replyto == SM_REPLY_CONSOLE)
+ {
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+ engine->ClientPrintf(pPlayer->GetEdict(), buffer);
+ } else if (replyto == SM_REPLY_CHAT) {
+ if (len >= 191)
+ {
+ len = 191;
+ }
+ buffer[len] = '\0';
+ g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
+ }
+
+ return 1;
+}
+
+static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
+{
+ return g_ChatTriggers.GetReplyTo();
+}
+
+static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
+{
+ return g_ChatTriggers.SetReplyTo(params[1]);
+}
+
+static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
+{
+ GlobCmdIter *iter = new GlobCmdIter;
+ iter->started = false;
+
+ Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
+ if (hndl == BAD_HANDLE)
+ {
+ delete iter;
+ }
+
+ return hndl;
+}
+
+static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
+{
+ GlobCmdIter *iter;
+ HandleError err;
+ HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
+
+ if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
+ }
+
+ const List &cmds = g_ConCmds.GetCommandList();
+
+ if (!iter->started)
+ {
+ iter->iter = cmds.begin();
+ iter->started = true;
+ }
+
+ while (iter->iter != cmds.end()
+ && !(*(iter->iter))->sourceMod)
+ {
+ iter->iter++;
+ }
+
+ if (iter->iter == cmds.end())
+ {
+ return 0;
+ }
+
+ ConCmdInfo *pInfo = (*(iter->iter));
+
+ pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
+ pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
+
+ cell_t *addr;
+ pContext->LocalToPhysAddr(params[4], &addr);
+ *addr = pInfo->admin.eflags;
+
+ iter->iter++;
+
+ return 1;
+}
+
+static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
+{
+ if (params[1] == 0)
+ {
+ return 1;
+ }
+
+ char *cmd;
+ pContext->LocalToString(params[2], &cmd);
+
+ /* Auto-detect a command if we can */
+ FlagBits bits = params[3];
+ bool found_command = false;
+ if (params[0] < 4 || !params[4])
+ {
+ found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
+ }
+
+ if (!found_command)
+ {
+ g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
+ }
+
+ return g_ConCmds.CheckCommandAccess(params[1], cmd, bits) ? 1 : 0;
+}
+
+static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
+{
+ return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
+}
+
+static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
+{
+ char *name;
+ pContext->LocalToString(params[1], &name);
+
+ return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
+}
+
+static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
+{
+ char *name;
+ int flags;
+ pContext->LocalToString(params[1], &name);
+
+ return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
+}
+
+static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl;
+ ConCmdIter *pIter;
+ cell_t *pIsCmd, *pFlags;
+ const ConCommandBase *pConCmd;
+ const char *desc;
+
+ pContext->LocalToPhysAddr(params[3], &pIsCmd);
+ pContext->LocalToPhysAddr(params[4], &pFlags);
+
+ pConCmd = icvar->GetCommands();
+
+ if (pConCmd == NULL)
+ {
+ return BAD_HANDLE;
+ }
+
+ pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
+ *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
+ *pFlags = pConCmd->GetFlags();
+
+ if (params[6])
+ {
+ desc = pConCmd->GetHelpText();
+ pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
+ }
+
+ pIter = new ConCmdIter;
+ pIter->pLast = pConCmd;
+
+ if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
+ == BAD_HANDLE)
+ {
+ delete pIter;
+ return BAD_HANDLE;
+ }
+
+ return hndl;
+}
+
+static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
+{
+ HandleError err;
+ ConCmdIter *pIter;
+ cell_t *pIsCmd, *pFlags;
+ const char *desc;
+ HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
+
+ if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
+ }
+
+ if (pIter->pLast == NULL)
+ {
+ return 0;
+ }
+
+ if ((pIter->pLast = pIter->pLast->GetNext()) == NULL)
+ {
+ return 0;
+ }
+
+ pContext->LocalToPhysAddr(params[4], &pIsCmd);
+ pContext->LocalToPhysAddr(params[5], &pFlags);
+
+ pContext->StringToLocalUTF8(params[2], params[3], pIter->pLast->GetName(), NULL);
+ *pIsCmd = pIter->pLast->IsCommand() ? 1 : 0;
+ *pFlags = pIter->pLast->GetFlags();
+
+ if (params[7])
+ {
+ desc = pIter->pLast->GetHelpText();
+ pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
+ }
+
+ return 1;
+}
+
+static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
+{
+ Handle_t hndl = static_cast(params[2]);
+ HandleError err;
+ ConVar *pConVar;
+
+ char *value;
+ pContext->LocalToString(params[3], &value);
+
+ if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
+ != HandleError_None)
+ {
+ return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
+ }
+
+ char data[256];
+ bf_write buffer(data, sizeof(data));
+
+ buffer.WriteUBitLong(NET_SETCONVAR, 5);
+ buffer.WriteByte(1);
+ buffer.WriteString(pConVar->GetName());
+ buffer.WriteString(value);
+
+ CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
+
+ if (!pPlayer)
+ {
+ return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
+ }
+
+ if (!pPlayer->IsConnected())
+ {
+ return pContext->ThrowNativeError("Client %d is not connected", params[1]);
+ }
+
+ if (pPlayer->IsFakeClient())
+ {
+ return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
+ }
+
+ INetChannel *netchan = static_cast(engine->GetPlayerNetInfo(params[1]));
+ netchan->SendData(buffer);
+
+ return 1;
+}
+
+REGISTER_NATIVES(consoleNatives)
+{
+ {"CreateConVar", sm_CreateConVar},
+ {"FindConVar", sm_FindConVar},
+ {"HookConVarChange", sm_HookConVarChange},
+ {"UnhookConVarChange", sm_UnhookConVarChange},
+ {"GetConVarBool", sm_GetConVarBool},
+ {"SetConVarBool", sm_SetConVarNum},
+ {"GetConVarInt", sm_GetConVarInt},
+ {"SetConVarInt", sm_SetConVarNum},
+ {"GetConVarFloat", sm_GetConVarFloat},
+ {"SetConVarFloat", sm_SetConVarFloat},
+ {"GetConVarString", sm_GetConVarString},
+ {"SetConVarString", sm_SetConVarString},
+ {"GetConVarFlags", sm_GetConVarFlags},
+ {"SetConVarFlags", sm_SetConVarFlags},
+ {"ResetConVar", sm_ResetConVar},
+ {"GetConVarName", sm_GetConVarName},
+ {"GetConVarBounds", sm_GetConVarBounds},
+ {"SetConVarBounds", sm_SetConVarBounds},
+ {"QueryClientConVar", sm_QueryClientConVar},
+ {"RegServerCmd", sm_RegServerCmd},
+ {"RegConsoleCmd", sm_RegConsoleCmd},
+ {"GetCmdArgString", sm_GetCmdArgString},
+ {"GetCmdArgs", sm_GetCmdArgs},
+ {"GetCmdArg", sm_GetCmdArg},
+ {"PrintToServer", sm_PrintToServer},
+ {"PrintToConsole", sm_PrintToConsole},
+ {"RegAdminCmd", sm_RegAdminCmd},
+ {"ServerCommand", sm_ServerCommand},
+ {"InsertServerCommand", sm_InsertServerCommand},
+ {"ServerExecute", sm_ServerExecute},
+ {"ClientCommand", sm_ClientCommand},
+ {"FakeClientCommand", FakeClientCommand},
+ {"ReplyToCommand", ReplyToCommand},
+ {"GetCmdReplySource", GetCmdReplyTarget},
+ {"SetCmdReplySource", SetCmdReplyTarget},
+ {"GetCommandIterator", GetCommandIterator},
+ {"ReadCommandIterator", ReadCommandIterator},
+ {"CheckCommandAccess", CheckCommandAccess},
+ {"FakeClientCommandEx", FakeClientCommandEx},
+ {"IsChatTrigger", IsChatTrigger},
+ {"SetCommandFlags", SetCommandFlags},
+ {"GetCommandFlags", GetCommandFlags},
+ {"FindFirstConCommand", FindFirstConCommand},
+ {"FindNextConCommand", FindNextConCommand},
+ {"SendConVarValue", SendConVarValue},
+ {NULL, NULL}
+};