1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/PlayerManager.cpp Sat Mar 10 21:18:07 2007 +0000
1.3 @@ -0,0 +1,539 @@
1.4 +/**
1.5 + * ===============================================================
1.6 + * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
1.7 + * ===============================================================
1.8 + *
1.9 + * This file is not open source and may not be copied without explicit
1.10 + * written permission of AlliedModders LLC. This file may not be redistributed
1.11 + * in whole or significant part.
1.12 + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.13 + *
1.14 + * Version: $Id$
1.15 + */
1.16 +
1.17 +#include "PlayerManager.h"
1.18 +#include "ForwardSys.h"
1.19 +#include "ShareSys.h"
1.20 +#include "AdminCache.h"
1.21 +#include "ConCmdManager.h"
1.22 +
1.23 +CPlayerManager g_Players;
1.24 +
1.25 +SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
1.26 +SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
1.27 +SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
1.28 +SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
1.29 +SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
1.30 +SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
1.31 +
1.32 +CPlayerManager::CPlayerManager()
1.33 +{
1.34 + m_AuthQueue = NULL;
1.35 + m_FirstPass = true;
1.36 +}
1.37 +
1.38 +CPlayerManager::~CPlayerManager()
1.39 +{
1.40 + delete [] m_AuthQueue;
1.41 +}
1.42 +
1.43 +void CPlayerManager::OnSourceModAllInitialized()
1.44 +{
1.45 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false);
1.46 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect_Post, true);
1.47 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true);
1.48 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false);
1.49 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true);
1.50 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false);
1.51 + SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true);
1.52 + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true);
1.53 +
1.54 + g_ShareSys.AddInterface(NULL, this);
1.55 +
1.56 + ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
1.57 + ParamType p2[] = {Param_Cell};
1.58 +
1.59 + m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
1.60 + m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
1.61 + m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
1.62 + m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
1.63 + m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
1.64 + m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
1.65 + m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
1.66 +}
1.67 +
1.68 +void CPlayerManager::OnSourceModShutdown()
1.69 +{
1.70 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false);
1.71 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &CPlayerManager::OnClientPutInServer, true);
1.72 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect, false);
1.73 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &CPlayerManager::OnClientDisconnect_Post, true);
1.74 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &CPlayerManager::OnClientCommand, false);
1.75 + SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &CPlayerManager::OnClientSettingsChanged, true);
1.76 + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &CPlayerManager::OnServerActivate, true);
1.77 +
1.78 + /* Release forwards */
1.79 + g_Forwards.ReleaseForward(m_clconnect);
1.80 + g_Forwards.ReleaseForward(m_clputinserver);
1.81 + g_Forwards.ReleaseForward(m_cldisconnect);
1.82 + g_Forwards.ReleaseForward(m_cldisconnect_post);
1.83 + g_Forwards.ReleaseForward(m_clcommand);
1.84 + g_Forwards.ReleaseForward(m_clinfochanged);
1.85 + g_Forwards.ReleaseForward(m_clauth);
1.86 +
1.87 + delete [] m_Players;
1.88 +}
1.89 +
1.90 +void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
1.91 +{
1.92 + if (m_FirstPass)
1.93 + {
1.94 + /* Initialize all players */
1.95 + m_maxClients = clientMax;
1.96 + m_PlayerCount = 0;
1.97 + m_Players = new CPlayer[m_maxClients + 1];
1.98 + m_AuthQueue = new unsigned int[m_maxClients + 1];
1.99 + m_FirstPass = false;
1.100 +
1.101 + memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
1.102 + }
1.103 +}
1.104 +
1.105 +void CPlayerManager::RunAuthChecks()
1.106 +{
1.107 + CPlayer *pPlayer;
1.108 + const char *authstr;
1.109 + unsigned int removed = 0;
1.110 + for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
1.111 + {
1.112 + pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
1.113 + authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
1.114 + if (authstr && authstr[0] != '\0'
1.115 + && (strcmp(authstr, "STEAM_ID_PENDING") != 0))
1.116 + {
1.117 + /* Set authorization */
1.118 + pPlayer->m_AuthID.assign(authstr);
1.119 + pPlayer->m_IsAuthorized = true;
1.120 +
1.121 + /* Send to extensions */
1.122 + List<IClientListener *>::iterator iter;
1.123 + IClientListener *pListener;
1.124 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.125 + {
1.126 + pListener = (*iter);
1.127 + pListener->OnClientAuthorized(m_AuthQueue[i], authstr);
1.128 + }
1.129 +
1.130 + /* Send to plugins */
1.131 + if (m_clauth->GetFunctionCount())
1.132 + {
1.133 + m_clauth->PushCell(m_AuthQueue[i]);
1.134 + m_clauth->PushString(authstr);
1.135 + m_clauth->Execute(NULL);
1.136 + }
1.137 +
1.138 + /* Mark as removed from queue */
1.139 + m_AuthQueue[i] = 0;
1.140 + removed++;
1.141 + }
1.142 + }
1.143 +
1.144 + /* Clean up the queue */
1.145 + if (removed)
1.146 + {
1.147 + /* We don't have to compcat the list if it's empty */
1.148 + if (removed != m_AuthQueue[0])
1.149 + {
1.150 + unsigned int diff = 0;
1.151 + for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
1.152 + {
1.153 + /* If this member is removed... */
1.154 + if (m_AuthQueue[i] == 0)
1.155 + {
1.156 + /* Increase the differential */
1.157 + diff++;
1.158 + } else {
1.159 + /* diff cannot increase faster than i+1 */
1.160 + assert(i > diff);
1.161 + assert(i - diff >= 1);
1.162 + /* move this index down */
1.163 + m_AuthQueue[i - diff] = m_AuthQueue[i];
1.164 + }
1.165 + }
1.166 + m_AuthQueue[0] -= removed;
1.167 + } else {
1.168 + m_AuthQueue[0] = 0;
1.169 + g_SourceMod.SetAuthChecking(false);
1.170 + }
1.171 + }
1.172 +}
1.173 +
1.174 +bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
1.175 +{
1.176 + int client = engine->IndexOfEdict(pEntity);
1.177 +
1.178 + List<IClientListener *>::iterator iter;
1.179 + IClientListener *pListener = NULL;
1.180 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.181 + {
1.182 + pListener = (*iter);
1.183 + if (!pListener->InterceptClientConnect(client, reject, maxrejectlen))
1.184 + {
1.185 + return false;
1.186 + }
1.187 + }
1.188 +
1.189 + cell_t res = 1;
1.190 +
1.191 + m_Players[client].Initialize(pszName, pszAddress, pEntity);
1.192 + m_clconnect->PushCell(client);
1.193 + m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK);
1.194 + m_clconnect->PushCell(maxrejectlen);
1.195 + m_clconnect->Execute(&res, NULL);
1.196 +
1.197 + if (res)
1.198 + {
1.199 + m_AuthQueue[++m_AuthQueue[0]] = client;
1.200 + g_SourceMod.SetAuthChecking(true);
1.201 + } else {
1.202 + RETURN_META_VALUE(MRES_SUPERCEDE, false);
1.203 + }
1.204 +
1.205 + return true;
1.206 +}
1.207 +
1.208 +bool CPlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
1.209 +{
1.210 + int client = engine->IndexOfEdict(pEntity);
1.211 + bool orig_value = META_RESULT_ORIG_RET(bool);
1.212 + if (orig_value)
1.213 + {
1.214 + List<IClientListener *>::iterator iter;
1.215 + IClientListener *pListener = NULL;
1.216 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.217 + {
1.218 + pListener = (*iter);
1.219 + pListener->OnClientConnected(client);
1.220 + }
1.221 + }
1.222 +
1.223 + return true;
1.224 +}
1.225 +
1.226 +void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername)
1.227 +{
1.228 + cell_t res;
1.229 + int client = engine->IndexOfEdict(pEntity);
1.230 +
1.231 + CPlayer *pPlayer = GetPlayerByIndex(client);
1.232 + if (!pPlayer->IsConnected())
1.233 + {
1.234 + /* Run manual connection routines */
1.235 + char error[255];
1.236 + if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
1.237 + {
1.238 + /* :TODO: kick the bot if it's rejected */
1.239 + return;
1.240 + }
1.241 + List<IClientListener *>::iterator iter;
1.242 + IClientListener *pListener = NULL;
1.243 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.244 + {
1.245 + pListener = (*iter);
1.246 + pListener->OnClientConnected(client);
1.247 + }
1.248 + }
1.249 +
1.250 + List<IClientListener *>::iterator iter;
1.251 + IClientListener *pListener = NULL;
1.252 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.253 + {
1.254 + pListener = (*iter);
1.255 + pListener->OnClientPutInServer(client);
1.256 + }
1.257 +
1.258 + m_Players[client].Connect();
1.259 + m_PlayerCount++;
1.260 + m_clputinserver->PushCell(client);
1.261 + m_clputinserver->Execute(&res, NULL);
1.262 +}
1.263 +
1.264 +void CPlayerManager::OnClientDisconnect(edict_t *pEntity)
1.265 +{
1.266 + cell_t res;
1.267 + int client = engine->IndexOfEdict(pEntity);
1.268 +
1.269 + if (m_Players[client].IsConnected())
1.270 + {
1.271 + m_cldisconnect->PushCell(client);
1.272 + m_cldisconnect->Execute(&res, NULL);
1.273 + }
1.274 +
1.275 + if (m_Players[client].IsInGame())
1.276 + {
1.277 + m_PlayerCount--;
1.278 + }
1.279 +
1.280 + List<IClientListener *>::iterator iter;
1.281 + IClientListener *pListener = NULL;
1.282 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.283 + {
1.284 + pListener = (*iter);
1.285 + pListener->OnClientDisconnecting(client);
1.286 + }
1.287 +
1.288 + /**
1.289 + * Remove client from auth queue if necessary
1.290 + */
1.291 + if (!m_Players[client].IsAuthorized())
1.292 + {
1.293 + for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
1.294 + {
1.295 + if (m_AuthQueue[i] == (unsigned)client)
1.296 + {
1.297 + /* Move everything ahead of us back by one */
1.298 + for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
1.299 + {
1.300 + m_AuthQueue[j-1] = m_AuthQueue[j];
1.301 + }
1.302 + /* Remove us and break */
1.303 + m_AuthQueue[0]--;
1.304 + break;
1.305 + }
1.306 + }
1.307 + }
1.308 +
1.309 + m_Players[client].Disconnect();
1.310 +}
1.311 +
1.312 +void CPlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
1.313 +{
1.314 + cell_t res;
1.315 + int client = engine->IndexOfEdict(pEntity);
1.316 +
1.317 + m_cldisconnect_post->PushCell(client);
1.318 + m_cldisconnect_post->Execute(&res, NULL);
1.319 +
1.320 + List<IClientListener *>::iterator iter;
1.321 + IClientListener *pListener = NULL;
1.322 + for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
1.323 + {
1.324 + pListener = (*iter);
1.325 + pListener->OnClientDisconnected(client);
1.326 + }
1.327 +}
1.328 +
1.329 +void CPlayerManager::OnClientCommand(edict_t *pEntity)
1.330 +{
1.331 + cell_t res = Pl_Continue;
1.332 + int client = engine->IndexOfEdict(pEntity);
1.333 +
1.334 + int args = engine->Cmd_Argc() - 1;
1.335 +
1.336 + m_clcommand->PushCell(client);
1.337 + m_clcommand->PushCell(args);
1.338 + m_clcommand->Execute(&res, NULL);
1.339 +
1.340 + if (res >= Pl_Stop)
1.341 + {
1.342 + RETURN_META(MRES_SUPERCEDE);
1.343 + }
1.344 +
1.345 + res = g_ConCmds.DispatchClientCommand(client, (ResultType)res);
1.346 +
1.347 + if (res >= Pl_Handled)
1.348 + {
1.349 + RETURN_META(MRES_SUPERCEDE);
1.350 + }
1.351 +}
1.352 +
1.353 +void CPlayerManager::OnClientSettingsChanged(edict_t *pEntity)
1.354 +{
1.355 + cell_t res;
1.356 + int client = engine->IndexOfEdict(pEntity);
1.357 +
1.358 + m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity));
1.359 + m_clinfochanged->Execute(&res, NULL);
1.360 + m_Players[client].SetName(engine->GetClientConVarValue(client, "name"));
1.361 +}
1.362 +
1.363 +int CPlayerManager::GetMaxClients()
1.364 +{
1.365 + return m_maxClients;
1.366 +}
1.367 +
1.368 +CPlayer *CPlayerManager::GetPlayerByIndex(int client) const
1.369 +{
1.370 + if (client > m_maxClients || client < 1)
1.371 + {
1.372 + return NULL;
1.373 + }
1.374 + return &m_Players[client];
1.375 +}
1.376 +
1.377 +int CPlayerManager::GetNumPlayers()
1.378 +{
1.379 + return m_PlayerCount;
1.380 +}
1.381 +
1.382 +void CPlayerManager::AddClientListener(IClientListener *listener)
1.383 +{
1.384 + m_hooks.push_back(listener);
1.385 +}
1.386 +
1.387 +void CPlayerManager::RemoveClientListener(IClientListener *listener)
1.388 +{
1.389 + m_hooks.remove(listener);
1.390 +}
1.391 +
1.392 +IGamePlayer *CPlayerManager::GetGamePlayer(edict_t *pEdict)
1.393 +{
1.394 + int index = engine->IndexOfEdict(pEdict);
1.395 + return GetGamePlayer(index);
1.396 +}
1.397 +
1.398 +IGamePlayer *CPlayerManager::GetGamePlayer(int client)
1.399 +{
1.400 + return GetPlayerByIndex(client);
1.401 +}
1.402 +
1.403 +void CPlayerManager::ClearAdminId(AdminId id)
1.404 +{
1.405 + for (int i=1; i<=m_maxClients; i++)
1.406 + {
1.407 + if (m_Players[i].m_Admin == id)
1.408 + {
1.409 + m_Players[i].DumpAdmin(true);
1.410 + }
1.411 + }
1.412 +}
1.413 +
1.414 +void CPlayerManager::ClearAllAdmins()
1.415 +{
1.416 + for (int i=1; i<=m_maxClients; i++)
1.417 + {
1.418 + m_Players[i].DumpAdmin(true);
1.419 + }
1.420 +}
1.421 +
1.422 +
1.423 +/*******************
1.424 + *** PLAYER CODE ***
1.425 + *******************/
1.426 +
1.427 +CPlayer::CPlayer()
1.428 +{
1.429 + m_IsConnected = false;
1.430 + m_IsInGame = false;
1.431 + m_IsAuthorized = false;
1.432 + m_pEdict = NULL;
1.433 + m_Admin = INVALID_ADMIN_ID;
1.434 + m_TempAdmin = false;
1.435 +}
1.436 +
1.437 +void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
1.438 +{
1.439 + m_IsConnected = true;
1.440 + m_Name.assign(name);
1.441 + m_Ip.assign(ip);
1.442 + m_pEdict = pEntity;
1.443 +}
1.444 +
1.445 +void CPlayer::Connect()
1.446 +{
1.447 + m_IsInGame = true;
1.448 +}
1.449 +
1.450 +void CPlayer::Authorize(const char *steamid)
1.451 +{
1.452 + m_IsAuthorized = true;
1.453 + m_AuthID.assign(steamid);
1.454 +}
1.455 +
1.456 +void CPlayer::Disconnect()
1.457 +{
1.458 + DumpAdmin(false);
1.459 + m_IsConnected = false;
1.460 + m_IsInGame = false;
1.461 + m_IsAuthorized = false;
1.462 + m_Name.clear();
1.463 + m_Ip.clear();
1.464 + m_AuthID.clear();
1.465 + m_pEdict = NULL;
1.466 +}
1.467 +
1.468 +void CPlayer::SetName(const char *name)
1.469 +{
1.470 + m_Name.assign(name);
1.471 +}
1.472 +
1.473 +const char *CPlayer::GetName() const
1.474 +{
1.475 + return m_Name.c_str();
1.476 +}
1.477 +
1.478 +const char *CPlayer::GetIPAddress() const
1.479 +{
1.480 + return m_Ip.c_str();
1.481 +}
1.482 +
1.483 +const char *CPlayer::GetAuthString() const
1.484 +{
1.485 + return m_AuthID.c_str();
1.486 +}
1.487 +
1.488 +edict_t *CPlayer::GetEdict() const
1.489 +{
1.490 + return m_pEdict;
1.491 +}
1.492 +
1.493 +bool CPlayer::IsInGame() const
1.494 +{
1.495 + return m_IsInGame;
1.496 +}
1.497 +
1.498 +bool CPlayer::IsConnected() const
1.499 +{
1.500 + return m_IsConnected;
1.501 +}
1.502 +
1.503 +bool CPlayer::IsAuthorized() const
1.504 +{
1.505 + return m_IsAuthorized;
1.506 +}
1.507 +
1.508 +bool CPlayer::IsFakeClient() const
1.509 +{
1.510 + return (strcmp(m_AuthID.c_str(), "BOT") == 0);
1.511 +}
1.512 +
1.513 +void CPlayer::SetAdminId(AdminId id, bool temporary)
1.514 +{
1.515 + if (!m_IsConnected)
1.516 + {
1.517 + return;
1.518 + }
1.519 +
1.520 + DumpAdmin(false);
1.521 +
1.522 + m_Admin = id;
1.523 + m_TempAdmin = temporary;
1.524 +}
1.525 +
1.526 +AdminId CPlayer::GetAdminId() const
1.527 +{
1.528 + return m_Admin;
1.529 +}
1.530 +
1.531 +void CPlayer::DumpAdmin(bool deleting)
1.532 +{
1.533 + if (m_Admin != INVALID_ADMIN_ID)
1.534 + {
1.535 + if (m_TempAdmin && !deleting)
1.536 + {
1.537 + g_Admins.InvalidateAdmin(m_Admin);
1.538 + }
1.539 + m_Admin = INVALID_ADMIN_ID;
1.540 + m_TempAdmin = false;
1.541 + }
1.542 +}