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