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