More consistency of some sort...
Oh god, what has possessed me to do this?
3 * ===============================================================
4 * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
5 * ===============================================================
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
15 #include "PlayerManager.h"
16 #include "ForwardSys.h"
18 #include "AdminCache.h"
19 #include "ConCmdManager.h"
21 PlayerManager g_Players;
23 SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
24 SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
25 SH_DECL_HOOK1_void(IServerGameClients, ClientDisconnect, SH_NOATTRIB, 0, edict_t *);
26 SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *);
27 SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
28 SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
30 PlayerManager::PlayerManager()
36 PlayerManager::~PlayerManager()
38 delete [] m_AuthQueue;
41 void PlayerManager::OnSourceModAllInitialized()
43 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false);
44 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect_Post, true);
45 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true);
46 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false);
47 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true);
48 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false);
49 SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true);
50 SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true);
52 g_ShareSys.AddInterface(NULL, this);
54 ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
55 ParamType p2[] = {Param_Cell};
57 m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
58 m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
59 m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
60 m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
61 m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 2, NULL, Param_Cell, Param_Cell);
62 m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
63 m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, NULL, Param_Cell, Param_String);
64 m_onActivate = g_Forwards.CreateForward("OnServerLoad", ET_Ignore, 0, NULL);
67 void PlayerManager::OnSourceModShutdown()
69 SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &PlayerManager::OnClientConnect, false);
70 SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientPutInServer, serverClients, this, &PlayerManager::OnClientPutInServer, true);
71 SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect, false);
72 SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientDisconnect, serverClients, this, &PlayerManager::OnClientDisconnect_Post, true);
73 SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, serverClients, this, &PlayerManager::OnClientCommand, false);
74 SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientSettingsChanged, serverClients, this, &PlayerManager::OnClientSettingsChanged, true);
75 SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &PlayerManager::OnServerActivate, true);
77 /* Release forwards */
78 g_Forwards.ReleaseForward(m_clconnect);
79 g_Forwards.ReleaseForward(m_clputinserver);
80 g_Forwards.ReleaseForward(m_cldisconnect);
81 g_Forwards.ReleaseForward(m_cldisconnect_post);
82 g_Forwards.ReleaseForward(m_clcommand);
83 g_Forwards.ReleaseForward(m_clinfochanged);
84 g_Forwards.ReleaseForward(m_clauth);
85 g_Forwards.ReleaseForward(m_onActivate);
90 void PlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
94 /* Initialize all players */
95 m_maxClients = clientMax;
97 m_Players = new CPlayer[m_maxClients + 1];
98 m_AuthQueue = new unsigned int[m_maxClients + 1];
101 memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
103 m_onActivate->Execute(NULL);
106 void PlayerManager::RunAuthChecks()
110 unsigned int removed = 0;
111 for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
113 pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
114 authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
115 if (authstr && authstr[0] != '\0'
116 && (strcmp(authstr, "STEAM_ID_PENDING") != 0))
118 /* Set authorization */
119 pPlayer->m_AuthID.assign(authstr);
120 pPlayer->m_IsAuthorized = true;
122 /* Mark as removed from queue */
123 unsigned int client = m_AuthQueue[i];
127 /* Send to extensions */
128 List<IClientListener *>::iterator iter;
129 IClientListener *pListener;
130 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
133 pListener->OnClientAuthorized(client, authstr);
134 if (!pPlayer->IsConnected())
140 /* Send to plugins if player is still connected */
141 if (pPlayer->IsConnected() && m_clauth->GetFunctionCount())
143 /* :TODO: handle the case of a player disconnecting in the middle */
144 m_clauth->PushCell(client);
145 m_clauth->PushString(authstr);
146 m_clauth->Execute(NULL);
151 /* Clean up the queue */
154 /* We don't have to compcat the list if it's empty */
155 if (removed != m_AuthQueue[0])
157 unsigned int diff = 0;
158 for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
160 /* If this member is removed... */
161 if (m_AuthQueue[i] == 0)
163 /* Increase the differential */
166 /* diff cannot increase faster than i+1 */
168 assert(i - diff >= 1);
169 /* move this index down */
170 m_AuthQueue[i - diff] = m_AuthQueue[i];
173 m_AuthQueue[0] -= removed;
176 g_SourceMod.SetAuthChecking(false);
181 bool PlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
183 int client = engine->IndexOfEdict(pEntity);
185 List<IClientListener *>::iterator iter;
186 IClientListener *pListener = NULL;
187 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
190 if (!pListener->InterceptClientConnect(client, reject, maxrejectlen))
198 m_Players[client].Initialize(pszName, pszAddress, pEntity);
199 m_clconnect->PushCell(client);
200 m_clconnect->PushStringEx(reject, maxrejectlen, SM_PARAM_STRING_UTF8, SM_PARAM_COPYBACK);
201 m_clconnect->PushCell(maxrejectlen);
202 m_clconnect->Execute(&res, NULL);
206 if (!m_Players[client].IsAuthorized())
208 m_AuthQueue[++m_AuthQueue[0]] = client;
209 g_SourceMod.SetAuthChecking(true);
212 RETURN_META_VALUE(MRES_SUPERCEDE, false);
218 bool PlayerManager::OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen)
220 int client = engine->IndexOfEdict(pEntity);
221 bool orig_value = META_RESULT_ORIG_RET(bool);
224 List<IClientListener *>::iterator iter;
225 IClientListener *pListener = NULL;
226 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
229 pListener->OnClientConnected(client);
236 void PlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playername)
239 int client = engine->IndexOfEdict(pEntity);
241 CPlayer *pPlayer = GetPlayerByIndex(client);
242 /* If they're not connected, they're a bot */
243 if (!pPlayer->IsConnected())
245 /* Run manual connection routines */
247 const char *authid = engine->GetPlayerNetworkIDString(pEntity);
248 pPlayer->Authorize(authid);
249 if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
251 /* :TODO: kick the bot if it's rejected */
254 List<IClientListener *>::iterator iter;
255 IClientListener *pListener = NULL;
256 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
259 pListener->OnClientConnected(client);
260 /* See if bot was kicked */
261 if (!pPlayer->IsConnected())
266 /* Now do authorization */
267 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
270 pListener->OnClientAuthorized(client, authid);
271 /* See if bot was kicked */
272 if (!pPlayer->IsConnected())
277 /* Finally, tell plugins */
278 if (m_clauth->GetFunctionCount())
280 m_clauth->PushCell(client);
281 m_clauth->PushString(authid);
282 m_clauth->Execute(NULL);
288 pPlayer->m_Info = playerinfo->GetPlayerInfo(pEntity);
291 List<IClientListener *>::iterator iter;
292 IClientListener *pListener = NULL;
293 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
296 pListener->OnClientPutInServer(client);
297 /* See if player was kicked */
298 if (!pPlayer->IsConnected())
304 m_Players[client].Connect();
306 m_clputinserver->PushCell(client);
307 m_clputinserver->Execute(&res, NULL);
310 void PlayerManager::OnClientDisconnect(edict_t *pEntity)
313 int client = engine->IndexOfEdict(pEntity);
315 if (m_Players[client].IsConnected())
317 m_cldisconnect->PushCell(client);
318 m_cldisconnect->Execute(&res, NULL);
321 if (m_Players[client].IsInGame())
326 List<IClientListener *>::iterator iter;
327 IClientListener *pListener = NULL;
328 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
331 pListener->OnClientDisconnecting(client);
335 * Remove client from auth queue if necessary
337 if (!m_Players[client].IsAuthorized())
339 for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
341 if (m_AuthQueue[i] == (unsigned)client)
343 /* Move everything ahead of us back by one */
344 for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
346 m_AuthQueue[j-1] = m_AuthQueue[j];
348 /* Remove us and break */
355 m_Players[client].Disconnect();
358 void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
361 int client = engine->IndexOfEdict(pEntity);
363 m_cldisconnect_post->PushCell(client);
364 m_cldisconnect_post->Execute(&res, NULL);
366 List<IClientListener *>::iterator iter;
367 IClientListener *pListener = NULL;
368 for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
371 pListener->OnClientDisconnected(client);
375 void PlayerManager::OnClientCommand(edict_t *pEntity)
377 cell_t res = Pl_Continue;
378 int client = engine->IndexOfEdict(pEntity);
380 int args = engine->Cmd_Argc() - 1;
382 m_clcommand->PushCell(client);
383 m_clcommand->PushCell(args);
384 m_clcommand->Execute(&res, NULL);
388 RETURN_META(MRES_SUPERCEDE);
391 res = g_ConCmds.DispatchClientCommand(client, (ResultType)res);
393 if (res >= Pl_Handled)
395 RETURN_META(MRES_SUPERCEDE);
399 void PlayerManager::OnClientSettingsChanged(edict_t *pEntity)
402 int client = engine->IndexOfEdict(pEntity);
404 m_clinfochanged->PushCell(engine->IndexOfEdict(pEntity));
405 m_clinfochanged->Execute(&res, NULL);
406 m_Players[client].SetName(engine->GetClientConVarValue(client, "name"));
409 int PlayerManager::GetMaxClients()
414 CPlayer *PlayerManager::GetPlayerByIndex(int client) const
416 if (client > m_maxClients || client < 1)
420 return &m_Players[client];
423 int PlayerManager::GetNumPlayers()
425 return m_PlayerCount;
428 void PlayerManager::AddClientListener(IClientListener *listener)
430 m_hooks.push_back(listener);
433 void PlayerManager::RemoveClientListener(IClientListener *listener)
435 m_hooks.remove(listener);
438 IGamePlayer *PlayerManager::GetGamePlayer(edict_t *pEdict)
440 int index = engine->IndexOfEdict(pEdict);
441 return GetGamePlayer(index);
444 IGamePlayer *PlayerManager::GetGamePlayer(int client)
446 return GetPlayerByIndex(client);
449 void PlayerManager::ClearAdminId(AdminId id)
451 for (int i=1; i<=m_maxClients; i++)
453 if (m_Players[i].m_Admin == id)
455 m_Players[i].DumpAdmin(true);
460 void PlayerManager::ClearAllAdmins()
462 for (int i=1; i<=m_maxClients; i++)
464 m_Players[i].DumpAdmin(true);
475 m_IsConnected = false;
477 m_IsAuthorized = false;
479 m_Admin = INVALID_ADMIN_ID;
484 void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
486 m_IsConnected = true;
492 void CPlayer::Connect()
497 void CPlayer::Authorize(const char *steamid)
499 m_IsAuthorized = true;
500 m_AuthID.assign(steamid);
503 void CPlayer::Disconnect()
506 m_IsConnected = false;
508 m_IsAuthorized = false;
516 void CPlayer::SetName(const char *name)
521 const char *CPlayer::GetName()
523 return m_Name.c_str();
526 const char *CPlayer::GetIPAddress()
531 const char *CPlayer::GetAuthString()
533 return m_AuthID.c_str();
536 edict_t *CPlayer::GetEdict()
541 bool CPlayer::IsInGame()
546 bool CPlayer::IsConnected()
548 return m_IsConnected;
551 bool CPlayer::IsAuthorized()
553 return m_IsAuthorized;
556 IPlayerInfo *CPlayer::GetPlayerInfo()
561 bool CPlayer::IsFakeClient()
563 return (strcmp(m_AuthID.c_str(), "BOT") == 0);
566 void CPlayer::SetAdminId(AdminId id, bool temporary)
576 m_TempAdmin = temporary;
579 AdminId CPlayer::GetAdminId()
584 void CPlayer::DumpAdmin(bool deleting)
586 if (m_Admin != INVALID_ADMIN_ID)
588 if (m_TempAdmin && !deleting)
590 g_Admins.InvalidateAdmin(m_Admin);
592 m_Admin = INVALID_ADMIN_ID;