Triggering build against new mac libprotobuf.
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>
46 #include <tier0/dbg.h>
48 #include "ConsoleDetours.h"
49 #include "ConCommandBaseIterator.h"
51 #if SOURCE_ENGINE == SE_CSGO
52 #include <netmessages.pb.h>
55 #if SOURCE_ENGINE >= SE_EYE
61 #if SOURCE_ENGINE >= SE_LEFT4DEAD
62 #define NET_SETCONVAR 6
64 #define NET_SETCONVAR 5
69 ConVarBound_Upper = 0,
73 HandleType_t hCmdIterType = 0;
74 HandleType_t htConCmdIter = 0;
79 List<ConCmdInfo *>::iterator iter;
82 class ConsoleHelpers :
84 public IHandleTypeDispatch
87 virtual void OnSourceModAllInitialized()
91 g_HandleSys.InitAccessDefaults(NULL, &access);
93 htConCmdIter = g_HandleSys.CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
95 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
97 hCmdIterType = g_HandleSys.CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
99 virtual void OnHandleDestroy(HandleType_t type, void *object)
101 if (type == hCmdIterType)
103 GlobCmdIter *iter = (GlobCmdIter *)object;
106 else if (type == htConCmdIter)
108 ConCommandBaseIterator *iter = (ConCommandBaseIterator * )object;
112 virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
114 if (type == htConCmdIter)
116 *pSize = sizeof(ConCommandBaseIterator);
119 else if (type == hCmdIterType)
121 *pSize = sizeof(GlobCmdIter);
128 class CommandFlagsHelper : public IConCommandTracker
131 void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
133 m_CmdFlags.remove(name);
135 bool GetFlags(const char *name, int *flags)
137 ConCommandBase **ppCmd;
138 ConCommandBase *pCmd;
139 if ((ppCmd=m_CmdFlags.retrieve(name)))
141 TrackConCommandBase((*ppCmd), this);
142 *flags = (*ppCmd)->GetFlags();
145 else if ((pCmd=FindCommandBase(name)))
147 m_CmdFlags.insert(name, pCmd);
148 TrackConCommandBase(pCmd, this);
149 *flags = pCmd->GetFlags();
157 bool SetFlags(const char *name, int flags)
159 ConCommandBase **ppCmd;
160 ConCommandBase *pCmd;
161 if ((ppCmd=m_CmdFlags.retrieve(name)))
163 (*ppCmd)->SetFlags(flags);
164 TrackConCommandBase((*ppCmd), this);
167 else if ((pCmd=FindCommandBase(name)))
169 m_CmdFlags.insert(name, pCmd);
170 pCmd->SetFlags(flags);
171 TrackConCommandBase(pCmd, this);
180 KTrie<ConCommandBase *> m_CmdFlags;
181 } s_CommandFlagsHelper;
183 #if SOURCE_ENGINE < SE_ORANGEBOX
184 static void ReplicateConVar(ConVar *pConVar)
186 int maxClients = g_Players.GetMaxClients();
189 bf_write buffer(data, sizeof(data));
191 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
193 buffer.WriteString(pConVar->GetName());
194 buffer.WriteString(pConVar->GetString());
196 for (int i = 1; i <= maxClients; i++)
198 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
200 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
202 if (INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i)))
203 netchan->SendData(buffer);
208 static void NotifyConVar(ConVar *pConVar)
210 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
211 pEvent->SetString("cvarname", pConVar->GetName());
212 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
214 pEvent->SetString("cvarvalue", "***PROTECTED***");
218 pEvent->SetString("cvarvalue", pConVar->GetString());
221 gameevents->FireEvent(pEvent);
225 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
227 char *name, *defaultVal, *helpText;
229 pContext->LocalToString(params[1], &name);
231 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
232 if (name == NULL || strcmp(name, "") == 0)
234 return pContext->ThrowNativeError("Convar with blank name is not permitted");
237 pContext->LocalToString(params[2], &defaultVal);
238 pContext->LocalToString(params[3], &helpText);
240 bool hasMin = params[5] ? true : false;
241 bool hasMax = params[7] ? true : false;
242 float min = sp_ctof(params[6]);
243 float max = sp_ctof(params[8]);
245 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
247 if (hndl == BAD_HANDLE)
249 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
255 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
259 pContext->LocalToString(params[1], &name);
261 return g_ConVarManager.FindConVar(name);
264 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
266 Handle_t hndl = static_cast<Handle_t>(params[1]);
270 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
273 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
276 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
280 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
283 g_ConVarManager.HookConVarChange(pConVar, pFunction);
288 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
290 Handle_t hndl = static_cast<Handle_t>(params[1]);
294 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
297 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
300 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
304 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
307 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
312 static cell_t sm_GetConVarBool(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->GetBool();
327 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
329 Handle_t hndl = static_cast<Handle_t>(params[1]);
333 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
336 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
339 return pConVar->GetInt();
342 /* This handles both SetConVarBool() and SetConVarInt() */
343 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
345 Handle_t hndl = static_cast<Handle_t>(params[1]);
349 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
352 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
355 pConVar->SetValue(params[2]);
357 #if SOURCE_ENGINE < SE_ORANGEBOX
358 /* Should we replicate it? */
359 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
361 ReplicateConVar(pConVar);
364 /* Should we notify clients? */
365 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
367 NotifyConVar(pConVar);
374 static cell_t sm_GetConVarFloat(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 = pConVar->GetFloat();
388 return sp_ftoc(value);
391 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
393 Handle_t hndl = static_cast<Handle_t>(params[1]);
397 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
400 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
403 float value = sp_ctof(params[2]);
404 pConVar->SetValue(value);
406 #if SOURCE_ENGINE < SE_ORANGEBOX
407 /* Should we replicate it? */
408 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
410 ReplicateConVar(pConVar);
413 /* Should we notify clients? */
414 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
416 NotifyConVar(pConVar);
423 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
425 Handle_t hndl = static_cast<Handle_t>(params[1]);
429 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
432 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
435 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
440 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
442 Handle_t hndl = static_cast<Handle_t>(params[1]);
446 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
449 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
453 pContext->LocalToString(params[2], &value);
455 pConVar->SetValue(value);
457 #if SOURCE_ENGINE < SE_ORANGEBOX
458 /* Should we replicate it? */
459 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
461 ReplicateConVar(pConVar);
464 /* Should we notify clients? */
465 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
467 NotifyConVar(pConVar);
474 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
476 Handle_t hndl = static_cast<Handle_t>(params[1]);
480 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
483 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
488 #if SOURCE_ENGINE < SE_ORANGEBOX
489 /* Should we replicate it? */
490 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
492 ReplicateConVar(pConVar);
495 /* Should we notify clients? */
496 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
498 NotifyConVar(pConVar);
505 static cell_t GetConVarDefault(IPluginContext *pContext, const cell_t *params)
507 Handle_t hndl = static_cast<Handle_t>(params[1]);
511 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
514 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
518 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetDefault(), &bytes);
523 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
525 Handle_t hndl = static_cast<Handle_t>(params[1]);
529 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
532 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
535 return pConVar->GetFlags();
538 static cell_t sm_SetConVarFlags(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);
550 pConVar->SetFlags(params[2]);
555 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
557 Handle_t hndl = static_cast<Handle_t>(params[1]);
561 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
564 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
573 case ConVarBound_Upper:
574 hasBound = pConVar->GetMax(bound);
576 case ConVarBound_Lower:
577 hasBound = pConVar->GetMin(bound);
580 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
583 pContext->LocalToPhysAddr(params[3], &addr);
584 *addr = sp_ftoc(bound);
589 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
591 Handle_t hndl = static_cast<Handle_t>(params[1]);
595 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
598 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
603 case ConVarBound_Upper:
604 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
606 case ConVarBound_Lower:
607 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
610 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
616 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
618 Handle_t hndl = static_cast<Handle_t>(params[1]);
622 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
625 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
628 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
633 static bool s_QueryAlreadyWarned = false;
635 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
639 IPluginFunction *pCallback;
641 if (!g_ConVarManager.IsQueryingSupported())
643 if (!s_QueryAlreadyWarned)
645 s_QueryAlreadyWarned = true;
646 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
652 pPlayer = g_Players.GetPlayerByIndex(params[1]);
656 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
659 if (!pPlayer->IsConnected())
661 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
664 /* Trying a query on a bot results in callback not be fired, so don't bother */
665 if (pPlayer->IsFakeClient())
670 pContext->LocalToString(params[2], &name);
671 pCallback = pContext->GetFunctionById(params[3]);
675 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
678 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
681 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
684 IPluginFunction *pFunction;
686 pContext->LocalToString(params[1], &name);
688 if (strcasecmp(name, "sm") == 0)
690 return pContext->ThrowNativeError("Cannot register \"sm\" command");
693 pContext->LocalToString(params[3], &help);
694 pFunction = pContext->GetFunctionById(params[2]);
698 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
701 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
703 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
709 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
712 IPluginFunction *pFunction;
714 pContext->LocalToString(params[1], &name);
716 if (strcasecmp(name, "sm") == 0)
718 return pContext->ThrowNativeError("Cannot register \"sm\" command");
721 pContext->LocalToString(params[3], &help);
722 pFunction = pContext->GetFunctionById(params[2]);
726 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
729 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
730 const char *group = pPlugin->GetFilename();
731 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, 0, help, params[4]))
733 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
739 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
743 IPluginFunction *pFunction;
744 FlagBits flags = params[3];
745 int cmdflags = params[6];
747 pContext->LocalToString(params[1], &name);
749 if (strcasecmp(name, "sm") == 0)
751 return pContext->ThrowNativeError("Cannot register \"sm\" command");
754 pContext->LocalToString(params[4], &help);
755 pContext->LocalToString(params[5], (char **)&group);
756 pFunction = pContext->GetFunctionById(params[2]);
758 if (group[0] == '\0')
760 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
761 group = pPlugin->GetFilename();
766 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
769 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
771 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
777 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
779 const CCommand *pCmd = g_HL2.PeekCommandStack();
783 return pContext->ThrowNativeError("No command callback available");
786 return pCmd->ArgC() - 1;
789 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
791 const CCommand *pCmd = g_HL2.PeekCommandStack();
795 return pContext->ThrowNativeError("No command callback available");
800 const char *arg = pCmd->Arg(params[1]);
802 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
804 return (cell_t)length;
807 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
809 const CCommand *pCmd = g_HL2.PeekCommandStack();
813 return pContext->ThrowNativeError("No command callback available");
816 const char *args = pCmd->ArgS();
824 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
826 return (cell_t)length;
829 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
835 pCtx->LocalToString(params[1], &fmt);
836 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
838 buffer[res++] = '\n';
841 META_CONPRINT(buffer);
846 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
848 int index = params[1];
849 if ((index < 0) || (index > g_Players.GetMaxClients()))
851 return pCtx->ThrowNativeError("Client index %d is invalid", index);
854 CPlayer *pPlayer = NULL;
857 pPlayer = g_Players.GetPlayerByIndex(index);
858 if (!pPlayer->IsInGame())
860 return pCtx->ThrowNativeError("Client %d is not in game", index);
863 /* Silent fail on bots, engine will crash */
864 if (pPlayer->IsFakeClient())
874 pCtx->LocalToString(params[2], &fmt);
875 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
877 buffer[res++] = '\n';
882 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
884 META_CONPRINT(buffer);
890 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
892 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
895 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
897 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
902 /* One byte for null terminator, one for newline */
903 buffer[len++] = '\n';
906 engine->ServerCommand(buffer);
911 char *g_ServerCommandBuffer = NULL;
912 cell_t g_ServerCommandBufferLength;
914 bool g_ShouldCatchSpew = false;
916 #if SOURCE_ENGINE < SE_LEFT4DEAD2
917 SpewOutputFunc_t g_OriginalSpewOutputFunc = NULL;
919 SpewRetval_t SourcemodSpewOutputFunc(SpewType_t spewType, tchar const *pMsg)
921 if (g_ServerCommandBuffer)
923 V_strcat(g_ServerCommandBuffer, pMsg, g_ServerCommandBufferLength);
926 if (g_OriginalSpewOutputFunc)
928 return g_OriginalSpewOutputFunc(spewType, pMsg);
930 return SPEW_CONTINUE;
934 class CSourcemodLoggingListener: public ILoggingListener
937 void Log(const LoggingContext_t *pContext, const tchar *pMessage)
939 if (g_ServerCommandBuffer)
941 V_strcat(g_ServerCommandBuffer, pMessage, g_ServerCommandBufferLength);
944 } g_SourcemodLoggingListener;
947 CON_COMMAND(sm_conhook_start, "")
949 if (!g_ShouldCatchSpew)
951 Warning("You shouldn't run this command!\n");
955 #if SOURCE_ENGINE < SE_LEFT4DEAD2
956 g_OriginalSpewOutputFunc = GetSpewOutputFunc();
957 SpewOutputFunc(SourcemodSpewOutputFunc);
959 #if SOURCE_ENGINE < SE_ALIENSWARM
960 LoggingSystem_PushLoggingState(false);
962 LoggingSystem_PushLoggingState(false, false);
964 LoggingSystem_RegisterLoggingListener(&g_SourcemodLoggingListener);
968 CON_COMMAND(sm_conhook_stop, "")
970 if (!g_ShouldCatchSpew)
972 Warning("You shouldn't run this command!\n");
976 #if SOURCE_ENGINE < SE_LEFT4DEAD2
977 SpewOutputFunc(g_OriginalSpewOutputFunc);
979 LoggingSystem_PopLoggingState(false);
982 g_ShouldCatchSpew = false;
985 static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params)
987 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
990 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 3);
992 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
997 /* One byte for null terminator, one for newline */
998 buffer[len++] = '\n';
1001 pContext->LocalToString(params[1], &g_ServerCommandBuffer);
1002 g_ServerCommandBufferLength = params[2];
1004 if (g_ServerCommandBufferLength > 0)
1006 g_ServerCommandBuffer[0] = '\0';
1009 engine->ServerExecute();
1011 g_ShouldCatchSpew = true;
1012 engine->ServerCommand("sm_conhook_start\n");
1013 engine->ServerCommand(buffer);
1014 engine->ServerCommand("sm_conhook_stop\n");
1016 engine->ServerExecute();
1018 if (g_ServerCommandBufferLength > 0)
1020 g_ServerCommandBuffer[g_ServerCommandBufferLength-1] = '\0';
1023 g_ServerCommandBuffer = NULL;
1024 g_ServerCommandBufferLength = 0;
1029 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
1031 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
1034 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
1036 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1041 /* One byte for null terminator, one for newline */
1042 buffer[len++] = '\n';
1045 InsertServerCommand(buffer);
1050 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
1052 engine->ServerExecute();
1057 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
1059 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1063 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1066 if (!pPlayer->IsConnected())
1068 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1071 g_SourceMod.SetGlobalTarget(params[1]);
1074 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1076 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1081 engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
1086 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
1088 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1092 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1095 if (!pPlayer->IsConnected())
1097 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1101 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1103 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1108 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
1113 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
1115 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1119 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1122 if (!pPlayer->IsConnected())
1124 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1128 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1130 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1135 g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
1140 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
1142 g_SourceMod.SetGlobalTarget(params[1]);
1144 /* Build the format string */
1146 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
1148 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1153 /* If we're printing to the server, shortcut out */
1157 buffer[len++] = '\n';
1159 META_CONPRINT(buffer);
1163 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1167 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1170 if (!pPlayer->IsConnected())
1172 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1175 g_SourceMod.SetGlobalTarget(params[1]);
1177 unsigned int replyto = g_ChatTriggers.GetReplyTo();
1178 if (replyto == SM_REPLY_CONSOLE)
1180 buffer[len++] = '\n';
1182 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1183 } else if (replyto == SM_REPLY_CHAT) {
1189 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1195 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1197 return g_ChatTriggers.GetReplyTo();
1200 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1202 return g_ChatTriggers.SetReplyTo(params[1]);
1205 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1207 GlobCmdIter *iter = new GlobCmdIter;
1208 iter->started = false;
1210 Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1211 if (hndl == BAD_HANDLE)
1219 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1223 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1225 if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1226 != HandleError_None)
1228 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1231 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1235 iter->iter = cmds.begin();
1236 iter->started = true;
1239 while (iter->iter != cmds.end()
1240 && !(*(iter->iter))->sourceMod)
1245 if (iter->iter == cmds.end())
1250 ConCmdInfo *pInfo = (*(iter->iter));
1252 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1253 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1256 pContext->LocalToPhysAddr(params[4], &addr);
1257 *addr = pInfo->admin.eflags;
1264 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1272 pContext->LocalToString(params[2], &cmd);
1274 /* Match up with an admin command if possible */
1275 FlagBits bits = params[3];
1276 bool found_command = false;
1277 if (params[0] < 4 || !params[4])
1279 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1284 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1287 return g_ConCmds.CheckClientCommandAccess(params[1], cmd, bits) ? 1 : 0;
1290 static cell_t CheckAccess(IPluginContext *pContext, const cell_t *params)
1293 pContext->LocalToString(params[2], &cmd);
1295 /* Match up with an admin command if possible */
1296 FlagBits bits = params[3];
1297 bool found_command = false;
1298 if (params[0] < 4 || !params[4])
1300 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1305 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1308 return g_ConCmds.CheckAdminCommandAccess(params[1], cmd, bits) ? 1 : 0;
1311 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1313 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1316 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1319 pContext->LocalToString(params[1], &name);
1321 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1324 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1328 pContext->LocalToString(params[1], &name);
1330 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1333 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1336 ConCommandBaseIterator *pIter;
1337 cell_t *pIsCmd, *pFlags;
1338 const ConCommandBase *pConCmd;
1341 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1342 pContext->LocalToPhysAddr(params[4], &pFlags);
1344 pIter = new ConCommandBaseIterator();
1346 if (!pIter->IsValid())
1352 pConCmd = pIter->Get();
1354 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1355 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1356 *pFlags = pConCmd->GetFlags();
1360 desc = pConCmd->GetHelpText();
1361 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1364 if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1374 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1377 ConCommandBaseIterator *pIter;
1378 cell_t *pIsCmd, *pFlags;
1380 const ConCommandBase *pConCmd;
1381 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1383 if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1385 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1388 if (!pIter->IsValid())
1394 if (!pIter->IsValid())
1398 pConCmd = pIter->Get();
1400 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1401 pContext->LocalToPhysAddr(params[5], &pFlags);
1403 pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
1404 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1405 *pFlags = pConCmd->GetFlags();
1409 desc = pConCmd->GetHelpText();
1410 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1416 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1418 Handle_t hndl = static_cast<Handle_t>(params[2]);
1423 pContext->LocalToString(params[3], &value);
1425 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1426 != HandleError_None)
1428 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1432 bf_write buffer(data, sizeof(data));
1434 #if SOURCE_ENGINE == SE_CSGO
1435 CNETMsg_SetConVar msg;
1436 CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();
1438 cvar->set_name(pConVar->GetName());
1439 cvar->set_value(value);
1441 buffer.WriteVarInt32(net_SetConVar);
1442 buffer.WriteVarInt32(msg.ByteSize());
1443 msg.SerializeWithCachedSizesToArray( (uint8 *)( buffer.GetBasePointer() + buffer.GetNumBytesWritten() ) );
1445 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
1446 buffer.WriteByte(1);
1447 buffer.WriteString(pConVar->GetName());
1448 buffer.WriteString(value);
1451 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1455 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1458 if (!pPlayer->IsConnected())
1460 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1463 if (pPlayer->IsFakeClient())
1465 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1468 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1469 if (netchan == NULL)
1474 netchan->SendData(buffer);
1479 static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
1484 static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
1489 static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
1492 IPluginFunction *pFunction;
1494 pContext->LocalToString(params[2], &name);
1496 if (strcasecmp(name, "sm") == 0)
1498 g_Logger.LogError("Request to register \"sm\" command denied.");
1502 pFunction = pContext->GetFunctionById(params[1]);
1505 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1507 if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
1508 return pContext->ThrowNativeError("This game does not support command listeners");
1513 static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
1516 IPluginFunction *pFunction;
1518 pContext->LocalToString(params[2], &name);
1519 pFunction = pContext->GetFunctionById(params[1]);
1521 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1523 if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
1524 return pContext->ThrowNativeError("No matching callback was registered");
1529 REGISTER_NATIVES(consoleNatives)
1531 {"CreateConVar", sm_CreateConVar},
1532 {"FindConVar", sm_FindConVar},
1533 {"HookConVarChange", sm_HookConVarChange},
1534 {"UnhookConVarChange", sm_UnhookConVarChange},
1535 {"GetConVarBool", sm_GetConVarBool},
1536 {"SetConVarBool", sm_SetConVarNum},
1537 {"GetConVarInt", sm_GetConVarInt},
1538 {"SetConVarInt", sm_SetConVarNum},
1539 {"GetConVarFloat", sm_GetConVarFloat},
1540 {"SetConVarFloat", sm_SetConVarFloat},
1541 {"GetConVarString", sm_GetConVarString},
1542 {"SetConVarString", sm_SetConVarString},
1543 {"GetConVarFlags", sm_GetConVarFlags},
1544 {"SetConVarFlags", sm_SetConVarFlags},
1545 {"ResetConVar", sm_ResetConVar},
1546 {"GetConVarName", sm_GetConVarName},
1547 {"GetConVarBounds", sm_GetConVarBounds},
1548 {"SetConVarBounds", sm_SetConVarBounds},
1549 {"QueryClientConVar", sm_QueryClientConVar},
1550 {"GetConVarDefault", GetConVarDefault},
1551 {"RegServerCmd", sm_RegServerCmd},
1552 {"RegConsoleCmd", sm_RegConsoleCmd},
1553 {"GetCmdArgString", sm_GetCmdArgString},
1554 {"GetCmdArgs", sm_GetCmdArgs},
1555 {"GetCmdArg", sm_GetCmdArg},
1556 {"PrintToServer", sm_PrintToServer},
1557 {"PrintToConsole", sm_PrintToConsole},
1558 {"RegAdminCmd", sm_RegAdminCmd},
1559 {"ServerCommand", sm_ServerCommand},
1560 {"ServerCommandEx", sm_ServerCommandEx},
1561 {"InsertServerCommand", sm_InsertServerCommand},
1562 {"ServerExecute", sm_ServerExecute},
1563 {"ClientCommand", sm_ClientCommand},
1564 {"FakeClientCommand", FakeClientCommand},
1565 {"ReplyToCommand", ReplyToCommand},
1566 {"GetCmdReplySource", GetCmdReplyTarget},
1567 {"SetCmdReplySource", SetCmdReplyTarget},
1568 {"GetCommandIterator", GetCommandIterator},
1569 {"ReadCommandIterator", ReadCommandIterator},
1570 {"CheckCommandAccess", CheckCommandAccess},
1571 {"CheckAccess", CheckAccess},
1572 {"FakeClientCommandEx", FakeClientCommandEx},
1573 {"IsChatTrigger", IsChatTrigger},
1574 {"SetCommandFlags", SetCommandFlags},
1575 {"GetCommandFlags", GetCommandFlags},
1576 {"FindFirstConCommand", FindFirstConCommand},
1577 {"FindNextConCommand", FindNextConCommand},
1578 {"SendConVarValue", SendConVarValue},
1579 {"AddServerTag", AddServerTag},
1580 {"RemoveServerTag", RemoveServerTag},
1581 {"AddCommandListener", AddCommandListener},
1582 {"RemoveCommandListener", RemoveCommandListener},