core/PlayerManager.cpp
changeset 1952 b7aa2b626807
child 1993 8c08aaff4d39
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/core/PlayerManager.cpp	Sun Mar 30 07:00:22 2008 +0000
     1.3 @@ -0,0 +1,1558 @@
     1.4 +/**
     1.5 + * vim: set ts=4 :
     1.6 + * =============================================================================
     1.7 + * SourceMod
     1.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     1.9 + * =============================================================================
    1.10 + *
    1.11 + * This program is free software; you can redistribute it and/or modify it under
    1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    1.13 + * Free Software Foundation.
    1.14 + * 
    1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.18 + * details.
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License along with
    1.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.22 + *
    1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    1.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.30 + * or <http://www.sourcemod.net/license.php>.
    1.31 + *
    1.32 + * Version: $Id$
    1.33 + */
    1.34 +
    1.35 +#include "PlayerManager.h"
    1.36 +#include "ForwardSys.h"
    1.37 +#include "ShareSys.h"
    1.38 +#include "AdminCache.h"
    1.39 +#include "ConCmdManager.h"
    1.40 +#include "MenuStyle_Valve.h"
    1.41 +#include "MenuStyle_Radio.h"
    1.42 +#include "sm_stringutil.h"
    1.43 +#include "CoreConfig.h"
    1.44 +#include "TimerSys.h"
    1.45 +#include "Translator.h"
    1.46 +#include "Logger.h"
    1.47 +#include "ChatTriggers.h"
    1.48 +#include "HalfLife2.h"
    1.49 +#include <inetchannel.h>
    1.50 +#include <iclient.h>
    1.51 +#include "GameConfigs.h"
    1.52 +
    1.53 +PlayerManager g_Players;
    1.54 +bool g_OnMapStarted = false;
    1.55 +IForward *PreAdminCheck = NULL;
    1.56 +IForward *PostAdminCheck = NULL;
    1.57 +IForward *PostAdminFilter = NULL;
    1.58 +const unsigned int *g_NumPlayersToAuth = NULL;
    1.59 +int lifestate_offset = -1;
    1.60 +List<ICommandTargetProcessor *> target_processors;
    1.61 +
    1.62 +SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
    1.63 +SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
    1.64 +SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
    1.65 +#if defined ORANGEBOX_BUILD
    1.66 +SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *, const CCommand &);
    1.67 +#else
    1.68 +SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
    1.69 +#endif
    1.70 +SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
    1.71 +SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
    1.72 +
    1.73 +class KickPlayerTimer : public ITimedEvent
    1.74 +{
    1.75 +public:
    1.76 +	ResultType OnTimer(ITimer *pTimer, void *pData)
    1.77 +	{
    1.78 +		int userid = (int)pData;
    1.79 +		int client = g_Players.GetClientOfUserId(userid);
    1.80 +		if (client)
    1.81 +		{
    1.82 +			CPlayer *player = g_Players.GetPlayerByIndex(client);
    1.83 +			player->Kick("Your name is reserved by SourceMod; set your password to use it.");
    1.84 +		}
    1.85 +		return Pl_Stop;
    1.86 +	}
    1.87 +	void OnTimerEnd(ITimer *pTimer, void *pData)
    1.88 +	{
    1.89 +	}
    1.90 +} s_KickPlayerTimer;
    1.91 +
    1.92 +PlayerManager::PlayerManager()
    1.93 +{
    1.94 +	m_AuthQueue = NULL;
    1.95 +	m_FirstPass = false;
    1.96 +	m_maxClients = 0;
    1.97 +
    1.98 +	m_UserIdLookUp = new int[USHRT_MAX+1];
    1.99 +	memset(m_UserIdLookUp, 0, sizeof(int) * (USHRT_MAX+1));
   1.100 +}
   1.101 +
   1.102 +PlayerManager::~PlayerManager()
   1.103 +{
   1.104 +	g_NumPlayersToAuth = NULL;
   1.105 +
   1.106 +	delete [] m_AuthQueue;
   1.107 +	delete [] m_UserIdLookUp;
   1.108 +}
   1.109 +
   1.110 +void PlayerManager::OnSourceModAllInitialized()
   1.111 +{
   1.112 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false);
   1.113 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect_Post, true);
   1.114 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true);
   1.115 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false);
   1.116 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true);
   1.117 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false);
   1.118 +	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true);
   1.119 +	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true);
   1.120 +
   1.121 +	g_ShareSys.AddInterface(NULL, this);
   1.122 +
   1.123 +	ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
   1.124 +	ParamType p2[] = {Param_Cell};
   1.125 +
   1.126 +	m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
   1.127 +	m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
   1.128 +	m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
   1.129 +	m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
   1.130 +	m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
   1.131 +	m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
   1.132 +	m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
   1.133 +	m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
   1.134 +	m_onActivate2 = g_Forwards.CreateForward("OnMapStart", ET_Ignore, 0, NULL);
   1.135 +
   1.136 +	PreAdminCheck = g_Forwards.CreateForward("OnClientPreAdminCheck", ET_Event, 1, p1);
   1.137 +	PostAdminCheck = g_Forwards.CreateForward("OnClientPostAdminCheck", ET_Ignore, 1, p1);
   1.138 +	PostAdminFilter = g_Forwards.CreateForward("OnClientPostAdminFilter", ET_Ignore, 1, p1);
   1.139 +}
   1.140 +
   1.141 +void PlayerManager::OnSourceModShutdown()
   1.142 +{
   1.143 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false);
   1.144 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true);
   1.145 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false);
   1.146 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true);
   1.147 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false);
   1.148 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true);
   1.149 +	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true);
   1.150 +
   1.151 +	/* Release forwards */
   1.152 +	g_Forwards.ReleaseForward(m_clconnect);
   1.153 +	g_Forwards.ReleaseForward(m_clputinserver);
   1.154 +	g_Forwards.ReleaseForward(m_cldisconnect);
   1.155 +	g_Forwards.ReleaseForward(m_cldisconnect_post);
   1.156 +	g_Forwards.ReleaseForward(m_clcommand);
   1.157 +	g_Forwards.ReleaseForward(m_clinfochanged);
   1.158 +	g_Forwards.ReleaseForward(m_clauth);
   1.159 +	g_Forwards.ReleaseForward(m_onActivate);
   1.160 +	g_Forwards.ReleaseForward(m_onActivate2);
   1.161 +
   1.162 +	g_Forwards.ReleaseForward(PreAdminCheck);
   1.163 +	g_Forwards.ReleaseForward(PostAdminCheck);
   1.164 +	g_Forwards.ReleaseForward(PostAdminFilter);
   1.165 +
   1.166 +	delete [] m_Players;
   1.167 +}
   1.168 +
   1.169 +ConfigResult PlayerManager::OnSourceModConfigChanged(const char *key, 
   1.170 +												 const char *value, 
   1.171 +												 ConfigSource source, 
   1.172 +												 char *error, 
   1.173 +												 size_t maxlength)
   1.174 +{
   1.175 +	if (strcmp(key, "PassInfoVar") == 0)
   1.176 +	{
   1.177 +		if (strcmp(value, "_password") != 0)
   1.178 +		{
   1.179 +			m_PassInfoVar.assign(value);
   1.180 +		}
   1.181 +		return ConfigResult_Accept;
   1.182 +	} else if (strcmp(key, "AllowClLanguageVar") == 0) {
   1.183 +		if (strcasecmp(value, "on") == 0)
   1.184 +		{
   1.185 +			m_QueryLang = true;
   1.186 +		} else if (strcasecmp(value, "off") == 0) {
   1.187 +			m_QueryLang = false;
   1.188 +		} else {
   1.189 +			UTIL_Format(error, maxlength, "Invalid value: must be \"on\" or \"off\"");
   1.190 +			return ConfigResult_Reject;
   1.191 +		}
   1.192 +		return ConfigResult_Accept;
   1.193 +	}
   1.194 +	return ConfigResult_Ignore;
   1.195 +}
   1.196 +
   1.197 +void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
   1.198 +{
   1.199 +	if (!m_FirstPass)
   1.200 +	{
   1.201 +		/* Initialize all players */
   1.202 +		m_maxClients = clientMax;
   1.203 +		m_PlayerCount = 0;
   1.204 +		m_Players = new CPlayer[m_maxClients + 1];
   1.205 +		m_AuthQueue = new unsigned int[m_maxClients + 1];
   1.206 +		m_FirstPass = true;
   1.207 +
   1.208 +		memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
   1.209 +
   1.210 +		g_NumPlayersToAuth = &m_AuthQueue[0];
   1.211 +	}
   1.212 +	m_onActivate->Execute(NULL);
   1.213 +	m_onActivate2->Execute(NULL);
   1.214 +
   1.215 +	List<IClientListener *>::iterator iter;
   1.216 +	for (iter = m_hooks.begin(); iter != m_hooks.end(); iter++)
   1.217 +	{
   1.218 +		if ((*iter)->GetClientListenerVersion() >= 5)
   1.219 +		{
   1.220 +			(*iter)->OnServerActivated(clientMax);
   1.221 +		}
   1.222 +	}
   1.223 +
   1.224 +	g_OnMapStarted = true;
   1.225 +
   1.226 +	SM_ExecuteAllConfigs();
   1.227 +}
   1.228 +
   1.229 +bool PlayerManager::IsServerActivated()
   1.230 +{
   1.231 +	return m_FirstPass;
   1.232 +}
   1.233 +
   1.234 +bool PlayerManager::CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id)
   1.235 +{
   1.236 +	const char *password = g_Admins.GetAdminPassword(id);
   1.237 +	if (password != NULL)
   1.238 +	{
   1.239 +		if (m_PassInfoVar.size() < 1)
   1.240 +		{
   1.241 +			return false;
   1.242 +		}
   1.243 +
   1.244 +		/* Whoa... the user needs a password! */
   1.245 +		const char *given = engine->GetClientConVarValue(index, m_PassInfoVar.c_str());
   1.246 +		if (!given || strcmp(given, password) != 0)
   1.247 +		{
   1.248 +			return false;
   1.249 +		}
   1.250 +	}
   1.251 +
   1.252 +	pPlayer->SetAdminId(id, false);
   1.253 +
   1.254 +	return true;
   1.255 +}
   1.256 +
   1.257 +bool PlayerManager::CheckSetAdminName(int index, CPlayer *pPlayer, AdminId id)
   1.258 +{
   1.259 +	const char *password = g_Admins.GetAdminPassword(id);
   1.260 +	if (password == NULL)
   1.261 +	{
   1.262 +		return false;
   1.263 +	}
   1.264 +
   1.265 +	if (m_PassInfoVar.size() < 1)
   1.266 +	{
   1.267 +		return false;
   1.268 +	}
   1.269 +
   1.270 +	/* Whoa... the user needs a password! */
   1.271 +	const char *given = engine->GetClientConVarValue(index, m_PassInfoVar.c_str());
   1.272 +	if (!given || strcmp(given, password) != 0)
   1.273 +	{
   1.274 +		return false;
   1.275 +	}
   1.276 +
   1.277 +	pPlayer->SetAdminId(id, false);
   1.278 +
   1.279 +	return true;
   1.280 +}
   1.281 +
   1.282 +void PlayerManager::RunAuthChecks()
   1.283 +{
   1.284 +	CPlayer *pPlayer;
   1.285 +	const char *authstr;
   1.286 +	unsigned int removed = 0;
   1.287 +	for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   1.288 +	{
   1.289 +		pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
   1.290 +		authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
   1.291 +		if (authstr && authstr[0] != '\0'
   1.292 +			&& (strcmp(authstr, "STEAM_ID_PENDING") != 0))
   1.293 +		{
   1.294 +			/* Set authorization */
   1.295 +			pPlayer->Authorize(authstr);
   1.296 +
   1.297 +			/* Mark as removed from queue */
   1.298 +			unsigned int client = m_AuthQueue[i];
   1.299 +			m_AuthQueue[i] = 0;
   1.300 +			removed++;
   1.301 +
   1.302 +			/* Send to extensions */
   1.303 +			List<IClientListener *>::iterator iter;
   1.304 +			IClientListener *pListener;
   1.305 +			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.306 +			{
   1.307 +				pListener = (*iter);
   1.308 +				pListener->OnClientAuthorized(client, authstr);
   1.309 +				if (!pPlayer->IsConnected())
   1.310 +				{
   1.311 +					break;
   1.312 +				}
   1.313 +			}
   1.314 +
   1.315 +			/* Send to plugins if player is still connected */
   1.316 +			if (pPlayer->IsConnected() && m_clauth->GetFunctionCount())
   1.317 +			{
   1.318 +				/* :TODO: handle the case of a player disconnecting in the middle */
   1.319 +				m_clauth->PushCell(client);
   1.320 +				m_clauth->PushString(authstr);
   1.321 +				m_clauth->Execute(NULL);
   1.322 +			}
   1.323 +
   1.324 +			if (pPlayer->IsConnected())
   1.325 +			{
   1.326 +				pPlayer->Authorize_Post();
   1.327 +			}
   1.328 +		}
   1.329 +	}
   1.330 +
   1.331 +	/* Clean up the queue */
   1.332 +	if (removed)
   1.333 +	{
   1.334 +		/* We don't have to compact the list if it's empty */
   1.335 +		if (removed != m_AuthQueue[0])
   1.336 +		{
   1.337 +			unsigned int diff = 0;
   1.338 +			for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   1.339 +			{
   1.340 +				/* If this member is removed... */
   1.341 +				if (m_AuthQueue[i] == 0)
   1.342 +				{
   1.343 +					/* Increase the differential */
   1.344 +					diff++;
   1.345 +				} else {
   1.346 +					/* diff cannot increase faster than i+1 */
   1.347 +					assert(i > diff);
   1.348 +					assert(i - diff >= 1);
   1.349 +					/* move this index down */
   1.350 +					m_AuthQueue[i - diff] = m_AuthQueue[i];
   1.351 +				}
   1.352 +			}
   1.353 +			m_AuthQueue[0] -= removed;
   1.354 +		} else {
   1.355 +			m_AuthQueue[0] = 0;
   1.356 +		}
   1.357 +	}
   1.358 +}
   1.359 +
   1.360 +bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
   1.361 +{
   1.362 +	int client = engine->IndexOfEdict(pEntity);
   1.363 +
   1.364 +	List<IClientListener *>::iterator iter;
   1.365 +	IClientListener *pListener = NULL;
   1.366 +	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.367 +	{
   1.368 +		pListener = (*iter);
   1.369 +		if (!pListener->InterceptClientConnect(client, reject, maxrejectlen))
   1.370 +		{
   1.371 +			return false;
   1.372 +		}
   1.373 +	}
   1.374 +
   1.375 +	cell_t res = 1;
   1.376 +
   1.377 +	m_Players[client].Initialize(pszName, pszAddress, pEntity);
   1.378 +	m_clconnect->PushCell(client);
   1.379 +	m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK);
   1.380 +	m_clconnect->PushCell(maxrejectlen);
   1.381 +	m_clconnect->Execute(&res, NULL);
   1.382 +
   1.383 +	if (res)
   1.384 +	{
   1.385 +		if (!m_Players[client].IsAuthorized())
   1.386 +		{
   1.387 +			m_AuthQueue[++m_AuthQueue[0]] = client;
   1.388 +		}
   1.389 +	} else {
   1.390 +		RETURN_META_VALUE(MRES_SUPERCEDE, false);
   1.391 +	}
   1.392 +
   1.393 +	m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = client;
   1.394 +
   1.395 +	return true;
   1.396 +}
   1.397 +
   1.398 +bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
   1.399 +{
   1.400 +	int client = engine->IndexOfEdict(pEntity);
   1.401 +	bool orig_value = META_RESULT_ORIG_RET(bool);
   1.402 +	CPlayer *pPlayer = GetPlayerByIndex(client);
   1.403 +
   1.404 +	if (orig_value)
   1.405 +	{
   1.406 +		List<IClientListener *>::iterator iter;
   1.407 +		IClientListener *pListener = NULL;
   1.408 +		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.409 +		{
   1.410 +			pListener = (*iter);
   1.411 +			pListener->OnClientConnected(client);
   1.412 +			if (!pPlayer->IsConnected())
   1.413 +			{
   1.414 +				break;
   1.415 +			}
   1.416 +		}
   1.417 +	}
   1.418 +
   1.419 +	return true;
   1.420 +}
   1.421 +
   1.422 +void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername)
   1.423 +{
   1.424 +	cell_t res;
   1.425 +	int client = engine->IndexOfEdict(pEntity);
   1.426 +
   1.427 +	CPlayer *pPlayer = GetPlayerByIndex(client);
   1.428 +	/* If they're not connected, they're a bot */
   1.429 +	if (!pPlayer->IsConnected())
   1.430 +	{
   1.431 +		/* Run manual connection routines */
   1.432 +		char error[255];
   1.433 +		const char *authid = engine->GetPlayerNetworkIDString(pEntity);
   1.434 +		pPlayer->Authorize(authid);
   1.435 +		if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
   1.436 +		{
   1.437 +			/* :TODO: kick the bot if it's rejected */
   1.438 +			return;
   1.439 +		}
   1.440 +		List<IClientListener *>::iterator iter;
   1.441 +		IClientListener *pListener = NULL;
   1.442 +		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.443 +		{
   1.444 +			pListener = (*iter);
   1.445 +			pListener->OnClientConnected(client);
   1.446 +			/* See if bot was kicked */
   1.447 +			if (!pPlayer->IsConnected())
   1.448 +			{
   1.449 +				return;
   1.450 +			}
   1.451 +		}
   1.452 +		/* Now do authorization */
   1.453 +		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.454 +		{
   1.455 +			pListener = (*iter);
   1.456 +			pListener->OnClientAuthorized(client, authid);
   1.457 +		}
   1.458 +		/* Finally, tell plugins */
   1.459 +		if (m_clauth->GetFunctionCount())
   1.460 +		{
   1.461 +			m_clauth->PushCell(client);
   1.462 +			m_clauth->PushString(authid);
   1.463 +			m_clauth->Execute(NULL);
   1.464 +		}
   1.465 +		pPlayer->Authorize_Post();
   1.466 +	}
   1.467 +
   1.468 +	if (playerinfo)
   1.469 +	{
   1.470 +		pPlayer->m_Info = playerinfo->GetPlayerInfo(pEntity);
   1.471 +	}
   1.472 +
   1.473 +	/* Get the client's language */
   1.474 +	if (m_QueryLang)
   1.475 +	{
   1.476 +		const char *name;
   1.477 +		if (!pPlayer->IsFakeClient() && (name=engine->GetClientConVarValue(client, "cl_language")))
   1.478 +		{
   1.479 +			unsigned int langid;
   1.480 +			pPlayer->m_LangId = (g_Translator.GetLanguageByName(name, &langid)) ? langid : g_Translator.GetServerLanguage();
   1.481 +		} else {
   1.482 +			pPlayer->m_LangId = g_Translator.GetServerLanguage();
   1.483 +		}
   1.484 +	}
   1.485 +
   1.486 +	m_Players[client].Connect();
   1.487 +	m_PlayerCount++;
   1.488 +
   1.489 +	List<IClientListener *>::iterator iter;
   1.490 +	IClientListener *pListener = NULL;
   1.491 +	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.492 +	{
   1.493 +		pListener = (*iter);
   1.494 +		pListener->OnClientPutInServer(client);
   1.495 +	}
   1.496 +
   1.497 +	m_clputinserver->PushCell(client);
   1.498 +	m_clputinserver->Execute(&res, NULL);
   1.499 +
   1.500 +	if (m_Players[client].IsAuthorized())
   1.501 +	{
   1.502 +		m_Players[client].DoPostConnectAuthorization();
   1.503 +	}
   1.504 +}
   1.505 +
   1.506 +void PlayerManager::OnSourceModLevelEnd()
   1.507 +{
   1.508 +	/* Disconnect all bots still in game */
   1.509 +	for (int i=1; i<=m_maxClients; i++)
   1.510 +	{
   1.511 +		if (m_Players[i].IsConnected())
   1.512 +		{
   1.513 +			OnClientDisconnect(m_Players[i].GetEdict());
   1.514 +		}
   1.515 +	}
   1.516 +	m_PlayerCount = 0;
   1.517 +}
   1.518 +
   1.519 +void PlayerManager::OnClientDisconnect(edict_t *pEntity)
   1.520 +{
   1.521 +	cell_t res;
   1.522 +	int client = engine->IndexOfEdict(pEntity);
   1.523 +
   1.524 +	if (m_Players[client].IsConnected())
   1.525 +	{
   1.526 +		m_cldisconnect->PushCell(client);
   1.527 +		m_cldisconnect->Execute(&res, NULL);
   1.528 +	} else {
   1.529 +		/* We don't care, prevent a double call */
   1.530 +		return;
   1.531 +	}
   1.532 +
   1.533 +	if (m_Players[client].WasCountedAsInGame())
   1.534 +	{
   1.535 +		m_PlayerCount--;
   1.536 +	}
   1.537 +
   1.538 +	List<IClientListener *>::iterator iter;
   1.539 +	IClientListener *pListener = NULL;
   1.540 +	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.541 +	{
   1.542 +		pListener = (*iter);
   1.543 +		pListener->OnClientDisconnecting(client);
   1.544 +	}
   1.545 +
   1.546 +	/**
   1.547 +	 * Remove client from auth queue if necessary
   1.548 +	 */
   1.549 +	if (!m_Players[client].IsAuthorized())
   1.550 +	{
   1.551 +		for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   1.552 +		{
   1.553 +			if (m_AuthQueue[i] == (unsigned)client)
   1.554 +			{
   1.555 +				/* Move everything ahead of us back by one */
   1.556 +				for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
   1.557 +				{
   1.558 +					m_AuthQueue[j-1] = m_AuthQueue[j];
   1.559 +				}
   1.560 +				/* Remove us and break */
   1.561 +				m_AuthQueue[0]--;
   1.562 +				break;
   1.563 +			}
   1.564 +		}
   1.565 +	}
   1.566 +
   1.567 +	m_Players[client].Disconnect();
   1.568 +	m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = 0;
   1.569 +}
   1.570 +
   1.571 +void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
   1.572 +{
   1.573 +	cell_t res;
   1.574 +	int client = engine->IndexOfEdict(pEntity);
   1.575 +
   1.576 +	m_cldisconnect_post->PushCell(client);
   1.577 +	m_cldisconnect_post->Execute(&res, NULL);
   1.578 +
   1.579 +	List<IClientListener *>::iterator iter;
   1.580 +	IClientListener *pListener = NULL;
   1.581 +	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   1.582 +	{
   1.583 +		pListener = (*iter);
   1.584 +		pListener->OnClientDisconnected(client);
   1.585 +	}
   1.586 +}
   1.587 +
   1.588 +#if defined ORANGEBOX_BUILD
   1.589 +void PlayerManager::OnClientCommand(edict_t *pEntity, const CCommand &args)
   1.590 +{
   1.591 +#else
   1.592 +void PlayerManager::OnClientCommand(edict_t *pEntity)
   1.593 +{
   1.594 +	CCommand args;
   1.595 +#endif
   1.596 +	int client = engine->IndexOfEdict(pEntity);
   1.597 +	cell_t res = Pl_Continue;
   1.598 +
   1.599 +	CPlayer *pPlayer = GetPlayerByIndex(client);
   1.600 +	if (!pPlayer || !pPlayer->IsConnected())
   1.601 +	{
   1.602 +		return;
   1.603 +	}
   1.604 +
   1.605 +	g_HL2.PushCommandStack(&args);
   1.606 +
   1.607 +	int argcount = args.ArgC() - 1;
   1.608 +	const char *cmd = g_HL2.CurrentCommandName();
   1.609 +
   1.610 +	bool result = g_ValveMenuStyle.OnClientCommand(client, cmd, args);
   1.611 +	if (result)
   1.612 +	{
   1.613 +		res = Pl_Handled;
   1.614 +	} else {
   1.615 +		result = g_RadioMenuStyle.OnClientCommand(client, cmd, args);
   1.616 +		if (result)
   1.617 +		{
   1.618 +			res = Pl_Handled;
   1.619 +		}
   1.620 +	}
   1.621 +
   1.622 +	cell_t res2 = Pl_Continue;
   1.623 +	m_clcommand->PushCell(client);
   1.624 +	m_clcommand->PushCell(argcount);
   1.625 +	m_clcommand->Execute(&res2, NULL);
   1.626 +
   1.627 +	if (res2 > res)
   1.628 +	{
   1.629 +		res = res2;
   1.630 +	}
   1.631 +
   1.632 +	if (res >= Pl_Stop)
   1.633 +	{
   1.634 +		g_HL2.PopCommandStack();
   1.635 +		RETURN_META(MRES_SUPERCEDE);
   1.636 +	}
   1.637 +
   1.638 +	res = g_ConCmds.DispatchClientCommand(client, cmd, argcount, (ResultType)res);
   1.639 +
   1.640 +	g_HL2.PopCommandStack();
   1.641 +
   1.642 +	if (res >= Pl_Handled)
   1.643 +	{
   1.644 +		RETURN_META(MRES_SUPERCEDE);
   1.645 +	}
   1.646 +}
   1.647 +
   1.648 +void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
   1.649 +{
   1.650 +	cell_t res;
   1.651 +	int client = engine->IndexOfEdict(pEntity);
   1.652 +
   1.653 +	if (!m_Players[client].IsConnected())
   1.654 +	{
   1.655 +		return;
   1.656 +	}
   1.657 +
   1.658 +	m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity));
   1.659 +	m_clinfochanged->Execute(&res, NULL);
   1.660 +
   1.661 +	IPlayerInfo *info = m_Players[client].GetPlayerInfo();
   1.662 +	const char *new_name = info ? info->GetName() : engine->GetClientConVarValue(client, "name");
   1.663 +	const char *old_name = m_Players[client].m_Name.c_str();
   1.664 +
   1.665 +	if (strcmp(old_name, new_name) != 0)
   1.666 +	{
   1.667 +		AdminId id = g_Admins.FindAdminByIdentity("name", new_name);
   1.668 +		if (id != INVALID_ADMIN_ID && m_Players[client].GetAdminId() != id)
   1.669 +		{
   1.670 +			if (!CheckSetAdminName(client, &m_Players[client], id))
   1.671 +			{
   1.672 +				m_Players[client].Kick("Your name is reserved by SourceMod; set your password to use it.");
   1.673 +				RETURN_META(MRES_IGNORED);
   1.674 +			}
   1.675 +		} else if ((id = g_Admins.FindAdminByIdentity("name", old_name)) != INVALID_ADMIN_ID) {
   1.676 +			if (id == m_Players[client].GetAdminId())
   1.677 +			{
   1.678 +				/* This player is changing their name; force them to drop admin privileges! */
   1.679 +				m_Players[client].SetAdminId(INVALID_ADMIN_ID, false);
   1.680 +			}
   1.681 +		}
   1.682 +		m_Players[client].SetName(new_name);
   1.683 +	}
   1.684 +	
   1.685 +	if (m_PassInfoVar.size() > 0)
   1.686 +	{
   1.687 +		/* Try for a password change */
   1.688 +		const char *old_pass = m_Players[client].m_LastPassword.c_str();
   1.689 +		const char *new_pass = engine->GetClientConVarValue(client, m_PassInfoVar.c_str());
   1.690 +		if (strcmp(old_pass, new_pass) != 0)
   1.691 +		{
   1.692 +			m_Players[client].m_LastPassword.assign(new_pass);
   1.693 +			if (m_Players[client].IsInGame() && m_Players[client].IsAuthorized())
   1.694 +			{
   1.695 +				/* If there is already an admin id assigned, this will just bail out. */
   1.696 +				m_Players[client].DoBasicAdminChecks();
   1.697 +			}
   1.698 +		}
   1.699 +	}
   1.700 +}
   1.701 +
   1.702 +int PlayerManager::GetMaxClients()
   1.703 +{
   1.704 +	return m_maxClients;
   1.705 +}
   1.706 +
   1.707 +CPlayer *PlayerManager::GetPlayerByIndex(int client) const
   1.708 +{
   1.709 +	if (client > m_maxClients || client < 1)
   1.710 +	{
   1.711 +		return NULL;
   1.712 +	}
   1.713 +	return &m_Players[client];
   1.714 +}
   1.715 +
   1.716 +int PlayerManager::GetNumPlayers()
   1.717 +{
   1.718 +	return m_PlayerCount;
   1.719 +}
   1.720 +
   1.721 +int PlayerManager::GetClientOfUserId(int userid)
   1.722 +{
   1.723 +	if (userid < 0 || userid > USHRT_MAX)
   1.724 +	{
   1.725 +		return 0;
   1.726 +	}
   1.727 +	
   1.728 +	int client = m_UserIdLookUp[userid];
   1.729 +
   1.730 +	/* Verify the userid.  The cache can get messed up with older
   1.731 +	 * Valve engines.  :TODO: If this gets fixed, do an old engine 
   1.732 +	 * check before invoking this backwards compat code.
   1.733 +	 */
   1.734 +	if (client)
   1.735 +	{
   1.736 +		CPlayer *player = GetPlayerByIndex(client);
   1.737 +		if (player && player->IsConnected())
   1.738 +		{
   1.739 +			int realUserId = engine->GetPlayerUserId(player->GetEdict());
   1.740 +			if (realUserId == userid)
   1.741 +			{
   1.742 +				return client;
   1.743 +			}
   1.744 +		}
   1.745 +	}
   1.746 +
   1.747 +	/* If we can't verify the userid, we have to do a manual loop */
   1.748 +	CPlayer *player;
   1.749 +	for (int i = 1; i <= m_maxClients; i++)
   1.750 +	{
   1.751 +		player = GetPlayerByIndex(i);
   1.752 +		if (!player || !player->IsConnected())
   1.753 +		{
   1.754 +			continue;
   1.755 +		}
   1.756 +		if (engine->GetPlayerUserId(player->GetEdict()) == userid)
   1.757 +		{
   1.758 +			m_UserIdLookUp[userid] = i;
   1.759 +			return i;
   1.760 +		}
   1.761 +	}
   1.762 +
   1.763 +	return 0;
   1.764 +}
   1.765 +
   1.766 +void PlayerManager::AddClientListener(IClientListener *listener)
   1.767 +{
   1.768 +	m_hooks.push_back(listener);
   1.769 +}
   1.770 +
   1.771 +void PlayerManager::RemoveClientListener(IClientListener *listener)
   1.772 +{
   1.773 +	m_hooks.remove(listener);
   1.774 +}
   1.775 +
   1.776 +IGamePlayer *PlayerManager::GetGamePlayer(edict_t *pEdict)
   1.777 +{
   1.778 +	int index = engine->IndexOfEdict(pEdict);
   1.779 +	return GetGamePlayer(index);
   1.780 +}
   1.781 +
   1.782 +IGamePlayer *PlayerManager::GetGamePlayer(int client)
   1.783 +{
   1.784 +	return GetPlayerByIndex(client);
   1.785 +}
   1.786 +
   1.787 +void PlayerManager::ClearAdminId(AdminId id)
   1.788 +{
   1.789 +	for (int i=1; i<=m_maxClients; i++)
   1.790 +	{
   1.791 +		if (m_Players[i].m_Admin == id)
   1.792 +		{
   1.793 +			m_Players[i].DumpAdmin(true);
   1.794 +		}
   1.795 +	}
   1.796 +}
   1.797 +
   1.798 +void PlayerManager::ClearAllAdmins()
   1.799 +{
   1.800 +	for (int i=1; i<=m_maxClients; i++)
   1.801 +	{
   1.802 +		m_Players[i].DumpAdmin(true);
   1.803 +	}
   1.804 +}
   1.805 +
   1.806 +const char *PlayerManager::GetPassInfoVar()
   1.807 +{
   1.808 +	return m_PassInfoVar.c_str();
   1.809 +}
   1.810 +
   1.811 +void PlayerManager::RecheckAnyAdmins()
   1.812 +{
   1.813 +	for (int i=1; i<=m_maxClients; i++)
   1.814 +	{
   1.815 +		if (m_Players[i].IsInGame() && m_Players[i].IsAuthorized())
   1.816 +		{
   1.817 +			m_Players[i].DoBasicAdminChecks();
   1.818 +		}
   1.819 +	}
   1.820 +}
   1.821 +
   1.822 +unsigned int PlayerManager::GetReplyTo()
   1.823 +{
   1.824 +	return g_ChatTriggers.GetReplyTo();
   1.825 +}
   1.826 +
   1.827 +unsigned int PlayerManager::SetReplyTo(unsigned int reply)
   1.828 +{
   1.829 +	return g_ChatTriggers.SetReplyTo(reply);
   1.830 +}
   1.831 +
   1.832 +int PlayerManager::FilterCommandTarget(IGamePlayer *pAdmin, IGamePlayer *pTarget, int flags)
   1.833 +{
   1.834 +	return InternalFilterCommandTarget((CPlayer *)pAdmin, (CPlayer *)pTarget, flags);
   1.835 +}
   1.836 +
   1.837 +void PlayerManager::RegisterCommandTargetProcessor(ICommandTargetProcessor *pHandler)
   1.838 +{
   1.839 +	target_processors.push_back(pHandler);
   1.840 +}
   1.841 +
   1.842 +void PlayerManager::UnregisterCommandTargetProcessor(ICommandTargetProcessor *pHandler)
   1.843 +{
   1.844 +	target_processors.remove(pHandler);
   1.845 +}
   1.846 +
   1.847 +int PlayerManager::InternalFilterCommandTarget(CPlayer *pAdmin, CPlayer *pTarget, int flags)
   1.848 +{
   1.849 +	if ((flags & COMMAND_FILTER_CONNECTED) == COMMAND_FILTER_CONNECTED
   1.850 +		&& !pTarget->IsConnected())
   1.851 +	{
   1.852 +		return COMMAND_TARGET_NONE;
   1.853 +	}
   1.854 +	else if ((flags & COMMAND_FILTER_CONNECTED) != COMMAND_FILTER_CONNECTED && 
   1.855 +		!pTarget->IsInGame())
   1.856 +	{
   1.857 +		return COMMAND_TARGET_NOT_IN_GAME;
   1.858 +	}
   1.859 +
   1.860 +	if ((flags & COMMAND_FILTER_NO_BOTS) == COMMAND_FILTER_NO_BOTS
   1.861 +		&& pTarget->IsFakeClient())
   1.862 +	{
   1.863 +		return COMMAND_TARGET_NOT_HUMAN;
   1.864 +	}
   1.865 +
   1.866 +	if (pAdmin != NULL)
   1.867 +	{
   1.868 +		if ((flags & COMMAND_FILTER_NO_IMMUNITY) != COMMAND_FILTER_NO_IMMUNITY
   1.869 +			&& !g_Admins.CanAdminTarget(pAdmin->GetAdminId(), pTarget->GetAdminId()))
   1.870 +		{
   1.871 +			return COMMAND_TARGET_IMMUNE;
   1.872 +		}
   1.873 +	}
   1.874 +
   1.875 +	if ((flags & COMMAND_FILTER_ALIVE) == COMMAND_FILTER_ALIVE 
   1.876 +		&& pTarget->GetLifeState() != PLAYER_LIFE_ALIVE)
   1.877 +	{
   1.878 +		return COMMAND_TARGET_NOT_ALIVE;
   1.879 +	}
   1.880 +
   1.881 +	if ((flags & COMMAND_FILTER_DEAD) == COMMAND_FILTER_DEAD
   1.882 +		&& pTarget->GetLifeState() != PLAYER_LIFE_DEAD)
   1.883 +	{
   1.884 +		return COMMAND_TARGET_NOT_DEAD;
   1.885 +	}
   1.886 +
   1.887 +	return COMMAND_TARGET_VALID;
   1.888 +}
   1.889 +
   1.890 +void PlayerManager::ProcessCommandTarget(cmd_target_info_t *info)
   1.891 +{
   1.892 +	CPlayer *pTarget, *pAdmin;
   1.893 +	int max_clients, total = 0;
   1.894 +
   1.895 +	max_clients = GetMaxClients();
   1.896 +
   1.897 +	if (info->max_targets < 1)
   1.898 +	{
   1.899 +		info->reason = COMMAND_TARGET_NONE;
   1.900 +		info->num_targets = 0;
   1.901 +	}
   1.902 +
   1.903 +	if (info->admin == 0)
   1.904 +	{
   1.905 +		pAdmin = NULL;
   1.906 +	}
   1.907 +	else
   1.908 +	{
   1.909 +		pAdmin = GetPlayerByIndex(info->admin);
   1.910 +	}
   1.911 +
   1.912 +	if (info->pattern[0] == '#')
   1.913 +	{
   1.914 +		int userid = atoi(&info->pattern[1]);
   1.915 +		int client = GetClientOfUserId(userid);
   1.916 +
   1.917 +		/* See if a valid userid matched */
   1.918 +		if (client > 0)
   1.919 +		{
   1.920 +			IGamePlayer *pTarget = GetPlayerByIndex(client);
   1.921 +			if (pTarget != NULL)
   1.922 +			{
   1.923 +				if ((info->reason = FilterCommandTarget(pAdmin, pTarget, info->flags)) == COMMAND_TARGET_VALID)
   1.924 +				{
   1.925 +					info->targets[0] = client;
   1.926 +					info->num_targets = 1;
   1.927 +					strncopy(info->target_name, pTarget->GetName(), info->target_name_maxlength);
   1.928 +					info->target_name_style = COMMAND_TARGETNAME_RAW;
   1.929 +				}
   1.930 +				else
   1.931 +				{
   1.932 +					info->num_targets = 0;
   1.933 +				}
   1.934 +				return;
   1.935 +			}
   1.936 +		}
   1.937 +
   1.938 +		/* Do we need to look for a steam id? */
   1.939 +		if (strncmp(&info->pattern[1], "STEAM_", 6) == 0)
   1.940 +		{
   1.941 +			size_t p, len;
   1.942 +			char new_pattern[256];
   1.943 +
   1.944 +			strcpy(new_pattern, "STEAM_");
   1.945 +			len = strlen(&info->pattern[7]);
   1.946 +			for (p = 0; p < len; p++)
   1.947 +			{
   1.948 +				new_pattern[6 + p] = info->pattern[7 + p];
   1.949 +				if (new_pattern[6 + p] == '_')
   1.950 +				{
   1.951 +					new_pattern[6 + p] = ':';
   1.952 +				}
   1.953 +			}
   1.954 +			new_pattern[6 + p] = '\0';
   1.955 +
   1.956 +			for (int i = 1; i <= max_clients; i++)
   1.957 +			{
   1.958 +				if ((pTarget = GetPlayerByIndex(i)) == NULL)
   1.959 +				{
   1.960 +					continue;
   1.961 +				}
   1.962 +				if (!pTarget->IsConnected() || !pTarget->IsAuthorized())
   1.963 +				{
   1.964 +					continue;
   1.965 +				}
   1.966 +				if (strcmp(pTarget->GetAuthString(), new_pattern) == 0)
   1.967 +				{
   1.968 +					if ((info->reason = FilterCommandTarget(pAdmin, pTarget, info->flags))
   1.969 +						== COMMAND_TARGET_VALID)
   1.970 +					{
   1.971 +						info->targets[0] = i;
   1.972 +						info->num_targets = 1;
   1.973 +						strncopy(info->target_name, pTarget->GetName(), info->target_name_maxlength);
   1.974 +						info->target_name_style = COMMAND_TARGETNAME_RAW;
   1.975 +					}
   1.976 +					else
   1.977 +					{
   1.978 +						info->num_targets = 0;
   1.979 +					}
   1.980 +					return;
   1.981 +				}
   1.982 +			}
   1.983 +		}
   1.984 +
   1.985 +		/* See if an exact name matches */
   1.986 +		for (int i = 1; i <= max_clients; i++)
   1.987 +		{
   1.988 +			if ((pTarget = GetPlayerByIndex(i)) == NULL)
   1.989 +			{
   1.990 +				continue;
   1.991 +			}
   1.992 +			if  (!pTarget->IsConnected())
   1.993 +			{
   1.994 +				continue;
   1.995 +			}
   1.996 +			if (strcmp(pTarget->GetName(), &info->pattern[1]) == 0)
   1.997 +			{
   1.998 +				if ((info->reason = FilterCommandTarget(pAdmin, pTarget, info->flags))
   1.999 +					== COMMAND_TARGET_VALID)
  1.1000 +				{
  1.1001 +					info->targets[0] = i;
  1.1002 +					info->num_targets = 1;
  1.1003 +					strncopy(info->target_name, pTarget->GetName(), info->target_name_maxlength);
  1.1004 +					info->target_name_style = COMMAND_TARGETNAME_RAW;
  1.1005 +				}
  1.1006 +				else
  1.1007 +				{
  1.1008 +					info->num_targets = 0;
  1.1009 +				}
  1.1010 +				return;
  1.1011 +			}
  1.1012 +		}
  1.1013 +	}
  1.1014 +
  1.1015 +	if (strcmp(info->pattern, "@me") == 0 && info->admin != 0)
  1.1016 +	{
  1.1017 +		info->targets[0] = info->admin;
  1.1018 +		info->num_targets = 1;
  1.1019 +		strncopy(info->target_name, pAdmin->GetName(), info->target_name_maxlength);
  1.1020 +		info->target_name_style = COMMAND_TARGETNAME_RAW;
  1.1021 +		return;
  1.1022 +	}
  1.1023 +
  1.1024 +	if ((info->flags & COMMAND_FILTER_NO_MULTI) != COMMAND_FILTER_NO_MULTI)
  1.1025 +	{
  1.1026 +		bool is_multi = false;
  1.1027 +		bool bots_only = false;
  1.1028 +		int skip_client = -1;
  1.1029 +
  1.1030 +		if (strcmp(info->pattern, "@all") == 0)
  1.1031 +		{
  1.1032 +			is_multi = true;
  1.1033 +			strncopy(info->target_name, "all players", info->target_name_maxlength);
  1.1034 +			info->target_name_style = COMMAND_TARGETNAME_ML;
  1.1035 +		}
  1.1036 +		else if (strcmp(info->pattern, "@dead") == 0)
  1.1037 +		{
  1.1038 +			is_multi = true;
  1.1039 +			if ((info->flags & COMMAND_FILTER_ALIVE) == COMMAND_FILTER_ALIVE)
  1.1040 +			{
  1.1041 +				info->num_targets = 0;
  1.1042 +				info->reason = COMMAND_TARGET_NOT_ALIVE;
  1.1043 +				return;
  1.1044 +			}
  1.1045 +			info->flags |= COMMAND_FILTER_DEAD;
  1.1046 +			strncopy(info->target_name, "all dead players", info->target_name_maxlength);
  1.1047 +			info->target_name_style = COMMAND_TARGETNAME_ML;
  1.1048 +		}
  1.1049 +		else if (strcmp(info->pattern, "@alive") == 0)
  1.1050 +		{
  1.1051 +			is_multi = true;
  1.1052 +			if ((info->flags & COMMAND_FILTER_DEAD) == COMMAND_FILTER_DEAD)
  1.1053 +			{
  1.1054 +				info->num_targets = 0;
  1.1055 +				info->reason = COMMAND_TARGET_NOT_DEAD;
  1.1056 +				return;
  1.1057 +			}
  1.1058 +			strncopy(info->target_name, "all alive players", info->target_name_maxlength);
  1.1059 +			info->target_name_style = COMMAND_TARGETNAME_ML;
  1.1060 +			info->flags |= COMMAND_FILTER_ALIVE;
  1.1061 +		}
  1.1062 +		else if (strcmp(info->pattern, "@bots") == 0)
  1.1063 +		{
  1.1064 +			is_multi = true;
  1.1065 +			if ((info->flags & COMMAND_FILTER_NO_BOTS) == COMMAND_FILTER_NO_BOTS)
  1.1066 +			{
  1.1067 +				info->num_targets = 0;
  1.1068 +				info->reason = COMMAND_FILTER_NO_BOTS;
  1.1069 +				return;
  1.1070 +			}
  1.1071 +			strncopy(info->target_name, "all bots", info->target_name_maxlength);
  1.1072 +			info->target_name_style = COMMAND_TARGETNAME_ML;
  1.1073 +			bots_only = true;
  1.1074 +		}
  1.1075 +		else if (strcmp(info->pattern, "@humans") == 0)
  1.1076 +		{
  1.1077 +			is_multi = true;
  1.1078 +			strncopy(info->target_name, "all humans", info->target_name_maxlength);
  1.1079 +			info->target_name_style = COMMAND_TARGETNAME_ML;
  1.1080 +			info->flags |= COMMAND_FILTER_NO_BOTS;
  1.1081 +		}
  1.1082 +		else if (strcmp(info->pattern, "@!me") == 0)
  1.1083 +		{
  1.1084 +			is_multi = true;
  1.1085 +			strncopy(info->target_name, "all players", info->target_name_maxlength);
  1.1086 +			info->target_name_style = COMMAND_TARGETNAME_ML;
  1.1087 +			skip_client = info->admin;
  1.1088 +		}
  1.1089 +
  1.1090 +		if (is_multi)
  1.1091 +		{
  1.1092 +			for (int i = 1; i <= max_clients && total < info->max_targets; i++)
  1.1093 +			{
  1.1094 +				if ((pTarget = GetPlayerByIndex(i)) == NULL)
  1.1095 +				{
  1.1096 +					continue;
  1.1097 +				}
  1.1098 +				if (FilterCommandTarget(pAdmin, pTarget, info->flags) > 0)
  1.1099 +				{
  1.1100 +					if ((!bots_only || pTarget->IsFakeClient())
  1.1101 +						&& skip_client != i)
  1.1102 +					{
  1.1103 +						info->targets[total++] = i;
  1.1104 +					}
  1.1105 +				}
  1.1106 +			}
  1.1107 +
  1.1108 +			info->num_targets = total;
  1.1109 +			info->reason = (info->num_targets) ? COMMAND_TARGET_VALID : COMMAND_TARGET_EMPTY_FILTER;
  1.1110 +			return;
  1.1111 +		}
  1.1112 +	}
  1.1113 +
  1.1114 +	List<ICommandTargetProcessor *>::iterator iter;
  1.1115 +	for (iter = target_processors.begin(); iter != target_processors.end(); iter++)
  1.1116 +	{
  1.1117 +		ICommandTargetProcessor *pProcessor = (*iter);
  1.1118 +		if (pProcessor->ProcessCommandTarget(info))
  1.1119 +		{
  1.1120 +			return;
  1.1121 +		}
  1.1122 +	}
  1.1123 +
  1.1124 +	/* Check partial names */
  1.1125 +	int found_client = 0;
  1.1126 +	CPlayer *pFoundClient = NULL;
  1.1127 +	for (int i = 1; i <= max_clients; i++)
  1.1128 +	{
  1.1129 +		if ((pTarget = GetPlayerByIndex(i)) == NULL)
  1.1130 +		{
  1.1131 +			continue;
  1.1132 +		}
  1.1133 +
  1.1134 +		if (stristr(pTarget->GetName(), info->pattern) != NULL)
  1.1135 +		{
  1.1136 +			if (found_client)
  1.1137 +			{
  1.1138 +				info->num_targets = 0;
  1.1139 +				info->reason = COMMAND_TARGET_AMBIGUOUS;
  1.1140 +				return;
  1.1141 +			}
  1.1142 +			else
  1.1143 +			{
  1.1144 +				found_client = i;
  1.1145 +				pFoundClient = pTarget;
  1.1146 +			}
  1.1147 +		}
  1.1148 +	}
  1.1149 +
  1.1150 +	if (found_client)
  1.1151 +	{
  1.1152 +		if ((info->reason = FilterCommandTarget(pAdmin, pFoundClient, info->flags)) 
  1.1153 +			== COMMAND_TARGET_VALID)
  1.1154 +		{
  1.1155 +			info->targets[0] = found_client;
  1.1156 +			info->num_targets = 1;
  1.1157 +			strncopy(info->target_name, pFoundClient->GetName(), info->target_name_maxlength);
  1.1158 +			info->target_name_style = COMMAND_TARGETNAME_RAW;
  1.1159 +		}
  1.1160 +		else
  1.1161 +		{
  1.1162 +			info->num_targets = 0;
  1.1163 +		}
  1.1164 +	}
  1.1165 +	else
  1.1166 +	{
  1.1167 +		info->num_targets = 0;
  1.1168 +		info->reason = COMMAND_TARGET_NONE;
  1.1169 +	}
  1.1170 +}
  1.1171 +
  1.1172 +/*******************
  1.1173 + *** PLAYER CODE ***
  1.1174 + *******************/
  1.1175 +
  1.1176 +CPlayer::CPlayer()
  1.1177 +{
  1.1178 +	m_IsConnected = false;
  1.1179 +	m_IsInGame = false;
  1.1180 +	m_IsAuthorized = false;
  1.1181 +	m_pEdict = NULL;
  1.1182 +	m_Admin = INVALID_ADMIN_ID;
  1.1183 +	m_TempAdmin = false;
  1.1184 +	m_Info = NULL;
  1.1185 +	m_bAdminCheckSignalled = false;
  1.1186 +	m_bIsInKickQueue = false;
  1.1187 +	m_LastPassword.clear();
  1.1188 +	m_LangId = LANGUAGE_ENGLISH;
  1.1189 +}
  1.1190 +
  1.1191 +void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
  1.1192 +{
  1.1193 +	m_IsConnected = true;
  1.1194 +	m_Name.assign(name);
  1.1195 +	m_Ip.assign(ip);
  1.1196 +	m_pEdict = pEntity;
  1.1197 +	m_iIndex = engine->IndexOfEdict(pEntity);
  1.1198 +	m_LangId = g_Translator.GetServerLanguage();
  1.1199 +
  1.1200 +	char ip2[24], *ptr;
  1.1201 +	strncopy(ip2, ip, sizeof(ip2));
  1.1202 +	if ((ptr = strchr(ip2, ':')) != NULL)
  1.1203 +	{
  1.1204 +		*ptr = '\0';
  1.1205 +	}
  1.1206 +	m_IpNoPort.assign(ip2);
  1.1207 +}
  1.1208 +
  1.1209 +void CPlayer::Connect()
  1.1210 +{
  1.1211 +	if (m_IsInGame)
  1.1212 +	{
  1.1213 +		return;
  1.1214 +	}
  1.1215 +
  1.1216 +	m_IsInGame = true;
  1.1217 +
  1.1218 +	const char *var = g_Players.GetPassInfoVar();
  1.1219 +	int client = engine->IndexOfEdict(m_pEdict);
  1.1220 +	if (var[0] != '\0')
  1.1221 +	{
  1.1222 +		const char *pass = engine->GetClientConVarValue(client, var);
  1.1223 +		m_LastPassword.assign(pass ? pass : "");
  1.1224 +	}
  1.1225 +	else
  1.1226 +	{
  1.1227 +		m_LastPassword.assign("");
  1.1228 +	}
  1.1229 +}
  1.1230 +
  1.1231 +void CPlayer::Authorize(const char *steamid)
  1.1232 +{
  1.1233 +	if (m_IsAuthorized)
  1.1234 +	{
  1.1235 +		return;
  1.1236 +	}
  1.1237 +
  1.1238 +	m_IsAuthorized = true;
  1.1239 +	m_AuthID.assign(steamid);
  1.1240 +}
  1.1241 +
  1.1242 +void CPlayer::Disconnect()
  1.1243 +{
  1.1244 +	DumpAdmin(false);
  1.1245 +	m_IsConnected = false;
  1.1246 +	m_IsInGame = false;
  1.1247 +	m_IsAuthorized = false;
  1.1248 +	m_Name.clear();
  1.1249 +	m_Ip.clear();
  1.1250 +	m_AuthID.clear();
  1.1251 +	m_pEdict = NULL;
  1.1252 +	m_Info = NULL;
  1.1253 +	m_bAdminCheckSignalled = false;
  1.1254 +	m_UserId = -1;
  1.1255 +	m_bIsInKickQueue = false;
  1.1256 +}
  1.1257 +
  1.1258 +void CPlayer::SetName(const char *name)
  1.1259 +{
  1.1260 +	m_Name.assign(name);
  1.1261 +}
  1.1262 +
  1.1263 +const char *CPlayer::GetName()
  1.1264 +{
  1.1265 +	if (m_Info && m_pEdict->GetUnknown())
  1.1266 +	{
  1.1267 +		return m_Info->GetName();
  1.1268 +	}
  1.1269 +	
  1.1270 +	return m_Name.c_str();
  1.1271 +}
  1.1272 +
  1.1273 +const char *CPlayer::GetIPAddress()
  1.1274 +{
  1.1275 +	return m_Ip.c_str();
  1.1276 +}
  1.1277 +
  1.1278 +const char *CPlayer::GetAuthString()
  1.1279 +{
  1.1280 +	return m_AuthID.c_str();
  1.1281 +}
  1.1282 +
  1.1283 +edict_t *CPlayer::GetEdict()
  1.1284 +{
  1.1285 +	return m_pEdict;
  1.1286 +}
  1.1287 +
  1.1288 +bool CPlayer::IsInGame()
  1.1289 +{
  1.1290 +	return m_IsInGame && (m_pEdict->GetUnknown() != NULL);
  1.1291 +}
  1.1292 +
  1.1293 +bool CPlayer::WasCountedAsInGame()
  1.1294 +{
  1.1295 +	return m_IsInGame;
  1.1296 +}
  1.1297 +
  1.1298 +bool CPlayer::IsConnected()
  1.1299 +{
  1.1300 +	return m_IsConnected;
  1.1301 +}
  1.1302 +
  1.1303 +bool CPlayer::IsAuthorized()
  1.1304 +{
  1.1305 +	return m_IsAuthorized;
  1.1306 +}
  1.1307 +
  1.1308 +IPlayerInfo *CPlayer::GetPlayerInfo()
  1.1309 +{
  1.1310 +	if (m_pEdict->GetUnknown())
  1.1311 +	{
  1.1312 +		return m_Info;
  1.1313 +	}
  1.1314 +
  1.1315 +	return NULL;
  1.1316 +}
  1.1317 +
  1.1318 +bool CPlayer::IsFakeClient()
  1.1319 +{
  1.1320 +	return (strcmp(m_AuthID.c_str(), "BOT") == 0);
  1.1321 +}
  1.1322 +
  1.1323 +void CPlayer::SetAdminId(AdminId id, bool temporary)
  1.1324 +{
  1.1325 +	if (!m_IsConnected)
  1.1326 +	{
  1.1327 +		return;
  1.1328 +	}
  1.1329 +
  1.1330 +	DumpAdmin(false);
  1.1331 +
  1.1332 +	m_Admin = id;
  1.1333 +	m_TempAdmin = temporary;
  1.1334 +}
  1.1335 +
  1.1336 +AdminId CPlayer::GetAdminId()
  1.1337 +{
  1.1338 +	return m_Admin;
  1.1339 +}
  1.1340 +
  1.1341 +void CPlayer::DumpAdmin(bool deleting)
  1.1342 +{
  1.1343 +	if (m_Admin != INVALID_ADMIN_ID)
  1.1344 +	{
  1.1345 +		if (m_TempAdmin && !deleting)
  1.1346 +		{
  1.1347 +			g_Admins.InvalidateAdmin(m_Admin);
  1.1348 +		}
  1.1349 +		m_Admin = INVALID_ADMIN_ID;
  1.1350 +		m_TempAdmin = false;
  1.1351 +	}
  1.1352 +}
  1.1353 +
  1.1354 +void CPlayer::Kick(const char *str)
  1.1355 +{
  1.1356 +	MarkAsBeingKicked();
  1.1357 +	INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(m_iIndex));
  1.1358 +	IClient *pClient = static_cast<IClient *>(pNetChan->GetMsgHandler());
  1.1359 +	pClient->Disconnect("%s", str);
  1.1360 +}
  1.1361 +
  1.1362 +void CPlayer::Authorize_Post()
  1.1363 +{
  1.1364 +	if (m_IsInGame)
  1.1365 +	{
  1.1366 +		DoPostConnectAuthorization();
  1.1367 +	}
  1.1368 +}
  1.1369 +
  1.1370 +void CPlayer::DoPostConnectAuthorization()
  1.1371 +{
  1.1372 +	bool delay = false;
  1.1373 +
  1.1374 +	List<IClientListener *>::iterator iter;
  1.1375 +	for (iter = g_Players.m_hooks.begin();
  1.1376 +		 iter != g_Players.m_hooks.end();
  1.1377 +		 iter++)
  1.1378 +	{
  1.1379 +		IClientListener *pListener = (*iter);
  1.1380 +#if defined MIN_API_FOR_ADMINCALLS
  1.1381 +		if (pListener->GetClientListenerVersion() < MIN_API_FOR_ADMINCALLS)
  1.1382 +		{
  1.1383 +			continue;
  1.1384 +		}
  1.1385 +#endif
  1.1386 +		if (!pListener->OnClientPreAdminCheck(m_iIndex))
  1.1387 +		{
  1.1388 +			delay = true;
  1.1389 +		}
  1.1390 +	}
  1.1391 +	
  1.1392 +	cell_t result = 0;
  1.1393 +	PreAdminCheck->PushCell(m_iIndex);
  1.1394 +	PreAdminCheck->Execute(&result);
  1.1395 +
  1.1396 +	/* Defer, for better or worse */
  1.1397 +	if (delay || (ResultType)result >= Pl_Handled)
  1.1398 +	{
  1.1399 +		return;
  1.1400 +	}
  1.1401 +
  1.1402 +	/* Sanity check */
  1.1403 +	if (!IsConnected())
  1.1404 +	{
  1.1405 +		return;
  1.1406 +	}
  1.1407 +
  1.1408 +	/* Otherwise, go ahead and do admin checks */
  1.1409 +	DoBasicAdminChecks();
  1.1410 +
  1.1411 +	/* Send the notification out */
  1.1412 +	NotifyPostAdminChecks();
  1.1413 +}
  1.1414 +
  1.1415 +bool CPlayer::RunAdminCacheChecks()
  1.1416 +{
  1.1417 +	AdminId old_id = GetAdminId();
  1.1418 +
  1.1419 +	DoBasicAdminChecks();
  1.1420 +
  1.1421 +	return (GetAdminId() != old_id);
  1.1422 +}
  1.1423 +
  1.1424 +void CPlayer::NotifyPostAdminChecks()
  1.1425 +{
  1.1426 +	if (m_bAdminCheckSignalled)
  1.1427 +	{
  1.1428 +		return;
  1.1429 +	}
  1.1430 +
  1.1431 +	/* Block beforehand so they can't double-call */
  1.1432 +	m_bAdminCheckSignalled = true;
  1.1433 +
  1.1434 +	List<IClientListener *>::iterator iter;
  1.1435 +	for (iter = g_Players.m_hooks.begin();
  1.1436 +		iter != g_Players.m_hooks.end();
  1.1437 +		iter++)
  1.1438 +	{
  1.1439 +		IClientListener *pListener = (*iter);
  1.1440 +#if defined MIN_API_FOR_ADMINCALLS
  1.1441 +		if (pListener->GetClientListenerVersion() < MIN_API_FOR_ADMINCALLS)
  1.1442 +		{
  1.1443 +			continue;
  1.1444 +		}
  1.1445 +#endif
  1.1446 +		pListener->OnClientPostAdminCheck(m_iIndex);
  1.1447 +	}
  1.1448 +
  1.1449 +	PostAdminFilter->PushCell(m_iIndex);
  1.1450 +	PostAdminFilter->Execute(NULL);
  1.1451 +
  1.1452 +	PostAdminCheck->PushCell(m_iIndex);
  1.1453 +	PostAdminCheck->Execute(NULL);
  1.1454 +}
  1.1455 +
  1.1456 +void CPlayer::DoBasicAdminChecks()
  1.1457 +{
  1.1458 +	if (GetAdminId() != INVALID_ADMIN_ID)
  1.1459 +	{
  1.1460 +		return;
  1.1461 +	}
  1.1462 +
  1.1463 +	/* First check the name */
  1.1464 +	AdminId id;
  1.1465 +	int client = engine->IndexOfEdict(m_pEdict);
  1.1466 +
  1.1467 +	if ((id = g_Admins.FindAdminByIdentity("name", GetName())) != INVALID_ADMIN_ID)
  1.1468 +	{
  1.1469 +		if (!g_Players.CheckSetAdminName(client, this, id))
  1.1470 +		{
  1.1471 +			int userid = engine->GetPlayerUserId(m_pEdict);
  1.1472 +			g_Timers.CreateTimer(&s_KickPlayerTimer, 0.1f, (void *)userid, 0);
  1.1473 +		}
  1.1474 +		return;
  1.1475 +	}
  1.1476 +	
  1.1477 +	/* Check IP */
  1.1478 +	if ((id = g_Admins.FindAdminByIdentity("ip", m_IpNoPort.c_str())) != INVALID_ADMIN_ID)
  1.1479 +	{
  1.1480 +		if (g_Players.CheckSetAdmin(client, this, id))
  1.1481 +		{
  1.1482 +			return;
  1.1483 +		}
  1.1484 +	}
  1.1485 +
  1.1486 +	/* Check IP address */
  1.1487 +	if ((id = g_Admins.FindAdminByIdentity("steam", m_AuthID.c_str())) != INVALID_ADMIN_ID)
  1.1488 +	{
  1.1489 +		if (g_Players.CheckSetAdmin(client, this, id))
  1.1490 +		{
  1.1491 +			return;
  1.1492 +		}
  1.1493 +	}
  1.1494 +}
  1.1495 +
  1.1496 +unsigned int CPlayer::GetLanguageId()
  1.1497 +{
  1.1498 +	return m_LangId;
  1.1499 +}
  1.1500 +
  1.1501 +int CPlayer::GetUserId()
  1.1502 +{
  1.1503 +	if (m_UserId == -1)
  1.1504 +	{
  1.1505 +		m_UserId = engine->GetPlayerUserId(GetEdict());
  1.1506 +	}
  1.1507 +
  1.1508 +	return m_UserId;
  1.1509 +}
  1.1510 +
  1.1511 +bool CPlayer::IsInKickQueue()
  1.1512 +{
  1.1513 +	return m_bIsInKickQueue;
  1.1514 +}
  1.1515 +
  1.1516 +void CPlayer::MarkAsBeingKicked()
  1.1517 +{
  1.1518 +	m_bIsInKickQueue = true;
  1.1519 +}
  1.1520 +
  1.1521 +int CPlayer::GetLifeState()
  1.1522 +{
  1.1523 +	if (lifestate_offset == -1)
  1.1524 +	{
  1.1525 +		if (!g_pGameConf->GetOffset("m_lifeState", &lifestate_offset))
  1.1526 +		{
  1.1527 +			lifestate_offset = -2;
  1.1528 +		}
  1.1529 +	}
  1.1530 +
  1.1531 +	if (lifestate_offset < 0)
  1.1532 +	{
  1.1533 +		IPlayerInfo *info = GetPlayerInfo();
  1.1534 +		if (info == NULL)
  1.1535 +		{
  1.1536 +			return PLAYER_LIFE_UNKNOWN;
  1.1537 +		}
  1.1538 +		return info->IsDead() ? PLAYER_LIFE_DEAD : PLAYER_LIFE_ALIVE;
  1.1539 +	}
  1.1540 +
  1.1541 +	if (m_pEdict == NULL)
  1.1542 +	{
  1.1543 +		return PLAYER_LIFE_UNKNOWN;
  1.1544 +	}
  1.1545 +
  1.1546 +	CBaseEntity *pEntity;
  1.1547 +	IServerUnknown *pUnknown = m_pEdict->GetUnknown();
  1.1548 +	if (pUnknown == NULL || (pEntity = pUnknown->GetBaseEntity()) == NULL)
  1.1549 +	{
  1.1550 +		return PLAYER_LIFE_UNKNOWN;
  1.1551 +	}
  1.1552 +
  1.1553 +	if (*((uint8_t *)pEntity + lifestate_offset) == LIFE_ALIVE)
  1.1554 +	{
  1.1555 +		return PLAYER_LIFE_ALIVE;
  1.1556 +	}
  1.1557 +	else
  1.1558 +	{
  1.1559 +		return PLAYER_LIFE_DEAD;
  1.1560 +	}
  1.1561 +}