core/smn_console.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 29 02:44:37 2007 +0000 (2007-07-29)
changeset 1209 abcf0a55a177
parent 1119 9e3486386c04
child 1231 17badaf66ce4
permissions -rw-r--r--
fixed linux build for mysql
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "sm_globals.h"
    16 #include "HalfLife2.h"
    17 #include "sourcemm_api.h"
    18 #include "HandleSys.h"
    19 #include "ConVarManager.h"
    20 #include "ConCmdManager.h"
    21 #include "PluginSys.h"
    22 #include "sm_stringutil.h"
    23 #include "PlayerManager.h"
    24 #include "ChatTriggers.h"
    25 #include <inetchannel.h>
    26 #include <bitbuf.h>
    27 
    28 #define NET_SETCONVAR	5
    29 
    30 enum ConVarBounds
    31 {
    32 	ConVarBound_Upper = 0,
    33 	ConVarBound_Lower
    34 };
    35 
    36 HandleType_t hCmdIterType = 0;
    37 
    38 struct GlobCmdIter
    39 {
    40 	bool started;
    41 	List<ConCmdInfo *>::iterator iter;
    42 };
    43 
    44 class ConsoleHelpers : 
    45 	public SMGlobalClass,
    46 	public IHandleTypeDispatch
    47 {
    48 public:
    49 	virtual void OnSourceModAllInitialized()
    50 	{
    51 		HandleAccess access;
    52 		g_HandleSys.InitAccessDefaults(NULL, &access);
    53 		access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
    54 
    55 		hCmdIterType = g_HandleSys.CreateType(NULL, this, 0, NULL, &access, g_pCoreIdent, NULL);
    56 	}
    57 	virtual void OnHandleDestroy(HandleType_t type, void *object)
    58 	{
    59 		GlobCmdIter *iter = (GlobCmdIter *)object;
    60 		delete iter;
    61 	}
    62 } s_ConsoleHelpers;
    63 
    64 static void ReplicateConVar(ConVar *pConVar)
    65 {
    66 	int maxClients = g_Players.GetMaxClients();
    67 
    68 	char data[256];
    69 	bf_write buffer(data, sizeof(data));
    70 
    71 	buffer.WriteUBitLong(NET_SETCONVAR, 5);
    72 	buffer.WriteByte(1);
    73 	buffer.WriteString(pConVar->GetName());
    74 	buffer.WriteString(pConVar->GetString());
    75 
    76 	for (int i = 1; i <= maxClients; i++)
    77 	{
    78 		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
    79 
    80 		if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
    81 		{
    82 			INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i));
    83 			netchan->SendData(buffer);
    84 		}
    85 	}
    86 }
    87 
    88 static void NotifyConVar(ConVar *pConVar)
    89 {
    90 	IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
    91 	pEvent->SetString("cvarname", pConVar->GetName());
    92 	if (pConVar->IsBitSet(FCVAR_PROTECTED))
    93 	{
    94 		pEvent->SetString("cvarvalue", "***PROTECTED***");
    95 	} else {
    96 		pEvent->SetString("cvarvalue", pConVar->GetString());
    97 	}
    98 
    99 	gameevents->FireEvent(pEvent);
   100 }
   101 
   102 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
   103 {
   104 	char *name, *defaultVal, *helpText;
   105 
   106 	pContext->LocalToString(params[1], &name);
   107 
   108 	// While the engine seems to accept a blank convar name, it causes a crash upon server quit
   109 	if (name == NULL || strcmp(name, "") == 0)
   110 	{
   111 		return pContext->ThrowNativeError("Convar with blank name is not permitted");
   112 	}
   113 
   114 	pContext->LocalToString(params[2], &defaultVal);
   115 	pContext->LocalToString(params[3], &helpText);
   116 
   117 	bool hasMin = params[5] ? true : false;
   118 	bool hasMax = params[7] ? true : false;
   119 	float min = sp_ctof(params[6]);
   120 	float max = sp_ctof(params[8]);
   121 
   122 	Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
   123 
   124 	if (hndl == BAD_HANDLE)
   125 	{
   126 		return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
   127 	}
   128 
   129 	return hndl;
   130 }
   131 
   132 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
   133 {
   134 	char *name;
   135 
   136 	pContext->LocalToString(params[1], &name);
   137 
   138 	return g_ConVarManager.FindConVar(name);
   139 }
   140 
   141 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
   142 {
   143 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   144 	HandleError err;
   145 	ConVar *pConVar;
   146 
   147 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   148 		!= HandleError_None)
   149 	{
   150 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   151 	}
   152 
   153 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   154 
   155 	if (!pFunction)
   156 	{
   157 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   158 	}
   159 
   160 	g_ConVarManager.HookConVarChange(pConVar, pFunction);
   161 
   162 	return 1;
   163 }
   164 
   165 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
   166 {
   167 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   168 	HandleError err;
   169 	ConVar *pConVar;
   170 
   171 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   172 		!= HandleError_None)
   173 	{
   174 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   175 	}
   176 
   177 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   178 
   179 	if (!pFunction)
   180 	{
   181 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   182 	}
   183 
   184 	g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
   185 
   186 	return 1;
   187 }
   188 
   189 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
   190 {
   191 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   192 	HandleError err;
   193 	ConVar *pConVar;
   194 
   195 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   196 		!= HandleError_None)
   197 	{
   198 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   199 	}
   200 
   201 	return pConVar->GetBool();
   202 }
   203 
   204 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
   205 {
   206 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   207 	HandleError err;
   208 	ConVar *pConVar;
   209 
   210 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   211 		!= HandleError_None)
   212 	{
   213 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   214 	}
   215 
   216 	return pConVar->GetInt();
   217 }
   218 
   219 /* This handles both SetConVarBool() and SetConVarInt() */
   220 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
   221 {
   222 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   223 	HandleError err;
   224 	ConVar *pConVar;
   225 
   226 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   227 		!= HandleError_None)
   228 	{
   229 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   230 	}
   231 
   232 	pConVar->SetValue(params[2]);
   233 
   234 	/* Should we replicate it? */
   235 	if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED))
   236 	{
   237 		ReplicateConVar(pConVar);
   238 	}
   239 
   240 	/* Should we notify clients? */
   241 	if (params[4] && pConVar->IsBitSet(FCVAR_NOTIFY))
   242 	{
   243 		NotifyConVar(pConVar);
   244 	}
   245 
   246 	return 1;
   247 }
   248 
   249 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
   250 {
   251 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   252 	HandleError err;
   253 	ConVar *pConVar;
   254 
   255 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   256 		!= HandleError_None)
   257 	{
   258 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   259 	}
   260 	
   261 	float value = pConVar->GetFloat();
   262 
   263 	return sp_ftoc(value);
   264 }
   265 
   266 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
   267 {
   268 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   269 	HandleError err;
   270 	ConVar *pConVar;
   271 
   272 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   273 		!= HandleError_None)
   274 	{
   275 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   276 	}
   277 
   278 	float value = sp_ctof(params[2]);
   279 	pConVar->SetValue(value);
   280 
   281 	/* Should we replicate it? */
   282 	if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED))
   283 	{
   284 		ReplicateConVar(pConVar);
   285 	}
   286 
   287 	/* Should we notify clients? */
   288 	if (params[4] && pConVar->IsBitSet(FCVAR_NOTIFY))
   289 	{
   290 		NotifyConVar(pConVar);
   291 	}
   292 
   293 	return 1;
   294 }
   295 
   296 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
   297 {
   298 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   299 	HandleError err;
   300 	ConVar *pConVar;
   301 
   302 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   303 		!= HandleError_None)
   304 	{
   305 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   306 	}
   307 
   308 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
   309 
   310 	return 1;
   311 }
   312 
   313 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
   314 {
   315 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   316 	HandleError err;
   317 	ConVar *pConVar;
   318 
   319 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   320 		!= HandleError_None)
   321 	{
   322 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   323 	}
   324 
   325 	char *value;
   326 	pContext->LocalToString(params[2], &value);
   327 
   328 	pConVar->SetValue(value);
   329 
   330 	/* Should we replicate it? */
   331 	if (params[3] && pConVar->IsBitSet(FCVAR_REPLICATED))
   332 	{
   333 		ReplicateConVar(pConVar);
   334 	}
   335 
   336 	/* Should we notify clients? */
   337 	if (params[4] && pConVar->IsBitSet(FCVAR_NOTIFY))
   338 	{
   339 		NotifyConVar(pConVar);
   340 	}
   341 
   342 	return 1;
   343 }
   344 
   345 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
   346 {
   347 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   348 	HandleError err;
   349 	ConVar *pConVar;
   350 
   351 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   352 		!= HandleError_None)
   353 	{
   354 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   355 	}
   356 
   357 	return pConVar->GetFlags();
   358 }
   359 
   360 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
   361 {
   362 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   363 	HandleError err;
   364 	ConVar *pConVar;
   365 
   366 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   367 		!= HandleError_None)
   368 	{
   369 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   370 	}
   371 
   372 	pConVar->SetFlags(params[2]);
   373 
   374 	return 1;
   375 }
   376 
   377 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
   378 {
   379 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   380 	HandleError err;
   381 	ConVar *pConVar;
   382 
   383 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   384 		!= HandleError_None)
   385 	{
   386 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   387 	}
   388 
   389 	cell_t *addr;
   390 	bool hasBound;
   391 	float bound;
   392 
   393 	switch (params[2])
   394 	{
   395 	case ConVarBound_Upper:
   396 		hasBound = pConVar->GetMax(bound);
   397 		break;
   398 	case ConVarBound_Lower:
   399 		hasBound = pConVar->GetMin(bound);
   400 		break;
   401 	default:
   402 		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
   403 	}
   404 	
   405 	pContext->LocalToPhysAddr(params[3], &addr);
   406 	*addr = sp_ftoc(bound);
   407 
   408 	return hasBound;
   409 }
   410 
   411 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
   412 {
   413 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   414 	HandleError err;
   415 	ConVar *pConVar;
   416 
   417 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   418 		!= HandleError_None)
   419 	{
   420 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   421 	}
   422 
   423 	switch (params[2])
   424 	{
   425 	case ConVarBound_Upper:
   426 		pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
   427 		break;
   428 	case ConVarBound_Lower:
   429 		pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
   430 		break;
   431 	default:
   432 		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
   433 	}
   434 
   435 	return 1;
   436 }
   437 
   438 static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
   439 {
   440 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   441 	HandleError err;
   442 	ConVar *pConVar;
   443 
   444 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   445 		!= HandleError_None)
   446 	{
   447 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   448 	}
   449 
   450 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
   451 
   452 	return 1;
   453 }
   454 
   455 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
   456 {
   457 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   458 	HandleError err;
   459 	ConVar *pConVar;
   460 
   461 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   462 		!= HandleError_None)
   463 	{
   464 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   465 	}
   466 
   467 	pConVar->Revert();
   468 
   469 	return 1;
   470 }
   471 
   472 static bool s_QueryAlreadyWarned = false;
   473 
   474 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
   475 {
   476 	CPlayer *pPlayer;
   477 	char *name;
   478 	IPluginFunction *pCallback;
   479 
   480 	if (g_IsOriginalEngine)
   481 	{
   482 		if (!s_QueryAlreadyWarned)
   483 		{
   484 			s_QueryAlreadyWarned = true;
   485 			return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
   486 		}
   487 
   488 		return 0;
   489 	}
   490 
   491 	pPlayer = g_Players.GetPlayerByIndex(params[1]);
   492 
   493 	if (!pPlayer)
   494 	{
   495 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   496 	}
   497 
   498 	if (!pPlayer->IsConnected())
   499 	{
   500 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   501 	}
   502 
   503 	/* Trying a query on a bot results in callback not be fired, so don't bother */
   504 	if (pPlayer->IsFakeClient())
   505 	{
   506 		return 0;
   507 	}
   508 
   509 	pContext->LocalToString(params[2], &name);
   510 	pCallback = pContext->GetFunctionById(params[3]);
   511 
   512 	if (!pCallback)
   513 	{
   514 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   515 	}
   516 
   517 	return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
   518 }
   519 
   520 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
   521 {
   522 	char *name,*help;
   523 	IPluginFunction *pFunction;
   524 
   525 	pContext->LocalToString(params[1], &name);
   526 	pContext->LocalToString(params[3], &help);
   527 	pFunction = pContext->GetFunctionById(params[2]);
   528 
   529 	if (!pFunction)
   530 	{
   531 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   532 	}
   533 
   534 	if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
   535 	{
   536 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   537 	}
   538 
   539 	return 1;
   540 }
   541 
   542 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
   543 {
   544 	char *name,*help;
   545 	IPluginFunction *pFunction;
   546 
   547 	pContext->LocalToString(params[1], &name);
   548 	pContext->LocalToString(params[3], &help);
   549 	pFunction = pContext->GetFunctionById(params[2]);
   550 
   551 	if (!pFunction)
   552 	{
   553 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   554 	}
   555 
   556 	if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
   557 	{
   558 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   559 	}
   560 
   561 	return 1;
   562 }
   563 
   564 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
   565 {
   566 	char *name,*help;
   567 	const char *group;
   568 	IPluginFunction *pFunction;
   569 	FlagBits flags = params[3];
   570 	int cmdflags = params[6];
   571 
   572 	pContext->LocalToString(params[1], &name);
   573 	pContext->LocalToString(params[4], &help);
   574 	pContext->LocalToString(params[5], (char **)&group);
   575 	pFunction = pContext->GetFunctionById(params[2]);
   576 
   577 	if (group[0] == '\0')
   578 	{
   579 		CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   580 		group = pPlugin->GetFilename();
   581 	}
   582 
   583 	if (!pFunction)
   584 	{
   585 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   586 	}
   587 
   588 	if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
   589 	{
   590 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   591 	}
   592 
   593 	return 1;
   594 }
   595 
   596 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
   597 {
   598 	return engine->Cmd_Argc() - 1;
   599 }
   600 
   601 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
   602 {
   603 	const char *arg = engine->Cmd_Argv(params[1]);
   604 	
   605 	pContext->StringToLocalUTF8(params[2], params[3], arg, NULL);
   606 
   607 	return 1;
   608 }
   609 
   610 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
   611 {
   612 	const char *args = engine->Cmd_Args();
   613 
   614 	if (!args)
   615 	{
   616 		args = "";
   617 	}
   618 
   619 	pContext->StringToLocalUTF8(params[1], params[2], args, NULL);
   620 
   621 	return 1;
   622 }
   623 
   624 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
   625 {
   626 	char buffer[1024];
   627 	char *fmt;
   628 	int arg = 2;
   629 
   630 	pCtx->LocalToString(params[1], &fmt);
   631 	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
   632 
   633 	buffer[res++] = '\n';
   634 	buffer[res] = '\0';
   635 
   636 	META_CONPRINT(buffer);
   637 
   638 	return 1;
   639 }
   640 
   641 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
   642 {
   643 	int index = params[1];
   644 	if ((index < 0) || (index > g_Players.GetMaxClients()))
   645 	{
   646 		return pCtx->ThrowNativeError("Client index %d is invalid", index);
   647 	}
   648 
   649 	CPlayer *pPlayer = NULL;
   650 	if (index != 0)
   651 	{
   652 		pPlayer = g_Players.GetPlayerByIndex(index);
   653 		if (!pPlayer->IsInGame())
   654 		{
   655 			return pCtx->ThrowNativeError("Client %d is not in game", index);
   656 		}
   657 		
   658 		/* Silent fail on bots, engine will crash */
   659 		if (pPlayer->IsFakeClient())
   660 		{
   661 			return 0;
   662 		}
   663 	}
   664 
   665 	char buffer[1024];
   666 	char *fmt;
   667 	int arg = 3;
   668 
   669 	pCtx->LocalToString(params[2], &fmt);
   670 	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
   671 
   672 	buffer[res++] = '\n';
   673 	buffer[res] = '\0';
   674 
   675 	if (index != 0)
   676 	{
   677 		engine->ClientPrintf(pPlayer->GetEdict(), buffer);
   678 	} else {
   679 		META_CONPRINT(buffer);
   680 	}
   681 
   682 	return 1;
   683 }
   684 
   685 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
   686 {
   687 	char buffer[1024];
   688 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
   689 
   690 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   691 
   692 	/* One byte for null terminator, one for newline */
   693 	buffer[len++] = '\n';
   694 	buffer[len] = '\0';
   695 
   696 	engine->ServerCommand(buffer);
   697 
   698 	return 1;
   699 }
   700 
   701 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
   702 {
   703 	char buffer[1024];
   704 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
   705 
   706 	g_SourceMod.SetGlobalTarget(LANG_SERVER);
   707 
   708 	/* One byte for null terminator, one for newline */
   709 	buffer[len++] = '\n';
   710 	buffer[len] = '\0';
   711 
   712 	engine->InsertServerCommand(buffer);
   713 
   714 	return 1;
   715 }
   716 
   717 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
   718 {
   719 	engine->ServerExecute();
   720 
   721 	return 1;
   722 }
   723 
   724 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
   725 {
   726 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   727 
   728 	if (!pPlayer)
   729 	{
   730 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   731 	}
   732 
   733 	if (!pPlayer->IsConnected())
   734 	{
   735 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   736 	}
   737 
   738 	g_SourceMod.SetGlobalTarget(params[1]);
   739 
   740 	char buffer[256];
   741 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   742 
   743 	engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
   744 
   745 	return 1;
   746 }
   747 
   748 
   749 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
   750 {
   751 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   752 
   753 	if (!pPlayer)
   754 	{
   755 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   756 	}
   757 
   758 	if (!pPlayer->IsConnected())
   759 	{
   760 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   761 	}
   762 
   763 	char buffer[256];
   764 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   765 
   766 	unsigned int old = g_ChatTriggers.SetReplyTo(SM_REPLY_CONSOLE);
   767 	serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
   768 	g_ChatTriggers.SetReplyTo(old);
   769 
   770 	return 1;
   771 }
   772 
   773 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
   774 {
   775 	g_SourceMod.SetGlobalTarget(params[1]);
   776 
   777 	/* Build the format string */
   778 	char buffer[1024];
   779 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
   780 
   781 	/* If we're printing to the server, shortcut out */
   782 	if (params[1] == 0)
   783 	{
   784 		/* Print */
   785 		buffer[len++] = '\n';
   786 		buffer[len] = '\0';
   787 		META_CONPRINT(buffer);
   788 		return 1;
   789 	}
   790 
   791 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   792 
   793 	if (!pPlayer)
   794 	{
   795 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   796 	}
   797 
   798 	if (!pPlayer->IsConnected())
   799 	{
   800 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   801 	}
   802 
   803 	g_SourceMod.SetGlobalTarget(params[1]);
   804 
   805 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
   806 	if (replyto == SM_REPLY_CONSOLE)
   807 	{
   808 		buffer[len++] = '\n';
   809 		buffer[len] = '\0';
   810 		engine->ClientPrintf(pPlayer->GetEdict(), buffer);
   811 	} else if (replyto == SM_REPLY_CHAT) {
   812 		if (len >= 191)
   813 		{
   814 			len = 191;
   815 		}
   816 		buffer[len] = '\0';
   817 		g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
   818 	}
   819 
   820 	return 1;
   821 }
   822 
   823 static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
   824 {
   825 	return g_ChatTriggers.GetReplyTo();
   826 }
   827 
   828 static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
   829 {
   830 	return g_ChatTriggers.SetReplyTo(params[1]);
   831 }
   832 
   833 static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
   834 {
   835 	GlobCmdIter *iter = new GlobCmdIter;
   836 	iter->started = false;
   837 
   838 	Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
   839 	if (hndl == BAD_HANDLE)
   840 	{
   841 		delete iter;
   842 	}
   843 
   844 	return hndl;
   845 }
   846 
   847 static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
   848 {
   849 	GlobCmdIter *iter;
   850 	HandleError err;
   851 	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
   852 
   853 	if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
   854 		!= HandleError_None)
   855 	{
   856 		return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
   857 	}
   858 
   859 	const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
   860 
   861 	if (!iter->started)
   862 	{
   863 		iter->iter = cmds.begin();
   864 		iter->started = true;
   865 	}
   866 
   867 	while (iter->iter != cmds.end()
   868 			&& !(*(iter->iter))->sourceMod)
   869 	{
   870 		iter->iter++;
   871 	}
   872 
   873 	if (iter->iter == cmds.end())
   874 	{
   875 		return 0;
   876 	}
   877 
   878 	ConCmdInfo *pInfo = (*(iter->iter));
   879 
   880 	pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
   881 	pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
   882 	
   883 	cell_t *addr;
   884 	pContext->LocalToPhysAddr(params[4], &addr);
   885 	*addr = pInfo->admin.eflags;
   886 
   887 	iter->iter++;
   888 
   889 	return 1;
   890 }
   891 
   892 static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
   893 {
   894 	if (params[1] == 0)
   895 	{
   896 		return 1;
   897 	}
   898 
   899 	char *cmd;
   900 	pContext->LocalToString(params[2], &cmd);
   901 
   902 	return g_ConCmds.CheckCommandAccess(params[1], cmd, params[3]) ? 1 : 0;
   903 }
   904 
   905 REGISTER_NATIVES(consoleNatives)
   906 {
   907 	{"CreateConVar",		sm_CreateConVar},
   908 	{"FindConVar",			sm_FindConVar},
   909 	{"HookConVarChange",	sm_HookConVarChange},
   910 	{"UnhookConVarChange",	sm_UnhookConVarChange},
   911 	{"GetConVarBool",		sm_GetConVarBool},
   912 	{"SetConVarBool",		sm_SetConVarNum},
   913 	{"GetConVarInt",		sm_GetConVarInt},
   914 	{"SetConVarInt",		sm_SetConVarNum},
   915 	{"GetConVarFloat",		sm_GetConVarFloat},
   916 	{"SetConVarFloat",		sm_SetConVarFloat},
   917 	{"GetConVarString",		sm_GetConVarString},
   918 	{"SetConVarString",		sm_SetConVarString},
   919 	{"GetConVarFlags",		sm_GetConVarFlags},
   920 	{"SetConVarFlags",		sm_SetConVarFlags},
   921 	{"GetConVarName",		sm_GetConVarName},
   922 	{"GetConVarBounds",		sm_GetConVarBounds},
   923 	{"SetConVarBounds",		sm_SetConVarBounds},
   924 	{"ResetConVar",			sm_ResetConVar},
   925 	{"QueryClientConVar",	sm_QueryClientConVar},
   926 	{"RegServerCmd",		sm_RegServerCmd},
   927 	{"RegConsoleCmd",		sm_RegConsoleCmd},
   928 	{"GetCmdArgString",		sm_GetCmdArgString},
   929 	{"GetCmdArgs",			sm_GetCmdArgs},
   930 	{"GetCmdArg",			sm_GetCmdArg},
   931 	{"PrintToServer",		sm_PrintToServer},
   932 	{"PrintToConsole",		sm_PrintToConsole},
   933 	{"RegAdminCmd",			sm_RegAdminCmd},
   934 	{"ServerCommand",		sm_ServerCommand},
   935 	{"InsertServerCommand",	sm_InsertServerCommand},
   936 	{"ServerExecute",		sm_ServerExecute},
   937 	{"ClientCommand",		sm_ClientCommand},
   938 	{"FakeClientCommand",	FakeClientCommand},
   939 	{"ReplyToCommand",		ReplyToCommand},
   940 	{"GetCmdReplySource",	GetCmdReplyTarget},
   941 	{"SetCmdReplySource",	SetCmdReplyTarget},
   942 	{"GetCommandIterator",	GetCommandIterator},
   943 	{"ReadCommandIterator",	ReadCommandIterator},
   944 	{"CheckCommandAccess",	CheckCommandAccess},
   945 	{NULL,					NULL}
   946 };