core/CPlayerManager.cpp
author David Anderson <dvander@alliedmods.net>
Fri Feb 16 03:47:10 2007 +0000 (2007-02-16)
changeset 501 e209a7296936
parent 500 868e9b19a872
child 516 0807e52b4e02
permissions -rw-r--r--
removed this potential feature, not useful enough
     1 /**
     2  * ===============================================================
     3  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     4  * ===============================================================
     5  *
     6  * This file is not open source and may not be copied without explicit
     7  * written permission of AlliedModders LLC.  This file may not be redistributed 
     8  * in whole or significant part.
     9  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    10  *
    11  * Version: $Id$
    12  */
    13 
    14 #include "CPlayerManager.h"
    15 #include "ForwardSys.h"
    16 #include "ShareSys.h"
    17 #include "AdminCache.h"
    18 #include "CConCmdManager.h"
    19 
    20 CPlayerManager g_Players;
    21 
    22 SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
    23 SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
    24 SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
    25 SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
    26 SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
    27 SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
    28 
    29 CPlayerManager::CPlayerManager()
    30 {
    31 	m_AuthQueue = NULL;
    32 	m_FirstPass = true;
    33 }
    34 
    35 CPlayerManager::~CPlayerManager()
    36 {
    37 	delete [] m_AuthQueue;
    38 }
    39 
    40 void CPlayerManager::OnSourceModAllInitialized()
    41 {
    42 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false);
    43 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect_Post, true);
    44 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true);
    45 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false);
    46 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true);
    47 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false);
    48 	SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true);
    49 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true);
    50 
    51 	g_ShareSys.AddInterface(NULL, this);
    52 
    53 	ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
    54 	ParamType p2[] = {Param_Cell};
    55 
    56 	m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
    57 	m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
    58 	m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
    59 	m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
    60 	m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
    61 	m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
    62 	m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
    63 }
    64 
    65 void CPlayerManager::OnSourceModShutdown()
    66 {
    67 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false);
    68 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true);
    69 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false);
    70 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true);
    71 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false);
    72 	SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true);
    73 	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true);
    74 
    75 	/* Release forwards */
    76 	g_Forwards.ReleaseForward(m_clconnect);
    77 	g_Forwards.ReleaseForward(m_clputinserver);
    78 	g_Forwards.ReleaseForward(m_cldisconnect);
    79 	g_Forwards.ReleaseForward(m_cldisconnect_post);
    80 	g_Forwards.ReleaseForward(m_clcommand);
    81 	g_Forwards.ReleaseForward(m_clinfochanged);
    82 	g_Forwards.ReleaseForward(m_clauth);
    83 
    84 	delete [] m_Players;
    85 }
    86 
    87 void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
    88 {
    89 	if (m_FirstPass)
    90 	{
    91 		/* Initialize all players */
    92 		m_maxClients = clientMax;
    93 		m_PlayerCount = 0;
    94 		m_Players = new CPlayer[m_maxClients + 1];
    95 		m_AuthQueue = new unsigned int[m_maxClients + 1];
    96 		m_FirstPass = false;
    97 
    98 		memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
    99 	}
   100 }
   101 
   102 void CPlayerManager::RunAuthChecks()
   103 {
   104 	CPlayer *pPlayer;
   105 	const char *authstr;
   106 	unsigned int removed = 0;
   107 	for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   108 	{
   109 		pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
   110 		authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
   111 		if (authstr && authstr[0] != '\0'
   112 			&& (strcmp(authstr, "STEAM_ID_PENDING") != 0))
   113 		{
   114 			/* Set authorization */
   115 			pPlayer->m_AuthID.assign(authstr);
   116 			pPlayer->m_IsAuthorized = true;
   117 
   118 			/* Send to extensions */
   119 			List<IClientListener *>::iterator iter;
   120 			IClientListener *pListener;
   121 			for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   122 			{
   123 				pListener = (*iter);
   124 				pListener->OnClientAuthorized(m_AuthQueue[i], authstr);
   125 			}
   126 
   127 			/* Send to plugins */
   128 			if (m_clauth->GetFunctionCount())
   129 			{
   130 				m_clauth->PushCell(m_AuthQueue[i]);
   131 				m_clauth->PushString(authstr);
   132 				m_clauth->Execute(NULL);
   133 			}
   134 
   135 			/* Mark as removed from queue */
   136 			m_AuthQueue[i] = 0;
   137 			removed++;
   138 		}
   139 	}
   140 
   141 	/* Clean up the queue */
   142 	if (removed)
   143 	{
   144 		/* We don't have to compcat the list if it's empty */
   145 		if (removed != m_AuthQueue[0])
   146 		{
   147 			unsigned int diff = 0;
   148 			for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   149 			{
   150 				/* If this member is removed... */
   151 				if (m_AuthQueue[i] == 0)
   152 				{
   153 					/* Increase the differential */
   154 					diff++;
   155 				} else {
   156 					/* diff cannot increase faster than i+1 */
   157 					assert(i > diff);
   158 					assert(i - diff >= 1);
   159 					/* move this index down */
   160 					m_AuthQueue[i - diff] = m_AuthQueue[i];
   161 				}
   162 			}
   163 			m_AuthQueue[0] -= removed;
   164 		} else {
   165 			m_AuthQueue[0] = 0;
   166 			g_SourceMod.SetAuthChecking(false);
   167 		}
   168 	}
   169 }
   170 
   171 bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
   172 {
   173 	int client = engine->IndexOfEdict(pEntity);
   174 
   175 	List<IClientListener *>::iterator iter;
   176 	IClientListener *pListener = NULL;
   177 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   178 	{
   179 		pListener = (*iter);
   180 		if (!pListener->InterceptClientConnect(client, reject, maxrejectlen))
   181 		{
   182 			return false;
   183 		}
   184 	}
   185 
   186 	cell_t res = 1;
   187 
   188 	m_Players[client].Initialize(pszName, pszAddress, pEntity);
   189 	m_clconnect->PushCell(client);
   190 	m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK);
   191 	m_clconnect->PushCell(maxrejectlen);
   192 	m_clconnect->Execute(&res, NULL);
   193 
   194 	if (res)
   195 	{
   196 		m_AuthQueue[++m_AuthQueue[0]] = client;
   197 		g_SourceMod.SetAuthChecking(true);
   198 	}
   199 
   200 	//:todo: this must meta return
   201 	return (res) ? true : false;
   202 }
   203 
   204 bool CPlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
   205 {
   206 	int client = engine->IndexOfEdict(pEntity);
   207 	bool orig_value = META_RESULT_ORIG_RET(bool);
   208 	if (orig_value)
   209 	{
   210 		List<IClientListener *>::iterator iter;
   211 		IClientListener *pListener = NULL;
   212 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   213 		{
   214 			pListener = (*iter);
   215 			pListener->OnClientConnected(client);
   216 		}
   217 	}
   218 
   219 	return true;
   220 }
   221 
   222 void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername)
   223 {
   224 	cell_t res;
   225 	int client = engine->IndexOfEdict(pEntity);
   226 
   227 	CPlayer *pPlayer = GetPlayerByIndex(client);
   228 	if (!pPlayer->IsConnected())
   229 	{
   230 		/* Run manual connection routines */
   231 		char error[255];
   232 		if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
   233 		{
   234 			/* :TODO: kick the bot if it's rejected */
   235 			return;
   236 		}
   237 		List<IClientListener *>::iterator iter;
   238 		IClientListener *pListener = NULL;
   239 		for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   240 		{
   241 			pListener = (*iter);
   242 			pListener->OnClientConnected(client);
   243 		}
   244 	}
   245 
   246 	List<IClientListener *>::iterator iter;
   247 	IClientListener *pListener = NULL;
   248 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   249 	{
   250 		pListener = (*iter);
   251 		pListener->OnClientPutInServer(client);
   252 	}
   253 
   254 	m_Players[client].Connect();
   255 	m_PlayerCount++;
   256 	m_clputinserver->PushCell(client);
   257 	m_clputinserver->Execute(&res, NULL);
   258 }
   259 
   260 void CPlayerManager::OnClientAuthorized()
   261 {
   262 	//:TODO:
   263 }
   264 
   265 void CPlayerManager::OnClientDisconnect(edict_t *pEntity)
   266 {
   267 	cell_t res;
   268 	int client = engine->IndexOfEdict(pEntity);
   269 
   270 	if (m_Players[client].IsConnected())
   271 	{
   272 		m_cldisconnect->PushCell(client);
   273 		m_cldisconnect->Execute(&res, NULL);
   274 	}
   275 
   276 	if (m_Players[client].IsInGame())
   277 	{
   278 		m_PlayerCount--;
   279 	}
   280 
   281 	List<IClientListener *>::iterator iter;
   282 	IClientListener *pListener = NULL;
   283 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   284 	{
   285 		pListener = (*iter);
   286 		pListener->OnClientDisconnecting(client);
   287 	}
   288 
   289 	/**
   290 	 * Remove client from auth queue if necessary
   291 	 */
   292 	if (!m_Players[client].IsAuthorized())
   293 	{
   294 		for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
   295 		{
   296 			if (m_AuthQueue[i] == (unsigned)client)
   297 			{
   298 				/* Move everything ahead of us back by one */
   299 				for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
   300 				{
   301 					m_AuthQueue[j-1] = m_AuthQueue[j];
   302 				}
   303 				/* Remove us and break */
   304 				m_AuthQueue[0]--;
   305 				break;
   306 			}
   307 		}
   308 	}
   309 
   310 	m_Players[client].Disconnect();
   311 }
   312 
   313 void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
   314 {
   315 	cell_t res;
   316 	int client = engine->IndexOfEdict(pEntity);
   317 
   318 	m_cldisconnect_post->PushCell(client);
   319 	m_cldisconnect_post->Execute(&res, NULL);
   320 
   321 	List<IClientListener *>::iterator iter;
   322 	IClientListener *pListener = NULL;
   323 	for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
   324 	{
   325 		pListener = (*iter);
   326 		pListener->OnClientDisconnected(client);
   327 	}
   328 }
   329 
   330 void CPlayerManager::OnClientCommand(edict_t *pEntity)
   331 {
   332 	cell_t res = Pl_Continue;
   333 	int client = engine->IndexOfEdict(pEntity);
   334 
   335 	int args = engine->Cmd_Argc() - 1;
   336 
   337 	m_clcommand->PushCell(client);
   338 	m_clcommand->PushCell(args);
   339 	m_clcommand->Execute(&res, NULL);
   340 
   341 	if (res >= Pl_Stop)
   342 	{
   343 		RETURN_META(MRES_SUPERCEDE);
   344 	}
   345 
   346 	res = g_ConCmds.DispatchClientCommand(client, (ResultType)res);
   347 
   348 	if (res >= Pl_Handled)
   349 	{
   350 		RETURN_META(MRES_SUPERCEDE);
   351 	}
   352 }
   353 
   354 void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity)
   355 {
   356 	cell_t res;
   357 	int client = engine->IndexOfEdict(pEntity);
   358 
   359 	m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity));
   360 	m_clinfochanged->Execute(&res, NULL);
   361 	m_Players[client].SetName(engine->GetClientConVarValue(client, "name"));
   362 }
   363 
   364 int CPlayerManager::GetMaxClients()
   365 {
   366 	return m_maxClients;
   367 }
   368 
   369 CPlayer *CPlayerManager::GetPlayerByIndex(int client) const
   370 {
   371 	if (client > m_maxClients || client < 1)
   372 	{
   373 		return NULL;
   374 	}
   375 	return &m_Players[client];
   376 }
   377 
   378 int CPlayerManager::GetNumPlayers()
   379 {
   380 	return m_PlayerCount;
   381 }
   382 
   383 void CPlayerManager::AddClientListener(IClientListener *listener)
   384 {
   385 	m_hooks.push_back(listener);
   386 }
   387 
   388 void CPlayerManager::RemoveClientListener(IClientListener *listener)
   389 {
   390 	m_hooks.remove(listener);
   391 }
   392 
   393 IGamePlayer *CPlayerManager::GetGamePlayer(edict_t *pEdict)
   394 {
   395 	int index = engine->IndexOfEdict(pEdict);
   396 	return GetGamePlayer(index);
   397 }
   398 
   399 IGamePlayer *CPlayerManager::GetGamePlayer(int client)
   400 {
   401 	return GetPlayerByIndex(client);
   402 }
   403 
   404 void CPlayerManager::ClearAdminId(AdminId id)
   405 {
   406 	for (int i=1; i<=m_maxClients; i++)
   407 	{
   408 		if (m_Players[i].m_Admin == id)
   409 		{
   410 			m_Players[i].DumpAdmin(true);
   411 		}
   412 	}
   413 }
   414 
   415 void CPlayerManager::ClearAllAdmins()
   416 {
   417 	for (int i=1; i<=m_maxClients; i++)
   418 	{
   419 		m_Players[i].DumpAdmin(true);
   420 	}
   421 }
   422 
   423 
   424 /*******************
   425  *** PLAYER CODE ***
   426  *******************/
   427 
   428 CPlayer::CPlayer()
   429 {
   430 	m_IsConnected = false;
   431 	m_IsInGame = false;
   432 	m_IsAuthorized = false;
   433 	m_pEdict = NULL;
   434 	m_Admin = INVALID_ADMIN_ID;
   435 	m_TempAdmin = false;
   436 }
   437 
   438 void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
   439 {
   440 	m_IsConnected = true;
   441 	m_Name.assign(name);
   442 	m_Ip.assign(ip);
   443 	m_pEdict = pEntity;
   444 }
   445 
   446 void CPlayer::Connect()
   447 {
   448 	m_IsInGame = true;
   449 }
   450 
   451 void CPlayer::Authorize(const char *steamid)
   452 {
   453 	m_IsAuthorized = true;
   454 	m_AuthID.assign(steamid);
   455 }
   456 
   457 void CPlayer::Disconnect()
   458 {
   459 	DumpAdmin(false);
   460 	m_IsConnected = false;
   461 	m_IsInGame = false;
   462 	m_IsAuthorized = false;
   463 	m_Name.clear();
   464 	m_Ip.clear();
   465 	m_AuthID.clear();
   466 	m_pEdict = NULL;
   467 }
   468 
   469 void CPlayer::SetName(const char *name)
   470 {
   471 	m_Name.assign(name);
   472 }
   473 
   474 const char *CPlayer::GetName() const
   475 {
   476 	return m_Name.c_str();
   477 }
   478 
   479 const char *CPlayer::GetIPAddress() const
   480 {
   481 	return m_Ip.c_str();
   482 }
   483 
   484 const char *CPlayer::GetAuthString() const
   485 {
   486 	return m_AuthID.c_str();
   487 }
   488 
   489 edict_t *CPlayer::GetEdict() const
   490 {
   491 	return m_pEdict;
   492 }
   493 
   494 bool CPlayer::IsInGame() const
   495 {
   496 	return m_IsInGame;
   497 }
   498 
   499 bool CPlayer::IsConnected() const
   500 {
   501 	return m_IsConnected;
   502 }
   503 
   504 bool CPlayer::IsAuthorized() const
   505 {
   506 	return m_IsAuthorized;
   507 }
   508 
   509 bool CPlayer::IsFakeClient() const
   510 {
   511 	return (strcmp(m_AuthID.c_str(), "BOT") == 0);
   512 }
   513 
   514 void CPlayer::SetAdminId(AdminId id, bool temporary)
   515 {
   516 	if (!m_IsConnected)
   517 	{
   518 		return;
   519 	}
   520 
   521 	DumpAdmin(false);
   522 
   523 	m_Admin = id;
   524 	m_TempAdmin = temporary;
   525 }
   526 
   527 AdminId CPlayer::GetAdminId() const
   528 {
   529 	return m_Admin;
   530 }
   531 
   532 void CPlayer::DumpAdmin(bool deleting)
   533 {
   534 	if (m_Admin != INVALID_ADMIN_ID)
   535 	{
   536 		if (m_TempAdmin && !deleting)
   537 		{
   538 			g_Admins.InvalidateAdmin(m_Admin);
   539 		}
   540 		m_Admin = INVALID_ADMIN_ID;
   541 		m_TempAdmin = false;
   542 	}
   543 }