core/smn_console.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jun 07 04:08:34 2007 +0000 (2007-06-07)
changeset 904 69e4125ef38d
parent 895 a1068846fee8
child 910 153c052460af
permissions -rw-r--r--
fixed the Windows build! (it's not too often we say that, eh)
     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 
    26 enum ConVarBounds
    27 {
    28 	ConVarBound_Upper = 0,
    29 	ConVarBound_Lower
    30 };
    31 
    32 static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
    33 {
    34 	char *name, *defaultVal, *helpText;
    35 
    36 	pContext->LocalToString(params[1], &name);
    37 
    38 	// While the engine seems to accept a blank convar name, it causes a crash upon server quit
    39 	if (name == NULL || strcmp(name, "") == 0)
    40 	{
    41 		return pContext->ThrowNativeError("Convar with blank name is not permitted");
    42 	}
    43 
    44 	pContext->LocalToString(params[2], &defaultVal);
    45 	pContext->LocalToString(params[3], &helpText);
    46 
    47 	bool hasMin = params[5] ? true : false;
    48 	bool hasMax = params[7] ? true : false;
    49 	float min = sp_ctof(params[6]);
    50 	float max = sp_ctof(params[8]);
    51 
    52 	Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
    53 
    54 	if (hndl == BAD_HANDLE)
    55 	{
    56 		return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
    57 	}
    58 
    59 	return hndl;
    60 }
    61 
    62 static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
    63 {
    64 	char *name;
    65 
    66 	pContext->LocalToString(params[1], &name);
    67 
    68 	return g_ConVarManager.FindConVar(name);
    69 }
    70 
    71 static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
    72 {
    73 	Handle_t hndl = static_cast<Handle_t>(params[1]);
    74 	HandleError err;
    75 	ConVar *pConVar;
    76 
    77 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    78 		!= HandleError_None)
    79 	{
    80 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    81 	}
    82 
    83 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
    84 
    85 	if (!pFunction)
    86 	{
    87 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
    88 	}
    89 
    90 	g_ConVarManager.HookConVarChange(pConVar, pFunction);
    91 
    92 	return 1;
    93 }
    94 
    95 static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
    96 {
    97 	Handle_t hndl = static_cast<Handle_t>(params[1]);
    98 	HandleError err;
    99 	ConVar *pConVar;
   100 
   101 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   102 		!= HandleError_None)
   103 	{
   104 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   105 	}
   106 
   107 	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   108 
   109 	if (!pFunction)
   110 	{
   111 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   112 	}
   113 
   114 	g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
   115 
   116 	return 1;
   117 }
   118 
   119 static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
   120 {
   121 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   122 	HandleError err;
   123 	ConVar *pConVar;
   124 
   125 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   126 		!= HandleError_None)
   127 	{
   128 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   129 	}
   130 
   131 	return pConVar->GetBool();
   132 }
   133 
   134 static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
   135 {
   136 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   137 	HandleError err;
   138 	ConVar *pConVar;
   139 
   140 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   141 		!= HandleError_None)
   142 	{
   143 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   144 	}
   145 
   146 	return pConVar->GetInt();
   147 }
   148 
   149 /* This handles both SetConVarBool() and SetConVarInt() */
   150 static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
   151 {
   152 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   153 	HandleError err;
   154 	ConVar *pConVar;
   155 
   156 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   157 		!= HandleError_None)
   158 	{
   159 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   160 	}
   161 
   162 	pConVar->SetValue(params[2]);
   163 
   164 	return 1;
   165 }
   166 
   167 static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
   168 {
   169 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   170 	HandleError err;
   171 	ConVar *pConVar;
   172 
   173 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   174 		!= HandleError_None)
   175 	{
   176 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   177 	}
   178 	
   179 	float value = pConVar->GetFloat();
   180 
   181 	return sp_ftoc(value);
   182 }
   183 
   184 static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
   185 {
   186 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   187 	HandleError err;
   188 	ConVar *pConVar;
   189 
   190 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   191 		!= HandleError_None)
   192 	{
   193 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   194 	}
   195 
   196 	float value = sp_ctof(params[2]);
   197 	pConVar->SetValue(value);
   198 
   199 	return 1;
   200 }
   201 
   202 static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
   203 {
   204 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   205 	HandleError err;
   206 	ConVar *pConVar;
   207 
   208 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   209 		!= HandleError_None)
   210 	{
   211 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   212 	}
   213 
   214 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
   215 
   216 	return 1;
   217 }
   218 
   219 static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
   220 {
   221 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   222 	HandleError err;
   223 	ConVar *pConVar;
   224 
   225 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   226 		!= HandleError_None)
   227 	{
   228 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   229 	}
   230 
   231 	char *value;
   232 	pContext->LocalToString(params[2], &value);
   233 
   234 	pConVar->SetValue(value);
   235 
   236 	return 1;
   237 }
   238 
   239 static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
   240 {
   241 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   242 	HandleError err;
   243 	ConVar *pConVar;
   244 
   245 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   246 		!= HandleError_None)
   247 	{
   248 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   249 	}
   250 
   251 	return pConVar->GetFlags();
   252 }
   253 
   254 static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
   255 {
   256 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   257 	HandleError err;
   258 	ConVar *pConVar;
   259 
   260 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   261 		!= HandleError_None)
   262 	{
   263 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   264 	}
   265 
   266 	pConVar->SetFlags(params[2]);
   267 
   268 	return 1;
   269 }
   270 
   271 static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
   272 {
   273 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   274 	HandleError err;
   275 	ConVar *pConVar;
   276 
   277 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   278 		!= HandleError_None)
   279 	{
   280 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   281 	}
   282 
   283 	cell_t *addr;
   284 	bool hasBound;
   285 	float bound;
   286 
   287 	switch (params[2])
   288 	{
   289 	case ConVarBound_Upper:
   290 		hasBound = pConVar->GetMax(bound);
   291 		break;
   292 	case ConVarBound_Lower:
   293 		hasBound = pConVar->GetMin(bound);
   294 		break;
   295 	default:
   296 		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
   297 	}
   298 	
   299 	pContext->LocalToPhysAddr(params[3], &addr);
   300 	*addr = sp_ftoc(bound);
   301 
   302 	return hasBound;
   303 }
   304 
   305 static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
   306 {
   307 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   308 	HandleError err;
   309 	ConVar *pConVar;
   310 
   311 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   312 		!= HandleError_None)
   313 	{
   314 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   315 	}
   316 
   317 	switch (params[2])
   318 	{
   319 	case ConVarBound_Upper:
   320 		pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
   321 		break;
   322 	case ConVarBound_Lower:
   323 		pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
   324 		break;
   325 	default:
   326 		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
   327 	}
   328 
   329 	return 1;
   330 }
   331 
   332 static cell_t sm_GetConVarName(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_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   339 		!= HandleError_None)
   340 	{
   341 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   342 	}
   343 
   344 	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
   345 
   346 	return 1;
   347 }
   348 
   349 static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
   350 {
   351 	Handle_t hndl = static_cast<Handle_t>(params[1]);
   352 	HandleError err;
   353 	ConVar *pConVar;
   354 
   355 	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   356 		!= HandleError_None)
   357 	{
   358 		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   359 	}
   360 
   361 	pConVar->Revert();
   362 
   363 	return 1;
   364 }
   365 
   366 static bool s_QueryAlreadyWarned = false;
   367 
   368 static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
   369 {
   370 	CPlayer *pPlayer;
   371 	char *name;
   372 	IPluginFunction *pCallback;
   373 
   374 	if (g_IsOriginalEngine)
   375 	{
   376 		if (!s_QueryAlreadyWarned)
   377 		{
   378 			s_QueryAlreadyWarned = true;
   379 			return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
   380 		}
   381 
   382 		return 0;
   383 	}
   384 
   385 	pPlayer = g_Players.GetPlayerByIndex(params[1]);
   386 
   387 	if (!pPlayer)
   388 	{
   389 		return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
   390 	}
   391 
   392 	if (!pPlayer->IsConnected())
   393 	{
   394 		return pContext->ThrowNativeError("Player %d is not connected", params[1]);
   395 	}
   396 
   397 	/* Trying a query on a bot results in callback not be fired, so don't bother */
   398 	if (pPlayer->IsFakeClient())
   399 	{
   400 		return 0;
   401 	}
   402 
   403 	pContext->LocalToString(params[2], &name);
   404 	pCallback = pContext->GetFunctionById(params[3]);
   405 
   406 	if (!pCallback)
   407 	{
   408 		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
   409 	}
   410 
   411 	return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
   412 }
   413 
   414 static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
   415 {
   416 	char *name,*help;
   417 	IPluginFunction *pFunction;
   418 
   419 	pContext->LocalToString(params[1], &name);
   420 	pContext->LocalToString(params[3], &help);
   421 	pFunction = pContext->GetFunctionById(params[2]);
   422 
   423 	if (!pFunction)
   424 	{
   425 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   426 	}
   427 
   428 	if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
   429 	{
   430 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   431 	}
   432 
   433 	return 1;
   434 }
   435 
   436 static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
   437 {
   438 	char *name,*help;
   439 	IPluginFunction *pFunction;
   440 
   441 	pContext->LocalToString(params[1], &name);
   442 	pContext->LocalToString(params[3], &help);
   443 	pFunction = pContext->GetFunctionById(params[2]);
   444 
   445 	if (!pFunction)
   446 	{
   447 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   448 	}
   449 
   450 	if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
   451 	{
   452 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   453 	}
   454 
   455 	return 1;
   456 }
   457 
   458 static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
   459 {
   460 	char *name,*help;
   461 	const char *group;
   462 	IPluginFunction *pFunction;
   463 	FlagBits flags = params[3];
   464 	int cmdflags = params[6];
   465 
   466 	pContext->LocalToString(params[1], &name);
   467 	pContext->LocalToString(params[4], &help);
   468 	pContext->LocalToString(params[5], (char **)&group);
   469 	pFunction = pContext->GetFunctionById(params[2]);
   470 
   471 	if (group[0] == '\0')
   472 	{
   473 		CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
   474 		group = pPlugin->GetFilename();
   475 	}
   476 
   477 	if (!pFunction)
   478 	{
   479 		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
   480 	}
   481 
   482 	if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
   483 	{
   484 		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
   485 	}
   486 
   487 	return 1;
   488 }
   489 
   490 static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
   491 {
   492 	return engine->Cmd_Argc() - 1;
   493 }
   494 
   495 static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
   496 {
   497 	const char *arg = engine->Cmd_Argv(params[1]);
   498 	
   499 	pContext->StringToLocalUTF8(params[2], params[3], arg, NULL);
   500 
   501 	return 1;
   502 }
   503 
   504 static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
   505 {
   506 	const char *args = engine->Cmd_Args();
   507 
   508 	if (!args)
   509 	{
   510 		args = "";
   511 	}
   512 
   513 	pContext->StringToLocalUTF8(params[1], params[2], args, NULL);
   514 
   515 	return 1;
   516 }
   517 
   518 static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
   519 {
   520 	char buffer[1024];
   521 	char *fmt;
   522 	int arg = 2;
   523 
   524 	pCtx->LocalToString(params[1], &fmt);
   525 	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
   526 
   527 	buffer[res++] = '\n';
   528 	buffer[res] = '\0';
   529 
   530 	META_CONPRINT(buffer);
   531 
   532 	return 1;
   533 }
   534 
   535 static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
   536 {
   537 	int index = params[1];
   538 	if ((index < 0) || (index > g_Players.GetMaxClients()))
   539 	{
   540 		return pCtx->ThrowNativeError("Invalid client index %d", index);
   541 	}
   542 
   543 	CPlayer *pPlayer = NULL;
   544 	if (index != 0)
   545 	{
   546 		pPlayer = g_Players.GetPlayerByIndex(index);
   547 		if (!pPlayer->IsInGame())
   548 		{
   549 			return pCtx->ThrowNativeError("Client %d is not in game", index);
   550 		}
   551 		
   552 		/* Silent fail on bots, engine will crash */
   553 		if (pPlayer->IsFakeClient())
   554 		{
   555 			return 0;
   556 		}
   557 	}
   558 
   559 	char buffer[1024];
   560 	char *fmt;
   561 	int arg = 3;
   562 
   563 	pCtx->LocalToString(params[2], &fmt);
   564 	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
   565 
   566 	buffer[res++] = '\n';
   567 	buffer[res] = '\0';
   568 
   569 	if (index != 0)
   570 	{
   571 		engine->ClientPrintf(pPlayer->GetEdict(), buffer);
   572 	} else {
   573 		META_CONPRINT(buffer);
   574 	}
   575 
   576 	return 1;
   577 }
   578 
   579 static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
   580 {
   581 	char buffer[1024];
   582 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
   583 
   584 	/* One byte for null terminator, one for newline */
   585 	buffer[len++] = '\n';
   586 	buffer[len] = '\0';
   587 
   588 	engine->ServerCommand(buffer);
   589 
   590 	return 1;
   591 }
   592 
   593 static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
   594 {
   595 	char buffer[1024];
   596 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
   597 
   598 	/* One byte for null terminator, one for newline */
   599 	buffer[len++] = '\n';
   600 	buffer[len] = '\0';
   601 
   602 	engine->InsertServerCommand(buffer);
   603 
   604 	return 1;
   605 }
   606 
   607 static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
   608 {
   609 	engine->ServerExecute();
   610 
   611 	return 1;
   612 }
   613 
   614 static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
   615 {
   616 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   617 
   618 	if (!pPlayer)
   619 	{
   620 		return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
   621 	}
   622 
   623 	if (!pPlayer->IsConnected())
   624 	{
   625 		return pContext->ThrowNativeError("Player %d is not connected", params[1]);
   626 	}
   627 
   628 	char buffer[256];
   629 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   630 
   631 	engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
   632 
   633 	return 1;
   634 }
   635 
   636 
   637 static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
   638 {
   639 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   640 
   641 	if (!pPlayer)
   642 	{
   643 		return pContext->ThrowNativeError("Player %d is not a valid player", params[1]);
   644 	}
   645 
   646 	if (!pPlayer->IsConnected())
   647 	{
   648 		return pContext->ThrowNativeError("Player %d is not connected", params[1]);
   649 	}
   650 
   651 	char buffer[256];
   652 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   653 
   654 	unsigned int old = g_ChatTriggers.SetReplyTo(SM_REPLY_CONSOLE);
   655 	serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
   656 	g_ChatTriggers.SetReplyTo(old);
   657 
   658 	return 1;
   659 }
   660 
   661 static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
   662 {
   663 	/* Build the format string */
   664 	char buffer[1024];
   665 	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
   666 
   667 	/* If we're printing to the server, shortcut out */
   668 	if (params[1] == 0)
   669 	{
   670 		/* Print */
   671 		buffer[len++] = '\n';
   672 		buffer[len] = '\0';
   673 		META_CONPRINT(buffer);
   674 		return 1;
   675 	}
   676 
   677 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
   678 
   679 	if (!pPlayer)
   680 	{
   681 		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
   682 	}
   683 
   684 	if (!pPlayer->IsConnected())
   685 	{
   686 		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
   687 	}
   688 
   689 	unsigned int replyto = g_ChatTriggers.GetReplyTo();
   690 	if (replyto == SM_REPLY_CONSOLE)
   691 	{
   692 		buffer[len++] = '\n';
   693 		buffer[len] = '\0';
   694 		engine->ClientPrintf(pPlayer->GetEdict(), buffer);
   695 	} else if (replyto == SM_REPLY_CHAT) {
   696 		if (len >= 191)
   697 		{
   698 			len = 191;
   699 		}
   700 		buffer[len] = '\0';
   701 		g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
   702 	}
   703 
   704 	return 1;
   705 }
   706 
   707 REGISTER_NATIVES(consoleNatives)
   708 {
   709 	{"CreateConVar",		sm_CreateConVar},
   710 	{"FindConVar",			sm_FindConVar},
   711 	{"HookConVarChange",	sm_HookConVarChange},
   712 	{"UnhookConVarChange",	sm_UnhookConVarChange},
   713 	{"GetConVarBool",		sm_GetConVarBool},
   714 	{"SetConVarBool",		sm_SetConVarNum},
   715 	{"GetConVarInt",		sm_GetConVarInt},
   716 	{"SetConVarInt",		sm_SetConVarNum},
   717 	{"GetConVarFloat",		sm_GetConVarFloat},
   718 	{"SetConVarFloat",		sm_SetConVarFloat},
   719 	{"GetConVarString",		sm_GetConVarString},
   720 	{"SetConVarString",		sm_SetConVarString},
   721 	{"GetConVarFlags",		sm_GetConVarFlags},
   722 	{"SetConVarFlags",		sm_SetConVarFlags},
   723 	{"GetConVarName",		sm_GetConVarName},
   724 	{"GetConVarBounds",		sm_GetConVarBounds},
   725 	{"SetConVarBounds",		sm_SetConVarBounds},
   726 	{"ResetConVar",			sm_ResetConVar},
   727 	{"QueryClientConVar",	sm_QueryClientConVar},
   728 	{"RegServerCmd",		sm_RegServerCmd},
   729 	{"RegConsoleCmd",		sm_RegConsoleCmd},
   730 	{"GetCmdArgString",		sm_GetCmdArgString},
   731 	{"GetCmdArgs",			sm_GetCmdArgs},
   732 	{"GetCmdArg",			sm_GetCmdArg},
   733 	{"PrintToServer",		sm_PrintToServer},
   734 	{"PrintToConsole",		sm_PrintToConsole},
   735 	{"RegAdminCmd",			sm_RegAdminCmd},
   736 	{"ServerCommand",		sm_ServerCommand},
   737 	{"InsertServerCommand",	sm_InsertServerCommand},
   738 	{"ServerExecute",		sm_ServerExecute},
   739 	{"ClientCommand",		sm_ClientCommand},
   740 	{"FakeClientCommand",	FakeClientCommand},
   741 	{"ReplyToCommand",		ReplyToCommand},
   742 	{NULL,					NULL}
   743 };