Re-enabled PDB files.
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 #include "ConsoleDetours.h"
49 #if SOURCE_ENGINE == SE_LEFT4DEAD
50 #define NET_SETCONVAR 6
52 #define NET_SETCONVAR 5
57 ConVarBound_Upper = 0,
61 HandleType_t hCmdIterType = 0;
62 HandleType_t htConCmdIter = 0;
67 List<ConCmdInfo *>::iterator iter;
72 #if SOURCE_ENGINE == SE_LEFT4DEAD
73 ICvarIteratorInternal *pLast;
75 const ConCommandBase *pLast;
79 class ConsoleHelpers :
81 public IHandleTypeDispatch
84 virtual void OnSourceModAllInitialized()
88 g_HandleSys.InitAccessDefaults(NULL, &access);
90 htConCmdIter = g_HandleSys.CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
92 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
94 hCmdIterType = g_HandleSys.CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
96 virtual void OnHandleDestroy(HandleType_t type, void *object)
98 if (type == hCmdIterType)
100 GlobCmdIter *iter = (GlobCmdIter *)object;
103 else if (type == htConCmdIter)
105 ConCmdIter *iter = (ConCmdIter * )object;
106 #if SOURCE_ENGINE == SE_LEFT4DEAD
107 // ICvarIteratorInternal has no virtual destructor
108 g_pMemAlloc->Free(iter->pLast);
113 virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
115 if (type == htConCmdIter)
117 *pSize = sizeof(ConCmdIter);
120 else if (type == hCmdIterType)
122 *pSize = sizeof(GlobCmdIter);
129 class CommandFlagsHelper : public IConCommandTracker
132 void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
134 m_CmdFlags.remove(name);
136 bool GetFlags(const char *name, int *flags)
138 ConCommandBase **ppCmd;
139 ConCommandBase *pCmd;
140 if ((ppCmd=m_CmdFlags.retrieve(name)))
142 TrackConCommandBase((*ppCmd), this);
143 *flags = (*ppCmd)->GetFlags();
146 else if ((pCmd=FindCommandBase(name)))
148 m_CmdFlags.insert(name, pCmd);
149 TrackConCommandBase(pCmd, this);
150 *flags = pCmd->GetFlags();
158 bool SetFlags(const char *name, int flags)
160 ConCommandBase **ppCmd;
161 ConCommandBase *pCmd;
162 if ((ppCmd=m_CmdFlags.retrieve(name)))
164 (*ppCmd)->SetFlags(flags);
165 TrackConCommandBase((*ppCmd), this);
168 else if ((pCmd=FindCommandBase(name)))
170 m_CmdFlags.insert(name, pCmd);
171 pCmd->SetFlags(flags);
172 TrackConCommandBase(pCmd, this);
181 KTrie<ConCommandBase *> m_CmdFlags;
182 } s_CommandFlagsHelper;
184 #if SOURCE_ENGINE >= SE_ORANGEBOX
185 static void ReplicateConVar(ConVar *pConVar)
187 int maxClients = g_Players.GetMaxClients();
190 bf_write buffer(data, sizeof(data));
192 buffer.WriteUBitLong(NET_SETCONVAR, 5);
194 buffer.WriteString(pConVar->GetName());
195 buffer.WriteString(pConVar->GetString());
197 for (int i = 1; i <= maxClients; i++)
199 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
201 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
203 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i));
204 netchan->SendData(buffer);
209 static void NotifyConVar(ConVar *pConVar)
211 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
212 pEvent->SetString("cvarname", pConVar->GetName());
213 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
215 pEvent->SetString("cvarvalue", "***PROTECTED***");
219 pEvent->SetString("cvarvalue", pConVar->GetString());
222 gameevents->FireEvent(pEvent);
226 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
228 char *name, *defaultVal, *helpText;
230 pContext->LocalToString(params[1], &name);
232 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
233 if (name == NULL || strcmp(name, "") == 0)
235 return pContext->ThrowNativeError("Convar with blank name is not permitted");
238 pContext->LocalToString(params[2], &defaultVal);
239 pContext->LocalToString(params[3], &helpText);
241 bool hasMin = params[5] ? true : false;
242 bool hasMax = params[7] ? true : false;
243 float min = sp_ctof(params[6]);
244 float max = sp_ctof(params[8]);
246 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
248 if (hndl == BAD_HANDLE)
250 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
256 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
260 pContext->LocalToString(params[1], &name);
262 return g_ConVarManager.FindConVar(name);
265 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
267 Handle_t hndl = static_cast<Handle_t>(params[1]);
271 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
274 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
277 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
281 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
284 g_ConVarManager.HookConVarChange(pConVar, pFunction);
289 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
291 Handle_t hndl = static_cast<Handle_t>(params[1]);
295 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
298 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
301 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
305 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
308 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
313 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
315 Handle_t hndl = static_cast<Handle_t>(params[1]);
319 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
322 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
325 return pConVar->GetBool();
328 static cell_t sm_GetConVarInt(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 return pConVar->GetInt();
343 /* This handles both SetConVarBool() and SetConVarInt() */
344 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
346 Handle_t hndl = static_cast<Handle_t>(params[1]);
350 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
353 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
356 pConVar->SetValue(params[2]);
358 #if SOURCE_ENGINE >= SE_ORANGEBOX
359 /* Should we replicate it? */
360 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
362 ReplicateConVar(pConVar);
365 /* Should we notify clients? */
366 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
368 NotifyConVar(pConVar);
375 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
377 Handle_t hndl = static_cast<Handle_t>(params[1]);
381 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
384 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
387 float value = pConVar->GetFloat();
389 return sp_ftoc(value);
392 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
394 Handle_t hndl = static_cast<Handle_t>(params[1]);
398 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
401 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
404 float value = sp_ctof(params[2]);
405 pConVar->SetValue(value);
407 #if SOURCE_ENGINE >= SE_ORANGEBOX
408 /* Should we replicate it? */
409 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
411 ReplicateConVar(pConVar);
414 /* Should we notify clients? */
415 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
417 NotifyConVar(pConVar);
424 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
426 Handle_t hndl = static_cast<Handle_t>(params[1]);
430 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
433 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
436 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
441 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
443 Handle_t hndl = static_cast<Handle_t>(params[1]);
447 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
450 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
454 pContext->LocalToString(params[2], &value);
456 pConVar->SetValue(value);
458 #if SOURCE_ENGINE >= SE_ORANGEBOX
459 /* Should we replicate it? */
460 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
462 ReplicateConVar(pConVar);
465 /* Should we notify clients? */
466 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
468 NotifyConVar(pConVar);
475 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
477 Handle_t hndl = static_cast<Handle_t>(params[1]);
481 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
484 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
489 #if SOURCE_ENGINE >= SE_ORANGEBOX
490 /* Should we replicate it? */
491 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
493 ReplicateConVar(pConVar);
496 /* Should we notify clients? */
497 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
499 NotifyConVar(pConVar);
506 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
508 Handle_t hndl = static_cast<Handle_t>(params[1]);
512 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
515 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
518 return pConVar->GetFlags();
521 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
523 Handle_t hndl = static_cast<Handle_t>(params[1]);
527 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
530 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
533 pConVar->SetFlags(params[2]);
538 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
540 Handle_t hndl = static_cast<Handle_t>(params[1]);
544 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
547 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
556 case ConVarBound_Upper:
557 hasBound = pConVar->GetMax(bound);
559 case ConVarBound_Lower:
560 hasBound = pConVar->GetMin(bound);
563 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
566 pContext->LocalToPhysAddr(params[3], &addr);
567 *addr = sp_ftoc(bound);
572 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
574 Handle_t hndl = static_cast<Handle_t>(params[1]);
578 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
581 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
586 case ConVarBound_Upper:
587 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
589 case ConVarBound_Lower:
590 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
593 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
599 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
601 Handle_t hndl = static_cast<Handle_t>(params[1]);
605 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
608 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
611 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
616 static bool s_QueryAlreadyWarned = false;
618 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
622 IPluginFunction *pCallback;
624 if (!g_ConVarManager.IsQueryingSupported())
626 if (!s_QueryAlreadyWarned)
628 s_QueryAlreadyWarned = true;
629 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
635 pPlayer = g_Players.GetPlayerByIndex(params[1]);
639 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
642 if (!pPlayer->IsConnected())
644 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
647 /* Trying a query on a bot results in callback not be fired, so don't bother */
648 if (pPlayer->IsFakeClient())
653 pContext->LocalToString(params[2], &name);
654 pCallback = pContext->GetFunctionById(params[3]);
658 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
661 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
664 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
667 IPluginFunction *pFunction;
669 pContext->LocalToString(params[1], &name);
671 if (strcasecmp(name, "sm") == 0)
673 return pContext->ThrowNativeError("Cannot register \"sm\" command");
676 pContext->LocalToString(params[3], &help);
677 pFunction = pContext->GetFunctionById(params[2]);
681 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
684 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
686 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
692 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
695 IPluginFunction *pFunction;
697 pContext->LocalToString(params[1], &name);
699 if (strcasecmp(name, "sm") == 0)
701 return pContext->ThrowNativeError("Cannot register \"sm\" command");
704 pContext->LocalToString(params[3], &help);
705 pFunction = pContext->GetFunctionById(params[2]);
709 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
712 if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
714 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
720 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
724 IPluginFunction *pFunction;
725 FlagBits flags = params[3];
726 int cmdflags = params[6];
728 pContext->LocalToString(params[1], &name);
730 if (strcasecmp(name, "sm") == 0)
732 return pContext->ThrowNativeError("Cannot register \"sm\" command");
735 pContext->LocalToString(params[4], &help);
736 pContext->LocalToString(params[5], (char **)&group);
737 pFunction = pContext->GetFunctionById(params[2]);
739 if (group[0] == '\0')
741 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
742 group = pPlugin->GetFilename();
747 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
750 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
752 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
758 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
760 const CCommand *pCmd = g_HL2.PeekCommandStack();
764 return pContext->ThrowNativeError("No command callback available");
767 return pCmd->ArgC() - 1;
770 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
772 const CCommand *pCmd = g_HL2.PeekCommandStack();
776 return pContext->ThrowNativeError("No command callback available");
781 const char *arg = pCmd->Arg(params[1]);
783 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
785 return (cell_t)length;
788 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
790 const CCommand *pCmd = g_HL2.PeekCommandStack();
794 return pContext->ThrowNativeError("No command callback available");
797 const char *args = pCmd->ArgS();
805 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
807 return (cell_t)length;
810 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
816 pCtx->LocalToString(params[1], &fmt);
817 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
819 buffer[res++] = '\n';
822 META_CONPRINT(buffer);
827 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
829 int index = params[1];
830 if ((index < 0) || (index > g_Players.GetMaxClients()))
832 return pCtx->ThrowNativeError("Client index %d is invalid", index);
835 CPlayer *pPlayer = NULL;
838 pPlayer = g_Players.GetPlayerByIndex(index);
839 if (!pPlayer->IsInGame())
841 return pCtx->ThrowNativeError("Client %d is not in game", index);
844 /* Silent fail on bots, engine will crash */
845 if (pPlayer->IsFakeClient())
855 pCtx->LocalToString(params[2], &fmt);
856 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
858 buffer[res++] = '\n';
863 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
865 META_CONPRINT(buffer);
871 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
873 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
876 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
878 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
883 /* One byte for null terminator, one for newline */
884 buffer[len++] = '\n';
887 engine->ServerCommand(buffer);
892 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
894 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
897 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
899 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
904 /* One byte for null terminator, one for newline */
905 buffer[len++] = '\n';
908 InsertServerCommand(buffer);
913 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
915 engine->ServerExecute();
920 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
922 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
926 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
929 if (!pPlayer->IsConnected())
931 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
934 g_SourceMod.SetGlobalTarget(params[1]);
937 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
939 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
944 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
949 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
951 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
955 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
958 if (!pPlayer->IsConnected())
960 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
964 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
966 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
971 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
976 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
978 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
982 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
985 if (!pPlayer->IsConnected())
987 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
991 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
993 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
998 g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
1003 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
1005 g_SourceMod.SetGlobalTarget(params[1]);
1007 /* Build the format string */
1009 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
1011 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1016 /* If we're printing to the server, shortcut out */
1020 buffer[len++] = '\n';
1022 META_CONPRINT(buffer);
1026 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1030 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1033 if (!pPlayer->IsConnected())
1035 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1038 g_SourceMod.SetGlobalTarget(params[1]);
1040 unsigned int replyto = g_ChatTriggers.GetReplyTo();
1041 if (replyto == SM_REPLY_CONSOLE)
1043 buffer[len++] = '\n';
1045 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1046 } else if (replyto == SM_REPLY_CHAT) {
1052 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1058 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1060 return g_ChatTriggers.GetReplyTo();
1063 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1065 return g_ChatTriggers.SetReplyTo(params[1]);
1068 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1070 GlobCmdIter *iter = new GlobCmdIter;
1071 iter->started = false;
1073 Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1074 if (hndl == BAD_HANDLE)
1082 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1086 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1088 if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1089 != HandleError_None)
1091 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1094 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1098 iter->iter = cmds.begin();
1099 iter->started = true;
1102 while (iter->iter != cmds.end()
1103 && !(*(iter->iter))->sourceMod)
1108 if (iter->iter == cmds.end())
1113 ConCmdInfo *pInfo = (*(iter->iter));
1115 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1116 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1119 pContext->LocalToPhysAddr(params[4], &addr);
1120 *addr = pInfo->admin.eflags;
1127 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1135 pContext->LocalToString(params[2], &cmd);
1137 /* Auto-detect a command if we can */
1138 FlagBits bits = params[3];
1139 bool found_command = false;
1140 if (params[0] < 4 || !params[4])
1142 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1147 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1150 return g_ConCmds.CheckCommandAccess(params[1], cmd, bits) ? 1 : 0;
1153 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1155 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1158 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1161 pContext->LocalToString(params[1], &name);
1163 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1166 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1170 pContext->LocalToString(params[1], &name);
1172 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1175 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1179 cell_t *pIsCmd, *pFlags;
1180 const ConCommandBase *pConCmd;
1183 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1184 pContext->LocalToPhysAddr(params[4], &pFlags);
1186 #if SOURCE_ENGINE == SE_LEFT4DEAD
1187 ICvarIteratorInternal *cvarIter = icvar->FactoryInternalIterator();
1188 cvarIter->SetFirst();
1189 if (!cvarIter->IsValid())
1193 pConCmd = cvarIter->Get();
1195 pConCmd = icvar->GetCommands();
1196 if (pConCmd == NULL)
1202 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1203 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1204 *pFlags = pConCmd->GetFlags();
1208 desc = pConCmd->GetHelpText();
1209 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1212 pIter = new ConCmdIter;
1213 #if SOURCE_ENGINE == SE_LEFT4DEAD
1214 pIter->pLast = cvarIter;
1216 pIter->pLast = pConCmd;
1219 if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1229 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1233 cell_t *pIsCmd, *pFlags;
1235 const ConCommandBase *pConCmd;
1236 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1238 if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1240 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1243 if (pIter->pLast == NULL)
1248 #if SOURCE_ENGINE == SE_LEFT4DEAD
1249 ICvarIteratorInternal *cvarIter = pIter->pLast;
1251 if (!cvarIter->IsValid())
1255 pConCmd = cvarIter->Get();
1257 pConCmd = pIter->pLast->GetNext();
1258 if (pConCmd == NULL)
1262 pIter->pLast = pConCmd;
1265 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1266 pContext->LocalToPhysAddr(params[5], &pFlags);
1268 pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
1269 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1270 *pFlags = pConCmd->GetFlags();
1274 desc = pConCmd->GetHelpText();
1275 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1281 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1283 Handle_t hndl = static_cast<Handle_t>(params[2]);
1288 pContext->LocalToString(params[3], &value);
1290 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1291 != HandleError_None)
1293 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1297 bf_write buffer(data, sizeof(data));
1299 buffer.WriteUBitLong(NET_SETCONVAR, 5);
1300 buffer.WriteByte(1);
1301 buffer.WriteString(pConVar->GetName());
1302 buffer.WriteString(value);
1304 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1308 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1311 if (!pPlayer->IsConnected())
1313 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1316 if (pPlayer->IsFakeClient())
1318 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1321 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1322 netchan->SendData(buffer);
1327 static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
1332 static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
1337 static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
1340 IPluginFunction *pFunction;
1342 pContext->LocalToString(params[2], &name);
1344 if (strcasecmp(name, "sm") == 0)
1346 g_Logger.LogError("Request to register \"sm\" command denied.");
1350 pFunction = pContext->GetFunctionById(params[1]);
1353 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1355 if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
1356 return pContext->ThrowNativeError("This game does not support command listeners");
1361 static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
1364 IPluginFunction *pFunction;
1366 pContext->LocalToString(params[2], &name);
1367 pFunction = pContext->GetFunctionById(params[1]);
1369 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1371 if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
1372 return pContext->ThrowNativeError("No matching callback was registered");
1377 REGISTER_NATIVES(consoleNatives)
1379 {"CreateConVar", sm_CreateConVar},
1380 {"FindConVar", sm_FindConVar},
1381 {"HookConVarChange", sm_HookConVarChange},
1382 {"UnhookConVarChange", sm_UnhookConVarChange},
1383 {"GetConVarBool", sm_GetConVarBool},
1384 {"SetConVarBool", sm_SetConVarNum},
1385 {"GetConVarInt", sm_GetConVarInt},
1386 {"SetConVarInt", sm_SetConVarNum},
1387 {"GetConVarFloat", sm_GetConVarFloat},
1388 {"SetConVarFloat", sm_SetConVarFloat},
1389 {"GetConVarString", sm_GetConVarString},
1390 {"SetConVarString", sm_SetConVarString},
1391 {"GetConVarFlags", sm_GetConVarFlags},
1392 {"SetConVarFlags", sm_SetConVarFlags},
1393 {"ResetConVar", sm_ResetConVar},
1394 {"GetConVarName", sm_GetConVarName},
1395 {"GetConVarBounds", sm_GetConVarBounds},
1396 {"SetConVarBounds", sm_SetConVarBounds},
1397 {"QueryClientConVar", sm_QueryClientConVar},
1398 {"RegServerCmd", sm_RegServerCmd},
1399 {"RegConsoleCmd", sm_RegConsoleCmd},
1400 {"GetCmdArgString", sm_GetCmdArgString},
1401 {"GetCmdArgs", sm_GetCmdArgs},
1402 {"GetCmdArg", sm_GetCmdArg},
1403 {"PrintToServer", sm_PrintToServer},
1404 {"PrintToConsole", sm_PrintToConsole},
1405 {"RegAdminCmd", sm_RegAdminCmd},
1406 {"ServerCommand", sm_ServerCommand},
1407 {"InsertServerCommand", sm_InsertServerCommand},
1408 {"ServerExecute", sm_ServerExecute},
1409 {"ClientCommand", sm_ClientCommand},
1410 {"FakeClientCommand", FakeClientCommand},
1411 {"ReplyToCommand", ReplyToCommand},
1412 {"GetCmdReplySource", GetCmdReplyTarget},
1413 {"SetCmdReplySource", SetCmdReplyTarget},
1414 {"GetCommandIterator", GetCommandIterator},
1415 {"ReadCommandIterator", ReadCommandIterator},
1416 {"CheckCommandAccess", CheckCommandAccess},
1417 {"FakeClientCommandEx", FakeClientCommandEx},
1418 {"IsChatTrigger", IsChatTrigger},
1419 {"SetCommandFlags", SetCommandFlags},
1420 {"GetCommandFlags", GetCommandFlags},
1421 {"FindFirstConCommand", FindFirstConCommand},
1422 {"FindNextConCommand", FindNextConCommand},
1423 {"SendConVarValue", SendConVarValue},
1424 {"AddServerTag", AddServerTag},
1425 {"RemoveServerTag", RemoveServerTag},
1426 {"AddCommandListener", AddCommandListener},
1427 {"RemoveCommandListener", RemoveCommandListener},