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