core/PlayerManager.cpp
author David Anderson <dvander@alliedmods.net>
Fri Jun 08 07:54:45 2007 +0000 (2007-06-08)
changeset 930 4ce68e8f7577
parent 916 39ae94ad60ce
child 931 d1c12f218789
permissions -rw-r--r--
SourceMod now does authentication in core; admin-auth gets removed. this has an added bonus that OnClientAuthorized reliably has whether an admin is validated
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "PlayerManager.h"
    16 #include "ForwardSys.h"
    17 #include "ShareSys.h"
    18 #include "AdminCache.h"
    19 #include "ConCmdManager.h"
    20 #include "MenuStyle_Valve.h"
    21 #include "MenuStyle_Radio.h"
    22 #include "sm_stringutil.h"
    23 
    24 PlayerManager g_Players;
    25 bool g_OnMapStarted = false;
    26 
    27 SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
    28 SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
    29 SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
    30 SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
    31 SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
    32 SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
    33 
    34 PlayerManager::PlayerManager()
    35 {
    36 	m_AuthQueue = NULL;
    37 	m_FirstPass = true;
    38 
    39 	m_UserIdLookUp = new int[USHRT_MAX];
    40 	memset(m_UserIdLookUp, 0, sizeof(int) * USHRT_MAX);
    41 }
    42 
    43 PlayerManager::~PlayerManager()
    44 {
    45 	delete [] m_AuthQueue;
    46 	delete [] m_UserIdLookUp;
    47 }
    48 
    49 void PlayerManager::OnSourceModAllInitialized()
    50 {
    51 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false);
    52 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect_Post, true);
    53 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true);
    54 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false);
    55 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true);
    56 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false);
    57 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true);
    58 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true);
    59 
    60 	g_ShareSys.AddInterface(NULL, this);
    61 
    62 	ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
    63 	ParamType p2[] = {Param_Cell};
    64 
    65 	m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
    66 	m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
    67 	m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
    68 	m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
    69 	m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
    70 	m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
    71 	m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
    72 	m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
    73 	m_onActivate2 = g_Forwards.CreateForward("OnMapStart", ET_Ignore, 0, NULL);
    74 }
    75 
    76 void PlayerManager::OnSourceModShutdown()
    77 {
    78 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false);
    79 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true);
    80 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false);
    81 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true);
    82 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false);
    83 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true);
    84 	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true);
    85 
    86 	/* Release forwards */
    87 	g_Forwards.ReleaseForward(m_clconnect);
    88 	g_Forwards.ReleaseForward(m_clputinserver);
    89 	g_Forwards.ReleaseForward(m_cldisconnect);
    90 	g_Forwards.ReleaseForward(m_cldisconnect_post);
    91 	g_Forwards.ReleaseForward(m_clcommand);
    92 	g_Forwards.ReleaseForward(m_clinfochanged);
    93 	g_Forwards.ReleaseForward(m_clauth);
    94 	g_Forwards.ReleaseForward(m_onActivate);
    95 	g_Forwards.ReleaseForward(m_onActivate2);
    96 
    97 	delete [] m_Players;
    98 }
    99 
   100 void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
   101 {
   102 	if (m_FirstPass)
   103 	{
   104 		/* Initialize all players */
   105 		m_maxClients = clientMax;
   106 		m_PlayerCount = 0;
   107 		m_Players = new CPlayer[m_maxClients + 1];
   108 		m_AuthQueue = new unsigned int[m_maxClients + 1];
   109 		m_FirstPass = false;
   110 
   111 		memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
   112 	}
   113 	m_onActivate->Execute(NULL);
   114 	m_onActivate2->Execute(NULL);
   115 
   116 	g_OnMapStarted = true;
   117 }
   118 
   119 bool CheckSetAdmin(int index, CPlayer *pPlayer, AdminId id)
   120 {
   121 	const char *password = g_Admins.GetAdminPassword(id);
   122 	if (password != NULL)
   123 	{
   124 		/* Whoa... the user needs a password! */
   125 		const char *given = engine->GetClientConVarValue(index, "_password");
   126 		if (!given || strcmp(given, password) != 0)
   127 		{
   128 			return false;
   129 		}
   130 	}
   131 
   132 	pPlayer->SetAdminId(id, false);
   133 
   134 	return true;
   135 }
   136 
   137 void PlayerManager::RunAuthChecks()
   138 {
   139 	CPlayer *pPlayer;
   140 	const char *authstr;
   141 	unsigned int removed = 0;
   142 	for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   143 	{
   144 		pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
   145 		authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
   146 		if (authstr && authstr[0] != '\0'
   147 			&& (strcmp(authstr, "STEAM_ID_PENDING") != 0))
   148 		{
   149 			/* Set authorization */
   150 			pPlayer->m_AuthID.assign(authstr);
   151 			pPlayer->m_IsAuthorized = true;
   152 
   153 			/* Mark as removed from queue */
   154 			unsigned int client = m_AuthQueue[i];
   155 			m_AuthQueue[i] = 0;
   156 			removed++;
   157 
   158 			/* Do admin lookups */
   159 			AdminId id = g_Admins.FindAdminByIdentity("steam", authstr);
   160 			if (id != INVALID_ADMIN_ID)
   161 			{
   162 				CheckSetAdmin(client, pPlayer, id);
   163 			}
   164 
   165 			/* Send to extensions */
   166 			List<IClientListener *>::iterator iter;
   167 			IClientListener *pListener;
   168 			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   169 			{
   170 				pListener = (*iter);
   171 				pListener->OnClientAuthorized(client, authstr);
   172 				if (!pPlayer->IsConnected())
   173 				{
   174 					break;
   175 				}
   176 			}
   177 
   178 			/* Send to plugins if player is still connected */
   179 			if (pPlayer->IsConnected() && m_clauth->GetFunctionCount())
   180 			{
   181 				/* :TODO: handle the case of a player disconnecting in the middle */
   182 				m_clauth->PushCell(client);
   183 				m_clauth->PushString(authstr);
   184 				m_clauth->Execute(NULL);
   185 			}
   186 		}
   187 	}
   188 
   189 	/* Clean up the queue */
   190 	if (removed)
   191 	{
   192 		/* We don't have to compact the list if it's empty */
   193 		if (removed != m_AuthQueue[0])
   194 		{
   195 			unsigned int diff = 0;
   196 			for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   197 			{
   198 				/* If this member is removed... */
   199 				if (m_AuthQueue[i] == 0)
   200 				{
   201 					/* Increase the differential */
   202 					diff++;
   203 				} else {
   204 					/* diff cannot increase faster than i+1 */
   205 					assert(i > diff);
   206 					assert(i - diff >= 1);
   207 					/* move this index down */
   208 					m_AuthQueue[i - diff] = m_AuthQueue[i];
   209 				}
   210 			}
   211 			m_AuthQueue[0] -= removed;
   212 		} else {
   213 			m_AuthQueue[0] = 0;
   214 			g_SourceMod.SetAuthChecking(false);
   215 		}
   216 	}
   217 }
   218 
   219 bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
   220 {
   221 	int client = engine->IndexOfEdict(pEntity);
   222 
   223 	List<IClientListener *>::iterator iter;
   224 	IClientListener *pListener = NULL;
   225 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   226 	{
   227 		pListener = (*iter);
   228 		if (!pListener->InterceptClientConnect(client, reject, maxrejectlen))
   229 		{
   230 			return false;
   231 		}
   232 	}
   233 
   234 	cell_t res = 1;
   235 
   236 	m_Players[client].Initialize(pszName, pszAddress, pEntity);
   237 	m_clconnect->PushCell(client);
   238 	m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK);
   239 	m_clconnect->PushCell(maxrejectlen);
   240 	m_clconnect->Execute(&res, NULL);
   241 
   242 	if (res)
   243 	{
   244 		if (!m_Players[client].IsAuthorized())
   245 		{
   246 			m_AuthQueue[++m_AuthQueue[0]] = client;
   247 			g_SourceMod.SetAuthChecking(true);
   248 		}
   249 	} else {
   250 		RETURN_META_VALUE(MRES_SUPERCEDE, false);
   251 	}
   252 
   253 	m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = client;
   254 
   255 	return true;
   256 }
   257 
   258 bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
   259 {
   260 	int client = engine->IndexOfEdict(pEntity);
   261 	bool orig_value = META_RESULT_ORIG_RET(bool);
   262 	CPlayer *pPlayer = GetPlayerByIndex(client);
   263 	if (orig_value)
   264 	{
   265 		List<IClientListener *>::iterator iter;
   266 		IClientListener *pListener = NULL;
   267 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   268 		{
   269 			pListener = (*iter);
   270 			pListener->OnClientConnected(client);
   271 			if (!pPlayer->IsConnected())
   272 			{
   273 				break;
   274 			}
   275 		}
   276 	}
   277 
   278 	if (pPlayer->IsConnected())
   279 	{
   280 		/* Do an ip based lookup */
   281 		char ip[24], *ptr;
   282 		strncopy(ip, pszAddress, sizeof(ip));
   283 		if ((ptr = strchr(ip, ':')) != NULL)
   284 		{
   285 			*ptr = '\0';
   286 		}
   287 		
   288 		AdminId id = g_Admins.FindAdminByIdentity("ip", pPlayer->GetIPAddress());
   289 		if (id != INVALID_ADMIN_ID)
   290 		{
   291 			CheckSetAdmin(client, pPlayer, id);
   292 		}
   293 	}
   294 
   295 	return true;
   296 }
   297 
   298 void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername)
   299 {
   300 	cell_t res;
   301 	int client = engine->IndexOfEdict(pEntity);
   302 
   303 	CPlayer *pPlayer = GetPlayerByIndex(client);
   304 	/* If they're not connected, they're a bot */
   305 	if (!pPlayer->IsConnected())
   306 	{
   307 		/* Run manual connection routines */
   308 		char error[255];
   309 		const char *authid = engine->GetPlayerNetworkIDString(pEntity);
   310 		pPlayer->Authorize(authid);
   311 		if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
   312 		{
   313 			/* :TODO: kick the bot if it's rejected */
   314 			return;
   315 		}
   316 		List<IClientListener *>::iterator iter;
   317 		IClientListener *pListener = NULL;
   318 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   319 		{
   320 			pListener = (*iter);
   321 			pListener->OnClientConnected(client);
   322 			/* See if bot was kicked */
   323 			if (!pPlayer->IsConnected())
   324 			{
   325 				return;
   326 			}
   327 		}
   328 		/* Now do authorization */
   329 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   330 		{
   331 			pListener = (*iter);
   332 			pListener->OnClientAuthorized(client, authid);
   333 			/* See if bot was kicked */
   334 			if (!pPlayer->IsConnected())
   335 			{
   336 				return;
   337 			}
   338 		}
   339 		/* Finally, tell plugins */
   340 		if (m_clauth->GetFunctionCount())
   341 		{
   342 			m_clauth->PushCell(client);
   343 			m_clauth->PushString(authid);
   344 			m_clauth->Execute(NULL);
   345 		}
   346 	}
   347 
   348 	if (playerinfo)
   349 	{
   350 		pPlayer->m_Info = playerinfo->GetPlayerInfo(pEntity);
   351 	}
   352 
   353 	List<IClientListener *>::iterator iter;
   354 	IClientListener *pListener = NULL;
   355 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   356 	{
   357 		pListener = (*iter);
   358 		pListener->OnClientPutInServer(client);
   359 		/* See if player was kicked */
   360 		if (!pPlayer->IsConnected())
   361 		{
   362 			return;
   363 		}
   364 	}
   365 
   366 	m_Players[client].Connect();
   367 	m_PlayerCount++;
   368 	m_clputinserver->PushCell(client);
   369 	m_clputinserver->Execute(&res, NULL);
   370 }
   371 
   372 void PlayerManager::OnSourceModLevelEnd()
   373 {
   374 	/* Disconnect all bots still in game */
   375 	for (int i=1; i<=m_maxClients; i++)
   376 	{
   377 		if (m_Players[i].IsConnected() && m_Players[i].IsFakeClient())
   378 		{
   379 			OnClientDisconnect(m_Players[i].GetEdict());
   380 		}
   381 	}
   382 }
   383 
   384 void PlayerManager::OnClientDisconnect(edict_t *pEntity)
   385 {
   386 	cell_t res;
   387 	int client = engine->IndexOfEdict(pEntity);
   388 
   389 	if (m_Players[client].IsConnected())
   390 	{
   391 		m_cldisconnect->PushCell(client);
   392 		m_cldisconnect->Execute(&res, NULL);
   393 	}
   394 
   395 	if (m_Players[client].IsInGame())
   396 	{
   397 		m_PlayerCount--;
   398 	}
   399 
   400 	List<IClientListener *>::iterator iter;
   401 	IClientListener *pListener = NULL;
   402 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   403 	{
   404 		pListener = (*iter);
   405 		pListener->OnClientDisconnecting(client);
   406 	}
   407 
   408 	/**
   409 	 * Remove client from auth queue if necessary
   410 	 */
   411 	if (!m_Players[client].IsAuthorized())
   412 	{
   413 		for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   414 		{
   415 			if (m_AuthQueue[i] == (unsigned)client)
   416 			{
   417 				/* Move everything ahead of us back by one */
   418 				for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
   419 				{
   420 					m_AuthQueue[j-1] = m_AuthQueue[j];
   421 				}
   422 				/* Remove us and break */
   423 				m_AuthQueue[0]--;
   424 				break;
   425 			}
   426 		}
   427 	}
   428 
   429 	m_Players[client].Disconnect();
   430 	m_UserIdLookUp[engine->GetPlayerUserId(pEntity)] = 0;
   431 }
   432 
   433 void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
   434 {
   435 	cell_t res;
   436 	int client = engine->IndexOfEdict(pEntity);
   437 
   438 	m_cldisconnect_post->PushCell(client);
   439 	m_cldisconnect_post->Execute(&res, NULL);
   440 
   441 	List<IClientListener *>::iterator iter;
   442 	IClientListener *pListener = NULL;
   443 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   444 	{
   445 		pListener = (*iter);
   446 		pListener->OnClientDisconnected(client);
   447 	}
   448 }
   449 
   450 void PlayerManager::OnClientCommand(edict_t *pEntity)
   451 {
   452 	int client = engine->IndexOfEdict(pEntity);
   453 	cell_t res = Pl_Continue;
   454 
   455 	bool result = g_ValveMenuStyle.OnClientCommand(client);
   456 	if (result)
   457 	{
   458 		res = Pl_Handled;
   459 	} else {
   460 		result = g_RadioMenuStyle.OnClientCommand(client);
   461 		if (result)
   462 		{
   463 			res = Pl_Handled;
   464 		}
   465 	}
   466 
   467 	int args = engine->Cmd_Argc() - 1;
   468 
   469 	cell_t res2 = Pl_Continue;
   470 	m_clcommand->PushCell(client);
   471 	m_clcommand->PushCell(args);
   472 	m_clcommand->Execute(&res2, NULL);
   473 
   474 	if (res2 > res)
   475 	{
   476 		res = res2;
   477 	}
   478 
   479 	if (res >= Pl_Stop)
   480 	{
   481 		RETURN_META(MRES_SUPERCEDE);
   482 	}
   483 
   484 	res = g_ConCmds.DispatchClientCommand(client, (ResultType)res);
   485 
   486 	if (res >= Pl_Handled)
   487 	{
   488 		RETURN_META(MRES_SUPERCEDE);
   489 	}
   490 }
   491 
   492 void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
   493 {
   494 	cell_t res;
   495 	int client = engine->IndexOfEdict(pEntity);
   496 
   497 	m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity));
   498 	m_clinfochanged->Execute(&res, NULL);
   499 	m_Players[client].SetName(engine->GetClientConVarValue(client, "name"));
   500 }
   501 
   502 int PlayerManager::GetMaxClients()
   503 {
   504 	return m_maxClients;
   505 }
   506 
   507 CPlayer *PlayerManager::GetPlayerByIndex(int client) const
   508 {
   509 	if (client > m_maxClients || client < 1)
   510 	{
   511 		return NULL;
   512 	}
   513 	return &m_Players[client];
   514 }
   515 
   516 int PlayerManager::GetNumPlayers()
   517 {
   518 	return m_PlayerCount;
   519 }
   520 
   521 int PlayerManager::GetClientOfUserId(int userid)
   522 {
   523 	if (userid < 0 || userid > USHRT_MAX)
   524 	{
   525 		return 0;
   526 	}
   527 	
   528 	int client = m_UserIdLookUp[userid];
   529 
   530 	/* Verify the userid.  The cache can get messed up with older
   531 	 * Valve engines.  :TODO: If this gets fixed, do an old engine 
   532 	 * check before invoking this backwards compat code.
   533 	 */
   534 	if (client)
   535 	{
   536 		CPlayer *player = GetPlayerByIndex(client);
   537 		if (player && player->IsConnected())
   538 		{
   539 			int realUserId = engine->GetPlayerUserId(player->GetEdict());
   540 			if (realUserId == userid)
   541 			{
   542 				return client;
   543 			}
   544 		}
   545 	}
   546 
   547 	/* If we can't verify the userid, we have to do a manual loop */
   548 	CPlayer *player;
   549 	for (int i = 1; i <= m_maxClients; i++)
   550 	{
   551 		player = GetPlayerByIndex(i);
   552 		if (!player || !player->IsConnected())
   553 		{
   554 			continue;
   555 		}
   556 		if (engine->GetPlayerUserId(player->GetEdict()) == userid)
   557 		{
   558 			m_UserIdLookUp[userid] = i;
   559 			return i;
   560 		}
   561 	}
   562 
   563 	return 0;
   564 }
   565 
   566 void PlayerManager::AddClientListener(IClientListener *listener)
   567 {
   568 	m_hooks.push_back(listener);
   569 }
   570 
   571 void PlayerManager::RemoveClientListener(IClientListener *listener)
   572 {
   573 	m_hooks.remove(listener);
   574 }
   575 
   576 IGamePlayer *PlayerManager::GetGamePlayer(edict_t *pEdict)
   577 {
   578 	int index = engine->IndexOfEdict(pEdict);
   579 	return GetGamePlayer(index);
   580 }
   581 
   582 IGamePlayer *PlayerManager::GetGamePlayer(int client)
   583 {
   584 	return GetPlayerByIndex(client);
   585 }
   586 
   587 void PlayerManager::ClearAdminId(AdminId id)
   588 {
   589 	for (int i=1; i<=m_maxClients; i++)
   590 	{
   591 		if (m_Players[i].m_Admin == id)
   592 		{
   593 			m_Players[i].DumpAdmin(true);
   594 		}
   595 	}
   596 }
   597 
   598 void PlayerManager::ClearAllAdmins()
   599 {
   600 	for (int i=1; i<=m_maxClients; i++)
   601 	{
   602 		m_Players[i].DumpAdmin(true);
   603 	}
   604 }
   605 
   606 
   607 /*******************
   608  *** PLAYER CODE ***
   609  *******************/
   610 
   611 CPlayer::CPlayer()
   612 {
   613 	m_IsConnected = false;
   614 	m_IsInGame = false;
   615 	m_IsAuthorized = false;
   616 	m_pEdict = NULL;
   617 	m_Admin = INVALID_ADMIN_ID;
   618 	m_TempAdmin = false;
   619 	m_Info = NULL;
   620 }
   621 
   622 void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
   623 {
   624 	m_IsConnected = true;
   625 	m_Name.assign(name);
   626 	m_Ip.assign(ip);
   627 	m_pEdict = pEntity;
   628 }
   629 
   630 void CPlayer::Connect()
   631 {
   632 	m_IsInGame = true;
   633 }
   634 
   635 void CPlayer::Authorize(const char *steamid)
   636 {
   637 	m_IsAuthorized = true;
   638 	m_AuthID.assign(steamid);
   639 }
   640 
   641 void CPlayer::Disconnect()
   642 {
   643 	DumpAdmin(false);
   644 	m_IsConnected = false;
   645 	m_IsInGame = false;
   646 	m_IsAuthorized = false;
   647 	m_Name.clear();
   648 	m_Ip.clear();
   649 	m_AuthID.clear();
   650 	m_pEdict = NULL;
   651 	m_Info = NULL;
   652 }
   653 
   654 void CPlayer::SetName(const char *name)
   655 {
   656 	m_Name.assign(name);
   657 }
   658 
   659 const char *CPlayer::GetName()
   660 {
   661 	return (m_Info) ? m_Info->GetName(): m_Name.c_str();
   662 }
   663 
   664 const char *CPlayer::GetIPAddress()
   665 {
   666 	return m_Ip.c_str();
   667 }
   668 
   669 const char *CPlayer::GetAuthString()
   670 {
   671 	return m_AuthID.c_str();
   672 }
   673 
   674 edict_t *CPlayer::GetEdict()
   675 {
   676 	return m_pEdict;
   677 }
   678 
   679 bool CPlayer::IsInGame()
   680 {
   681 	return m_IsInGame;
   682 }
   683 
   684 bool CPlayer::IsConnected()
   685 {
   686 	return m_IsConnected;
   687 }
   688 
   689 bool CPlayer::IsAuthorized()
   690 {
   691 	return m_IsAuthorized;
   692 }
   693 
   694 IPlayerInfo *CPlayer::GetPlayerInfo()
   695 {
   696 	return m_Info;
   697 }
   698 
   699 bool CPlayer::IsFakeClient()
   700 {
   701 	return (strcmp(m_AuthID.c_str(), "BOT") == 0);
   702 }
   703 
   704 void CPlayer::SetAdminId(AdminId id, bool temporary)
   705 {
   706 	if (!m_IsConnected)
   707 	{
   708 		return;
   709 	}
   710 
   711 	DumpAdmin(false);
   712 
   713 	m_Admin = id;
   714 	m_TempAdmin = temporary;
   715 }
   716 
   717 AdminId CPlayer::GetAdminId()
   718 {
   719 	return m_Admin;
   720 }
   721 
   722 void CPlayer::DumpAdmin(bool deleting)
   723 {
   724 	if (m_Admin != INVALID_ADMIN_ID)
   725 	{
   726 		if (m_TempAdmin && !deleting)
   727 		{
   728 			g_Admins.InvalidateAdmin(m_Admin);
   729 		}
   730 		m_Admin = INVALID_ADMIN_ID;
   731 		m_TempAdmin = false;
   732 	}
   733 }