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