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 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: 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()); ds@936: if (pConVar->IsBitSet(FCVAR_PROTECTED)) ds@936: { ds@936: pEvent->SetString("cvarvalue", "***PROTECTED***"); ds@936: } else { 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: { ds@582: return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", 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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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? */ ds@936: if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED)) ds@936: { ds@936: ReplicateConVar(pConVar); ds@936: } ds@936: ds@936: /* Should we notify clients? */ ds@936: if (params[4] && pConVar->IsBitSet(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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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? */ ds@936: if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED)) ds@936: { ds@936: ReplicateConVar(pConVar); ds@936: } ds@936: ds@936: /* Should we notify clients? */ ds@936: if (params[4] && pConVar->IsBitSet(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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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? */ ds@936: if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED)) ds@936: { ds@936: ReplicateConVar(pConVar); ds@936: } ds@936: ds@936: /* Should we notify clients? */ ds@936: if (params[4] && pConVar->IsBitSet(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: ds@1301: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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? */ ds@1301: if (params[2] && pConVar->IsBitSet(FCVAR_REPLICATED)) ds@1301: { ds@1301: ReplicateConVar(pConVar); ds@1301: } ds@1301: ds@1301: /* Should we notify clients? */ ds@1301: if (params[3] && pConVar->IsBitSet(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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@576: if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&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: ds@696: if (g_IsOriginalEngine) 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@517: return engine->Cmd_Argc() - 1; dvander@517: } dvander@517: dvander@517: static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params) dvander@517: { dvander@517: const char *arg = engine->Cmd_Argv(params[1]); dvander@1421: size_t length; dvander@517: dvander@1421: pContext->StringToLocalUTF8(params[2], params[3], 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@517: const char *args = engine->Cmd_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: dvander@522: engine->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: 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}, dvander@498: {NULL, NULL} dvander@498: };