Fixed typo in Nuclear Dawn gamedata backcompat fix.
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 "ConVarManager.h"
36 #include "ConCmdManager.h"
37 #include "sm_stringutil.h"
38 #include "PlayerManager.h"
39 #include "ChatTriggers.h"
40 #include "AdminCache.h"
41 #include <inetchannel.h>
43 #include <sm_trie_tpl.h>
44 #include <tier0/dbg.h>
46 #include "ConsoleDetours.h"
47 #include "ConCommandBaseIterator.h"
48 #include "logic_bridge.h"
50 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
51 #include <netmessages.pb.h>
54 #if SOURCE_ENGINE >= SE_EYE
60 #if SOURCE_ENGINE >= SE_LEFT4DEAD
61 #define NET_SETCONVAR 6
63 #define NET_SETCONVAR 5
68 ConVarBound_Upper = 0,
72 HandleType_t hCmdIterType = 0;
73 HandleType_t htConCmdIter = 0;
78 List<ConCmdInfo *>::iterator iter;
81 class ConsoleHelpers :
83 public IHandleTypeDispatch
86 virtual void OnSourceModAllInitialized()
90 handlesys->InitAccessDefaults(NULL, &access);
92 htConCmdIter = handlesys->CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
94 access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
96 hCmdIterType = handlesys->CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
98 virtual void OnHandleDestroy(HandleType_t type, void *object)
100 if (type == hCmdIterType)
102 GlobCmdIter *iter = (GlobCmdIter *)object;
105 else if (type == htConCmdIter)
107 ConCommandBaseIterator *iter = (ConCommandBaseIterator * )object;
111 virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
113 if (type == htConCmdIter)
115 *pSize = sizeof(ConCommandBaseIterator);
118 else if (type == hCmdIterType)
120 *pSize = sizeof(GlobCmdIter);
127 class CommandFlagsHelper : public IConCommandTracker
130 void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
132 m_CmdFlags.remove(name);
134 bool GetFlags(const char *name, int *flags)
136 ConCommandBase **ppCmd;
137 ConCommandBase *pCmd;
138 if ((ppCmd=m_CmdFlags.retrieve(name)))
140 TrackConCommandBase((*ppCmd), this);
141 *flags = (*ppCmd)->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 **ppCmd;
159 ConCommandBase *pCmd;
160 if ((ppCmd=m_CmdFlags.retrieve(name)))
162 (*ppCmd)->SetFlags(flags);
163 TrackConCommandBase((*ppCmd), this);
166 else if ((pCmd=FindCommandBase(name)))
168 m_CmdFlags.insert(name, pCmd);
169 pCmd->SetFlags(flags);
170 TrackConCommandBase(pCmd, this);
179 KTrie<ConCommandBase *> m_CmdFlags;
180 } s_CommandFlagsHelper;
182 #if SOURCE_ENGINE < SE_ORANGEBOX
183 static void ReplicateConVar(ConVar *pConVar)
185 int maxClients = g_Players.GetMaxClients();
188 bf_write buffer(data, sizeof(data));
190 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
192 buffer.WriteString(pConVar->GetName());
193 buffer.WriteString(pConVar->GetString());
195 for (int i = 1; i <= maxClients; i++)
197 CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
199 if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
201 if (INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i)))
202 netchan->SendData(buffer);
207 static void NotifyConVar(ConVar *pConVar)
209 IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
210 pEvent->SetString("cvarname", pConVar->GetName());
211 if (IsFlagSet(pConVar, FCVAR_PROTECTED))
213 pEvent->SetString("cvarvalue", "***PROTECTED***");
217 pEvent->SetString("cvarvalue", pConVar->GetString());
220 gameevents->FireEvent(pEvent);
224 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
226 char *name, *defaultVal, *helpText;
228 pContext->LocalToString(params[1], &name);
230 // While the engine seems to accept a blank convar name, it causes a crash upon server quit
231 if (name == NULL || strcmp(name, "") == 0)
233 return pContext->ThrowNativeError("Convar with blank name is not permitted");
236 pContext->LocalToString(params[2], &defaultVal);
237 pContext->LocalToString(params[3], &helpText);
239 bool hasMin = params[5] ? true : false;
240 bool hasMax = params[7] ? true : false;
241 float min = sp_ctof(params[6]);
242 float max = sp_ctof(params[8]);
244 Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
246 if (hndl == BAD_HANDLE)
248 return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
254 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
258 pContext->LocalToString(params[1], &name);
260 return g_ConVarManager.FindConVar(name);
263 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
265 Handle_t hndl = static_cast<Handle_t>(params[1]);
269 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
272 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
275 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
279 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
282 g_ConVarManager.HookConVarChange(pConVar, pFunction);
287 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
289 Handle_t hndl = static_cast<Handle_t>(params[1]);
293 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
296 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
299 IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
303 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
306 g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
311 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
313 Handle_t hndl = static_cast<Handle_t>(params[1]);
317 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
320 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
323 return pConVar->GetBool();
326 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
328 Handle_t hndl = static_cast<Handle_t>(params[1]);
332 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
335 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
338 return pConVar->GetInt();
341 /* This handles both SetConVarBool() and SetConVarInt() */
342 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
344 Handle_t hndl = static_cast<Handle_t>(params[1]);
348 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
351 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
354 pConVar->SetValue(params[2]);
356 #if SOURCE_ENGINE < SE_ORANGEBOX
357 /* Should we replicate it? */
358 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
360 ReplicateConVar(pConVar);
363 /* Should we notify clients? */
364 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
366 NotifyConVar(pConVar);
373 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
375 Handle_t hndl = static_cast<Handle_t>(params[1]);
379 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
382 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
385 float value = pConVar->GetFloat();
387 return sp_ftoc(value);
390 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
392 Handle_t hndl = static_cast<Handle_t>(params[1]);
396 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
399 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
402 float value = sp_ctof(params[2]);
403 pConVar->SetValue(value);
405 #if SOURCE_ENGINE < SE_ORANGEBOX
406 /* Should we replicate it? */
407 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
409 ReplicateConVar(pConVar);
412 /* Should we notify clients? */
413 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
415 NotifyConVar(pConVar);
422 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
424 Handle_t hndl = static_cast<Handle_t>(params[1]);
428 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
431 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
434 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
439 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
441 Handle_t hndl = static_cast<Handle_t>(params[1]);
445 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
448 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
452 pContext->LocalToString(params[2], &value);
454 pConVar->SetValue(value);
456 #if SOURCE_ENGINE < SE_ORANGEBOX
457 /* Should we replicate it? */
458 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
460 ReplicateConVar(pConVar);
463 /* Should we notify clients? */
464 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
466 NotifyConVar(pConVar);
473 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
475 Handle_t hndl = static_cast<Handle_t>(params[1]);
479 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
482 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
487 #if SOURCE_ENGINE < SE_ORANGEBOX
488 /* Should we replicate it? */
489 if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
491 ReplicateConVar(pConVar);
494 /* Should we notify clients? */
495 if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
497 NotifyConVar(pConVar);
504 static cell_t GetConVarDefault(IPluginContext *pContext, const cell_t *params)
506 Handle_t hndl = static_cast<Handle_t>(params[1]);
510 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
513 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
517 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetDefault(), &bytes);
522 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
524 Handle_t hndl = static_cast<Handle_t>(params[1]);
528 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
531 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
534 return pConVar->GetFlags();
537 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
539 Handle_t hndl = static_cast<Handle_t>(params[1]);
543 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
546 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
549 pConVar->SetFlags(params[2]);
554 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
556 Handle_t hndl = static_cast<Handle_t>(params[1]);
560 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
563 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
572 case ConVarBound_Upper:
573 hasBound = pConVar->GetMax(bound);
575 case ConVarBound_Lower:
576 hasBound = pConVar->GetMin(bound);
579 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
582 pContext->LocalToPhysAddr(params[3], &addr);
583 *addr = sp_ftoc(bound);
588 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
590 Handle_t hndl = static_cast<Handle_t>(params[1]);
594 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
597 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
602 case ConVarBound_Upper:
603 pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
605 case ConVarBound_Lower:
606 pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
609 return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
615 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
617 Handle_t hndl = static_cast<Handle_t>(params[1]);
621 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
624 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
627 pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
632 static bool s_QueryAlreadyWarned = false;
634 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
638 IPluginFunction *pCallback;
640 if (!g_ConVarManager.IsQueryingSupported())
642 if (!s_QueryAlreadyWarned)
644 s_QueryAlreadyWarned = true;
645 return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
651 pPlayer = g_Players.GetPlayerByIndex(params[1]);
655 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
658 if (!pPlayer->IsConnected())
660 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
663 /* Trying a query on a bot results in callback not be fired, so don't bother */
664 if (pPlayer->IsFakeClient())
669 pContext->LocalToString(params[2], &name);
670 pCallback = pContext->GetFunctionById(params[3]);
674 return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
677 return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
680 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
683 IPluginFunction *pFunction;
685 pContext->LocalToString(params[1], &name);
687 if (strcasecmp(name, "sm") == 0)
689 return pContext->ThrowNativeError("Cannot register \"sm\" command");
692 pContext->LocalToString(params[3], &help);
693 pFunction = pContext->GetFunctionById(params[2]);
697 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
700 if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
702 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
708 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
711 IPluginFunction *pFunction;
713 pContext->LocalToString(params[1], &name);
715 if (strcasecmp(name, "sm") == 0)
717 return pContext->ThrowNativeError("Cannot register \"sm\" command");
720 pContext->LocalToString(params[3], &help);
721 pFunction = pContext->GetFunctionById(params[2]);
725 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
728 IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
729 const char *group = pPlugin->GetFilename();
730 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, 0, help, params[4]))
732 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
738 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
742 IPluginFunction *pFunction;
743 FlagBits flags = params[3];
744 int cmdflags = params[6];
746 pContext->LocalToString(params[1], &name);
748 if (strcasecmp(name, "sm") == 0)
750 return pContext->ThrowNativeError("Cannot register \"sm\" command");
753 pContext->LocalToString(params[4], &help);
754 pContext->LocalToString(params[5], (char **)&group);
755 pFunction = pContext->GetFunctionById(params[2]);
757 if (group[0] == '\0')
759 IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
760 group = pPlugin->GetFilename();
765 return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
768 if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
770 return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
776 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
778 const CCommand *pCmd = g_HL2.PeekCommandStack();
782 return pContext->ThrowNativeError("No command callback available");
785 return pCmd->ArgC() - 1;
788 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
790 const CCommand *pCmd = g_HL2.PeekCommandStack();
794 return pContext->ThrowNativeError("No command callback available");
799 const char *arg = pCmd->Arg(params[1]);
801 pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
803 return (cell_t)length;
806 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
808 const CCommand *pCmd = g_HL2.PeekCommandStack();
812 return pContext->ThrowNativeError("No command callback available");
815 const char *args = pCmd->ArgS();
823 pContext->StringToLocalUTF8(params[1], params[2], args, &length);
825 return (cell_t)length;
828 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
834 pCtx->LocalToString(params[1], &fmt);
835 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
837 buffer[res++] = '\n';
840 META_CONPRINT(buffer);
845 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
847 int index = params[1];
848 if ((index < 0) || (index > g_Players.GetMaxClients()))
850 return pCtx->ThrowNativeError("Client index %d is invalid", index);
853 CPlayer *pPlayer = NULL;
856 pPlayer = g_Players.GetPlayerByIndex(index);
857 if (!pPlayer->IsInGame())
859 return pCtx->ThrowNativeError("Client %d is not in game", index);
862 /* Silent fail on bots, engine will crash */
863 if (pPlayer->IsFakeClient())
873 pCtx->LocalToString(params[2], &fmt);
874 size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
876 buffer[res++] = '\n';
881 #if SOURCE_ENGINE == SE_DOTA
882 engine->ClientPrintf(pPlayer->GetIndex(), buffer);
884 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
887 META_CONPRINT(buffer);
893 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
895 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
898 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
900 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
905 /* One byte for null terminator, one for newline */
906 buffer[len++] = '\n';
909 engine->ServerCommand(buffer);
914 char *g_ServerCommandBuffer = NULL;
915 cell_t g_ServerCommandBufferLength;
917 bool g_ShouldCatchSpew = false;
919 #if SOURCE_ENGINE < SE_NUCLEARDAWN
920 SpewOutputFunc_t g_OriginalSpewOutputFunc = NULL;
922 SpewRetval_t SourcemodSpewOutputFunc(SpewType_t spewType, tchar const *pMsg)
924 if (g_ServerCommandBuffer)
926 V_strcat(g_ServerCommandBuffer, pMsg, g_ServerCommandBufferLength);
929 if (g_OriginalSpewOutputFunc)
931 return g_OriginalSpewOutputFunc(spewType, pMsg);
933 return SPEW_CONTINUE;
937 class CSourcemodLoggingListener: public ILoggingListener
940 void Log(const LoggingContext_t *pContext, const tchar *pMessage)
942 if (g_ServerCommandBuffer)
944 V_strcat(g_ServerCommandBuffer, pMessage, g_ServerCommandBufferLength);
947 } g_SourcemodLoggingListener;
950 CON_COMMAND(sm_conhook_start, "")
952 if (!g_ShouldCatchSpew)
954 Warning("You shouldn't run this command!\n");
958 #if SOURCE_ENGINE < SE_NUCLEARDAWN
959 g_OriginalSpewOutputFunc = GetSpewOutputFunc();
960 SpewOutputFunc(SourcemodSpewOutputFunc);
962 #if SOURCE_ENGINE < SE_ALIENSWARM
963 LoggingSystem_PushLoggingState(false);
965 LoggingSystem_PushLoggingState(false, false);
967 LoggingSystem_RegisterLoggingListener(&g_SourcemodLoggingListener);
971 CON_COMMAND(sm_conhook_stop, "")
973 if (!g_ShouldCatchSpew)
975 Warning("You shouldn't run this command!\n");
979 #if SOURCE_ENGINE < SE_NUCLEARDAWN
980 SpewOutputFunc(g_OriginalSpewOutputFunc);
982 LoggingSystem_PopLoggingState(false);
985 g_ShouldCatchSpew = false;
988 static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params)
990 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
993 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 3);
995 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1000 /* One byte for null terminator, one for newline */
1001 buffer[len++] = '\n';
1004 pContext->LocalToString(params[1], &g_ServerCommandBuffer);
1005 g_ServerCommandBufferLength = params[2];
1007 if (g_ServerCommandBufferLength > 0)
1009 g_ServerCommandBuffer[0] = '\0';
1012 engine->ServerExecute();
1014 g_ShouldCatchSpew = true;
1015 engine->ServerCommand("sm_conhook_start\n");
1016 engine->ServerCommand(buffer);
1017 engine->ServerCommand("sm_conhook_stop\n");
1019 engine->ServerExecute();
1021 if (g_ServerCommandBufferLength > 0)
1023 g_ServerCommandBuffer[g_ServerCommandBufferLength-1] = '\0';
1026 g_ServerCommandBuffer = NULL;
1027 g_ServerCommandBufferLength = 0;
1032 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
1034 g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
1037 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
1039 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1044 /* One byte for null terminator, one for newline */
1045 buffer[len++] = '\n';
1048 InsertServerCommand(buffer);
1053 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
1055 engine->ServerExecute();
1060 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
1062 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1066 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1069 if (!pPlayer->IsConnected())
1071 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1074 g_SourceMod.SetGlobalTarget(params[1]);
1077 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1079 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1084 engine->ClientCommand(
1085 #if SOURCE_ENGINE == SE_DOTA
1086 pPlayer->GetIndex(),
1088 pPlayer->GetEdict(),
1095 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
1097 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1101 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1104 if (!pPlayer->IsConnected())
1106 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1110 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1112 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1117 #if SOURCE_ENGINE == SE_DOTA
1118 engine->ClientCommand(pPlayer->GetIndex(), "%s", buffer);
1120 serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
1126 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
1128 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1132 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1135 if (!pPlayer->IsConnected())
1137 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1141 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
1143 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1148 g_HL2.AddToFakeCliCmdQueue(params[1], GetPlayerUserId(pPlayer->GetEdict()), buffer);
1153 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
1155 g_SourceMod.SetGlobalTarget(params[1]);
1157 /* Build the format string */
1159 size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
1161 if (pContext->GetLastNativeError() != SP_ERROR_NONE)
1166 /* If we're printing to the server, shortcut out */
1170 buffer[len++] = '\n';
1172 META_CONPRINT(buffer);
1176 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1180 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1183 if (!pPlayer->IsConnected())
1185 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1188 g_SourceMod.SetGlobalTarget(params[1]);
1190 unsigned int replyto = g_ChatTriggers.GetReplyTo();
1191 if (replyto == SM_REPLY_CONSOLE)
1193 buffer[len++] = '\n';
1195 #if SOURCE_ENGINE == SE_DOTA
1196 engine->ClientPrintf(pPlayer->GetIndex(), buffer);
1198 engine->ClientPrintf(pPlayer->GetEdict(), buffer);
1200 } else if (replyto == SM_REPLY_CHAT) {
1206 g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
1212 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1214 return g_ChatTriggers.GetReplyTo();
1217 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
1219 return g_ChatTriggers.SetReplyTo(params[1]);
1222 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
1224 GlobCmdIter *iter = new GlobCmdIter;
1225 iter->started = false;
1227 Handle_t hndl = handlesys->CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
1228 if (hndl == BAD_HANDLE)
1236 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
1240 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1242 if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
1243 != HandleError_None)
1245 return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
1248 const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
1252 iter->iter = cmds.begin();
1253 iter->started = true;
1256 while (iter->iter != cmds.end()
1257 && !(*(iter->iter))->sourceMod)
1262 if (iter->iter == cmds.end())
1267 ConCmdInfo *pInfo = (*(iter->iter));
1269 pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
1270 pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
1273 pContext->LocalToPhysAddr(params[4], &addr);
1274 *addr = pInfo->admin.eflags;
1281 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
1289 pContext->LocalToString(params[2], &cmd);
1291 /* Match up with an admin command if possible */
1292 FlagBits bits = params[3];
1293 bool found_command = false;
1294 if (params[0] < 4 || !params[4])
1296 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1301 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1304 return g_ConCmds.CheckClientCommandAccess(params[1], cmd, bits) ? 1 : 0;
1307 static cell_t CheckAccess(IPluginContext *pContext, const cell_t *params)
1310 pContext->LocalToString(params[2], &cmd);
1312 /* Match up with an admin command if possible */
1313 FlagBits bits = params[3];
1314 bool found_command = false;
1315 if (params[0] < 4 || !params[4])
1317 found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
1322 g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
1325 return g_ConCmds.CheckAdminCommandAccess(params[1], cmd, bits) ? 1 : 0;
1328 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
1330 return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
1333 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
1336 pContext->LocalToString(params[1], &name);
1338 return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
1341 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
1345 pContext->LocalToString(params[1], &name);
1347 return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
1350 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
1353 ConCommandBaseIterator *pIter;
1354 cell_t *pIsCmd, *pFlags;
1355 const ConCommandBase *pConCmd;
1358 pContext->LocalToPhysAddr(params[3], &pIsCmd);
1359 pContext->LocalToPhysAddr(params[4], &pFlags);
1361 pIter = new ConCommandBaseIterator();
1363 if (!pIter->IsValid())
1369 pConCmd = pIter->Get();
1371 pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
1372 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1373 *pFlags = pConCmd->GetFlags();
1377 desc = pConCmd->GetHelpText();
1378 pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
1381 if ((hndl = handlesys->CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
1391 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
1394 ConCommandBaseIterator *pIter;
1395 cell_t *pIsCmd, *pFlags;
1397 const ConCommandBase *pConCmd;
1398 HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
1400 if ((err = handlesys->ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
1402 return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
1405 if (!pIter->IsValid())
1411 if (!pIter->IsValid())
1415 pConCmd = pIter->Get();
1417 pContext->LocalToPhysAddr(params[4], &pIsCmd);
1418 pContext->LocalToPhysAddr(params[5], &pFlags);
1420 pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
1421 *pIsCmd = pConCmd->IsCommand() ? 1 : 0;
1422 *pFlags = pConCmd->GetFlags();
1426 desc = pConCmd->GetHelpText();
1427 pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
1433 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
1435 Handle_t hndl = static_cast<Handle_t>(params[2]);
1440 pContext->LocalToString(params[3], &value);
1442 if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
1443 != HandleError_None)
1445 return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
1449 bf_write buffer(data, sizeof(data));
1451 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
1452 CNETMsg_SetConVar msg;
1453 CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();
1455 cvar->set_name(pConVar->GetName());
1456 cvar->set_value(value);
1458 int msgsize = msg.ByteSize();
1460 buffer.WriteVarInt32(net_SetConVar);
1461 buffer.WriteVarInt32(msgsize);
1462 msg.SerializeWithCachedSizesToArray( (uint8 *)( buffer.GetBasePointer() + buffer.GetNumBytesWritten() ) );
1463 buffer.SeekToBit( ( buffer.GetNumBytesWritten() + msgsize ) * 8 );
1465 buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
1466 buffer.WriteByte(1);
1467 buffer.WriteString(pConVar->GetName());
1468 buffer.WriteString(value);
1471 CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
1475 return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
1478 if (!pPlayer->IsConnected())
1480 return pContext->ThrowNativeError("Client %d is not connected", params[1]);
1483 if (pPlayer->IsFakeClient())
1485 return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
1488 INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
1489 if (netchan == NULL)
1494 netchan->SendData(buffer);
1499 static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
1504 static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
1509 static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
1512 IPluginFunction *pFunction;
1514 pContext->LocalToString(params[2], &name);
1516 if (strcasecmp(name, "sm") == 0)
1518 g_Logger.LogError("Request to register \"sm\" command denied.");
1522 pFunction = pContext->GetFunctionById(params[1]);
1525 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1527 if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
1528 return pContext->ThrowNativeError("This game does not support command listeners");
1533 static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
1536 IPluginFunction *pFunction;
1538 pContext->LocalToString(params[2], &name);
1539 pFunction = pContext->GetFunctionById(params[1]);
1541 return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
1543 if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
1544 return pContext->ThrowNativeError("No matching callback was registered");
1549 REGISTER_NATIVES(consoleNatives)
1551 {"CreateConVar", sm_CreateConVar},
1552 {"FindConVar", sm_FindConVar},
1553 {"HookConVarChange", sm_HookConVarChange},
1554 {"UnhookConVarChange", sm_UnhookConVarChange},
1555 {"GetConVarBool", sm_GetConVarBool},
1556 {"SetConVarBool", sm_SetConVarNum},
1557 {"GetConVarInt", sm_GetConVarInt},
1558 {"SetConVarInt", sm_SetConVarNum},
1559 {"GetConVarFloat", sm_GetConVarFloat},
1560 {"SetConVarFloat", sm_SetConVarFloat},
1561 {"GetConVarString", sm_GetConVarString},
1562 {"SetConVarString", sm_SetConVarString},
1563 {"GetConVarFlags", sm_GetConVarFlags},
1564 {"SetConVarFlags", sm_SetConVarFlags},
1565 {"ResetConVar", sm_ResetConVar},
1566 {"GetConVarName", sm_GetConVarName},
1567 {"GetConVarBounds", sm_GetConVarBounds},
1568 {"SetConVarBounds", sm_SetConVarBounds},
1569 {"QueryClientConVar", sm_QueryClientConVar},
1570 {"GetConVarDefault", GetConVarDefault},
1571 {"RegServerCmd", sm_RegServerCmd},
1572 {"RegConsoleCmd", sm_RegConsoleCmd},
1573 {"GetCmdArgString", sm_GetCmdArgString},
1574 {"GetCmdArgs", sm_GetCmdArgs},
1575 {"GetCmdArg", sm_GetCmdArg},
1576 {"PrintToServer", sm_PrintToServer},
1577 {"PrintToConsole", sm_PrintToConsole},
1578 {"RegAdminCmd", sm_RegAdminCmd},
1579 {"ServerCommand", sm_ServerCommand},
1580 {"ServerCommandEx", sm_ServerCommandEx},
1581 {"InsertServerCommand", sm_InsertServerCommand},
1582 {"ServerExecute", sm_ServerExecute},
1583 {"ClientCommand", sm_ClientCommand},
1584 {"FakeClientCommand", FakeClientCommand},
1585 {"ReplyToCommand", ReplyToCommand},
1586 {"GetCmdReplySource", GetCmdReplyTarget},
1587 {"SetCmdReplySource", SetCmdReplyTarget},
1588 {"GetCommandIterator", GetCommandIterator},
1589 {"ReadCommandIterator", ReadCommandIterator},
1590 {"CheckCommandAccess", CheckCommandAccess},
1591 {"CheckAccess", CheckAccess},
1592 {"FakeClientCommandEx", FakeClientCommandEx},
1593 {"IsChatTrigger", IsChatTrigger},
1594 {"SetCommandFlags", SetCommandFlags},
1595 {"GetCommandFlags", GetCommandFlags},
1596 {"FindFirstConCommand", FindFirstConCommand},
1597 {"FindNextConCommand", FindNextConCommand},
1598 {"SendConVarValue", SendConVarValue},
1599 {"AddServerTag", AddServerTag},
1600 {"RemoveServerTag", RemoveServerTag},
1601 {"AddCommandListener", AddCommandListener},
1602 {"RemoveCommandListener", RemoveCommandListener},