core/smn_console.cpp
author Scott Ehlert <ds@alliedmods.net>
Mon Mar 03 05:20:40 2014 -0600 (2014-03-03)
changeset 4272 8b39aa02b05b
parent 4217 4c87212c5817
permissions -rw-r--r--
Add gamedata for EntityFactoryDictionary and IServer for Dota 2 on Linux (bug 6068, r=psychonic).
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     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.
    11  * 
    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
    15  * details.
    16  *
    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/>.
    19  *
    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>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    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>
    43 #include <bitbuf.h>
    44 #include <tier0/dbg.h>
    45 #include "Logger.h"
    46 #include "ConsoleDetours.h"
    47 #include "ConCommandBaseIterator.h"
    48 #include "logic_bridge.h"
    49 #include <sm_namehashset.h>
    50 
    51 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
    52 #include <netmessages.pb.h>
    53 #endif
    54 
    55 #if SOURCE_ENGINE >= SE_EYE
    56 #define NETMSG_BITS 6
    57 #else
    58 #define NETMSG_BITS 5
    59 #endif
    60 
    61 #if SOURCE_ENGINE >= SE_LEFT4DEAD
    62 #define NET_SETCONVAR	6
    63 #else
    64 #define NET_SETCONVAR	5
    65 #endif
    66 
    67 enum ConVarBounds
    68 {
    69 	ConVarBound_Upper = 0,
    70 	ConVarBound_Lower
    71 };
    72 
    73 HandleType_t hCmdIterType = 0;
    74 HandleType_t htConCmdIter = 0;
    75 
    76 struct GlobCmdIter
    77 {
    78 	bool started;
    79 	List<ConCmdInfo *>::iterator iter;
    80 };
    81 
    82 class ConsoleHelpers : 
    83 	public SMGlobalClass,
    84 	public IHandleTypeDispatch
    85 {
    86 public:
    87 	virtual void OnSourceModAllInitialized()
    88 	{
    89 		HandleAccess access;
    90 
    91 		handlesys->InitAccessDefaults(NULL, &access);
    92 
    93 		htConCmdIter = handlesys->CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
    94 
    95 		access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
    96 
    97 		hCmdIterType = handlesys->CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
    98 	}
    99 	virtual void OnHandleDestroy(HandleType_t type, void *object)
   100 	{
   101 		if (type == hCmdIterType)
   102 		{
   103 			GlobCmdIter *iter = (GlobCmdIter *)object;
   104 			delete iter;
   105 		}
   106 		else if (type == htConCmdIter)
   107 		{
   108 			ConCommandBaseIterator *iter = (ConCommandBaseIterator * )object;
   109 			delete iter;
   110 		}
   111 	}
   112 	virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
   113 	{
   114 		if (type == htConCmdIter)
   115 		{
   116 			*pSize = sizeof(ConCommandBaseIterator);
   117 			return true;
   118 		}
   119 		else if (type == hCmdIterType)
   120 		{
   121 			*pSize = sizeof(GlobCmdIter);
   122 			return true;
   123 		}
   124 		return false;
   125 	}
   126 } s_ConsoleHelpers;
   127 
   128 class CommandFlagsHelper : public IConCommandTracker
   129 {
   130 public:
   131 	void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
   132 	{
   133 		m_CmdFlags.remove(name);
   134 	}
   135 	bool GetFlags(const char *name, int *flags)
   136 	{
   137 		ConCommandBase *pCmd;
   138 		if (m_CmdFlags.retrieve(name, &pCmd))
   139 		{
   140 			TrackConCommandBase(pCmd, this);
   141 			*flags = pCmd->GetFlags();
   142 			return true;
   143 		}
   144 		else if ((pCmd=FindCommandBase(name)))
   145 		{
   146 			m_CmdFlags.insert(name, pCmd);
   147 			TrackConCommandBase(pCmd, this);
   148 			*flags = pCmd->GetFlags();
   149 			return true;
   150 		}
   151 		else
   152 		{
   153 			return false;
   154 		}
   155 	}
   156 	bool SetFlags(const char *name, int flags)
   157 	{
   158 		ConCommandBase *pCmd;
   159 		if (m_CmdFlags.retrieve(name, &pCmd))
   160 		{
   161 			pCmd->SetFlags(flags);
   162 			TrackConCommandBase(pCmd, this);
   163 			return true;
   164 		}
   165 		else if ((pCmd=FindCommandBase(name)))
   166 		{
   167 			m_CmdFlags.insert(name, pCmd);
   168 			pCmd->SetFlags(flags);
   169 			TrackConCommandBase(pCmd, this);
   170 			return true;
   171 		}
   172 		else
   173 		{
   174 			return false;
   175 		}
   176 	}
   177 private:
   178 	struct ConCommandPolicy
   179 	{
   180 		static inline bool matches(const char *name, ConCommandBase *base)
   181 		{
   182 			return strcmp(name, base->GetName()) == 0;
   183 		}
   184 	};
   185 	NameHashSet<ConCommandBase *, ConCommandPolicy> m_CmdFlags;
   186 } s_CommandFlagsHelper;
   187 
   188 #if SOURCE_ENGINE < SE_ORANGEBOX
   189 static void ReplicateConVar(ConVar *pConVar)
   190 {
   191 	int maxClients = g_Players.GetMaxClients();
   192 
   193 	char data[256];
   194 	bf_write buffer(data, sizeof(data));
   195 
   196 	buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
   197 	buffer.WriteByte(1);
   198 	buffer.WriteString(pConVar->GetName());
   199 	buffer.WriteString(pConVar->GetString());
   200 
   201 	for (int i = 1; i <= maxClients; i++)
   202 	{
   203 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
   204 
   205 		if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
   206 		{
   207 			if (INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i)))
   208 				netchan->SendData(buffer);
   209 		}
   210 	}
   211 }
   212 
   213 static void NotifyConVar(ConVar *pConVar)
   214 {
   215 	IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
   216 	pEvent->SetString("cvarname", pConVar->GetName());
   217 	if (IsFlagSet(pConVar, FCVAR_PROTECTED))
   218 	{
   219 		pEvent->SetString("cvarvalue", "***PROTECTED***");
   220 	}
   221 	else
   222 	{
   223 		pEvent->SetString("cvarvalue", pConVar->GetString());
   224 	}
   225 
   226 	gameevents->FireEvent(pEvent);
   227 }
   228 #endif
   229 
   230 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
   231 {
   232 	char *name, *defaultVal, *helpText;
   233 
   234 	pContext->LocalToString(params[1], &name);
   235 
   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)
   238 	{
   239 		return pContext->ThrowNativeError("Convar with blank name is not permitted");
   240 	}
   241 
   242 	pContext->LocalToString(params[2], &defaultVal);
   243 	pContext->LocalToString(params[3], &helpText);
   244 
   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]);
   249 
   250 	Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
   251 
   252 	if (hndl == BAD_HANDLE)
   253 	{
   254 		return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
   255 	}
   256 
   257 	return hndl;
   258 }
   259 
   260 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
   261 {
   262 	char *name;
   263 
   264 	pContext->LocalToString(params[1], &name);
   265 
   266 	return g_ConVarManager.FindConVar(name);
   267 }
   268 
   269 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
   270 {
   271 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   272 	HandleError err;
   273 	ConVar *pConVar;
   274 
   275 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   276 		!= HandleError_None)
   277 	{
   278 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   279 	}
   280 
   281 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   282 
   283 	if (!pFunction)
   284 	{
   285 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   286 	}
   287 
   288 	g_ConVarManager.HookConVarChange(pConVar, pFunction);
   289 
   290 	return 1;
   291 }
   292 
   293 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
   294 {
   295 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   296 	HandleError err;
   297 	ConVar *pConVar;
   298 
   299 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   300 		!= HandleError_None)
   301 	{
   302 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   303 	}
   304 
   305 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   306 
   307 	if (!pFunction)
   308 	{
   309 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   310 	}
   311 
   312 	g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
   313 
   314 	return 1;
   315 }
   316 
   317 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
   318 {
   319 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   320 	HandleError err;
   321 	ConVar *pConVar;
   322 
   323 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   324 		!= HandleError_None)
   325 	{
   326 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   327 	}
   328 
   329 	return pConVar->GetBool();
   330 }
   331 
   332 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
   333 {
   334 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   335 	HandleError err;
   336 	ConVar *pConVar;
   337 
   338 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   339 		!= HandleError_None)
   340 	{
   341 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   342 	}
   343 
   344 	return pConVar->GetInt();
   345 }
   346 
   347 /* This handles both SetConVarBool() and SetConVarInt() */
   348 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
   349 {
   350 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   351 	HandleError err;
   352 	ConVar *pConVar;
   353 
   354 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   355 		!= HandleError_None)
   356 	{
   357 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   358 	}
   359 
   360 	pConVar->SetValue(params[2]);
   361 
   362 #if SOURCE_ENGINE < SE_ORANGEBOX
   363 	/* Should we replicate it? */
   364 	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
   365 	{
   366 		ReplicateConVar(pConVar);
   367 	}
   368 
   369 	/* Should we notify clients? */
   370 	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
   371 	{
   372 		NotifyConVar(pConVar);
   373 	}
   374 #endif
   375 
   376 	return 1;
   377 }
   378 
   379 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
   380 {
   381 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   382 	HandleError err;
   383 	ConVar *pConVar;
   384 
   385 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   386 		!= HandleError_None)
   387 	{
   388 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   389 	}
   390 	
   391 	float value = pConVar->GetFloat();
   392 
   393 	return sp_ftoc(value);
   394 }
   395 
   396 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
   397 {
   398 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   399 	HandleError err;
   400 	ConVar *pConVar;
   401 
   402 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   403 		!= HandleError_None)
   404 	{
   405 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   406 	}
   407 
   408 	float value = sp_ctof(params[2]);
   409 	pConVar->SetValue(value);
   410 
   411 #if SOURCE_ENGINE < SE_ORANGEBOX
   412 	/* Should we replicate it? */
   413 	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
   414 	{
   415 		ReplicateConVar(pConVar);
   416 	}
   417 
   418 	/* Should we notify clients? */
   419 	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
   420 	{
   421 		NotifyConVar(pConVar);
   422 	}
   423 #endif
   424 
   425 	return 1;
   426 }
   427 
   428 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
   429 {
   430 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   431 	HandleError err;
   432 	ConVar *pConVar;
   433 
   434 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   435 		!= HandleError_None)
   436 	{
   437 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   438 	}
   439 
   440 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
   441 
   442 	return 1;
   443 }
   444 
   445 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
   446 {
   447 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   448 	HandleError err;
   449 	ConVar *pConVar;
   450 
   451 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   452 		!= HandleError_None)
   453 	{
   454 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   455 	}
   456 
   457 	char *value;
   458 	pContext->LocalToString(params[2], &value);
   459 
   460 	pConVar->SetValue(value);
   461 
   462 #if SOURCE_ENGINE < SE_ORANGEBOX
   463 	/* Should we replicate it? */
   464 	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
   465 	{
   466 		ReplicateConVar(pConVar);
   467 	}
   468 
   469 	/* Should we notify clients? */
   470 	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
   471 	{
   472 		NotifyConVar(pConVar);
   473 	}
   474 #endif
   475 
   476 	return 1;
   477 }
   478 
   479 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
   480 {
   481 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   482 	HandleError err;
   483 	ConVar *pConVar;
   484 
   485 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   486 		!= HandleError_None)
   487 	{
   488 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   489 	}
   490 
   491 	pConVar->Revert();
   492 	
   493 #if SOURCE_ENGINE < SE_ORANGEBOX
   494 	/* Should we replicate it? */
   495 	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
   496 	{
   497 		ReplicateConVar(pConVar);
   498 	}
   499 
   500 	/* Should we notify clients? */
   501 	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
   502 	{
   503 		NotifyConVar(pConVar);
   504 	}
   505 #endif
   506 
   507 	return 1;
   508 }
   509 
   510 static cell_t GetConVarDefault(IPluginContext *pContext, const cell_t *params)
   511 {
   512 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   513 	HandleError err;
   514 	ConVar *pConVar;
   515 
   516 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   517 		!= HandleError_None)
   518 	{
   519 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   520 	}
   521 
   522 	size_t bytes;
   523 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetDefault(), &bytes);
   524 
   525 	return bytes;
   526 }
   527 
   528 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
   529 {
   530 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   531 	HandleError err;
   532 	ConVar *pConVar;
   533 
   534 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   535 		!= HandleError_None)
   536 	{
   537 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   538 	}
   539 
   540 	return pConVar->GetFlags();
   541 }
   542 
   543 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
   544 {
   545 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   546 	HandleError err;
   547 	ConVar *pConVar;
   548 
   549 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   550 		!= HandleError_None)
   551 	{
   552 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   553 	}
   554 
   555 	pConVar->SetFlags(params[2]);
   556 
   557 	return 1;
   558 }
   559 
   560 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
   561 {
   562 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   563 	HandleError err;
   564 	ConVar *pConVar;
   565 
   566 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   567 		!= HandleError_None)
   568 	{
   569 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   570 	}
   571 
   572 	cell_t *addr;
   573 	bool hasBound;
   574 	float bound;
   575 
   576 	switch (params[2])
   577 	{
   578 	case ConVarBound_Upper:
   579 		hasBound = pConVar->GetMax(bound);
   580 		break;
   581 	case ConVarBound_Lower:
   582 		hasBound = pConVar->GetMin(bound);
   583 		break;
   584 	default:
   585 		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
   586 	}
   587 	
   588 	pContext->LocalToPhysAddr(params[3], &addr);
   589 	*addr = sp_ftoc(bound);
   590 
   591 	return hasBound;
   592 }
   593 
   594 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
   595 {
   596 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   597 	HandleError err;
   598 	ConVar *pConVar;
   599 
   600 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   601 		!= HandleError_None)
   602 	{
   603 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   604 	}
   605 
   606 	switch (params[2])
   607 	{
   608 	case ConVarBound_Upper:
   609 		pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
   610 		break;
   611 	case ConVarBound_Lower:
   612 		pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
   613 		break;
   614 	default:
   615 		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
   616 	}
   617 
   618 	return 1;
   619 }
   620 
   621 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
   622 {
   623 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   624 	HandleError err;
   625 	ConVar *pConVar;
   626 
   627 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   628 		!= HandleError_None)
   629 	{
   630 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   631 	}
   632 
   633 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
   634 
   635 	return 1;
   636 }
   637 
   638 static bool s_QueryAlreadyWarned = false;
   639 
   640 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
   641 {
   642 	CPlayer *pPlayer;
   643 	char *name;
   644 	IPluginFunction *pCallback;
   645 
   646 	if (!g_ConVarManager.IsQueryingSupported())
   647 	{
   648 		if (!s_QueryAlreadyWarned)
   649 		{
   650 			s_QueryAlreadyWarned = true;
   651 			return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
   652 		}
   653 
   654 		return 0;
   655 	}
   656 
   657 	pPlayer = g_Players.GetPlayerByIndex(params[1]);
   658 
   659 	if (!pPlayer)
   660 	{
   661 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   662 	}
   663 
   664 	if (!pPlayer->IsConnected())
   665 	{
   666 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   667 	}
   668 
   669 	/* Trying a query on a bot results in callback not be fired, so don't bother */
   670 	if (pPlayer->IsFakeClient())
   671 	{
   672 		return 0;
   673 	}
   674 
   675 	pContext->LocalToString(params[2], &name);
   676 	pCallback = pContext->GetFunctionById(params[3]);
   677 
   678 	if (!pCallback)
   679 	{
   680 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   681 	}
   682 
   683 	return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
   684 }
   685 
   686 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
   687 {
   688 	char *name,*help;
   689 	IPluginFunction *pFunction;
   690 
   691 	pContext->LocalToString(params[1], &name);
   692 
   693 	if (strcasecmp(name, "sm") == 0)
   694 	{
   695 		return pContext->ThrowNativeError("Cannot register \"sm\" command");
   696 	}
   697 
   698 	pContext->LocalToString(params[3], &help);
   699 	pFunction = pContext->GetFunctionById(params[2]);
   700 
   701 	if (!pFunction)
   702 	{
   703 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   704 	}
   705 
   706 	if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
   707 	{
   708 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   709 	}
   710 
   711 	return 1;
   712 }
   713 
   714 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
   715 {
   716 	char *name,*help;
   717 	IPluginFunction *pFunction;
   718 
   719 	pContext->LocalToString(params[1], &name);
   720 
   721 	if (strcasecmp(name, "sm") == 0)
   722 	{
   723 		return pContext->ThrowNativeError("Cannot register \"sm\" command");
   724 	}
   725 
   726 	pContext->LocalToString(params[3], &help);
   727 	pFunction = pContext->GetFunctionById(params[2]);
   728 
   729 	if (!pFunction)
   730 	{
   731 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   732 	}
   733 
   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]))
   737 	{
   738 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   739 	}
   740 
   741 	return 1;
   742 }
   743 
   744 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
   745 {
   746 	char *name,*help;
   747 	const char *group;
   748 	IPluginFunction *pFunction;
   749 	FlagBits flags = params[3];
   750 	int cmdflags = params[6];
   751 
   752 	pContext->LocalToString(params[1], &name);
   753 
   754 	if (strcasecmp(name, "sm") == 0)
   755 	{
   756 		return pContext->ThrowNativeError("Cannot register \"sm\" command");
   757 	}
   758 
   759 	pContext->LocalToString(params[4], &help);
   760 	pContext->LocalToString(params[5], (char **)&group);
   761 	pFunction = pContext->GetFunctionById(params[2]);
   762 
   763 	if (group[0] == '\0')
   764 	{
   765 		IPlugin *pPlugin = scripts->FindPluginByContext(pContext->GetContext());
   766 		group = pPlugin->GetFilename();
   767 	}
   768 
   769 	if (!pFunction)
   770 	{
   771 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   772 	}
   773 
   774 	if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
   775 	{
   776 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   777 	}
   778 
   779 	return 1;
   780 }
   781 
   782 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
   783 {
   784 	const CCommand *pCmd = g_HL2.PeekCommandStack();
   785 
   786 	if (!pCmd)
   787 	{
   788 		return pContext->ThrowNativeError("No command callback available");
   789 	}
   790 
   791 	return pCmd->ArgC() - 1;
   792 }
   793 
   794 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
   795 {
   796 	const CCommand *pCmd = g_HL2.PeekCommandStack();
   797 
   798 	if (!pCmd)
   799 	{
   800 		return pContext->ThrowNativeError("No command callback available");
   801 	}
   802 
   803 	size_t length;
   804 
   805 	const char *arg = pCmd->Arg(params[1]);
   806 	
   807 	pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
   808 
   809 	return (cell_t)length;
   810 }
   811 
   812 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
   813 {
   814 	const CCommand *pCmd = g_HL2.PeekCommandStack();
   815 
   816 	if (!pCmd)
   817 	{
   818 		return pContext->ThrowNativeError("No command callback available");
   819 	}
   820 
   821 	const char *args = pCmd->ArgS();
   822 	size_t length;
   823 
   824 	if (!args)
   825 	{
   826 		args = "";
   827 	}
   828 
   829 	pContext->StringToLocalUTF8(params[1], params[2], args, &length);
   830 
   831 	return (cell_t)length;
   832 }
   833 
   834 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
   835 {
   836 	char buffer[1024];
   837 	char *fmt;
   838 	int arg = 2;
   839 
   840 	pCtx->LocalToString(params[1], &fmt);
   841 	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
   842 
   843 	buffer[res++] = '\n';
   844 	buffer[res] = '\0';
   845 
   846 	META_CONPRINT(buffer);
   847 
   848 	return 1;
   849 }
   850 
   851 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
   852 {
   853 	int index = params[1];
   854 	if ((index < 0) || (index > g_Players.GetMaxClients()))
   855 	{
   856 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   857 	}
   858 
   859 	CPlayer *pPlayer = NULL;
   860 	if (index != 0)
   861 	{
   862 		pPlayer = g_Players.GetPlayerByIndex(index);
   863 		if (!pPlayer->IsInGame())
   864 		{
   865 			return pCtx->ThrowNativeError("Client %d is not in game", index);
   866 		}
   867 		
   868 		/* Silent fail on bots, engine will crash */
   869 		if (pPlayer->IsFakeClient())
   870 		{
   871 			return 0;
   872 		}
   873 	}
   874 
   875 	char buffer[1024];
   876 	char *fmt;
   877 	int arg = 3;
   878 
   879 	pCtx->LocalToString(params[2], &fmt);
   880 	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
   881 
   882 	buffer[res++] = '\n';
   883 	buffer[res] = '\0';
   884 
   885 	if (index != 0)
   886 	{
   887 		pPlayer->PrintToConsole(buffer);
   888 	} else {
   889 		META_CONPRINT(buffer);
   890 	}
   891 
   892 	return 1;
   893 }
   894 
   895 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
   896 {
   897 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   898 
   899 	char buffer[1024];
   900 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
   901 
   902 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   903 	{
   904 		return 0;
   905 	}
   906 
   907 	/* One byte for null terminator, one for newline */
   908 	buffer[len++] = '\n';
   909 	buffer[len] = '\0';
   910 
   911 	engine->ServerCommand(buffer);
   912 
   913 	return 1;
   914 }
   915 
   916 char *g_ServerCommandBuffer = NULL;
   917 cell_t g_ServerCommandBufferLength;
   918 
   919 bool g_ShouldCatchSpew = false;
   920 
   921 #if SOURCE_ENGINE < SE_NUCLEARDAWN
   922 SpewOutputFunc_t g_OriginalSpewOutputFunc = NULL;
   923 
   924 SpewRetval_t SourcemodSpewOutputFunc(SpewType_t spewType, tchar const *pMsg)
   925 {
   926 	if (g_ServerCommandBuffer)
   927 	{
   928 		V_strcat(g_ServerCommandBuffer, pMsg, g_ServerCommandBufferLength);
   929 	}
   930 
   931 	if (g_OriginalSpewOutputFunc)
   932 	{
   933 		return g_OriginalSpewOutputFunc(spewType, pMsg);
   934 	} else {
   935 		return SPEW_CONTINUE;
   936 	}
   937 }
   938 #else
   939 class CSourcemodLoggingListener: public ILoggingListener
   940 {
   941 public:
   942 	void Log(const LoggingContext_t *pContext, const tchar *pMessage)
   943 	{
   944 		if (g_ServerCommandBuffer)
   945 		{
   946 			V_strcat(g_ServerCommandBuffer, pMessage, g_ServerCommandBufferLength);
   947 		}
   948 	}
   949 } g_SourcemodLoggingListener;
   950 #endif
   951 
   952 CON_COMMAND(sm_conhook_start, "")
   953 {
   954 	if (!g_ShouldCatchSpew)
   955 	{
   956 		Warning("You shouldn't run this command!\n");
   957 		return;
   958 	}
   959 
   960 #if SOURCE_ENGINE < SE_NUCLEARDAWN
   961 	g_OriginalSpewOutputFunc = GetSpewOutputFunc();
   962 	SpewOutputFunc(SourcemodSpewOutputFunc);
   963 #else
   964 #if SOURCE_ENGINE < SE_ALIENSWARM
   965 	LoggingSystem_PushLoggingState(false);
   966 #else
   967 	LoggingSystem_PushLoggingState(false, false);
   968 #endif
   969 	LoggingSystem_RegisterLoggingListener(&g_SourcemodLoggingListener);
   970 #endif
   971 }
   972 
   973 CON_COMMAND(sm_conhook_stop, "")
   974 {
   975 	if (!g_ShouldCatchSpew)
   976 	{
   977 		Warning("You shouldn't run this command!\n");
   978 		return;
   979 	}
   980 
   981 #if SOURCE_ENGINE < SE_NUCLEARDAWN
   982 	SpewOutputFunc(g_OriginalSpewOutputFunc);
   983 #else
   984 	LoggingSystem_PopLoggingState(false);
   985 #endif
   986 
   987 	g_ShouldCatchSpew = false;
   988 }
   989 
   990 static cell_t sm_ServerCommandEx(IPluginContext *pContext, const cell_t *params)
   991 {
   992 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
   993 
   994 	char buffer[1024];
   995 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 3);
   996 
   997 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
   998 	{
   999 		return 0;
  1000 	}
  1001 
  1002 	/* One byte for null terminator, one for newline */
  1003 	buffer[len++] = '\n';
  1004 	buffer[len] = '\0';
  1005 
  1006 	pContext->LocalToString(params[1], &g_ServerCommandBuffer);
  1007 	g_ServerCommandBufferLength = params[2];
  1008 	
  1009 	if (g_ServerCommandBufferLength > 0)
  1010 	{
  1011 		g_ServerCommandBuffer[0] = '\0';
  1012 	}
  1013 
  1014 	engine->ServerExecute();
  1015 
  1016 	g_ShouldCatchSpew = true;
  1017 	engine->ServerCommand("sm_conhook_start\n");
  1018 	engine->ServerCommand(buffer);
  1019 	engine->ServerCommand("sm_conhook_stop\n");
  1020 
  1021 	engine->ServerExecute();
  1022 
  1023 	if (g_ServerCommandBufferLength > 0)
  1024 	{
  1025 		g_ServerCommandBuffer[g_ServerCommandBufferLength-1] = '\0';
  1026 	}
  1027 
  1028 	g_ServerCommandBuffer = NULL;
  1029 	g_ServerCommandBufferLength = 0;
  1030 
  1031 	return 1;
  1032 }
  1033 
  1034 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
  1035 {
  1036 	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
  1037 
  1038 	char buffer[1024];
  1039 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
  1040 
  1041 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1042 	{
  1043 		return 0;
  1044 	}
  1045 
  1046 	/* One byte for null terminator, one for newline */
  1047 	buffer[len++] = '\n';
  1048 	buffer[len] = '\0';
  1049 
  1050 	InsertServerCommand(buffer);
  1051 
  1052 	return 1;
  1053 }
  1054 
  1055 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
  1056 {
  1057 	engine->ServerExecute();
  1058 
  1059 	return 1;
  1060 }
  1061 
  1062 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
  1063 {
  1064 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
  1065 
  1066 	if (!pPlayer)
  1067 	{
  1068 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
  1069 	}
  1070 
  1071 	if (!pPlayer->IsConnected())
  1072 	{
  1073 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
  1074 	}
  1075 
  1076 	g_SourceMod.SetGlobalTarget(params[1]);
  1077 
  1078 	char buffer[256];
  1079 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1080 
  1081 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1082 	{
  1083 		return 0;
  1084 	}
  1085 
  1086 	engine->ClientCommand(
  1087 #if SOURCE_ENGINE == SE_DOTA
  1088 		pPlayer->GetIndex(),
  1089 #else
  1090 		pPlayer->GetEdict(),
  1091 #endif
  1092 		"%s", buffer);
  1093 
  1094 	return 1;
  1095 }
  1096 
  1097 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
  1098 {
  1099 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
  1100 
  1101 	if (!pPlayer)
  1102 	{
  1103 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
  1104 	}
  1105 
  1106 	if (!pPlayer->IsConnected())
  1107 	{
  1108 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
  1109 	}
  1110 
  1111 	g_SourceMod.SetGlobalTarget(params[1]);
  1112 
  1113 	char buffer[256];
  1114 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1115 
  1116 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1117 	{
  1118 		return 0;
  1119 	}
  1120 
  1121 #if SOURCE_ENGINE == SE_DOTA
  1122 	engine->ClientCommand(pPlayer->GetIndex(), "%s", buffer);
  1123 #else
  1124 	serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
  1125 #endif
  1126 
  1127 	return 1;
  1128 }
  1129 
  1130 static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
  1131 {
  1132 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
  1133 
  1134 	if (!pPlayer)
  1135 	{
  1136 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
  1137 	}
  1138 
  1139 	if (!pPlayer->IsConnected())
  1140 	{
  1141 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
  1142 	}
  1143 
  1144 	g_SourceMod.SetGlobalTarget(params[1]);
  1145 
  1146 	char buffer[256];
  1147 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
  1148 
  1149 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1150 	{
  1151 		return 0;
  1152 	}
  1153 
  1154 	g_HL2.AddToFakeCliCmdQueue(params[1], GetPlayerUserId(pPlayer->GetEdict()), buffer);
  1155 
  1156 	return 1;
  1157 }
  1158 
  1159 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
  1160 {
  1161 	g_SourceMod.SetGlobalTarget(params[1]);
  1162 
  1163 	/* Build the format string */
  1164 	char buffer[1024];
  1165 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
  1166 
  1167 	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
  1168 	{
  1169 		return 0;
  1170 	}
  1171 
  1172 	/* If we're printing to the server, shortcut out */
  1173 	if (params[1] == 0)
  1174 	{
  1175 		/* Print */
  1176 		buffer[len++] = '\n';
  1177 		buffer[len] = '\0';
  1178 		META_CONPRINT(buffer);
  1179 		return 1;
  1180 	}
  1181 
  1182 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
  1183 
  1184 	if (!pPlayer)
  1185 	{
  1186 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
  1187 	}
  1188 
  1189 	if (!pPlayer->IsConnected())
  1190 	{
  1191 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
  1192 	}
  1193 
  1194 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
  1195 	if (replyto == SM_REPLY_CONSOLE)
  1196 	{
  1197 		buffer[len++] = '\n';
  1198 		buffer[len] = '\0';
  1199 		pPlayer->PrintToConsole(buffer);
  1200 	} else if (replyto == SM_REPLY_CHAT) {
  1201 		if (len >= 191)
  1202 		{
  1203 			len = 191;
  1204 		}
  1205 		buffer[len] = '\0';
  1206 		g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
  1207 	}
  1208 
  1209 	return 1;
  1210 }
  1211 
  1212 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
  1213 {
  1214 	return g_ChatTriggers.GetReplyTo();
  1215 }
  1216 
  1217 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
  1218 {
  1219 	return g_ChatTriggers.SetReplyTo(params[1]);
  1220 }
  1221 
  1222 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
  1223 {
  1224 	GlobCmdIter *iter = new GlobCmdIter;
  1225 	iter->started = false;
  1226 
  1227 	Handle_t hndl = handlesys->CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
  1228 	if (hndl == BAD_HANDLE)
  1229 	{
  1230 		delete iter;
  1231 	}
  1232 
  1233 	return hndl;
  1234 }
  1235 
  1236 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
  1237 {
  1238 	GlobCmdIter *iter;
  1239 	HandleError err;
  1240 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
  1241 
  1242 	if ((err = handlesys->ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
  1243 		!= HandleError_None)
  1244 	{
  1245 		return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
  1246 	}
  1247 
  1248 	const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
  1249 
  1250 	if (!iter->started)
  1251 	{
  1252 		iter->iter = cmds.begin();
  1253 		iter->started = true;
  1254 	}
  1255 
  1256 	while (iter->iter != cmds.end()
  1257 			&& !(*(iter->iter))->sourceMod)
  1258 	{
  1259 		iter->iter++;
  1260 	}
  1261 
  1262 	if (iter->iter == cmds.end())
  1263 	{
  1264 		return 0;
  1265 	}
  1266 
  1267 	ConCmdInfo *pInfo = (*(iter->iter));
  1268 
  1269 	pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
  1270 	pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
  1271 	
  1272 	cell_t *addr;
  1273 	pContext->LocalToPhysAddr(params[4], &addr);
  1274 	*addr = pInfo->eflags;
  1275 
  1276 	iter->iter++;
  1277 
  1278 	return 1;
  1279 }
  1280 
  1281 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
  1282 {
  1283 	if (params[1] == 0)
  1284 	{
  1285 		return 1;
  1286 	}
  1287 
  1288 	char *cmd;
  1289 	pContext->LocalToString(params[2], &cmd);
  1290 
  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])
  1295 	{
  1296 		found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
  1297 	}
  1298 	
  1299 	if (!found_command)
  1300 	{
  1301 		g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
  1302 	}
  1303 
  1304 	return g_ConCmds.CheckClientCommandAccess(params[1], cmd, bits) ? 1 : 0;
  1305 }
  1306 
  1307 static cell_t CheckAccess(IPluginContext *pContext, const cell_t *params)
  1308 {
  1309 	char *cmd;
  1310 	pContext->LocalToString(params[2], &cmd);
  1311 
  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])
  1316 	{
  1317 		found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
  1318 	}
  1319 	
  1320 	if (!found_command)
  1321 	{
  1322 		g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
  1323 	}
  1324 
  1325 	return g_ConCmds.CheckAdminCommandAccess(params[1], cmd, bits) ? 1 : 0;
  1326 }
  1327 
  1328 static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
  1329 {
  1330 	return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
  1331 }
  1332 
  1333 static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
  1334 {
  1335 	char *name;
  1336 	pContext->LocalToString(params[1], &name);
  1337 
  1338 	return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
  1339 }
  1340 
  1341 static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
  1342 {
  1343 	char *name;
  1344 	int flags;
  1345 	pContext->LocalToString(params[1], &name);
  1346 
  1347 	return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
  1348 }
  1349 
  1350 static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
  1351 {
  1352 	Handle_t hndl;
  1353 	ConCommandBaseIterator *pIter;
  1354 	cell_t *pIsCmd, *pFlags;
  1355 	const ConCommandBase *pConCmd;
  1356 	const char *desc;
  1357 
  1358 	pContext->LocalToPhysAddr(params[3], &pIsCmd);
  1359 	pContext->LocalToPhysAddr(params[4], &pFlags);
  1360 
  1361 	pIter = new ConCommandBaseIterator();
  1362 
  1363 	if (!pIter->IsValid())
  1364 	{
  1365 		delete pIter;
  1366 		return BAD_HANDLE;
  1367 	}
  1368 
  1369 	pConCmd = pIter->Get();
  1370 
  1371 	pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
  1372 	*pIsCmd = pConCmd->IsCommand() ? 1 : 0;
  1373 	*pFlags = pConCmd->GetFlags();
  1374 
  1375 	if (params[6])
  1376 	{
  1377 		desc = pConCmd->GetHelpText();
  1378 		pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
  1379 	}
  1380 
  1381 	if ((hndl = handlesys->CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
  1382 		== BAD_HANDLE)
  1383 	{
  1384 		delete pIter;
  1385 		return BAD_HANDLE;
  1386 	}
  1387 
  1388 	return hndl;
  1389 }
  1390 
  1391 static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
  1392 {
  1393 	HandleError err;
  1394 	ConCommandBaseIterator *pIter;
  1395 	cell_t *pIsCmd, *pFlags;
  1396 	const char *desc;
  1397 	const ConCommandBase *pConCmd;
  1398 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
  1399 
  1400 	if ((err = handlesys->ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
  1401 	{
  1402 		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
  1403 	}
  1404 
  1405 	if (!pIter->IsValid())
  1406 	{
  1407 		return 0;
  1408 	}
  1409 
  1410 	pIter->Next();
  1411 	if (!pIter->IsValid())
  1412 	{
  1413 		return 0;
  1414 	}
  1415 	pConCmd = pIter->Get();
  1416 
  1417 	pContext->LocalToPhysAddr(params[4], &pIsCmd);
  1418 	pContext->LocalToPhysAddr(params[5], &pFlags);
  1419 
  1420 	pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
  1421 	*pIsCmd = pConCmd->IsCommand() ? 1 : 0;
  1422 	*pFlags = pConCmd->GetFlags();
  1423 
  1424 	if (params[7])
  1425 	{
  1426 		desc = pConCmd->GetHelpText();
  1427 		pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
  1428 	}
  1429 
  1430 	return 1;
  1431 }
  1432 
  1433 static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
  1434 {
  1435 	Handle_t hndl = static_cast<Handle_t>(params[2]);
  1436 	HandleError err;
  1437 	ConVar *pConVar;
  1438 
  1439 	char *value;
  1440 	pContext->LocalToString(params[3], &value);
  1441 
  1442 	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
  1443 		!= HandleError_None)
  1444 	{
  1445 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
  1446 	}
  1447 
  1448 	char data[256];
  1449 	bf_write buffer(data, sizeof(data));
  1450 
  1451 #if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_DOTA
  1452 	CNETMsg_SetConVar msg;
  1453 	CMsg_CVars_CVar *cvar = msg.mutable_convars()->add_cvars();
  1454 
  1455 	cvar->set_name(pConVar->GetName());
  1456 	cvar->set_value(value);
  1457 
  1458 	int msgsize = msg.ByteSize();
  1459    
  1460 	buffer.WriteVarInt32(net_SetConVar);
  1461 	buffer.WriteVarInt32(msgsize);
  1462 	msg.SerializeWithCachedSizesToArray( (uint8 *)( buffer.GetBasePointer() + buffer.GetNumBytesWritten() ) );
  1463 	buffer.SeekToBit( ( buffer.GetNumBytesWritten() + msgsize ) * 8 );
  1464 #else
  1465 	buffer.WriteUBitLong(NET_SETCONVAR, NETMSG_BITS);
  1466 	buffer.WriteByte(1);
  1467 	buffer.WriteString(pConVar->GetName());
  1468 	buffer.WriteString(value);
  1469 #endif
  1470 
  1471 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
  1472 
  1473 	if (!pPlayer)
  1474 	{
  1475 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
  1476 	}
  1477 
  1478 	if (!pPlayer->IsConnected())
  1479 	{
  1480 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
  1481 	}
  1482 
  1483 	if (pPlayer->IsFakeClient())
  1484 	{
  1485 		return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
  1486 	}
  1487 
  1488 	INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
  1489 	if (netchan == NULL)
  1490 	{
  1491 		return 0;
  1492 	}
  1493 
  1494 	netchan->SendData(buffer);
  1495 
  1496 	return 1;
  1497 }
  1498 
  1499 static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
  1500 {
  1501 	return 0;
  1502 }
  1503 
  1504 static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
  1505 {
  1506 	return 0;
  1507 }
  1508 
  1509 static cell_t AddCommandListener(IPluginContext *pContext, const cell_t *params)
  1510 {
  1511 	char *name;
  1512 	IPluginFunction *pFunction;
  1513 
  1514 	pContext->LocalToString(params[2], &name);
  1515 
  1516 	if (strcasecmp(name, "sm") == 0)
  1517 	{
  1518 		g_Logger.LogError("Request to register \"sm\" command denied.");
  1519 		return 0;
  1520 	}
  1521 
  1522 	pFunction = pContext->GetFunctionById(params[1]);
  1523 
  1524 	if (!pFunction)
  1525 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1526 
  1527 	if (!g_ConsoleDetours.AddListener(pFunction, name[0] == '\0' ? NULL : name))
  1528 		return pContext->ThrowNativeError("This game does not support command listeners");
  1529 
  1530 	return 1;
  1531 }
  1532 
  1533 static cell_t RemoveCommandListener(IPluginContext *pContext, const cell_t *params)
  1534 {
  1535 	char *name;
  1536 	IPluginFunction *pFunction;
  1537 
  1538 	pContext->LocalToString(params[2], &name);
  1539 	pFunction = pContext->GetFunctionById(params[1]);
  1540 	if (!pFunction)
  1541 		return pContext->ThrowNativeError("Invalid function id (%X)", params[1]);
  1542 
  1543 	if (!g_ConsoleDetours.RemoveListener(pFunction, name[0] == '\0' ? NULL : name))
  1544 		return pContext->ThrowNativeError("No matching callback was registered");
  1545 	
  1546 	return 1;
  1547 }
  1548 
  1549 REGISTER_NATIVES(consoleNatives)
  1550 {
  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},
  1603 	{NULL,					NULL}
  1604 };