Update linux dep script (no bug, r=NPOTB).
2 * vim: set ts=4 sw=4 tw=99 noet :
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 "sourcemod.h"
34 #include "HalfLife2.h"
35 #include "sourcemm_api.h"
36 #include "ConVarManager.h"
37 #include "ConCmdManager.h"
38 #include "sm_stringutil.h"
39 #include "PlayerManager.h"
40 #include "ChatTriggers.h"
41 #include "AdminCache.h"
42 #include <inetchannel.h>
44 #include <tier0/dbg.h>
46 #include "ConsoleDetours.h"
47 #include "ConCommandBaseIterator.h"
48 #include "logic_bridge.h"
49 #include <sm_namehashset.h>
51 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
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 handlesys->InitAccessDefaults(NULL, &access);
93 htConCmdIter = handlesys->CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
95 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
97 hCmdIterType = 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 *pCmd;
138 if (m_CmdFlags.retrieve(name, &pCmd))
140 TrackConCommandBase(pCmd, this);
141 *flags = pCmd->GetFlags();
144 else if ((pCmd=FindCommandBase(name)))
146 m_CmdFlags.insert(name, pCmd);
147 TrackConCommandBase(pCmd, this);
148 *flags = pCmd->GetFlags();
156 bool SetFlags(const char *name, int flags)
158 ConCommandBase *pCmd;
159 if (m_CmdFlags.retrieve(name, &pCmd))
161 pCmd->SetFlags(flags);
162 TrackConCommandBase(pCmd, this);
165 else if ((pCmd=FindCommandBase(name)))
167 m_CmdFlags.insert(name, pCmd);
168 pCmd->SetFlags(flags);
169 TrackConCommandBase(pCmd, this);
178 struct ConCommandPolicy
180 static inline bool matches(const char *name, ConCommandBase *base)
182 return strcmp(name, base->GetName()) == 0;
185 NameHashSet<ConCommandBase *, ConCommandPolicy> m_CmdFlags;
186 } s_CommandFlagsHelper;
188 #if SOURCE_ENGINE < SE_ORANGEBOX
189 static void ReplicateConVar(ConVar *pConVar)
191 int maxClients = g_Players.GetMaxClients();
194 bf_write buffer(data, sizeof(data));
196 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
198 buffer.WriteString(pConVar->GetName());
199 buffer.WriteString(pConVar->GetString());
201 for (int i = 1; i <= maxClients; i++)
203 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
205 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
207 if (INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i)))
208 netchan->SendData(buffer);
213 static void NotifyConVar(ConVar *pConVar)
215 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
216 pEvent->SetString("cvarname", pConVar->GetName());
217 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
219 pEvent->SetString("cvarvalue", "***PROTECTED***");
223 pEvent->SetString("cvarvalue", pConVar->GetString());
226 gameevents->FireEvent(pEvent);
230 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
232 char *name, *defaultVal, *helpText;
234 pContext->LocalToString(params[1], &name);
236 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
237 if (name == NULL || strcmp(name, "") == 0)
239 return pContext->ThrowNativeError("Convar with blank name is not permitted");
242 pContext->LocalToString(params[2], &defaultVal);
243 pContext->LocalToString(params[3], &helpText);
245 bool hasMin = params[5] ? true : false;
246 bool hasMax = params[7] ? true : false;
247 float min = sp_ctof(params[6]);
248 float max = sp_ctof(params[8]);
250 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
252 if (hndl == BAD_HANDLE)
254 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
260 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
264 pContext->LocalToString(params[1], &name);
266 return g_ConVarManager.FindConVar(name);
269 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
271 Handle_t hndl = static_cast<Handle_t>(params[1]);
275 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
278 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
281 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
285 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
288 g_ConVarManager.HookConVarChange(pConVar, pFunction);
293 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
295 Handle_t hndl = static_cast<Handle_t>(params[1]);
299 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
302 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
305 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
309 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
312 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
317 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
319 Handle_t hndl = static_cast<Handle_t>(params[1]);
323 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
326 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
329 return pConVar->GetBool();
332 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
334 Handle_t hndl = static_cast<Handle_t>(params[1]);
338 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
341 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
344 return pConVar->GetInt();
347 /* This handles both SetConVarBool() and SetConVarInt() */
348 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
350 Handle_t hndl = static_cast<Handle_t>(params[1]);
354 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
357 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
360 pConVar->SetValue(params[2]);
362 #if SOURCE_ENGINE < SE_ORANGEBOX
363 /* Should we replicate it? */
364 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
366 ReplicateConVar(pConVar);
369 /* Should we notify clients? */
370 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
372 NotifyConVar(pConVar);
379 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
381 Handle_t hndl = static_cast<Handle_t>(params[1]);
385 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
388 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
391 float value = pConVar->GetFloat();
393 return sp_ftoc(value);
396 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
398 Handle_t hndl = static_cast<Handle_t>(params[1]);
402 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
405 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
408 float value = sp_ctof(params[2]);
409 pConVar->SetValue(value);
411 #if SOURCE_ENGINE < SE_ORANGEBOX
412 /* Should we replicate it? */
413 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
415 ReplicateConVar(pConVar);
418 /* Should we notify clients? */
419 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
421 NotifyConVar(pConVar);
428 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
430 Handle_t hndl = static_cast<Handle_t>(params[1]);
434 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
437 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
440 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
445 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
447 Handle_t hndl = static_cast<Handle_t>(params[1]);
451 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
454 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
458 pContext->LocalToString(params[2], &value);
460 pConVar->SetValue(value);
462 #if SOURCE_ENGINE < SE_ORANGEBOX
463 /* Should we replicate it? */
464 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
466 ReplicateConVar(pConVar);
469 /* Should we notify clients? */
470 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
472 NotifyConVar(pConVar);
479 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
481 Handle_t hndl = static_cast<Handle_t>(params[1]);
485 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
488 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
493 #if SOURCE_ENGINE < SE_ORANGEBOX
494 /* Should we replicate it? */
495 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
497 ReplicateConVar(pConVar);
500 /* Should we notify clients? */
501 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
503 NotifyConVar(pConVar);
510 static cell_t GetConVarDefault(IPluginContext *pContext, const cell_t *params)
512 Handle_t hndl = static_cast<Handle_t>(params[1]);
516 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
519 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
523 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetDefault(), &bytes);
528 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
530 Handle_t hndl = static_cast<Handle_t>(params[1]);
534 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
537 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
540 return pConVar->GetFlags();
543 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
545 Handle_t hndl = static_cast<Handle_t>(params[1]);
549 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
552 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
555 pConVar->SetFlags(params[2]);
560 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
562 Handle_t hndl = static_cast<Handle_t>(params[1]);
566 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
569 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
578 case ConVarBound_Upper:
579 hasBound = pConVar->GetMax(bound);
581 case ConVarBound_Lower:
582 hasBound = pConVar->GetMin(bound);
585 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
588 pContext->LocalToPhysAddr(params[3], &addr);
589 *addr = sp_ftoc(bound);
594 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
596 Handle_t hndl = static_cast<Handle_t>(params[1]);
600 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
603 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
608 case ConVarBound_Upper:
609 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
611 case ConVarBound_Lower:
612 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
615 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
621 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
623 Handle_t hndl = static_cast<Handle_t>(params[1]);
627 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
630 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
633 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
638 static bool s_QueryAlreadyWarned = false;
640 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
644 IPluginFunction *pCallback;
646 if (!g_ConVarManager.IsQueryingSupported())
648 if (!s_QueryAlreadyWarned)
650 s_QueryAlreadyWarned = true;
651 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
657 pPlayer = g_Players.GetPlayerByIndex(params[1]);
661 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
664 if (!pPlayer->IsConnected())
666 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
669 /* Trying a query on a bot results in callback not be fired, so don't bother */
670 if (pPlayer->IsFakeClient())
675 pContext->LocalToString(params[2], &name);
676 pCallback = pContext->GetFunctionById(params[3]);
680 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
683 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
686 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
689 IPluginFunction *pFunction;
691 pContext->LocalToString(params[1], &name);
693 if (strcasecmp(name, "sm") == 0)
695 return pContext->ThrowNativeError("Cannot register \"sm\" command");
698 pContext->LocalToString(params[3], &help);
699 pFunction = pContext->GetFunctionById(params[2]);
703 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
706 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
708 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
714 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
717 IPluginFunction *pFunction;
719 pContext->LocalToString(params[1], &name);
721 if (strcasecmp(name, "sm") == 0)
723 return pContext->ThrowNativeError("Cannot register \"sm\" command");
726 pContext->LocalToString(params[3], &help);
727 pFunction = pContext->GetFunctionById(params[2]);
731 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
734 IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
735 const char *group = pPlugin->GetFilename();
736 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, 0, help, params[4]))
738 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
744 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
748 IPluginFunction *pFunction;
749 FlagBits flags = params[3];
750 int cmdflags = params[6];
752 pContext->LocalToString(params[1], &name);
754 if (strcasecmp(name, "sm") == 0)
756 return pContext->ThrowNativeError("Cannot register \"sm\" command");
759 pContext->LocalToString(params[4], &help);
760 pContext->LocalToString(params[5], (char **)&group);
761 pFunction = pContext->GetFunctionById(params[2]);
763 if (group[0] == '\0')
765 IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
766 group = pPlugin->GetFilename();
771 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
774 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
776 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
782 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
784 const CCommand *pCmd = g_HL2.PeekCommandStack();
788 return pContext->ThrowNativeError("No command callback available");
791 return pCmd->ArgC() - 1;
794 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
796 const CCommand *pCmd = g_HL2.PeekCommandStack();
800 return pContext->ThrowNativeError("No command callback available");
805 const char *arg = pCmd->Arg(params[1]);
807 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
809 return (cell_t)length;
812 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
814 const CCommand *pCmd = g_HL2.PeekCommandStack();
818 return pContext->ThrowNativeError("No command callback available");
821 const char *args = pCmd->ArgS();
829 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
831 return (cell_t)length;
834 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
840 pCtx->LocalToString(params[1], &fmt);
841 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
843 buffer[res++] = '\n';
846 META_CONPRINT(buffer);
851 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
853 int index = params[1];
854 if ((index < 0) || (index > g_Players.GetMaxClients()))
856 return pCtx->ThrowNativeError("Client index %d is invalid", index);
859 CPlayer *pPlayer = NULL;
862 pPlayer = g_Players.GetPlayerByIndex(index);
863 if (!pPlayer->IsInGame())
865 return pCtx->ThrowNativeError("Client %d is not in game", index);
868 /* Silent fail on bots, engine will crash */
869 if (pPlayer->IsFakeClient())
879 pCtx->LocalToString(params[2], &fmt);
880 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
882 buffer[res++] = '\n';
887 #if SOURCE_ENGINE == SE_DOTA
888 engine->ClientPrintf(pPlayer->GetIndex(), buffer);
890 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
893 META_CONPRINT(buffer);
899 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
901 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
904 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
906 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
911 /* One byte for null terminator, one for newline */
912 buffer[len++] = '\n';
915 engine->ServerCommand(buffer);
920 char *g_ServerCommandBuffer = NULL;
921 cell_t g_ServerCommandBufferLength;
923 bool g_ShouldCatchSpew = false;
925 #if SOURCE_ENGINE < SE_NUCLEARDAWN
926 SpewOutputFunc_t g_OriginalSpewOutputFunc = NULL;
928 SpewRetval_t SourcemodSpewOutputFunc(SpewType_t spewType, tchar const *pMsg)
930 if (g_ServerCommandBuffer)
932 V_strcat(g_ServerCommandBuffer, pMsg, g_ServerCommandBufferLength);
935 if (g_OriginalSpewOutputFunc)
937 return g_OriginalSpewOutputFunc(spewType, pMsg);
939 return SPEW_CONTINUE;
943 class CSourcemodLoggingListener: public ILoggingListener
946 void Log(const LoggingContext_t *pContext, const tchar *pMessage)
948 if (g_ServerCommandBuffer)
950 V_strcat(g_ServerCommandBuffer, pMessage, g_ServerCommandBufferLength);
953 } g_SourcemodLoggingListener;
956 CON_COMMAND(sm_conhook_start, "")
958 if (!g_ShouldCatchSpew)
960 Warning("You shouldn't run this command!\n");
964 #if SOURCE_ENGINE < SE_NUCLEARDAWN
965 g_OriginalSpewOutputFunc = GetSpewOutputFunc();
966 SpewOutputFunc(SourcemodSpewOutputFunc);
968 #if SOURCE_ENGINE < SE_ALIENSWARM
969 LoggingSystem_PushLoggingState(false);
971 LoggingSystem_PushLoggingState(false, false);
973 LoggingSystem_RegisterLoggingListener(&g_SourcemodLoggingListener);
977 CON_COMMAND(sm_conhook_stop, "")
979 if (!g_ShouldCatchSpew)
981 Warning("You shouldn't run this command!\n");
985 #if SOURCE_ENGINE < SE_NUCLEARDAWN
986 SpewOutputFunc(g_OriginalSpewOutputFunc);
988 LoggingSystem_PopLoggingState(false);
991 g_ShouldCatchSpew = false;
994 static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params)
996 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
999 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 3);
1001 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1006 /* One byte for null terminator, one for newline */
1007 buffer[len++] = '\n';
1010 pContext->LocalToString(params[1], &g_ServerCommandBuffer);
1011 g_ServerCommandBufferLength = params[2];
1013 if (g_ServerCommandBufferLength > 0)
1015 g_ServerCommandBuffer[0] = '\0';
1018 engine->ServerExecute();
1020 g_ShouldCatchSpew = true;
1021 engine->ServerCommand("sm_conhook_start\n");
1022 engine->ServerCommand(buffer);
1023 engine->ServerCommand("sm_conhook_stop\n");
1025 engine->ServerExecute();
1027 if (g_ServerCommandBufferLength > 0)
1029 g_ServerCommandBuffer[g_ServerCommandBufferLength-1] = '\0';
1032 g_ServerCommandBuffer = NULL;
1033 g_ServerCommandBufferLength = 0;
1038 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
1040 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
1043 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
1045 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1050 /* One byte for null terminator, one for newline */
1051 buffer[len++] = '\n';
1054 InsertServerCommand(buffer);
1059 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
1061 engine->ServerExecute();
1066 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
1068 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1072 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1075 if (!pPlayer->IsConnected())
1077 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1080 g_SourceMod.SetGlobalTarget(params[1]);
1083 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1085 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1090 engine->ClientCommand(
1091 #if SOURCE_ENGINE == SE_DOTA
1092 pPlayer->GetIndex(),
1094 pPlayer->GetEdict(),
1101 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
1103 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1107 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1110 if (!pPlayer->IsConnected())
1112 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1115 g_SourceMod.SetGlobalTarget(params[1]);
1118 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1120 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1125 #if SOURCE_ENGINE == SE_DOTA
1126 engine->ClientCommand(pPlayer->GetIndex(), "%s", buffer);
1128 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
1134 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
1136 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1140 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1143 if (!pPlayer->IsConnected())
1145 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1148 g_SourceMod.SetGlobalTarget(params[1]);
1151 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1153 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1158 g_HL2.AddToFakeCliCmdQueue(params[1], GetPlayerUserId(pPlayer->GetEdict()), buffer);
1163 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
1165 g_SourceMod.SetGlobalTarget(params[1]);
1167 /* Build the format string */
1169 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
1171 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1176 /* If we're printing to the server, shortcut out */
1180 buffer[len++] = '\n';
1182 META_CONPRINT(buffer);
1186 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1190 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1193 if (!pPlayer->IsConnected())
1195 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1198 unsigned int replyto = g_ChatTriggers.GetReplyTo();
1199 if (replyto == SM_REPLY_CONSOLE)
1201 buffer[len++] = '\n';
1203 #if SOURCE_ENGINE == SE_DOTA
1204 engine->ClientPrintf(pPlayer->GetIndex(), buffer);
1206 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1208 } else if (replyto == SM_REPLY_CHAT) {
1214 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1220 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1222 return g_ChatTriggers.GetReplyTo();
1225 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1227 return g_ChatTriggers.SetReplyTo(params[1]);
1230 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1232 GlobCmdIter *iter = new GlobCmdIter;
1233 iter->started = false;
1235 Handle_t hndl = handlesys->CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1236 if (hndl == BAD_HANDLE)
1244 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1248 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1250 if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1251 != HandleError_None)
1253 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1256 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1260 iter->iter = cmds.begin();
1261 iter->started = true;
1264 while (iter->iter != cmds.end()
1265 && !(*(iter->iter))->sourceMod)
1270 if (iter->iter == cmds.end())
1275 ConCmdInfo *pInfo = (*(iter->iter));
1277 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1278 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1281 pContext->LocalToPhysAddr(params[4], &addr);
1282 *addr = pInfo->eflags;
1289 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1297 pContext->LocalToString(params[2], &cmd);
1299 /* Match up with an admin command if possible */
1300 FlagBits bits = params[3];
1301 bool found_command = false;
1302 if (params[0] < 4 || !params[4])
1304 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1309 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1312 return g_ConCmds.CheckClientCommandAccess(params[1], cmd, bits) ? 1 : 0;
1315 static cell_t CheckAccess(IPluginContext *pContext, const cell_t *params)
1318 pContext->LocalToString(params[2], &cmd);
1320 /* Match up with an admin command if possible */
1321 FlagBits bits = params[3];
1322 bool found_command = false;
1323 if (params[0] < 4 || !params[4])
1325 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1330 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1333 return g_ConCmds.CheckAdminCommandAccess(params[1], cmd, bits) ? 1 : 0;
1336 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1338 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1341 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1344 pContext->LocalToString(params[1], &name);
1346 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1349 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1353 pContext->LocalToString(params[1], &name);
1355 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1358 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1361 ConCommandBaseIterator *pIter;
1362 cell_t *pIsCmd, *pFlags;
1363 const ConCommandBase *pConCmd;
1366 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1367 pContext->LocalToPhysAddr(params[4], &pFlags);
1369 pIter = new ConCommandBaseIterator();
1371 if (!pIter->IsValid())
1377 pConCmd = pIter->Get();
1379 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1380 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1381 *pFlags = pConCmd->GetFlags();
1385 desc = pConCmd->GetHelpText();
1386 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1389 if ((hndl = handlesys->CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1399 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1402 ConCommandBaseIterator *pIter;
1403 cell_t *pIsCmd, *pFlags;
1405 const ConCommandBase *pConCmd;
1406 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1408 if ((err = handlesys->ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1410 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1413 if (!pIter->IsValid())
1419 if (!pIter->IsValid())
1423 pConCmd = pIter->Get();
1425 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1426 pContext->LocalToPhysAddr(params[5], &pFlags);
1428 pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
1429 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1430 *pFlags = pConCmd->GetFlags();
1434 desc = pConCmd->GetHelpText();
1435 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1441 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1443 Handle_t hndl = static_cast<Handle_t>(params[2]);
1448 pContext->LocalToString(params[3], &value);
1450 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1451 != HandleError_None)
1453 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1457 bf_write buffer(data, sizeof(data));
1459 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
1460 CNETMsg_SetConVar msg;
1461 CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();
1463 cvar->set_name(pConVar->GetName());
1464 cvar->set_value(value);
1466 int msgsize = msg.ByteSize();
1468 buffer.WriteVarInt32(net_SetConVar);
1469 buffer.WriteVarInt32(msgsize);
1470 msg.SerializeWithCachedSizesToArray( (uint8 *)( buffer.GetBasePointer() + buffer.GetNumBytesWritten() ) );
1471 buffer.SeekToBit( ( buffer.GetNumBytesWritten() + msgsize ) * 8 );
1473 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
1474 buffer.WriteByte(1);
1475 buffer.WriteString(pConVar->GetName());
1476 buffer.WriteString(value);
1479 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1483 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1486 if (!pPlayer->IsConnected())
1488 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1491 if (pPlayer->IsFakeClient())
1493 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1496 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1497 if (netchan == NULL)
1502 netchan->SendData(buffer);
1507 static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
1512 static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
1517 static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
1520 IPluginFunction *pFunction;
1522 pContext->LocalToString(params[2], &name);
1524 if (strcasecmp(name, "sm") == 0)
1526 g_Logger.LogError("Request to register \"sm\" command denied.");
1530 pFunction = pContext->GetFunctionById(params[1]);
1533 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1535 if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
1536 return pContext->ThrowNativeError("This game does not support command listeners");
1541 static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
1544 IPluginFunction *pFunction;
1546 pContext->LocalToString(params[2], &name);
1547 pFunction = pContext->GetFunctionById(params[1]);
1549 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1551 if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
1552 return pContext->ThrowNativeError("No matching callback was registered");
1557 REGISTER_NATIVES(consoleNatives)
1559 {"CreateConVar", sm_CreateConVar},
1560 {"FindConVar", sm_FindConVar},
1561 {"HookConVarChange", sm_HookConVarChange},
1562 {"UnhookConVarChange", sm_UnhookConVarChange},
1563 {"GetConVarBool", sm_GetConVarBool},
1564 {"SetConVarBool", sm_SetConVarNum},
1565 {"GetConVarInt", sm_GetConVarInt},
1566 {"SetConVarInt", sm_SetConVarNum},
1567 {"GetConVarFloat", sm_GetConVarFloat},
1568 {"SetConVarFloat", sm_SetConVarFloat},
1569 {"GetConVarString", sm_GetConVarString},
1570 {"SetConVarString", sm_SetConVarString},
1571 {"GetConVarFlags", sm_GetConVarFlags},
1572 {"SetConVarFlags", sm_SetConVarFlags},
1573 {"ResetConVar", sm_ResetConVar},
1574 {"GetConVarName", sm_GetConVarName},
1575 {"GetConVarBounds", sm_GetConVarBounds},
1576 {"SetConVarBounds", sm_SetConVarBounds},
1577 {"QueryClientConVar", sm_QueryClientConVar},
1578 {"GetConVarDefault", GetConVarDefault},
1579 {"RegServerCmd", sm_RegServerCmd},
1580 {"RegConsoleCmd", sm_RegConsoleCmd},
1581 {"GetCmdArgString", sm_GetCmdArgString},
1582 {"GetCmdArgs", sm_GetCmdArgs},
1583 {"GetCmdArg", sm_GetCmdArg},
1584 {"PrintToServer", sm_PrintToServer},
1585 {"PrintToConsole", sm_PrintToConsole},
1586 {"RegAdminCmd", sm_RegAdminCmd},
1587 {"ServerCommand", sm_ServerCommand},
1588 {"ServerCommandEx", sm_ServerCommandEx},
1589 {"InsertServerCommand", sm_InsertServerCommand},
1590 {"ServerExecute", sm_ServerExecute},
1591 {"ClientCommand", sm_ClientCommand},
1592 {"FakeClientCommand", FakeClientCommand},
1593 {"ReplyToCommand", ReplyToCommand},
1594 {"GetCmdReplySource", GetCmdReplyTarget},
1595 {"SetCmdReplySource", SetCmdReplyTarget},
1596 {"GetCommandIterator", GetCommandIterator},
1597 {"ReadCommandIterator", ReadCommandIterator},
1598 {"CheckCommandAccess", CheckCommandAccess},
1599 {"CheckAccess", CheckAccess},
1600 {"FakeClientCommandEx", FakeClientCommandEx},
1601 {"IsChatTrigger", IsChatTrigger},
1602 {"SetCommandFlags", SetCommandFlags},
1603 {"GetCommandFlags", GetCommandFlags},
1604 {"FindFirstConCommand", FindFirstConCommand},
1605 {"FindNextConCommand", FindNextConCommand},
1606 {"SendConVarValue", SendConVarValue},
1607 {"AddServerTag", AddServerTag},
1608 {"RemoveServerTag", RemoveServerTag},
1609 {"AddCommandListener", AddCommandListener},
1610 {"RemoveCommandListener", RemoveCommandListener},