3 * =============================================================================
5 * Copyright (C) 2004-2008 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 #define NET_SETCONVAR 5
51 ConVarBound_Upper = 0,
55 HandleType_t hCmdIterType = 0;
56 HandleType_t htConCmdIter = 0;
61 List<ConCmdInfo *>::iterator iter;
66 const ConCommandBase *pLast;
69 class ConsoleHelpers :
71 public IHandleTypeDispatch
74 virtual void OnSourceModAllInitialized()
78 g_HandleSys.InitAccessDefaults(NULL, &access);
80 htConCmdIter = g_HandleSys.CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
82 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
84 hCmdIterType = g_HandleSys.CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
86 virtual void OnHandleDestroy(HandleType_t type, void *object)
88 if (type == hCmdIterType)
90 GlobCmdIter *iter = (GlobCmdIter *)object;
93 else if (type == htConCmdIter)
95 ConCmdIter *iter = (ConCmdIter * )object;
99 virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
101 if (type == htConCmdIter)
103 *pSize = sizeof(ConCmdIter);
106 else if (type == hCmdIterType)
108 *pSize = sizeof(GlobCmdIter);
115 class CommandFlagsHelper : public IConCommandTracker
118 void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
120 m_CmdFlags.remove(name);
122 bool GetFlags(const char *name, int *flags)
124 ConCommandBase **ppCmd;
125 ConCommandBase *pCmd;
126 if ((ppCmd=m_CmdFlags.retrieve(name)))
128 TrackConCommandBase((*ppCmd), this);
129 *flags = (*ppCmd)->GetFlags();
132 else if ((pCmd=FindConCommandBase(name)))
134 m_CmdFlags.insert(name, pCmd);
135 TrackConCommandBase(pCmd, this);
136 *flags = pCmd->GetFlags();
144 bool SetFlags(const char *name, int flags)
146 ConCommandBase **ppCmd;
147 ConCommandBase *pCmd;
148 if ((ppCmd=m_CmdFlags.retrieve(name)))
150 (*ppCmd)->SetFlags(flags);
151 TrackConCommandBase((*ppCmd), this);
154 else if ((pCmd=FindConCommandBase(name)))
156 m_CmdFlags.insert(name, pCmd);
157 pCmd->SetFlags(flags);
158 TrackConCommandBase(pCmd, this);
167 KTrie<ConCommandBase *> m_CmdFlags;
168 } s_CommandFlagsHelper;
170 #ifndef ORANGEBOX_BUILD
171 static void ReplicateConVar(ConVar *pConVar)
173 int maxClients = g_Players.GetMaxClients();
176 bf_write buffer(data, sizeof(data));
178 buffer.WriteUBitLong(NET_SETCONVAR, 5);
180 buffer.WriteString(pConVar->GetName());
181 buffer.WriteString(pConVar->GetString());
183 for (int i = 1; i <= maxClients; i++)
185 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
187 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
189 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i));
190 netchan->SendData(buffer);
195 static void NotifyConVar(ConVar *pConVar)
197 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
198 pEvent->SetString("cvarname", pConVar->GetName());
199 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
201 pEvent->SetString("cvarvalue", "***PROTECTED***");
205 pEvent->SetString("cvarvalue", pConVar->GetString());
208 gameevents->FireEvent(pEvent);
212 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
214 char *name, *defaultVal, *helpText;
216 pContext->LocalToString(params[1], &name);
218 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
219 if (name == NULL || strcmp(name, "") == 0)
221 return pContext->ThrowNativeError("Convar with blank name is not permitted");
224 pContext->LocalToString(params[2], &defaultVal);
225 pContext->LocalToString(params[3], &helpText);
227 bool hasMin = params[5] ? true : false;
228 bool hasMax = params[7] ? true : false;
229 float min = sp_ctof(params[6]);
230 float max = sp_ctof(params[8]);
232 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
234 if (hndl == BAD_HANDLE)
236 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
242 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
246 pContext->LocalToString(params[1], &name);
248 return g_ConVarManager.FindConVar(name);
251 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
253 Handle_t hndl = static_cast<Handle_t>(params[1]);
257 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
260 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
263 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
267 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
270 g_ConVarManager.HookConVarChange(pConVar, pFunction);
275 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
277 Handle_t hndl = static_cast<Handle_t>(params[1]);
281 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
284 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
287 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
291 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
294 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
299 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
301 Handle_t hndl = static_cast<Handle_t>(params[1]);
305 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
308 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
311 return pConVar->GetBool();
314 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
316 Handle_t hndl = static_cast<Handle_t>(params[1]);
320 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
323 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
326 return pConVar->GetInt();
329 /* This handles both SetConVarBool() and SetConVarInt() */
330 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
332 Handle_t hndl = static_cast<Handle_t>(params[1]);
336 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
339 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
342 pConVar->SetValue(params[2]);
344 #ifndef ORANGEBOX_BUILD
345 /* Should we replicate it? */
346 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
348 ReplicateConVar(pConVar);
351 /* Should we notify clients? */
352 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
354 NotifyConVar(pConVar);
361 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
363 Handle_t hndl = static_cast<Handle_t>(params[1]);
367 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
370 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
373 float value = pConVar->GetFloat();
375 return sp_ftoc(value);
378 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
380 Handle_t hndl = static_cast<Handle_t>(params[1]);
384 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
387 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
390 float value = sp_ctof(params[2]);
391 pConVar->SetValue(value);
393 #ifndef ORANGEBOX_BUILD
394 /* Should we replicate it? */
395 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
397 ReplicateConVar(pConVar);
400 /* Should we notify clients? */
401 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
403 NotifyConVar(pConVar);
410 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
412 Handle_t hndl = static_cast<Handle_t>(params[1]);
416 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
419 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
422 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
427 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
429 Handle_t hndl = static_cast<Handle_t>(params[1]);
433 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
436 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
440 pContext->LocalToString(params[2], &value);
442 pConVar->SetValue(value);
444 #ifndef ORANGEBOX_BUILD
445 /* Should we replicate it? */
446 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
448 ReplicateConVar(pConVar);
451 /* Should we notify clients? */
452 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
454 NotifyConVar(pConVar);
461 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
463 Handle_t hndl = static_cast<Handle_t>(params[1]);
467 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
470 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
475 #ifndef ORANGEBOX_BUILD
476 /* Should we replicate it? */
477 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
479 ReplicateConVar(pConVar);
482 /* Should we notify clients? */
483 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
485 NotifyConVar(pConVar);
492 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
494 Handle_t hndl = static_cast<Handle_t>(params[1]);
498 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
501 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
504 return pConVar->GetFlags();
507 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
509 Handle_t hndl = static_cast<Handle_t>(params[1]);
513 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
516 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
519 pConVar->SetFlags(params[2]);
524 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
526 Handle_t hndl = static_cast<Handle_t>(params[1]);
530 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
533 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
542 case ConVarBound_Upper:
543 hasBound = pConVar->GetMax(bound);
545 case ConVarBound_Lower:
546 hasBound = pConVar->GetMin(bound);
549 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
552 pContext->LocalToPhysAddr(params[3], &addr);
553 *addr = sp_ftoc(bound);
558 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
560 Handle_t hndl = static_cast<Handle_t>(params[1]);
564 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
567 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
572 case ConVarBound_Upper:
573 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
575 case ConVarBound_Lower:
576 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
579 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
585 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
587 Handle_t hndl = static_cast<Handle_t>(params[1]);
591 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
594 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
597 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
602 static bool s_QueryAlreadyWarned = false;
604 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
608 IPluginFunction *pCallback;
610 if (!g_ConVarManager.IsQueryingSupported())
612 if (!s_QueryAlreadyWarned)
614 s_QueryAlreadyWarned = true;
615 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
621 pPlayer = g_Players.GetPlayerByIndex(params[1]);
625 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
628 if (!pPlayer->IsConnected())
630 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
633 /* Trying a query on a bot results in callback not be fired, so don't bother */
634 if (pPlayer->IsFakeClient())
639 pContext->LocalToString(params[2], &name);
640 pCallback = pContext->GetFunctionById(params[3]);
644 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
647 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
650 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
653 IPluginFunction *pFunction;
655 pContext->LocalToString(params[1], &name);
656 pContext->LocalToString(params[3], &help);
657 pFunction = pContext->GetFunctionById(params[2]);
661 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
664 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
666 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
672 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
675 IPluginFunction *pFunction;
677 pContext->LocalToString(params[1], &name);
678 pContext->LocalToString(params[3], &help);
679 pFunction = pContext->GetFunctionById(params[2]);
683 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
686 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
688 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
694 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
698 IPluginFunction *pFunction;
699 FlagBits flags = params[3];
700 int cmdflags = params[6];
702 pContext->LocalToString(params[1], &name);
703 pContext->LocalToString(params[4], &help);
704 pContext->LocalToString(params[5], (char **)&group);
705 pFunction = pContext->GetFunctionById(params[2]);
707 if (group[0] == '\0')
709 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
710 group = pPlugin->GetFilename();
715 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
718 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
720 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
726 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
728 const CCommand *pCmd = g_HL2.PeekCommandStack();
732 return pContext->ThrowNativeError("No command callback available");
735 return pCmd->ArgC() - 1;
738 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
740 const CCommand *pCmd = g_HL2.PeekCommandStack();
744 return pContext->ThrowNativeError("No command callback available");
749 const char *arg = pCmd->Arg(params[1]);
751 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
753 return (cell_t)length;
756 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
758 const CCommand *pCmd = g_HL2.PeekCommandStack();
762 return pContext->ThrowNativeError("No command callback available");
765 const char *args = pCmd->ArgS();
773 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
775 return (cell_t)length;
778 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
784 pCtx->LocalToString(params[1], &fmt);
785 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
787 buffer[res++] = '\n';
790 META_CONPRINT(buffer);
795 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
797 int index = params[1];
798 if ((index < 0) || (index > g_Players.GetMaxClients()))
800 return pCtx->ThrowNativeError("Client index %d is invalid", index);
803 CPlayer *pPlayer = NULL;
806 pPlayer = g_Players.GetPlayerByIndex(index);
807 if (!pPlayer->IsInGame())
809 return pCtx->ThrowNativeError("Client %d is not in game", index);
812 /* Silent fail on bots, engine will crash */
813 if (pPlayer->IsFakeClient())
823 pCtx->LocalToString(params[2], &fmt);
824 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
826 buffer[res++] = '\n';
831 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
833 META_CONPRINT(buffer);
839 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
841 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
844 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
846 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
851 /* One byte for null terminator, one for newline */
852 buffer[len++] = '\n';
855 engine->ServerCommand(buffer);
860 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
862 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
865 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
867 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
872 /* One byte for null terminator, one for newline */
873 buffer[len++] = '\n';
876 InsertServerCommand(buffer);
881 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
883 engine->ServerExecute();
888 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
890 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
894 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
897 if (!pPlayer->IsConnected())
899 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
902 g_SourceMod.SetGlobalTarget(params[1]);
905 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
907 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
912 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
917 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
919 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
923 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
926 if (!pPlayer->IsConnected())
928 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
932 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
934 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
939 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
944 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
946 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
950 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
953 if (!pPlayer->IsConnected())
955 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
959 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
961 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
966 g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
971 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
973 g_SourceMod.SetGlobalTarget(params[1]);
975 /* Build the format string */
977 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
979 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
984 /* If we're printing to the server, shortcut out */
988 buffer[len++] = '\n';
990 META_CONPRINT(buffer);
994 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
998 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1001 if (!pPlayer->IsConnected())
1003 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1006 g_SourceMod.SetGlobalTarget(params[1]);
1008 unsigned int replyto = g_ChatTriggers.GetReplyTo();
1009 if (replyto == SM_REPLY_CONSOLE)
1011 buffer[len++] = '\n';
1013 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1014 } else if (replyto == SM_REPLY_CHAT) {
1020 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1026 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1028 return g_ChatTriggers.GetReplyTo();
1031 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1033 return g_ChatTriggers.SetReplyTo(params[1]);
1036 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1038 GlobCmdIter *iter = new GlobCmdIter;
1039 iter->started = false;
1041 Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1042 if (hndl == BAD_HANDLE)
1050 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1054 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1056 if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1057 != HandleError_None)
1059 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1062 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1066 iter->iter = cmds.begin();
1067 iter->started = true;
1070 while (iter->iter != cmds.end()
1071 && !(*(iter->iter))->sourceMod)
1076 if (iter->iter == cmds.end())
1081 ConCmdInfo *pInfo = (*(iter->iter));
1083 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1084 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1087 pContext->LocalToPhysAddr(params[4], &addr);
1088 *addr = pInfo->admin.eflags;
1095 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1103 pContext->LocalToString(params[2], &cmd);
1105 /* Auto-detect a command if we can */
1106 FlagBits bits = params[3];
1107 bool found_command = false;
1108 if (params[0] < 4 || !params[4])
1110 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1115 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1118 return g_ConCmds.CheckCommandAccess(params[1], cmd, bits) ? 1 : 0;
1121 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1123 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1126 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1129 pContext->LocalToString(params[1], &name);
1131 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1134 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1138 pContext->LocalToString(params[1], &name);
1140 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1143 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1147 cell_t *pIsCmd, *pFlags;
1148 const ConCommandBase *pConCmd;
1151 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1152 pContext->LocalToPhysAddr(params[4], &pFlags);
1154 pConCmd = icvar->GetCommands();
1156 if (pConCmd == NULL)
1161 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1162 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1163 *pFlags = pConCmd->GetFlags();
1167 desc = pConCmd->GetHelpText();
1168 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1171 pIter = new ConCmdIter;
1172 pIter->pLast = pConCmd;
1174 if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1184 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1188 cell_t *pIsCmd, *pFlags;
1190 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1192 if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1194 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1197 if (pIter->pLast == NULL)
1202 if ((pIter->pLast = pIter->pLast->GetNext()) == NULL)
1207 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1208 pContext->LocalToPhysAddr(params[5], &pFlags);
1210 pContext->StringToLocalUTF8(params[2], params[3], pIter->pLast->GetName(), NULL);
1211 *pIsCmd = pIter->pLast->IsCommand() ? 1 : 0;
1212 *pFlags = pIter->pLast->GetFlags();
1216 desc = pIter->pLast->GetHelpText();
1217 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1223 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1225 Handle_t hndl = static_cast<Handle_t>(params[2]);
1230 pContext->LocalToString(params[3], &value);
1232 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1233 != HandleError_None)
1235 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1239 bf_write buffer(data, sizeof(data));
1241 buffer.WriteUBitLong(NET_SETCONVAR, 5);
1242 buffer.WriteByte(1);
1243 buffer.WriteString(pConVar->GetName());
1244 buffer.WriteString(value);
1246 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1250 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1253 if (!pPlayer->IsConnected())
1255 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1258 if (pPlayer->IsFakeClient())
1260 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1263 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1264 netchan->SendData(buffer);
1269 REGISTER_NATIVES(consoleNatives)
1271 {"CreateConVar", sm_CreateConVar},
1272 {"FindConVar", sm_FindConVar},
1273 {"HookConVarChange", sm_HookConVarChange},
1274 {"UnhookConVarChange", sm_UnhookConVarChange},
1275 {"GetConVarBool", sm_GetConVarBool},
1276 {"SetConVarBool", sm_SetConVarNum},
1277 {"GetConVarInt", sm_GetConVarInt},
1278 {"SetConVarInt", sm_SetConVarNum},
1279 {"GetConVarFloat", sm_GetConVarFloat},
1280 {"SetConVarFloat", sm_SetConVarFloat},
1281 {"GetConVarString", sm_GetConVarString},
1282 {"SetConVarString", sm_SetConVarString},
1283 {"GetConVarFlags", sm_GetConVarFlags},
1284 {"SetConVarFlags", sm_SetConVarFlags},
1285 {"ResetConVar", sm_ResetConVar},
1286 {"GetConVarName", sm_GetConVarName},
1287 {"GetConVarBounds", sm_GetConVarBounds},
1288 {"SetConVarBounds", sm_SetConVarBounds},
1289 {"QueryClientConVar", sm_QueryClientConVar},
1290 {"RegServerCmd", sm_RegServerCmd},
1291 {"RegConsoleCmd", sm_RegConsoleCmd},
1292 {"GetCmdArgString", sm_GetCmdArgString},
1293 {"GetCmdArgs", sm_GetCmdArgs},
1294 {"GetCmdArg", sm_GetCmdArg},
1295 {"PrintToServer", sm_PrintToServer},
1296 {"PrintToConsole", sm_PrintToConsole},
1297 {"RegAdminCmd", sm_RegAdminCmd},
1298 {"ServerCommand", sm_ServerCommand},
1299 {"InsertServerCommand", sm_InsertServerCommand},
1300 {"ServerExecute", sm_ServerExecute},
1301 {"ClientCommand", sm_ClientCommand},
1302 {"FakeClientCommand", FakeClientCommand},
1303 {"ReplyToCommand", ReplyToCommand},
1304 {"GetCmdReplySource", GetCmdReplyTarget},
1305 {"SetCmdReplySource", SetCmdReplyTarget},
1306 {"GetCommandIterator", GetCommandIterator},
1307 {"ReadCommandIterator", ReadCommandIterator},
1308 {"CheckCommandAccess", CheckCommandAccess},
1309 {"FakeClientCommandEx", FakeClientCommandEx},
1310 {"IsChatTrigger", IsChatTrigger},
1311 {"SetCommandFlags", SetCommandFlags},
1312 {"GetCommandFlags", GetCommandFlags},
1313 {"FindFirstConCommand", FindFirstConCommand},
1314 {"FindNextConCommand", FindNextConCommand},
1315 {"SendConVarValue", SendConVarValue},