core/smn_console.cpp
author David Anderson <dvander@alliedmods.net>
Thu Mar 05 02:06:59 2009 -0500 (2009-03-05)
changeset 2653 0ae7d8ab1de7
parent 2648 dbcc58361ada
child 2684 a802f5cebe28
permissions -rw-r--r--
Removed -dev tag for release.
dvander@498
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
ds@1947
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@562
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@562
    28
 *
dvander@562
    29
 * Version: $Id$
dvander@562
    30
 */
dvander@498
    31
dvander@498
    32
#include "sm_globals.h"
ds@696
    33
#include "HalfLife2.h"
dvander@498
    34
#include "sourcemm_api.h"
dvander@498
    35
#include "HandleSys.h"
ds@580
    36
#include "ConVarManager.h"
ds@579
    37
#include "ConCmdManager.h"
dvander@514
    38
#include "PluginSys.h"
dvander@518
    39
#include "sm_stringutil.h"
dvander@591
    40
#include "PlayerManager.h"
dvander@893
    41
#include "ChatTriggers.h"
dvander@1429
    42
#include "AdminCache.h"
ds@936
    43
#include <inetchannel.h>
ds@936
    44
#include <bitbuf.h>
faluco@1643
    45
#include <sm_trie_tpl.h>
pred@2648
    46
#include "TagsSystem.h"
ds@936
    47
ds@2400
    48
#if SOURCE_ENGINE == SE_LEFT4DEAD
ds@2400
    49
#define NET_SETCONVAR	6
ds@2400
    50
#else
ds@936
    51
#define NET_SETCONVAR	5
ds@2400
    52
#endif
dvander@498
    53
ds@714
    54
enum ConVarBounds
ds@714
    55
{
ds@714
    56
	ConVarBound_Upper = 0,
ds@714
    57
	ConVarBound_Lower
ds@714
    58
};
ds@714
    59
dvander@1119
    60
HandleType_t hCmdIterType = 0;
dvander@1795
    61
HandleType_t htConCmdIter = 0;
dvander@1119
    62
dvander@1119
    63
struct GlobCmdIter
dvander@1119
    64
{
dvander@1119
    65
	bool started;
dvander@1119
    66
	List<ConCmdInfo *>::iterator iter;
dvander@1119
    67
};
dvander@1119
    68
dvander@1795
    69
struct ConCmdIter
dvander@1795
    70
{
ds@2400
    71
#if SOURCE_ENGINE == SE_LEFT4DEAD
ds@2400
    72
	ICvarIteratorInternal *pLast;
ds@2400
    73
#else
dvander@1795
    74
	const ConCommandBase *pLast;
ds@2400
    75
#endif
dvander@1795
    76
};
dvander@1795
    77
dvander@1119
    78
class ConsoleHelpers : 
dvander@1119
    79
	public SMGlobalClass,
dvander@1119
    80
	public IHandleTypeDispatch
dvander@1119
    81
{
dvander@1119
    82
public:
dvander@1119
    83
	virtual void OnSourceModAllInitialized()
dvander@1119
    84
	{
dvander@1119
    85
		HandleAccess access;
dvander@1795
    86
dvander@1119
    87
		g_HandleSys.InitAccessDefaults(NULL, &access);
dvander@1795
    88
dvander@1795
    89
		htConCmdIter = g_HandleSys.CreateType("ConCmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
dvander@1795
    90
dvander@1119
    91
		access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER | HANDLE_RESTRICT_IDENTITY;
dvander@1119
    92
dvander@1795
    93
		hCmdIterType = g_HandleSys.CreateType("CmdIter", this, 0, NULL, &access, g_pCoreIdent, NULL);
dvander@1119
    94
	}
dvander@1119
    95
	virtual void OnHandleDestroy(HandleType_t type, void *object)
dvander@1119
    96
	{
dvander@1795
    97
		if (type == hCmdIterType)
dvander@1795
    98
		{
dvander@1795
    99
			GlobCmdIter *iter = (GlobCmdIter *)object;
dvander@1795
   100
			delete iter;
dvander@1795
   101
		}
dvander@1795
   102
		else if (type == htConCmdIter)
dvander@1795
   103
		{
dvander@1795
   104
			ConCmdIter *iter = (ConCmdIter * )object;
ds@2439
   105
#if SOURCE_ENGINE == SE_LEFT4DEAD
ds@2439
   106
			// ICvarIteratorInternal has no virtual destructor
ds@2439
   107
			g_pMemAlloc->Free(iter->pLast);
ds@2439
   108
#endif
dvander@1795
   109
			delete iter;
dvander@1795
   110
		}
dvander@1795
   111
	}
dvander@1795
   112
	virtual bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
dvander@1795
   113
	{
dvander@1795
   114
		if (type == htConCmdIter)
dvander@1795
   115
		{
dvander@1795
   116
			*pSize = sizeof(ConCmdIter);
dvander@1795
   117
			return true;
dvander@1795
   118
		}
dvander@1795
   119
		else if (type == hCmdIterType)
dvander@1795
   120
		{
dvander@1795
   121
			*pSize = sizeof(GlobCmdIter);
dvander@1795
   122
			return true;
dvander@1795
   123
		}
dvander@1795
   124
		return false;
dvander@1119
   125
	}
dvander@1119
   126
} s_ConsoleHelpers;
dvander@1119
   127
faluco@1643
   128
class CommandFlagsHelper : public IConCommandTracker
faluco@1643
   129
{
faluco@1643
   130
public:
faluco@1643
   131
	void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
faluco@1643
   132
	{
faluco@1643
   133
		m_CmdFlags.remove(name);
faluco@1643
   134
	}
faluco@1643
   135
	bool GetFlags(const char *name, int *flags)
faluco@1643
   136
	{
faluco@1643
   137
		ConCommandBase **ppCmd;
faluco@1643
   138
		ConCommandBase *pCmd;
faluco@1643
   139
		if ((ppCmd=m_CmdFlags.retrieve(name)))
faluco@1643
   140
		{
faluco@1643
   141
			TrackConCommandBase((*ppCmd), this);
faluco@1643
   142
			*flags = (*ppCmd)->GetFlags();
faluco@1643
   143
			return true;
faluco@1643
   144
		}
ds@2400
   145
		else if ((pCmd=FindCommandBase(name)))
faluco@1643
   146
		{
faluco@1643
   147
			m_CmdFlags.insert(name, pCmd);
faluco@1643
   148
			TrackConCommandBase(pCmd, this);
faluco@1643
   149
			*flags = pCmd->GetFlags();
faluco@1643
   150
			return true;
faluco@1643
   151
		}
faluco@1643
   152
		else
faluco@1643
   153
		{
faluco@1643
   154
			return false;
faluco@1643
   155
		}
faluco@1643
   156
	}
faluco@1643
   157
	bool SetFlags(const char *name, int flags)
faluco@1643
   158
	{
faluco@1643
   159
		ConCommandBase **ppCmd;
faluco@1643
   160
		ConCommandBase *pCmd;
faluco@1643
   161
		if ((ppCmd=m_CmdFlags.retrieve(name)))
faluco@1643
   162
		{
faluco@1643
   163
			(*ppCmd)->SetFlags(flags);
faluco@1643
   164
			TrackConCommandBase((*ppCmd), this);
faluco@1643
   165
			return true;
faluco@1643
   166
		}
ds@2400
   167
		else if ((pCmd=FindCommandBase(name)))
faluco@1643
   168
		{
faluco@1643
   169
			m_CmdFlags.insert(name, pCmd);
faluco@1643
   170
			pCmd->SetFlags(flags);
faluco@1643
   171
			TrackConCommandBase(pCmd, this);
faluco@1643
   172
			return true;
faluco@1643
   173
		}
faluco@1643
   174
		else
faluco@1643
   175
		{
faluco@1643
   176
			return false;
faluco@1643
   177
		}
faluco@1643
   178
	}
faluco@1643
   179
private:
faluco@1643
   180
	KTrie<ConCommandBase *> m_CmdFlags;
faluco@1643
   181
} s_CommandFlagsHelper;
faluco@1643
   182
ds@2400
   183
#if SOURCE_ENGINE >= SE_ORANGEBOX
ds@936
   184
static void ReplicateConVar(ConVar *pConVar)
ds@936
   185
{
ds@936
   186
	int maxClients = g_Players.GetMaxClients();
ds@936
   187
ds@936
   188
	char data[256];
ds@936
   189
	bf_write buffer(data, sizeof(data));
ds@936
   190
ds@936
   191
	buffer.WriteUBitLong(NET_SETCONVAR, 5);
ds@936
   192
	buffer.WriteByte(1);
ds@936
   193
	buffer.WriteString(pConVar->GetName());
ds@936
   194
	buffer.WriteString(pConVar->GetString());
ds@936
   195
ds@936
   196
	for (int i = 1; i <= maxClients; i++)
ds@936
   197
	{
ds@936
   198
		CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
ds@936
   199
ds@936
   200
		if (pPlayer && pPlayer->IsInGame() && !pPlayer->IsFakeClient())
ds@936
   201
		{
ds@936
   202
			INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(i));
ds@936
   203
			netchan->SendData(buffer);
ds@936
   204
		}
ds@936
   205
	}
ds@936
   206
}
ds@936
   207
ds@936
   208
static void NotifyConVar(ConVar *pConVar)
ds@936
   209
{
ds@936
   210
	IGameEvent *pEvent = gameevents->CreateEvent("server_cvar");
ds@936
   211
	pEvent->SetString("cvarname", pConVar->GetName());
faluco@1541
   212
	if (IsFlagSet(pConVar, FCVAR_PROTECTED))
ds@936
   213
	{
ds@936
   214
		pEvent->SetString("cvarvalue", "***PROTECTED***");
dvander@1582
   215
	}
dvander@1582
   216
	else
dvander@1582
   217
	{
ds@936
   218
		pEvent->SetString("cvarvalue", pConVar->GetString());
ds@936
   219
	}
ds@936
   220
ds@936
   221
	gameevents->FireEvent(pEvent);
ds@936
   222
}
ds@2397
   223
#endif
ds@936
   224
dvander@498
   225
static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
dvander@498
   226
{
dvander@498
   227
	char *name, *defaultVal, *helpText;
dvander@498
   228
dvander@498
   229
	pContext->LocalToString(params[1], &name);
dvander@498
   230
dvander@498
   231
	// While the engine seems to accept a blank convar name, it causes a crash upon server quit
dvander@498
   232
	if (name == NULL || strcmp(name, "") == 0)
dvander@498
   233
	{
ds@582
   234
		return pContext->ThrowNativeError("Convar with blank name is not permitted");
dvander@498
   235
	}
dvander@498
   236
dvander@498
   237
	pContext->LocalToString(params[2], &defaultVal);
dvander@498
   238
	pContext->LocalToString(params[3], &helpText);
dvander@498
   239
dvander@498
   240
	bool hasMin = params[5] ? true : false;
dvander@498
   241
	bool hasMax = params[7] ? true : false;
dvander@498
   242
	float min = sp_ctof(params[6]);
dvander@498
   243
	float max = sp_ctof(params[8]);
dvander@498
   244
ds@582
   245
	Handle_t hndl = g_ConVarManager.CreateConVar(pContext, name, defaultVal, helpText, params[4], hasMin, min, hasMax, max);
ds@582
   246
ds@582
   247
	if (hndl == BAD_HANDLE)
ds@582
   248
	{
dvander@1582
   249
		return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
ds@582
   250
	}
ds@582
   251
ds@582
   252
	return hndl;
dvander@498
   253
}
dvander@498
   254
dvander@498
   255
static cell_t sm_FindConVar(IPluginContext *pContext, const cell_t *params)
dvander@498
   256
{
dvander@498
   257
	char *name;
dvander@498
   258
dvander@498
   259
	pContext->LocalToString(params[1], &name);
dvander@498
   260
dvander@498
   261
	return g_ConVarManager.FindConVar(name);
dvander@498
   262
}
dvander@498
   263
dvander@498
   264
static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params)
dvander@498
   265
{
dvander@498
   266
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   267
	HandleError err;
ds@576
   268
	ConVar *pConVar;
dvander@498
   269
dvander@1582
   270
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   271
		!= HandleError_None)
dvander@498
   272
	{
ds@581
   273
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   274
	}
dvander@498
   275
ds@582
   276
	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
ds@582
   277
ds@582
   278
	if (!pFunction)
ds@582
   279
	{
ds@582
   280
		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
ds@582
   281
	}
ds@582
   282
ds@582
   283
	g_ConVarManager.HookConVarChange(pConVar, pFunction);
dvander@498
   284
dvander@498
   285
	return 1;
dvander@498
   286
}
dvander@498
   287
dvander@498
   288
static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *params)
dvander@498
   289
{
dvander@498
   290
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   291
	HandleError err;
ds@576
   292
	ConVar *pConVar;
dvander@498
   293
dvander@1582
   294
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   295
		!= HandleError_None)
dvander@498
   296
	{
ds@581
   297
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   298
	}
dvander@498
   299
ds@582
   300
	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
ds@582
   301
ds@582
   302
	if (!pFunction)
ds@582
   303
	{
ds@582
   304
		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
ds@582
   305
	}
ds@582
   306
ds@582
   307
	g_ConVarManager.UnhookConVarChange(pConVar, pFunction);
dvander@498
   308
dvander@498
   309
	return 1;
dvander@498
   310
}
dvander@498
   311
dvander@498
   312
static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
dvander@498
   313
{
dvander@498
   314
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   315
	HandleError err;
ds@576
   316
	ConVar *pConVar;
dvander@498
   317
dvander@1582
   318
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   319
		!= HandleError_None)
dvander@498
   320
	{
ds@581
   321
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   322
	}
dvander@498
   323
ds@576
   324
	return pConVar->GetBool();
dvander@498
   325
}
dvander@498
   326
dvander@498
   327
static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
dvander@498
   328
{
dvander@498
   329
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   330
	HandleError err;
ds@576
   331
	ConVar *pConVar;
dvander@498
   332
dvander@1582
   333
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   334
		!= HandleError_None)
dvander@498
   335
	{
ds@581
   336
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   337
	}
dvander@498
   338
ds@576
   339
	return pConVar->GetInt();
dvander@498
   340
}
dvander@498
   341
dvander@498
   342
/* This handles both SetConVarBool() and SetConVarInt() */
dvander@498
   343
static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
dvander@498
   344
{
dvander@498
   345
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   346
	HandleError err;
ds@576
   347
	ConVar *pConVar;
dvander@498
   348
dvander@1582
   349
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   350
		!= HandleError_None)
dvander@498
   351
	{
ds@581
   352
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   353
	}
dvander@498
   354
ds@576
   355
	pConVar->SetValue(params[2]);
dvander@498
   356
ds@2400
   357
#if SOURCE_ENGINE >= SE_ORANGEBOX
ds@936
   358
	/* Should we replicate it? */
faluco@1541
   359
	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
ds@936
   360
	{
ds@936
   361
		ReplicateConVar(pConVar);
ds@936
   362
	}
ds@936
   363
ds@936
   364
	/* Should we notify clients? */
faluco@1541
   365
	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
ds@936
   366
	{
ds@936
   367
		NotifyConVar(pConVar);
ds@936
   368
	}
ds@2396
   369
#endif
ds@936
   370
dvander@498
   371
	return 1;
dvander@498
   372
}
dvander@498
   373
dvander@498
   374
static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
dvander@498
   375
{
dvander@498
   376
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   377
	HandleError err;
ds@576
   378
	ConVar *pConVar;
dvander@498
   379
dvander@1582
   380
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   381
		!= HandleError_None)
dvander@498
   382
	{
ds@581
   383
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   384
	}
dvander@498
   385
	
ds@576
   386
	float value = pConVar->GetFloat();
dvander@498
   387
dvander@498
   388
	return sp_ftoc(value);
dvander@498
   389
}
dvander@498
   390
dvander@498
   391
static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
dvander@498
   392
{
dvander@498
   393
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   394
	HandleError err;
ds@576
   395
	ConVar *pConVar;
dvander@498
   396
dvander@1582
   397
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   398
		!= HandleError_None)
dvander@498
   399
	{
ds@581
   400
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   401
	}
dvander@498
   402
dvander@498
   403
	float value = sp_ctof(params[2]);
ds@576
   404
	pConVar->SetValue(value);
dvander@498
   405
ds@2400
   406
#if SOURCE_ENGINE >= SE_ORANGEBOX
ds@936
   407
	/* Should we replicate it? */
faluco@1541
   408
	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
ds@936
   409
	{
ds@936
   410
		ReplicateConVar(pConVar);
ds@936
   411
	}
ds@936
   412
ds@936
   413
	/* Should we notify clients? */
faluco@1541
   414
	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
ds@936
   415
	{
ds@936
   416
		NotifyConVar(pConVar);
ds@936
   417
	}
ds@2396
   418
#endif
ds@936
   419
dvander@498
   420
	return 1;
dvander@498
   421
}
dvander@498
   422
dvander@498
   423
static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
dvander@498
   424
{
dvander@498
   425
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   426
	HandleError err;
ds@576
   427
	ConVar *pConVar;
dvander@498
   428
dvander@1582
   429
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   430
		!= HandleError_None)
dvander@498
   431
	{
ds@581
   432
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   433
	}
dvander@498
   434
ds@576
   435
	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetString(), NULL);
dvander@498
   436
dvander@498
   437
	return 1;
dvander@498
   438
}
dvander@498
   439
dvander@498
   440
static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
dvander@498
   441
{
dvander@498
   442
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   443
	HandleError err;
ds@576
   444
	ConVar *pConVar;
dvander@498
   445
dvander@1582
   446
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   447
		!= HandleError_None)
dvander@498
   448
	{
ds@581
   449
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   450
	}
dvander@498
   451
dvander@498
   452
	char *value;
dvander@498
   453
	pContext->LocalToString(params[2], &value);
dvander@498
   454
ds@576
   455
	pConVar->SetValue(value);
dvander@498
   456
ds@2400
   457
#if SOURCE_ENGINE >= SE_ORANGEBOX
ds@936
   458
	/* Should we replicate it? */
faluco@1541
   459
	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
ds@936
   460
	{
ds@936
   461
		ReplicateConVar(pConVar);
ds@936
   462
	}
ds@936
   463
ds@936
   464
	/* Should we notify clients? */
faluco@1541
   465
	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
ds@936
   466
	{
ds@936
   467
		NotifyConVar(pConVar);
ds@936
   468
	}
ds@2396
   469
#endif
ds@936
   470
dvander@498
   471
	return 1;
dvander@498
   472
}
dvander@498
   473
ds@1301
   474
static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
ds@1301
   475
{
ds@1301
   476
	Handle_t hndl = static_cast<Handle_t>(params[1]);
ds@1301
   477
	HandleError err;
ds@1301
   478
	ConVar *pConVar;
ds@1301
   479
dvander@1582
   480
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
ds@1301
   481
		!= HandleError_None)
ds@1301
   482
	{
ds@1301
   483
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
ds@1301
   484
	}
ds@1301
   485
ds@1301
   486
	pConVar->Revert();
ds@1301
   487
	
ds@2400
   488
#if SOURCE_ENGINE >= SE_ORANGEBOX
ds@1301
   489
	/* Should we replicate it? */
ds@2396
   490
	if (params[3] && IsFlagSet(pConVar, FCVAR_REPLICATED))
ds@1301
   491
	{
ds@1301
   492
		ReplicateConVar(pConVar);
ds@1301
   493
	}
ds@1301
   494
ds@1301
   495
	/* Should we notify clients? */
ds@2396
   496
	if (params[4] && IsFlagSet(pConVar, FCVAR_NOTIFY))
ds@1301
   497
	{
ds@1301
   498
		NotifyConVar(pConVar);
ds@1301
   499
	}
ds@2396
   500
#endif
ds@1301
   501
ds@1301
   502
	return 1;
ds@1301
   503
}
ds@1301
   504
dvander@498
   505
static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
dvander@498
   506
{
dvander@498
   507
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   508
	HandleError err;
ds@576
   509
	ConVar *pConVar;
dvander@498
   510
dvander@1582
   511
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   512
		!= HandleError_None)
dvander@498
   513
	{
ds@581
   514
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   515
	}
dvander@498
   516
ds@576
   517
	return pConVar->GetFlags();
dvander@498
   518
}
dvander@498
   519
dvander@498
   520
static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
dvander@498
   521
{
dvander@498
   522
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   523
	HandleError err;
ds@576
   524
	ConVar *pConVar;
dvander@498
   525
dvander@1582
   526
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   527
		!= HandleError_None)
dvander@498
   528
	{
ds@581
   529
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   530
	}
dvander@498
   531
ds@576
   532
	pConVar->SetFlags(params[2]);
dvander@498
   533
dvander@498
   534
	return 1;
dvander@498
   535
}
dvander@498
   536
ds@714
   537
static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
dvander@498
   538
{
dvander@498
   539
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   540
	HandleError err;
ds@576
   541
	ConVar *pConVar;
dvander@498
   542
dvander@1582
   543
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   544
		!= HandleError_None)
dvander@498
   545
	{
ds@581
   546
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   547
	}
dvander@498
   548
dvander@498
   549
	cell_t *addr;
ds@714
   550
	bool hasBound;
ds@714
   551
	float bound;
dvander@498
   552
ds@714
   553
	switch (params[2])
ds@714
   554
	{
ds@714
   555
	case ConVarBound_Upper:
ds@714
   556
		hasBound = pConVar->GetMax(bound);
ds@714
   557
		break;
ds@714
   558
	case ConVarBound_Lower:
ds@714
   559
		hasBound = pConVar->GetMin(bound);
ds@714
   560
		break;
ds@714
   561
	default:
ds@714
   562
		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
ds@714
   563
	}
ds@714
   564
	
ds@714
   565
	pContext->LocalToPhysAddr(params[3], &addr);
ds@714
   566
	*addr = sp_ftoc(bound);
dvander@498
   567
ds@714
   568
	return hasBound;
dvander@498
   569
}
dvander@498
   570
ds@714
   571
static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
dvander@498
   572
{
dvander@498
   573
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   574
	HandleError err;
ds@576
   575
	ConVar *pConVar;
dvander@498
   576
dvander@1582
   577
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   578
		!= HandleError_None)
dvander@498
   579
	{
ds@581
   580
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   581
	}
dvander@498
   582
ds@714
   583
	switch (params[2])
ds@714
   584
	{
ds@714
   585
	case ConVarBound_Upper:
ds@714
   586
		pConVar->SetMax(params[3] ? true : false, sp_ctof(params[4]));
ds@714
   587
		break;
ds@714
   588
	case ConVarBound_Lower:
ds@714
   589
		pConVar->SetMin(params[3] ? true : false, sp_ctof(params[4]));
ds@714
   590
		break;
ds@714
   591
	default:
ds@714
   592
		return pContext->ThrowNativeError("Invalid ConVarBounds value %d");
ds@714
   593
	}
dvander@498
   594
ds@714
   595
	return 1;
dvander@498
   596
}
dvander@498
   597
dvander@498
   598
static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
dvander@498
   599
{
dvander@498
   600
	Handle_t hndl = static_cast<Handle_t>(params[1]);
dvander@498
   601
	HandleError err;
ds@576
   602
	ConVar *pConVar;
dvander@498
   603
dvander@1582
   604
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
dvander@498
   605
		!= HandleError_None)
dvander@498
   606
	{
ds@581
   607
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
dvander@498
   608
	}
dvander@498
   609
ds@576
   610
	pContext->StringToLocalUTF8(params[2], params[3], pConVar->GetName(), NULL);
dvander@498
   611
dvander@498
   612
	return 1;
dvander@498
   613
}
dvander@498
   614
ds@696
   615
static bool s_QueryAlreadyWarned = false;
ds@696
   616
ds@696
   617
static cell_t sm_QueryClientConVar(IPluginContext *pContext, const cell_t *params)
ds@696
   618
{
ds@696
   619
	CPlayer *pPlayer;
ds@696
   620
	char *name;
ds@696
   621
	IPluginFunction *pCallback;
ds@696
   622
dvander@1581
   623
	if (!g_ConVarManager.IsQueryingSupported())
ds@696
   624
	{
ds@696
   625
		if (!s_QueryAlreadyWarned)
ds@696
   626
		{
ds@696
   627
			s_QueryAlreadyWarned = true;
ds@696
   628
			return pContext->ThrowNativeError("Game does not support client convar querying (one time warning)");
ds@696
   629
		}
ds@696
   630
ds@696
   631
		return 0;
ds@696
   632
	}
ds@696
   633
ds@696
   634
	pPlayer = g_Players.GetPlayerByIndex(params[1]);
ds@696
   635
ds@696
   636
	if (!pPlayer)
ds@696
   637
	{
ds@994
   638
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
ds@696
   639
	}
ds@696
   640
ds@697
   641
	if (!pPlayer->IsConnected())
ds@696
   642
	{
ds@994
   643
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
ds@697
   644
	}
ds@697
   645
ds@697
   646
	/* Trying a query on a bot results in callback not be fired, so don't bother */
ds@697
   647
	if (pPlayer->IsFakeClient())
ds@697
   648
	{
ds@697
   649
		return 0;
ds@696
   650
	}
ds@696
   651
ds@696
   652
	pContext->LocalToString(params[2], &name);
ds@696
   653
	pCallback = pContext->GetFunctionById(params[3]);
ds@696
   654
ds@696
   655
	if (!pCallback)
ds@696
   656
	{
ds@696
   657
		return pContext->ThrowNativeError("Invalid function id (%X)", params[3]);
ds@696
   658
	}
ds@696
   659
ds@696
   660
	return g_ConVarManager.QueryClientConVar(pPlayer->GetEdict(), name, pCallback, params[4]);
ds@696
   661
}
ds@696
   662
dvander@498
   663
static cell_t sm_RegServerCmd(IPluginContext *pContext, const cell_t *params)
dvander@498
   664
{
dvander@498
   665
	char *name,*help;
dvander@498
   666
	IPluginFunction *pFunction;
dvander@498
   667
dvander@498
   668
	pContext->LocalToString(params[1], &name);
dvander@498
   669
	pContext->LocalToString(params[3], &help);
dvander@498
   670
	pFunction = pContext->GetFunctionById(params[2]);
dvander@498
   671
dvander@498
   672
	if (!pFunction)
dvander@498
   673
	{
dvander@498
   674
		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
dvander@498
   675
	}
dvander@498
   676
ds@579
   677
	if (!g_ConCmds.AddServerCommand(pFunction, name, help, params[4]))
ds@579
   678
	{
ds@579
   679
		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
ds@579
   680
	}
dvander@498
   681
dvander@498
   682
	return 1;
dvander@498
   683
}
dvander@498
   684
dvander@500
   685
static cell_t sm_RegConsoleCmd(IPluginContext *pContext, const cell_t *params)
dvander@500
   686
{
dvander@500
   687
	char *name,*help;
dvander@500
   688
	IPluginFunction *pFunction;
dvander@500
   689
dvander@500
   690
	pContext->LocalToString(params[1], &name);
dvander@500
   691
	pContext->LocalToString(params[3], &help);
dvander@500
   692
	pFunction = pContext->GetFunctionById(params[2]);
dvander@500
   693
dvander@500
   694
	if (!pFunction)
dvander@500
   695
	{
dvander@500
   696
		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
dvander@500
   697
	}
dvander@500
   698
ds@579
   699
	if (!g_ConCmds.AddConsoleCommand(pFunction, name, help, params[4]))
ds@579
   700
	{
ds@579
   701
		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
ds@579
   702
	}
dvander@500
   703
dvander@500
   704
	return 1;
dvander@500
   705
}
dvander@500
   706
dvander@514
   707
static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
dvander@514
   708
{
dvander@514
   709
	char *name,*help;
dvander@514
   710
	const char *group;
dvander@514
   711
	IPluginFunction *pFunction;
dvander@514
   712
	FlagBits flags = params[3];
dvander@514
   713
	int cmdflags = params[6];
dvander@514
   714
dvander@514
   715
	pContext->LocalToString(params[1], &name);
dvander@514
   716
	pContext->LocalToString(params[4], &help);
dvander@514
   717
	pContext->LocalToString(params[5], (char **)&group);
dvander@514
   718
	pFunction = pContext->GetFunctionById(params[2]);
dvander@514
   719
dvander@514
   720
	if (group[0] == '\0')
dvander@514
   721
	{
dvander@514
   722
		CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
dvander@514
   723
		group = pPlugin->GetFilename();
dvander@514
   724
	}
dvander@514
   725
dvander@514
   726
	if (!pFunction)
dvander@514
   727
	{
dvander@514
   728
		return pContext->ThrowNativeError("Invalid function id (%X)", params[2]);
dvander@514
   729
	}
dvander@514
   730
ds@579
   731
	if (!g_ConCmds.AddAdminCommand(pFunction, name, group, flags, help, cmdflags))
ds@579
   732
	{
ds@579
   733
		return pContext->ThrowNativeError("Command \"%s\" could not be created. A convar with the same name already exists.", name);
ds@579
   734
	}
dvander@514
   735
dvander@514
   736
	return 1;
dvander@514
   737
}
dvander@514
   738
dvander@517
   739
static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
dvander@517
   740
{
dvander@1544
   741
	const CCommand *pCmd = g_HL2.PeekCommandStack();
dvander@1544
   742
dvander@1544
   743
	if (!pCmd)
dvander@1544
   744
	{
dvander@1544
   745
		return pContext->ThrowNativeError("No command callback available");
dvander@1544
   746
	}
dvander@1544
   747
dvander@1544
   748
	return pCmd->ArgC() - 1;
dvander@517
   749
}
dvander@517
   750
dvander@517
   751
static cell_t sm_GetCmdArg(IPluginContext *pContext, const cell_t *params)
dvander@517
   752
{
dvander@1544
   753
	const CCommand *pCmd = g_HL2.PeekCommandStack();
dvander@1544
   754
dvander@1544
   755
	if (!pCmd)
dvander@1544
   756
	{
dvander@1544
   757
		return pContext->ThrowNativeError("No command callback available");
dvander@1544
   758
	}
dvander@1544
   759
dvander@1421
   760
	size_t length;
dvander@1544
   761
dvander@1544
   762
	const char *arg = pCmd->Arg(params[1]);
dvander@517
   763
	
dvander@1544
   764
	pContext->StringToLocalUTF8(params[2], params[3], arg ? arg : "", &length);
dvander@517
   765
dvander@1421
   766
	return (cell_t)length;
dvander@517
   767
}
dvander@517
   768
dvander@517
   769
static cell_t sm_GetCmdArgString(IPluginContext *pContext, const cell_t *params)
dvander@517
   770
{
dvander@1544
   771
	const CCommand *pCmd = g_HL2.PeekCommandStack();
dvander@1544
   772
dvander@1544
   773
	if (!pCmd)
dvander@1544
   774
	{
dvander@1544
   775
		return pContext->ThrowNativeError("No command callback available");
dvander@1544
   776
	}
dvander@1544
   777
dvander@1544
   778
	const char *args = pCmd->ArgS();
dvander@1421
   779
	size_t length;
dvander@517
   780
dvander@633
   781
	if (!args)
dvander@633
   782
	{
dvander@633
   783
		args = "";
dvander@633
   784
	}
dvander@633
   785
dvander@1421
   786
	pContext->StringToLocalUTF8(params[1], params[2], args, &length);
dvander@517
   787
dvander@1421
   788
	return (cell_t)length;
dvander@517
   789
}
dvander@517
   790
dvander@518
   791
static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
dvander@518
   792
{
dvander@518
   793
	char buffer[1024];
dvander@518
   794
	char *fmt;
dvander@518
   795
	int arg = 2;
dvander@518
   796
dvander@518
   797
	pCtx->LocalToString(params[1], &fmt);
dvander@518
   798
	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
dvander@518
   799
dvander@518
   800
	buffer[res++] = '\n';
dvander@518
   801
	buffer[res] = '\0';
dvander@518
   802
dvander@518
   803
	META_CONPRINT(buffer);
dvander@518
   804
dvander@518
   805
	return 1;
dvander@518
   806
}
dvander@518
   807
dvander@518
   808
static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
dvander@518
   809
{
dvander@518
   810
	int index = params[1];
dvander@520
   811
	if ((index < 0) || (index > g_Players.GetMaxClients()))
dvander@518
   812
	{
ds@994
   813
		return pCtx->ThrowNativeError("Client index %d is invalid", index);
dvander@518
   814
	}
dvander@518
   815
dvander@520
   816
	CPlayer *pPlayer = NULL;
dvander@520
   817
	if (index != 0)
dvander@518
   818
	{
dvander@520
   819
		pPlayer = g_Players.GetPlayerByIndex(index);
dvander@520
   820
		if (!pPlayer->IsInGame())
dvander@520
   821
		{
dvander@520
   822
			return pCtx->ThrowNativeError("Client %d is not in game", index);
dvander@520
   823
		}
dvander@520
   824
		
dvander@520
   825
		/* Silent fail on bots, engine will crash */
dvander@520
   826
		if (pPlayer->IsFakeClient())
dvander@520
   827
		{
dvander@520
   828
			return 0;
dvander@520
   829
		}
dvander@519
   830
	}
dvander@518
   831
dvander@518
   832
	char buffer[1024];
dvander@518
   833
	char *fmt;
dvander@518
   834
	int arg = 3;
dvander@518
   835
dvander@518
   836
	pCtx->LocalToString(params[2], &fmt);
dvander@518
   837
	size_t res = atcprintf(buffer, sizeof(buffer)-2, fmt, pCtx, params, &arg);
dvander@518
   838
dvander@518
   839
	buffer[res++] = '\n';
dvander@518
   840
	buffer[res] = '\0';
dvander@518
   841
dvander@520
   842
	if (index != 0)
dvander@520
   843
	{
dvander@520
   844
		engine->ClientPrintf(pPlayer->GetEdict(), buffer);
dvander@520
   845
	} else {
dvander@520
   846
		META_CONPRINT(buffer);
dvander@520
   847
	}
dvander@518
   848
dvander@518
   849
	return 1;
dvander@518
   850
}
dvander@518
   851
dvander@522
   852
static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
dvander@522
   853
{
dvander@2042
   854
	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
dvander@1273
   855
dvander@522
   856
	char buffer[1024];
dvander@522
   857
	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
dvander@522
   858
dvander@2193
   859
	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
dvander@1273
   860
	{
dvander@1273
   861
		return 0;
dvander@1273
   862
	}
dvander@1011
   863
dvander@522
   864
	/* One byte for null terminator, one for newline */
dvander@522
   865
	buffer[len++] = '\n';
dvander@522
   866
	buffer[len] = '\0';
dvander@522
   867
dvander@522
   868
	engine->ServerCommand(buffer);
dvander@522
   869
dvander@522
   870
	return 1;
dvander@522
   871
}
dvander@522
   872
dvander@522
   873
static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *params)
dvander@522
   874
{
dvander@2042
   875
	g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
dvander@1273
   876
dvander@522
   877
	char buffer[1024];
dvander@522
   878
	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
dvander@522
   879
dvander@2193
   880
	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
dvander@1273
   881
	{
dvander@1273
   882
		return 0;
dvander@1273
   883
	}
dvander@1011
   884
dvander@522
   885
	/* One byte for null terminator, one for newline */
dvander@522
   886
	buffer[len++] = '\n';
dvander@522
   887
	buffer[len] = '\0';
dvander@522
   888
faluco@1541
   889
	InsertServerCommand(buffer);
dvander@522
   890
dvander@522
   891
	return 1;
dvander@522
   892
}
dvander@522
   893
dvander@522
   894
static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params)
dvander@522
   895
{
dvander@522
   896
	engine->ServerExecute();
dvander@522
   897
dvander@522
   898
	return 1;
dvander@522
   899
}
dvander@522
   900
dvander@532
   901
static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
dvander@532
   902
{
dvander@532
   903
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
dvander@532
   904
dvander@532
   905
	if (!pPlayer)
dvander@532
   906
	{
ds@994
   907
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
dvander@532
   908
	}
dvander@532
   909
dvander@532
   910
	if (!pPlayer->IsConnected())
dvander@532
   911
	{
ds@994
   912
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
dvander@532
   913
	}
dvander@532
   914
dvander@1011
   915
	g_SourceMod.SetGlobalTarget(params[1]);
dvander@1011
   916
dvander@532
   917
	char buffer[256];
ds@873
   918
	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
dvander@532
   919
dvander@2193
   920
	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
dvander@1273
   921
	{
dvander@1273
   922
		return 0;
dvander@1273
   923
	}
dvander@1273
   924
dvander@532
   925
	engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer);
dvander@532
   926
dvander@532
   927
	return 1;
dvander@532
   928
}
dvander@532
   929
dvander@893
   930
static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
dvander@893
   931
{
dvander@893
   932
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
dvander@893
   933
dvander@893
   934
	if (!pPlayer)
dvander@893
   935
	{
ds@994
   936
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
dvander@893
   937
	}
dvander@893
   938
dvander@893
   939
	if (!pPlayer->IsConnected())
dvander@893
   940
	{
ds@994
   941
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
dvander@893
   942
	}
dvander@893
   943
dvander@893
   944
	char buffer[256];
dvander@893
   945
	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
dvander@893
   946
dvander@2193
   947
	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
dvander@1273
   948
	{
dvander@1273
   949
		return 0;
dvander@1273
   950
	}
dvander@1273
   951
dvander@893
   952
	serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer);
dvander@1337
   953
dvander@1337
   954
	return 1;
dvander@1337
   955
}
dvander@1337
   956
dvander@1337
   957
static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params)
dvander@1337
   958
{
dvander@1337
   959
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
dvander@1337
   960
dvander@1337
   961
	if (!pPlayer)
dvander@1337
   962
	{
dvander@1337
   963
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
dvander@1337
   964
	}
dvander@1337
   965
dvander@1337
   966
	if (!pPlayer->IsConnected())
dvander@1337
   967
	{
dvander@1337
   968
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
dvander@1337
   969
	}
dvander@1337
   970
dvander@1337
   971
	char buffer[256];
dvander@1337
   972
	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
dvander@1337
   973
dvander@2193
   974
	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
dvander@1337
   975
	{
dvander@1337
   976
		return 0;
dvander@1337
   977
	}
dvander@1337
   978
dvander@1338
   979
	g_HL2.AddToFakeCliCmdQueue(params[1], engine->GetPlayerUserId(pPlayer->GetEdict()), buffer);
dvander@893
   980
dvander@893
   981
	return 1;
dvander@893
   982
}
dvander@893
   983
dvander@893
   984
static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
dvander@893
   985
{
dvander@1011
   986
	g_SourceMod.SetGlobalTarget(params[1]);
dvander@1011
   987
dvander@893
   988
	/* Build the format string */
dvander@893
   989
	char buffer[1024];
dvander@893
   990
	size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
dvander@893
   991
dvander@2193
   992
	if (pContext->GetLastNativeError() != SP_ERROR_NONE)
dvander@1273
   993
	{
dvander@1273
   994
		return 0;
dvander@1273
   995
	}
dvander@1273
   996
dvander@893
   997
	/* If we're printing to the server, shortcut out */
dvander@893
   998
	if (params[1] == 0)
dvander@893
   999
	{
dvander@893
  1000
		/* Print */
dvander@893
  1001
		buffer[len++] = '\n';
dvander@893
  1002
		buffer[len] = '\0';
dvander@893
  1003
		META_CONPRINT(buffer);
dvander@893
  1004
		return 1;
dvander@893
  1005
	}
dvander@893
  1006
dvander@893
  1007
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
dvander@893
  1008
dvander@893
  1009
	if (!pPlayer)
dvander@893
  1010
	{
dvander@893
  1011
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
dvander@893
  1012
	}
dvander@893
  1013
dvander@893
  1014
	if (!pPlayer->IsConnected())
dvander@893
  1015
	{
dvander@893
  1016
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
dvander@893
  1017
	}
dvander@893
  1018
dvander@910
  1019
	g_SourceMod.SetGlobalTarget(params[1]);
dvander@910
  1020
dvander@893
  1021
	unsigned int replyto = g_ChatTriggers.GetReplyTo();
dvander@893
  1022
	if (replyto == SM_REPLY_CONSOLE)
dvander@893
  1023
	{
dvander@893
  1024
		buffer[len++] = '\n';
dvander@893
  1025
		buffer[len] = '\0';
dvander@893
  1026
		engine->ClientPrintf(pPlayer->GetEdict(), buffer);
dvander@893
  1027
	} else if (replyto == SM_REPLY_CHAT) {
dvander@893
  1028
		if (len >= 191)
dvander@893
  1029
		{
dvander@893
  1030
			len = 191;
dvander@893
  1031
		}
dvander@893
  1032
		buffer[len] = '\0';
dvander@893
  1033
		g_HL2.TextMsg(params[1], HUD_PRINTTALK, buffer);
dvander@893
  1034
	}
dvander@893
  1035
dvander@893
  1036
	return 1;
dvander@893
  1037
}
dvander@893
  1038
dvander@923
  1039
static cell_t GetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
dvander@923
  1040
{
dvander@923
  1041
	return g_ChatTriggers.GetReplyTo();
dvander@923
  1042
}
dvander@923
  1043
dvander@1071
  1044
static cell_t SetCmdReplyTarget(IPluginContext *pContext, const cell_t *params)
dvander@1071
  1045
{
dvander@1071
  1046
	return g_ChatTriggers.SetReplyTo(params[1]);
dvander@1071
  1047
}
dvander@1071
  1048
dvander@1119
  1049
static cell_t GetCommandIterator(IPluginContext *pContext, const cell_t *params)
dvander@1119
  1050
{
dvander@1119
  1051
	GlobCmdIter *iter = new GlobCmdIter;
dvander@1119
  1052
	iter->started = false;
dvander@1119
  1053
dvander@1119
  1054
	Handle_t hndl = g_HandleSys.CreateHandle(hCmdIterType, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
dvander@1119
  1055
	if (hndl == BAD_HANDLE)
dvander@1119
  1056
	{
dvander@1119
  1057
		delete iter;
dvander@1119
  1058
	}
dvander@1119
  1059
dvander@1119
  1060
	return hndl;
dvander@1119
  1061
}
dvander@1119
  1062
dvander@1119
  1063
static cell_t ReadCommandIterator(IPluginContext *pContext, const cell_t *params)
dvander@1119
  1064
{
dvander@1119
  1065
	GlobCmdIter *iter;
dvander@1119
  1066
	HandleError err;
dvander@1119
  1067
	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
dvander@1119
  1068
dvander@1119
  1069
	if ((err = g_HandleSys.ReadHandle(params[1], hCmdIterType, &sec, (void **)&iter))
dvander@1119
  1070
		!= HandleError_None)
dvander@1119
  1071
	{
dvander@1119
  1072
		return pContext->ThrowNativeError("Invalid GlobCmdIter Handle %x", params[1]);
dvander@1119
  1073
	}
dvander@1119
  1074
dvander@1119
  1075
	const List<ConCmdInfo *> &cmds = g_ConCmds.GetCommandList();
dvander@1119
  1076
dvander@1119
  1077
	if (!iter->started)
dvander@1119
  1078
	{
dvander@1119
  1079
		iter->iter = cmds.begin();
dvander@1119
  1080
		iter->started = true;
dvander@1119
  1081
	}
dvander@1119
  1082
dvander@1119
  1083
	while (iter->iter != cmds.end()
dvander@1119
  1084
			&& !(*(iter->iter))->sourceMod)
dvander@1119
  1085
	{
dvander@1119
  1086
		iter->iter++;
dvander@1119
  1087
	}
dvander@1119
  1088
dvander@1119
  1089
	if (iter->iter == cmds.end())
dvander@1119
  1090
	{
dvander@1119
  1091
		return 0;
dvander@1119
  1092
	}
dvander@1119
  1093
dvander@1119
  1094
	ConCmdInfo *pInfo = (*(iter->iter));
dvander@1119
  1095
dvander@1119
  1096
	pContext->StringToLocalUTF8(params[2], params[3], pInfo->pCmd->GetName(), NULL);
dvander@1119
  1097
	pContext->StringToLocalUTF8(params[5], params[6], pInfo->pCmd->GetHelpText(), NULL);
dvander@1119
  1098
	
dvander@1119
  1099
	cell_t *addr;
dvander@1119
  1100
	pContext->LocalToPhysAddr(params[4], &addr);
dvander@1119
  1101
	*addr = pInfo->admin.eflags;
dvander@1119
  1102
dvander@1119
  1103
	iter->iter++;
dvander@1119
  1104
dvander@1119
  1105
	return 1;
dvander@1119
  1106
}
dvander@1119
  1107
dvander@1119
  1108
static cell_t CheckCommandAccess(IPluginContext *pContext, const cell_t *params)
dvander@1119
  1109
{
dvander@1119
  1110
	if (params[1] == 0)
dvander@1119
  1111
	{
dvander@1119
  1112
		return 1;
dvander@1119
  1113
	}
dvander@1119
  1114
dvander@1119
  1115
	char *cmd;
dvander@1119
  1116
	pContext->LocalToString(params[2], &cmd);
dvander@1119
  1117
dvander@1429
  1118
	/* Auto-detect a command if we can */
dvander@1399
  1119
	FlagBits bits = params[3];
dvander@1429
  1120
	bool found_command = false;
dvander@1429
  1121
	if (params[0] < 4 || !params[4])
dvander@1399
  1122
	{
dvander@1429
  1123
		found_command = g_ConCmds.LookForCommandAdminFlags(cmd, &bits);
dvander@1429
  1124
	}
dvander@1429
  1125
	
dvander@1429
  1126
	if (!found_command)
dvander@1429
  1127
	{
dvander@1429
  1128
		g_Admins.GetCommandOverride(cmd, Override_Command, &bits);
dvander@1399
  1129
	}
dvander@1399
  1130
dvander@1399
  1131
	return g_ConCmds.CheckCommandAccess(params[1], cmd, bits) ? 1 : 0;
dvander@1119
  1132
}
dvander@1119
  1133
dvander@1469
  1134
static cell_t IsChatTrigger(IPluginContext *pContext, const cell_t *params)
dvander@1469
  1135
{
dvander@1469
  1136
	return g_ChatTriggers.IsChatTrigger() ? 1 : 0;
dvander@1469
  1137
}
dvander@1469
  1138
faluco@1643
  1139
static cell_t SetCommandFlags(IPluginContext *pContext, const cell_t *params)
faluco@1643
  1140
{
faluco@1643
  1141
	char *name;
faluco@1643
  1142
	pContext->LocalToString(params[1], &name);
faluco@1643
  1143
faluco@1643
  1144
	return (s_CommandFlagsHelper.SetFlags(name, params[2])) ? 1 : 0;
faluco@1643
  1145
}
faluco@1643
  1146
faluco@1643
  1147
static cell_t GetCommandFlags(IPluginContext *pContext, const cell_t *params)
faluco@1643
  1148
{
faluco@1643
  1149
	char *name;
faluco@1643
  1150
	int flags;
faluco@1643
  1151
	pContext->LocalToString(params[1], &name);
faluco@1643
  1152
faluco@1643
  1153
	return (s_CommandFlagsHelper.GetFlags(name, &flags)) ? flags : -1;
faluco@1643
  1154
}
faluco@1643
  1155
dvander@1795
  1156
static cell_t FindFirstConCommand(IPluginContext *pContext, const cell_t *params)
dvander@1795
  1157
{
dvander@1795
  1158
	Handle_t hndl;
dvander@1795
  1159
	ConCmdIter *pIter;
dvander@1795
  1160
	cell_t *pIsCmd, *pFlags;
dvander@1795
  1161
	const ConCommandBase *pConCmd;
faluco@1893
  1162
	const char *desc;
dvander@1795
  1163
dvander@1795
  1164
	pContext->LocalToPhysAddr(params[3], &pIsCmd);
dvander@1795
  1165
	pContext->LocalToPhysAddr(params[4], &pFlags);
dvander@1795
  1166
ds@2400
  1167
#if SOURCE_ENGINE == SE_LEFT4DEAD
ds@2400
  1168
	ICvarIteratorInternal *cvarIter = icvar->FactoryInternalIterator();
ds@2400
  1169
	cvarIter->SetFirst();
ds@2400
  1170
	if (!cvarIter->IsValid())
ds@2400
  1171
	{
ds@2400
  1172
		return BAD_HANDLE;
ds@2400
  1173
	}
ds@2400
  1174
	pConCmd = cvarIter->Get();
ds@2400
  1175
#else
dvander@1795
  1176
	pConCmd = icvar->GetCommands();
dvander@1795
  1177
	if (pConCmd == NULL)
dvander@1795
  1178
	{
dvander@1795
  1179
		return BAD_HANDLE;
dvander@1795
  1180
	}
ds@2400
  1181
#endif
dvander@1795
  1182
dvander@1795
  1183
	pContext->StringToLocalUTF8(params[1], params[2], pConCmd->GetName(), NULL);
dvander@1795
  1184
	*pIsCmd = pConCmd->IsCommand() ? 1 : 0;
dvander@1795
  1185
	*pFlags = pConCmd->GetFlags();
dvander@1795
  1186
faluco@1893
  1187
	if (params[6])
faluco@1893
  1188
	{
faluco@1893
  1189
		desc = pConCmd->GetHelpText();
faluco@1893
  1190
		pContext->StringToLocalUTF8(params[5], params[6], (desc && desc[0]) ? desc : "", NULL);
faluco@1893
  1191
	}
faluco@1893
  1192
dvander@1795
  1193
	pIter = new ConCmdIter;
ds@2400
  1194
#if SOURCE_ENGINE == SE_LEFT4DEAD
ds@2400
  1195
	pIter->pLast = cvarIter;
ds@2400
  1196
#else
dvander@1795
  1197
	pIter->pLast = pConCmd;
ds@2400
  1198
#endif
dvander@1795
  1199
dvander@1795
  1200
	if ((hndl = g_HandleSys.CreateHandle(htConCmdIter, pIter, pContext->GetIdentity(), g_pCoreIdent, NULL))
dvander@1795
  1201
		== BAD_HANDLE)
dvander@1795
  1202
	{
dvander@1795
  1203
		delete pIter;
dvander@1795
  1204
		return BAD_HANDLE;
dvander@1795
  1205
	}
dvander@1795
  1206
dvander@1795
  1207
	return hndl;
dvander@1795
  1208
}
dvander@1795
  1209
dvander@1795
  1210
static cell_t FindNextConCommand(IPluginContext *pContext, const cell_t *params)
dvander@1795
  1211
{
dvander@1795
  1212
	HandleError err;
dvander@1795
  1213
	ConCmdIter *pIter;
dvander@1795
  1214
	cell_t *pIsCmd, *pFlags;
faluco@1893
  1215
	const char *desc;
ds@2400
  1216
	const ConCommandBase *pConCmd;
dvander@1795
  1217
	HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent);
dvander@1795
  1218
dvander@1795
  1219
	if ((err = g_HandleSys.ReadHandle(params[1], htConCmdIter, &sec, (void **)&pIter)) != HandleError_None)
dvander@1795
  1220
	{
dvander@1795
  1221
		return pContext->ThrowNativeError("Invalid Handle %x (error %d)", params[1], err);
dvander@1795
  1222
	}
dvander@1795
  1223
dvander@1795
  1224
	if (pIter->pLast == NULL)
dvander@1795
  1225
	{
dvander@1795
  1226
		return 0;
dvander@1795
  1227
	}
dvander@1795
  1228
ds@2400
  1229
#if SOURCE_ENGINE == SE_LEFT4DEAD
ds@2400
  1230
	ICvarIteratorInternal *cvarIter = pIter->pLast;
ds@2400
  1231
	cvarIter->Next();
ds@2400
  1232
	if (!cvarIter->IsValid())
dvander@1795
  1233
	{
dvander@1795
  1234
		return 0;
dvander@1795
  1235
	}
ds@2400
  1236
	pConCmd = cvarIter->Get();
ds@2400
  1237
#else
ds@2400
  1238
	pConCmd = pIter->pLast->GetNext();
ds@2400
  1239
	if (pConCmd == NULL)
ds@2400
  1240
	{
ds@2400
  1241
		return 0;
ds@2400
  1242
	}
ds@2400
  1243
	pIter->pLast = pConCmd;
ds@2400
  1244
#endif
dvander@1795
  1245
dvander@1795
  1246
	pContext->LocalToPhysAddr(params[4], &pIsCmd);
dvander@1795
  1247
	pContext->LocalToPhysAddr(params[5], &pFlags);
dvander@1795
  1248
ds@2400
  1249
	pContext->StringToLocalUTF8(params[2], params[3], pConCmd->GetName(), NULL);
ds@2400
  1250
	*pIsCmd = pConCmd->IsCommand() ? 1 : 0;
ds@2400
  1251
	*pFlags = pConCmd->GetFlags();
dvander@1795
  1252
faluco@1893
  1253
	if (params[7])
faluco@1893
  1254
	{
ds@2400
  1255
		desc = pConCmd->GetHelpText();
faluco@1893
  1256
		pContext->StringToLocalUTF8(params[6], params[7], (desc && desc[0]) ? desc : "", NULL);
faluco@1893
  1257
	}
faluco@1893
  1258
dvander@1795
  1259
	return 1;
dvander@1795
  1260
}
dvander@1795
  1261
pred@1852
  1262
static cell_t SendConVarValue(IPluginContext *pContext, const cell_t *params)
pred@1852
  1263
{
pred@1852
  1264
	Handle_t hndl = static_cast<Handle_t>(params[2]);
pred@1852
  1265
	HandleError err;
pred@1852
  1266
	ConVar *pConVar;
pred@1852
  1267
pred@1852
  1268
	char *value;
pred@1852
  1269
	pContext->LocalToString(params[3], &value);
pred@1852
  1270
pred@1852
  1271
	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
pred@1852
  1272
		!= HandleError_None)
pred@1852
  1273
	{
pred@1852
  1274
		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
pred@1852
  1275
	}
pred@1852
  1276
pred@1852
  1277
	char data[256];
pred@1852
  1278
	bf_write buffer(data, sizeof(data));
pred@1852
  1279
pred@1852
  1280
	buffer.WriteUBitLong(NET_SETCONVAR, 5);
pred@1852
  1281
	buffer.WriteByte(1);
pred@1852
  1282
	buffer.WriteString(pConVar->GetName());
pred@1852
  1283
	buffer.WriteString(value);
pred@1852
  1284
pred@1852
  1285
	CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]);
pred@1852
  1286
pred@1852
  1287
	if (!pPlayer)
pred@1852
  1288
	{
pred@1852
  1289
		return pContext->ThrowNativeError("Client index %d is invalid", params[1]);
pred@1852
  1290
	}
pred@1852
  1291
pred@1852
  1292
	if (!pPlayer->IsConnected())
pred@1852
  1293
	{
pred@1852
  1294
		return pContext->ThrowNativeError("Client %d is not connected", params[1]);
pred@1852
  1295
	}
pred@1852
  1296
pred@1852
  1297
	if (pPlayer->IsFakeClient())
pred@1852
  1298
	{
pred@1852
  1299
		return pContext->ThrowNativeError("Client %d is fake and cannot be targeted", params[1]);
pred@1852
  1300
	}
pred@1852
  1301
pred@1852
  1302
	INetChannel *netchan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(params[1]));
pred@1852
  1303
	netchan->SendData(buffer);
pred@1852
  1304
pred@1852
  1305
	return 1;
pred@1852
  1306
}
pred@1852
  1307
pred@2648
  1308
static cell_t AddServerTag(IPluginContext *pContext, const cell_t *params)
pred@2648
  1309
{
pred@2648
  1310
	char *value;
pred@2648
  1311
	pContext->LocalToString(params[1], &value);
pred@2648
  1312
pred@2648
  1313
	if (!g_Tags.AddTag(value))
pred@2648
  1314
	{
pred@2648
  1315
		return 0;
pred@2648
  1316
	}
pred@2648
  1317
pred@2648
  1318
	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
pred@2648
  1319
	SourceHook::List<char *> *pList = NULL;
pred@2648
  1320
pred@2648
  1321
	if (!pPlugin->GetProperty("ServerTags", (void **)&pList, false) || !pList)
pred@2648
  1322
	{
pred@2648
  1323
		pList = new SourceHook::List<char *>;
pred@2648
  1324
		pPlugin->SetProperty("ServerTags", pList);
pred@2648
  1325
	}
pred@2648
  1326
pred@2648
  1327
	pList->push_back(strdup(value));
pred@2648
  1328
pred@2648
  1329
	return 1;
pred@2648
  1330
}
pred@2648
  1331
pred@2648
  1332
static cell_t RemoveServerTag(IPluginContext *pContext, const cell_t *params)
pred@2648
  1333
{
pred@2648
  1334
	char *value;
pred@2648
  1335
	pContext->LocalToString(params[1], &value);
pred@2648
  1336
pred@2648
  1337
	IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
pred@2648
  1338
	SourceHook::List<char *> *pList = NULL;
pred@2648
  1339
pred@2648
  1340
	if (!pPlugin->GetProperty("ServerTags", (void **)&pList, false) || !pList)
pred@2648
  1341
	{
pred@2648
  1342
		pList = new SourceHook::List<char *>;
pred@2648
  1343
		pPlugin->SetProperty("ServerTags", pList);
pred@2648
  1344
	}
pred@2648
  1345
pred@2648
  1346
	SourceHook::List<char *>::iterator iter = pList->begin();
pred@2648
  1347
pred@2648
  1348
	while (iter != pList->end())
pred@2648
  1349
	{
pred@2648
  1350
		if (strcmp(*iter, value) == 0)
pred@2648
  1351
		{
pred@2648
  1352
			g_pMemAlloc->Free(*iter);
pred@2648
  1353
			pList->erase(iter);
pred@2648
  1354
pred@2648
  1355
			return g_Tags.RemoveTag(value);
pred@2648
  1356
		}
pred@2648
  1357
	}
pred@2648
  1358
pred@2648
  1359
	return 0;
pred@2648
  1360
}
pred@2648
  1361
dvander@518
  1362
REGISTER_NATIVES(consoleNatives)
dvander@498
  1363
{
dvander@498
  1364
	{"CreateConVar",		sm_CreateConVar},
dvander@498
  1365
	{"FindConVar",			sm_FindConVar},
dvander@498
  1366
	{"HookConVarChange",	sm_HookConVarChange},
dvander@498
  1367
	{"UnhookConVarChange",	sm_UnhookConVarChange},
dvander@498
  1368
	{"GetConVarBool",		sm_GetConVarBool},
dvander@498
  1369
	{"SetConVarBool",		sm_SetConVarNum},
dvander@498
  1370
	{"GetConVarInt",		sm_GetConVarInt},
dvander@498
  1371
	{"SetConVarInt",		sm_SetConVarNum},
dvander@498
  1372
	{"GetConVarFloat",		sm_GetConVarFloat},
dvander@498
  1373
	{"SetConVarFloat",		sm_SetConVarFloat},
dvander@498
  1374
	{"GetConVarString",		sm_GetConVarString},
dvander@498
  1375
	{"SetConVarString",		sm_SetConVarString},
dvander@498
  1376
	{"GetConVarFlags",		sm_GetConVarFlags},
dvander@498
  1377
	{"SetConVarFlags",		sm_SetConVarFlags},
ds@1301
  1378
	{"ResetConVar",			sm_ResetConVar},
dvander@498
  1379
	{"GetConVarName",		sm_GetConVarName},
ds@714
  1380
	{"GetConVarBounds",		sm_GetConVarBounds},
ds@714
  1381
	{"SetConVarBounds",		sm_SetConVarBounds},
ds@696
  1382
	{"QueryClientConVar",	sm_QueryClientConVar},
dvander@498
  1383
	{"RegServerCmd",		sm_RegServerCmd},
dvander@500
  1384
	{"RegConsoleCmd",		sm_RegConsoleCmd},
dvander@517
  1385
	{"GetCmdArgString",		sm_GetCmdArgString},
dvander@517
  1386
	{"GetCmdArgs",			sm_GetCmdArgs},
dvander@517
  1387
	{"GetCmdArg",			sm_GetCmdArg},
dvander@518
  1388
	{"PrintToServer",		sm_PrintToServer},
dvander@518
  1389
	{"PrintToConsole",		sm_PrintToConsole},
dvander@520
  1390
	{"RegAdminCmd",			sm_RegAdminCmd},
dvander@522
  1391
	{"ServerCommand",		sm_ServerCommand},
dvander@522
  1392
	{"InsertServerCommand",	sm_InsertServerCommand},
dvander@522
  1393
	{"ServerExecute",		sm_ServerExecute},
dvander@532
  1394
	{"ClientCommand",		sm_ClientCommand},
dvander@893
  1395
	{"FakeClientCommand",	FakeClientCommand},
dvander@893
  1396
	{"ReplyToCommand",		ReplyToCommand},
dvander@923
  1397
	{"GetCmdReplySource",	GetCmdReplyTarget},
dvander@1077
  1398
	{"SetCmdReplySource",	SetCmdReplyTarget},
dvander@1119
  1399
	{"GetCommandIterator",	GetCommandIterator},
dvander@1119
  1400
	{"ReadCommandIterator",	ReadCommandIterator},
dvander@1119
  1401
	{"CheckCommandAccess",	CheckCommandAccess},
dvander@1338
  1402
	{"FakeClientCommandEx",	FakeClientCommandEx},
dvander@1469
  1403
	{"IsChatTrigger",		IsChatTrigger},
faluco@1643
  1404
	{"SetCommandFlags",		SetCommandFlags},
faluco@1643
  1405
	{"GetCommandFlags",		GetCommandFlags},
dvander@1795
  1406
	{"FindFirstConCommand",	FindFirstConCommand},
dvander@1795
  1407
	{"FindNextConCommand",	FindNextConCommand},
pred@1852
  1408
	{"SendConVarValue",		SendConVarValue},
pred@2648
  1409
	{"AddServerTag",		AddServerTag},
pred@2648
  1410
	{"RemoveServerTag",		RemoveServerTag},
dvander@498
  1411
	{NULL,					NULL}
dvander@498
  1412
};