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 static void ReplicateConVar(ConVar *pConVar)
172 int maxClients = g_Players.GetMaxClients();
175 bf_write buffer(data, sizeof(data));
177 buffer.WriteUBitLong(NET_SETCONVAR, 5);
179 buffer.WriteString(pConVar->GetName());
180 buffer.WriteString(pConVar->GetString());
182 for (int i = 1; i <= maxClients; i++)
184 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
186 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
188 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i));
189 netchan->SendData(buffer);
194 static void NotifyConVar(ConVar *pConVar)
196 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
197 pEvent->SetString("cvarname", pConVar->GetName());
198 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
200 pEvent->SetString("cvarvalue", "***PROTECTED***");
204 pEvent->SetString("cvarvalue", pConVar->GetString());
207 gameevents->FireEvent(pEvent);
210 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
212 char *name, *defaultVal, *helpText;
214 pContext->LocalToString(params[1], &name);
216 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
217 if (name == NULL || strcmp(name, "") == 0)
219 return pContext->ThrowNativeError("Convar with blank name is not permitted");
222 pContext->LocalToString(params[2], &defaultVal);
223 pContext->LocalToString(params[3], &helpText);
225 bool hasMin = params[5] ? true : false;
226 bool hasMax = params[7] ? true : false;
227 float min = sp_ctof(params[6]);
228 float max = sp_ctof(params[8]);
230 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
232 if (hndl == BAD_HANDLE)
234 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
240 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
244 pContext->LocalToString(params[1], &name);
246 return g_ConVarManager.FindConVar(name);
249 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
251 Handle_t hndl = static_cast<Handle_t>(params[1]);
255 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
258 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
261 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
265 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
268 g_ConVarManager.HookConVarChange(pConVar, pFunction);
273 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
275 Handle_t hndl = static_cast<Handle_t>(params[1]);
279 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
282 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
285 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
289 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
292 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
297 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
299 Handle_t hndl = static_cast<Handle_t>(params[1]);
303 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
306 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
309 return pConVar->GetBool();
312 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
314 Handle_t hndl = static_cast<Handle_t>(params[1]);
318 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
321 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
324 return pConVar->GetInt();
327 /* This handles both SetConVarBool() and SetConVarInt() */
328 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
330 Handle_t hndl = static_cast<Handle_t>(params[1]);
334 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
337 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
340 pConVar->SetValue(params[2]);
342 /* Should we replicate it? */
343 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
345 ReplicateConVar(pConVar);
348 /* Should we notify clients? */
349 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
351 NotifyConVar(pConVar);
357 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
359 Handle_t hndl = static_cast<Handle_t>(params[1]);
363 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
366 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
369 float value = pConVar->GetFloat();
371 return sp_ftoc(value);
374 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
376 Handle_t hndl = static_cast<Handle_t>(params[1]);
380 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
383 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
386 float value = sp_ctof(params[2]);
387 pConVar->SetValue(value);
389 /* Should we replicate it? */
390 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
392 ReplicateConVar(pConVar);
395 /* Should we notify clients? */
396 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
398 NotifyConVar(pConVar);
404 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
406 Handle_t hndl = static_cast<Handle_t>(params[1]);
410 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
413 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
416 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
421 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
423 Handle_t hndl = static_cast<Handle_t>(params[1]);
427 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
430 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
434 pContext->LocalToString(params[2], &value);
436 pConVar->SetValue(value);
438 /* Should we replicate it? */
439 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
441 ReplicateConVar(pConVar);
444 /* Should we notify clients? */
445 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
447 NotifyConVar(pConVar);
453 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
455 Handle_t hndl = static_cast<Handle_t>(params[1]);
459 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
462 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
467 /* Should we replicate it? */
468 if (params[2] && IsFlagSet(pConVar, FCVAR_REPLICATED))
470 ReplicateConVar(pConVar);
473 /* Should we notify clients? */
474 if (params[3] && IsFlagSet(pConVar, FCVAR_NOTIFY))
476 NotifyConVar(pConVar);
482 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
484 Handle_t hndl = static_cast<Handle_t>(params[1]);
488 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
491 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
494 return pConVar->GetFlags();
497 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
499 Handle_t hndl = static_cast<Handle_t>(params[1]);
503 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
506 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
509 pConVar->SetFlags(params[2]);
514 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
516 Handle_t hndl = static_cast<Handle_t>(params[1]);
520 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
523 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
532 case ConVarBound_Upper:
533 hasBound = pConVar->GetMax(bound);
535 case ConVarBound_Lower:
536 hasBound = pConVar->GetMin(bound);
539 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
542 pContext->LocalToPhysAddr(params[3], &addr);
543 *addr = sp_ftoc(bound);
548 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
550 Handle_t hndl = static_cast<Handle_t>(params[1]);
554 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
557 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
562 case ConVarBound_Upper:
563 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
565 case ConVarBound_Lower:
566 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
569 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
575 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
577 Handle_t hndl = static_cast<Handle_t>(params[1]);
581 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
584 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
587 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
592 static bool s_QueryAlreadyWarned = false;
594 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
598 IPluginFunction *pCallback;
600 if (!g_ConVarManager.IsQueryingSupported())
602 if (!s_QueryAlreadyWarned)
604 s_QueryAlreadyWarned = true;
605 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
611 pPlayer = g_Players.GetPlayerByIndex(params[1]);
615 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
618 if (!pPlayer->IsConnected())
620 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
623 /* Trying a query on a bot results in callback not be fired, so don't bother */
624 if (pPlayer->IsFakeClient())
629 pContext->LocalToString(params[2], &name);
630 pCallback = pContext->GetFunctionById(params[3]);
634 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
637 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
640 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
643 IPluginFunction *pFunction;
645 pContext->LocalToString(params[1], &name);
646 pContext->LocalToString(params[3], &help);
647 pFunction = pContext->GetFunctionById(params[2]);
651 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
654 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
656 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
662 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
665 IPluginFunction *pFunction;
667 pContext->LocalToString(params[1], &name);
668 pContext->LocalToString(params[3], &help);
669 pFunction = pContext->GetFunctionById(params[2]);
673 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
676 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
678 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
684 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
688 IPluginFunction *pFunction;
689 FlagBits flags = params[3];
690 int cmdflags = params[6];
692 pContext->LocalToString(params[1], &name);
693 pContext->LocalToString(params[4], &help);
694 pContext->LocalToString(params[5], (char **)&group);
695 pFunction = pContext->GetFunctionById(params[2]);
697 if (group[0] == '\0')
699 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
700 group = pPlugin->GetFilename();
705 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
708 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
710 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
716 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
718 const CCommand *pCmd = g_HL2.PeekCommandStack();
722 return pContext->ThrowNativeError("No command callback available");
725 return pCmd->ArgC() - 1;
728 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
730 const CCommand *pCmd = g_HL2.PeekCommandStack();
734 return pContext->ThrowNativeError("No command callback available");
739 const char *arg = pCmd->Arg(params[1]);
741 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
743 return (cell_t)length;
746 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
748 const CCommand *pCmd = g_HL2.PeekCommandStack();
752 return pContext->ThrowNativeError("No command callback available");
755 const char *args = pCmd->ArgS();
763 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
765 return (cell_t)length;
768 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
774 pCtx->LocalToString(params[1], &fmt);
775 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
777 buffer[res++] = '\n';
780 META_CONPRINT(buffer);
785 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
787 int index = params[1];
788 if ((index < 0) || (index > g_Players.GetMaxClients()))
790 return pCtx->ThrowNativeError("Client index %d is invalid", index);
793 CPlayer *pPlayer = NULL;
796 pPlayer = g_Players.GetPlayerByIndex(index);
797 if (!pPlayer->IsInGame())
799 return pCtx->ThrowNativeError("Client %d is not in game", index);
802 /* Silent fail on bots, engine will crash */
803 if (pPlayer->IsFakeClient())
813 pCtx->LocalToString(params[2], &fmt);
814 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
816 buffer[res++] = '\n';
821 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
823 META_CONPRINT(buffer);
829 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
831 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
834 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
836 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
841 /* One byte for null terminator, one for newline */
842 buffer[len++] = '\n';
845 engine->ServerCommand(buffer);
850 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
852 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
855 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
857 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
862 /* One byte for null terminator, one for newline */
863 buffer[len++] = '\n';
866 InsertServerCommand(buffer);
871 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
873 engine->ServerExecute();
878 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
880 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
884 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
887 if (!pPlayer->IsConnected())
889 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
892 g_SourceMod.SetGlobalTarget(params[1]);
895 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
897 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
902 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
907 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
909 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
913 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
916 if (!pPlayer->IsConnected())
918 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
922 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
924 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
929 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
934 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
936 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
940 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
943 if (!pPlayer->IsConnected())
945 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
949 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
951 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
956 g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
961 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
963 g_SourceMod.SetGlobalTarget(params[1]);
965 /* Build the format string */
967 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
969 if (pContext->GetContext()->n_err != SP_ERROR_NONE)
974 /* If we're printing to the server, shortcut out */
978 buffer[len++] = '\n';
980 META_CONPRINT(buffer);
984 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
988 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
991 if (!pPlayer->IsConnected())
993 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
996 g_SourceMod.SetGlobalTarget(params[1]);
998 unsigned int replyto = g_ChatTriggers.GetReplyTo();
999 if (replyto == SM_REPLY_CONSOLE)
1001 buffer[len++] = '\n';
1003 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1004 } else if (replyto == SM_REPLY_CHAT) {
1010 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1016 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1018 return g_ChatTriggers.GetReplyTo();
1021 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1023 return g_ChatTriggers.SetReplyTo(params[1]);
1026 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1028 GlobCmdIter *iter = new GlobCmdIter;
1029 iter->started = false;
1031 Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1032 if (hndl == BAD_HANDLE)
1040 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1044 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1046 if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1047 != HandleError_None)
1049 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1052 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1056 iter->iter = cmds.begin();
1057 iter->started = true;
1060 while (iter->iter != cmds.end()
1061 && !(*(iter->iter))->sourceMod)
1066 if (iter->iter == cmds.end())
1071 ConCmdInfo *pInfo = (*(iter->iter));
1073 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1074 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1077 pContext->LocalToPhysAddr(params[4], &addr);
1078 *addr = pInfo->admin.eflags;
1085 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1093 pContext->LocalToString(params[2], &cmd);
1095 /* Auto-detect a command if we can */
1096 FlagBits bits = params[3];
1097 bool found_command = false;
1098 if (params[0] < 4 || !params[4])
1100 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1105 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1108 return g_ConCmds.CheckCommandAccess(params[1], cmd, bits) ? 1 : 0;
1111 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1113 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1116 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1119 pContext->LocalToString(params[1], &name);
1121 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1124 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1128 pContext->LocalToString(params[1], &name);
1130 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1133 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1137 cell_t *pIsCmd, *pFlags;
1138 const ConCommandBase *pConCmd;
1141 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1142 pContext->LocalToPhysAddr(params[4], &pFlags);
1144 pConCmd = icvar->GetCommands();
1146 if (pConCmd == NULL)
1151 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1152 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1153 *pFlags = pConCmd->GetFlags();
1157 desc = pConCmd->GetHelpText();
1158 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1161 pIter = new ConCmdIter;
1162 pIter->pLast = pConCmd;
1164 if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1174 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1178 cell_t *pIsCmd, *pFlags;
1180 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1182 if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1184 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1187 if (pIter->pLast == NULL)
1192 if ((pIter->pLast = pIter->pLast->GetNext()) == NULL)
1197 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1198 pContext->LocalToPhysAddr(params[5], &pFlags);
1200 pContext->StringToLocalUTF8(params[2], params[3], pIter->pLast->GetName(), NULL);
1201 *pIsCmd = pIter->pLast->IsCommand() ? 1 : 0;
1202 *pFlags = pIter->pLast->GetFlags();
1206 desc = pIter->pLast->GetHelpText();
1207 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1213 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1215 Handle_t hndl = static_cast<Handle_t>(params[2]);
1220 pContext->LocalToString(params[3], &value);
1222 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1223 != HandleError_None)
1225 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1229 bf_write buffer(data, sizeof(data));
1231 buffer.WriteUBitLong(NET_SETCONVAR, 5);
1232 buffer.WriteByte(1);
1233 buffer.WriteString(pConVar->GetName());
1234 buffer.WriteString(value);
1236 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1240 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1243 if (!pPlayer->IsConnected())
1245 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1248 if (pPlayer->IsFakeClient())
1250 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1253 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1254 netchan->SendData(buffer);
1259 REGISTER_NATIVES(consoleNatives)
1261 {"CreateConVar", sm_CreateConVar},
1262 {"FindConVar", sm_FindConVar},
1263 {"HookConVarChange", sm_HookConVarChange},
1264 {"UnhookConVarChange", sm_UnhookConVarChange},
1265 {"GetConVarBool", sm_GetConVarBool},
1266 {"SetConVarBool", sm_SetConVarNum},
1267 {"GetConVarInt", sm_GetConVarInt},
1268 {"SetConVarInt", sm_SetConVarNum},
1269 {"GetConVarFloat", sm_GetConVarFloat},
1270 {"SetConVarFloat", sm_SetConVarFloat},
1271 {"GetConVarString", sm_GetConVarString},
1272 {"SetConVarString", sm_SetConVarString},
1273 {"GetConVarFlags", sm_GetConVarFlags},
1274 {"SetConVarFlags", sm_SetConVarFlags},
1275 {"ResetConVar", sm_ResetConVar},
1276 {"GetConVarName", sm_GetConVarName},
1277 {"GetConVarBounds", sm_GetConVarBounds},
1278 {"SetConVarBounds", sm_SetConVarBounds},
1279 {"QueryClientConVar", sm_QueryClientConVar},
1280 {"RegServerCmd", sm_RegServerCmd},
1281 {"RegConsoleCmd", sm_RegConsoleCmd},
1282 {"GetCmdArgString", sm_GetCmdArgString},
1283 {"GetCmdArgs", sm_GetCmdArgs},
1284 {"GetCmdArg", sm_GetCmdArg},
1285 {"PrintToServer", sm_PrintToServer},
1286 {"PrintToConsole", sm_PrintToConsole},
1287 {"RegAdminCmd", sm_RegAdminCmd},
1288 {"ServerCommand", sm_ServerCommand},
1289 {"InsertServerCommand", sm_InsertServerCommand},
1290 {"ServerExecute", sm_ServerExecute},
1291 {"ClientCommand", sm_ClientCommand},
1292 {"FakeClientCommand", FakeClientCommand},
1293 {"ReplyToCommand", ReplyToCommand},
1294 {"GetCmdReplySource", GetCmdReplyTarget},
1295 {"SetCmdReplySource", SetCmdReplyTarget},
1296 {"GetCommandIterator", GetCommandIterator},
1297 {"ReadCommandIterator", ReadCommandIterator},
1298 {"CheckCommandAccess", CheckCommandAccess},
1299 {"FakeClientCommandEx", FakeClientCommandEx},
1300 {"IsChatTrigger", IsChatTrigger},
1301 {"SetCommandFlags", SetCommandFlags},
1302 {"GetCommandFlags", GetCommandFlags},
1303 {"FindFirstConCommand", FindFirstConCommand},
1304 {"FindNextConCommand", FindNextConCommand},
1305 {"SendConVarValue", SendConVarValue},