3 * =============================================================================
5 * Copyright (C) 2004-2010 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
32 #include "sm_globals.h"
33 #include "HalfLife2.h"
34 #include "sourcemm_api.h"
35 #include "HandleSys.h"
36 #include "ConVarManager.h"
37 #include "ConCmdManager.h"
38 #include "PluginSys.h"
39 #include "sm_stringutil.h"
40 #include "PlayerManager.h"
41 #include "ChatTriggers.h"
42 #include "AdminCache.h"
43 #include <inetchannel.h>
45 #include <sm_trie_tpl.h>
47 #include "ConsoleDetours.h"
48 #include "ConCommandBaseIterator.h"
50 #if SOURCE_ENGINE >= SE_ORANGEBOXVALVE
56 #if SOURCE_ENGINE >= SE_LEFT4DEAD
57 #define NET_SETCONVAR 6
59 #define NET_SETCONVAR 5
64 ConVarBound_Upper = 0,
68 HandleType_t hCmdIterType = 0;
69 HandleType_t htConCmdIter = 0;
74 List<ConCmdInfo *>::iterator iter;
77 class ConsoleHelpers :
79 public IHandleTypeDispatch
82 virtual void OnSourceModAllInitialized()
86 g_HandleSys.InitAccessDefaults(NULL, &access);
88 htConCmdIter = g_HandleSys.CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
90 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
92 hCmdIterType = g_HandleSys.CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
94 virtual void OnHandleDestroy(HandleType_t type, void *object)
96 if (type == hCmdIterType)
98 GlobCmdIter *iter = (GlobCmdIter *)object;
101 else if (type == htConCmdIter)
103 ConCommandBaseIterator *iter = (ConCommandBaseIterator * )object;
107 virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
109 if (type == htConCmdIter)
111 *pSize = sizeof(ConCommandBaseIterator);
114 else if (type == hCmdIterType)
116 *pSize = sizeof(GlobCmdIter);
123 class CommandFlagsHelper : public IConCommandTracker
126 void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
128 m_CmdFlags.remove(name);
130 bool GetFlags(const char *name, int *flags)
132 ConCommandBase **ppCmd;
133 ConCommandBase *pCmd;
134 if ((ppCmd=m_CmdFlags.retrieve(name)))
136 TrackConCommandBase((*ppCmd), this);
137 *flags = (*ppCmd)->GetFlags();
140 else if ((pCmd=FindCommandBase(name)))
142 m_CmdFlags.insert(name, pCmd);
143 TrackConCommandBase(pCmd, this);
144 *flags = pCmd->GetFlags();
152 bool SetFlags(const char *name, int flags)
154 ConCommandBase **ppCmd;
155 ConCommandBase *pCmd;
156 if ((ppCmd=m_CmdFlags.retrieve(name)))
158 (*ppCmd)->SetFlags(flags);
159 TrackConCommandBase((*ppCmd), this);
162 else if ((pCmd=FindCommandBase(name)))
164 m_CmdFlags.insert(name, pCmd);
165 pCmd->SetFlags(flags);
166 TrackConCommandBase(pCmd, this);
175 KTrie<ConCommandBase *> m_CmdFlags;
176 } s_CommandFlagsHelper;
178 #if SOURCE_ENGINE < SE_ORANGEBOX
179 static void ReplicateConVar(ConVar *pConVar)
181 int maxClients = g_Players.GetMaxClients();
184 bf_write buffer(data, sizeof(data));
186 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
188 buffer.WriteString(pConVar->GetName());
189 buffer.WriteString(pConVar->GetString());
191 for (int i = 1; i <= maxClients; i++)
193 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
195 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
197 if (INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i)))
198 netchan->SendData(buffer);
203 static void NotifyConVar(ConVar *pConVar)
205 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
206 pEvent->SetString("cvarname", pConVar->GetName());
207 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
209 pEvent->SetString("cvarvalue", "***PROTECTED***");
213 pEvent->SetString("cvarvalue", pConVar->GetString());
216 gameevents->FireEvent(pEvent);
220 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
222 char *name, *defaultVal, *helpText;
224 pContext->LocalToString(params[1], &name);
226 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
227 if (name == NULL || strcmp(name, "") == 0)
229 return pContext->ThrowNativeError("Convar with blank name is not permitted");
232 pContext->LocalToString(params[2], &defaultVal);
233 pContext->LocalToString(params[3], &helpText);
235 bool hasMin = params[5] ? true : false;
236 bool hasMax = params[7] ? true : false;
237 float min = sp_ctof(params[6]);
238 float max = sp_ctof(params[8]);
240 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
242 if (hndl == BAD_HANDLE)
244 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
250 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
254 pContext->LocalToString(params[1], &name);
256 return g_ConVarManager.FindConVar(name);
259 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
261 Handle_t hndl = static_cast<Handle_t>(params[1]);
265 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
268 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
271 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
275 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
278 g_ConVarManager.HookConVarChange(pConVar, pFunction);
283 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
285 Handle_t hndl = static_cast<Handle_t>(params[1]);
289 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
292 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
295 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
299 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
302 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
307 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
309 Handle_t hndl = static_cast<Handle_t>(params[1]);
313 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
316 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
319 return pConVar->GetBool();
322 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
324 Handle_t hndl = static_cast<Handle_t>(params[1]);
328 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
331 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
334 return pConVar->GetInt();
337 /* This handles both SetConVarBool() and SetConVarInt() */
338 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
340 Handle_t hndl = static_cast<Handle_t>(params[1]);
344 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
347 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
350 pConVar->SetValue(params[2]);
352 #if SOURCE_ENGINE < SE_ORANGEBOX
353 /* Should we replicate it? */
354 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
356 ReplicateConVar(pConVar);
359 /* Should we notify clients? */
360 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
362 NotifyConVar(pConVar);
369 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
371 Handle_t hndl = static_cast<Handle_t>(params[1]);
375 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
378 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
381 float value = pConVar->GetFloat();
383 return sp_ftoc(value);
386 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
388 Handle_t hndl = static_cast<Handle_t>(params[1]);
392 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
395 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
398 float value = sp_ctof(params[2]);
399 pConVar->SetValue(value);
401 #if SOURCE_ENGINE < SE_ORANGEBOX
402 /* Should we replicate it? */
403 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
405 ReplicateConVar(pConVar);
408 /* Should we notify clients? */
409 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
411 NotifyConVar(pConVar);
418 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
420 Handle_t hndl = static_cast<Handle_t>(params[1]);
424 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
427 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
430 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
435 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
437 Handle_t hndl = static_cast<Handle_t>(params[1]);
441 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
444 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
448 pContext->LocalToString(params[2], &value);
450 pConVar->SetValue(value);
452 #if SOURCE_ENGINE < SE_ORANGEBOX
453 /* Should we replicate it? */
454 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
456 ReplicateConVar(pConVar);
459 /* Should we notify clients? */
460 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
462 NotifyConVar(pConVar);
469 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
471 Handle_t hndl = static_cast<Handle_t>(params[1]);
475 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
478 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
483 #if SOURCE_ENGINE < SE_ORANGEBOX
484 /* Should we replicate it? */
485 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
487 ReplicateConVar(pConVar);
490 /* Should we notify clients? */
491 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
493 NotifyConVar(pConVar);
500 static cell_t GetConVarDefault(IPluginContext *pContext, const cell_t *params)
502 Handle_t hndl = static_cast<Handle_t>(params[1]);
506 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
509 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
513 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetDefault(), &bytes);
518 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
520 Handle_t hndl = static_cast<Handle_t>(params[1]);
524 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
527 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
530 return pConVar->GetFlags();
533 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
535 Handle_t hndl = static_cast<Handle_t>(params[1]);
539 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
542 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
545 pConVar->SetFlags(params[2]);
550 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
552 Handle_t hndl = static_cast<Handle_t>(params[1]);
556 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
559 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
568 case ConVarBound_Upper:
569 hasBound = pConVar->GetMax(bound);
571 case ConVarBound_Lower:
572 hasBound = pConVar->GetMin(bound);
575 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
578 pContext->LocalToPhysAddr(params[3], &addr);
579 *addr = sp_ftoc(bound);
584 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
586 Handle_t hndl = static_cast<Handle_t>(params[1]);
590 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
593 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
598 case ConVarBound_Upper:
599 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
601 case ConVarBound_Lower:
602 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
605 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
611 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
613 Handle_t hndl = static_cast<Handle_t>(params[1]);
617 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
620 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
623 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
628 static bool s_QueryAlreadyWarned = false;
630 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
634 IPluginFunction *pCallback;
636 if (!g_ConVarManager.IsQueryingSupported())
638 if (!s_QueryAlreadyWarned)
640 s_QueryAlreadyWarned = true;
641 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
647 pPlayer = g_Players.GetPlayerByIndex(params[1]);
651 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
654 if (!pPlayer->IsConnected())
656 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
659 /* Trying a query on a bot results in callback not be fired, so don't bother */
660 if (pPlayer->IsFakeClient())
665 pContext->LocalToString(params[2], &name);
666 pCallback = pContext->GetFunctionById(params[3]);
670 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
673 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
676 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
679 IPluginFunction *pFunction;
681 pContext->LocalToString(params[1], &name);
683 if (strcasecmp(name, "sm") == 0)
685 return pContext->ThrowNativeError("Cannot register \"sm\" command");
688 pContext->LocalToString(params[3], &help);
689 pFunction = pContext->GetFunctionById(params[2]);
693 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
696 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
698 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
704 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
707 IPluginFunction *pFunction;
709 pContext->LocalToString(params[1], &name);
711 if (strcasecmp(name, "sm") == 0)
713 return pContext->ThrowNativeError("Cannot register \"sm\" command");
716 pContext->LocalToString(params[3], &help);
717 pFunction = pContext->GetFunctionById(params[2]);
721 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
724 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
726 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
732 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
736 IPluginFunction *pFunction;
737 FlagBits flags = params[3];
738 int cmdflags = params[6];
740 pContext->LocalToString(params[1], &name);
742 if (strcasecmp(name, "sm") == 0)
744 return pContext->ThrowNativeError("Cannot register \"sm\" command");
747 pContext->LocalToString(params[4], &help);
748 pContext->LocalToString(params[5], (char **)&group);
749 pFunction = pContext->GetFunctionById(params[2]);
751 if (group[0] == '\0')
753 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
754 group = pPlugin->GetFilename();
759 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
762 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
764 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
770 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
772 const CCommand *pCmd = g_HL2.PeekCommandStack();
776 return pContext->ThrowNativeError("No command callback available");
779 return pCmd->ArgC() - 1;
782 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
784 const CCommand *pCmd = g_HL2.PeekCommandStack();
788 return pContext->ThrowNativeError("No command callback available");
793 const char *arg = pCmd->Arg(params[1]);
795 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
797 return (cell_t)length;
800 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
802 const CCommand *pCmd = g_HL2.PeekCommandStack();
806 return pContext->ThrowNativeError("No command callback available");
809 const char *args = pCmd->ArgS();
817 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
819 return (cell_t)length;
822 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
828 pCtx->LocalToString(params[1], &fmt);
829 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
831 buffer[res++] = '\n';
834 META_CONPRINT(buffer);
839 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
841 int index = params[1];
842 if ((index < 0) || (index > g_Players.GetMaxClients()))
844 return pCtx->ThrowNativeError("Client index %d is invalid", index);
847 CPlayer *pPlayer = NULL;
850 pPlayer = g_Players.GetPlayerByIndex(index);
851 if (!pPlayer->IsInGame())
853 return pCtx->ThrowNativeError("Client %d is not in game", index);
856 /* Silent fail on bots, engine will crash */
857 if (pPlayer->IsFakeClient())
867 pCtx->LocalToString(params[2], &fmt);
868 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
870 buffer[res++] = '\n';
875 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
877 META_CONPRINT(buffer);
883 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
885 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
888 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
890 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
895 /* One byte for null terminator, one for newline */
896 buffer[len++] = '\n';
899 engine->ServerCommand(buffer);
904 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
906 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
909 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
911 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
916 /* One byte for null terminator, one for newline */
917 buffer[len++] = '\n';
920 InsertServerCommand(buffer);
925 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
927 engine->ServerExecute();
932 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
934 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
938 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
941 if (!pPlayer->IsConnected())
943 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
946 g_SourceMod.SetGlobalTarget(params[1]);
949 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
951 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
956 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
961 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
963 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
967 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
970 if (!pPlayer->IsConnected())
972 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
976 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
978 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
983 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
988 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
990 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
994 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
997 if (!pPlayer->IsConnected())
999 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1003 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1005 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1010 g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
1015 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
1017 g_SourceMod.SetGlobalTarget(params[1]);
1019 /* Build the format string */
1021 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
1023 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1028 /* If we're printing to the server, shortcut out */
1032 buffer[len++] = '\n';
1034 META_CONPRINT(buffer);
1038 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1042 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1045 if (!pPlayer->IsConnected())
1047 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1050 g_SourceMod.SetGlobalTarget(params[1]);
1052 unsigned int replyto = g_ChatTriggers.GetReplyTo();
1053 if (replyto == SM_REPLY_CONSOLE)
1055 buffer[len++] = '\n';
1057 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1058 } else if (replyto == SM_REPLY_CHAT) {
1064 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1070 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1072 return g_ChatTriggers.GetReplyTo();
1075 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1077 return g_ChatTriggers.SetReplyTo(params[1]);
1080 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1082 GlobCmdIter *iter = new GlobCmdIter;
1083 iter->started = false;
1085 Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1086 if (hndl == BAD_HANDLE)
1094 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1098 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1100 if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1101 != HandleError_None)
1103 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1106 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1110 iter->iter = cmds.begin();
1111 iter->started = true;
1114 while (iter->iter != cmds.end()
1115 && !(*(iter->iter))->sourceMod)
1120 if (iter->iter == cmds.end())
1125 ConCmdInfo *pInfo = (*(iter->iter));
1127 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1128 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1131 pContext->LocalToPhysAddr(params[4], &addr);
1132 *addr = pInfo->admin.eflags;
1139 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1147 pContext->LocalToString(params[2], &cmd);
1149 /* Auto-detect a command if we can */
1150 FlagBits bits = params[3];
1151 bool found_command = false;
1152 if (params[0] < 4 || !params[4])
1154 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1159 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1162 return g_ConCmds.CheckCommandAccess(params[1], cmd, bits) ? 1 : 0;
1165 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1167 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1170 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1173 pContext->LocalToString(params[1], &name);
1175 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1178 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1182 pContext->LocalToString(params[1], &name);
1184 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1187 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1190 ConCommandBaseIterator *pIter;
1191 cell_t *pIsCmd, *pFlags;
1192 const ConCommandBase *pConCmd;
1195 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1196 pContext->LocalToPhysAddr(params[4], &pFlags);
1198 pIter = new ConCommandBaseIterator();
1200 if (!pIter->IsValid())
1206 pConCmd = pIter->Get();
1208 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1209 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1210 *pFlags = pConCmd->GetFlags();
1214 desc = pConCmd->GetHelpText();
1215 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1218 if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1228 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1231 ConCommandBaseIterator *pIter;
1232 cell_t *pIsCmd, *pFlags;
1234 const ConCommandBase *pConCmd;
1235 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1237 if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1239 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1242 if (!pIter->IsValid())
1248 if (!pIter->IsValid())
1252 pConCmd = pIter->Get();
1254 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1255 pContext->LocalToPhysAddr(params[5], &pFlags);
1257 pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
1258 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1259 *pFlags = pConCmd->GetFlags();
1263 desc = pConCmd->GetHelpText();
1264 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1270 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1272 Handle_t hndl = static_cast<Handle_t>(params[2]);
1277 pContext->LocalToString(params[3], &value);
1279 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1280 != HandleError_None)
1282 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1286 bf_write buffer(data, sizeof(data));
1288 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
1289 buffer.WriteByte(1);
1290 buffer.WriteString(pConVar->GetName());
1291 buffer.WriteString(value);
1293 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1297 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1300 if (!pPlayer->IsConnected())
1302 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1305 if (pPlayer->IsFakeClient())
1307 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1310 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1311 if (netchan == NULL)
1316 netchan->SendData(buffer);
1321 static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
1326 static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
1331 static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
1334 IPluginFunction *pFunction;
1336 pContext->LocalToString(params[2], &name);
1338 if (strcasecmp(name, "sm") == 0)
1340 g_Logger.LogError("Request to register \"sm\" command denied.");
1344 pFunction = pContext->GetFunctionById(params[1]);
1347 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1349 if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
1350 return pContext->ThrowNativeError("This game does not support command listeners");
1355 static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
1358 IPluginFunction *pFunction;
1360 pContext->LocalToString(params[2], &name);
1361 pFunction = pContext->GetFunctionById(params[1]);
1363 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1365 if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
1366 return pContext->ThrowNativeError("No matching callback was registered");
1371 REGISTER_NATIVES(consoleNatives)
1373 {"CreateConVar", sm_CreateConVar},
1374 {"FindConVar", sm_FindConVar},
1375 {"HookConVarChange", sm_HookConVarChange},
1376 {"UnhookConVarChange", sm_UnhookConVarChange},
1377 {"GetConVarBool", sm_GetConVarBool},
1378 {"SetConVarBool", sm_SetConVarNum},
1379 {"GetConVarInt", sm_GetConVarInt},
1380 {"SetConVarInt", sm_SetConVarNum},
1381 {"GetConVarFloat", sm_GetConVarFloat},
1382 {"SetConVarFloat", sm_SetConVarFloat},
1383 {"GetConVarString", sm_GetConVarString},
1384 {"SetConVarString", sm_SetConVarString},
1385 {"GetConVarFlags", sm_GetConVarFlags},
1386 {"SetConVarFlags", sm_SetConVarFlags},
1387 {"ResetConVar", sm_ResetConVar},
1388 {"GetConVarName", sm_GetConVarName},
1389 {"GetConVarBounds", sm_GetConVarBounds},
1390 {"SetConVarBounds", sm_SetConVarBounds},
1391 {"QueryClientConVar", sm_QueryClientConVar},
1392 {"GetConVarDefault", GetConVarDefault},
1393 {"RegServerCmd", sm_RegServerCmd},
1394 {"RegConsoleCmd", sm_RegConsoleCmd},
1395 {"GetCmdArgString", sm_GetCmdArgString},
1396 {"GetCmdArgs", sm_GetCmdArgs},
1397 {"GetCmdArg", sm_GetCmdArg},
1398 {"PrintToServer", sm_PrintToServer},
1399 {"PrintToConsole", sm_PrintToConsole},
1400 {"RegAdminCmd", sm_RegAdminCmd},
1401 {"ServerCommand", sm_ServerCommand},
1402 {"InsertServerCommand", sm_InsertServerCommand},
1403 {"ServerExecute", sm_ServerExecute},
1404 {"ClientCommand", sm_ClientCommand},
1405 {"FakeClientCommand", FakeClientCommand},
1406 {"ReplyToCommand", ReplyToCommand},
1407 {"GetCmdReplySource", GetCmdReplyTarget},
1408 {"SetCmdReplySource", SetCmdReplyTarget},
1409 {"GetCommandIterator", GetCommandIterator},
1410 {"ReadCommandIterator", ReadCommandIterator},
1411 {"CheckCommandAccess", CheckCommandAccess},
1412 {"FakeClientCommandEx", FakeClientCommandEx},
1413 {"IsChatTrigger", IsChatTrigger},
1414 {"SetCommandFlags", SetCommandFlags},
1415 {"GetCommandFlags", GetCommandFlags},
1416 {"FindFirstConCommand", FindFirstConCommand},
1417 {"FindNextConCommand", FindNextConCommand},
1418 {"SendConVarValue", SendConVarValue},
1419 {"AddServerTag", AddServerTag},
1420 {"RemoveServerTag", RemoveServerTag},
1421 {"AddCommandListener", AddCommandListener},
1422 {"RemoveCommandListener", RemoveCommandListener},