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