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