added steamid auth functions

added better bot detection
added gameframe hook for timer
renamed more playermanager stuff

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40454
This commit is contained in:
David Anderson 2007-02-07 08:44:48 +00:00
parent 085264e837
commit 03fd3139c5
9 changed files with 225 additions and 54 deletions

View File

@ -15,7 +15,7 @@
#include "ForwardSys.h"
#include "ShareSys.h"
CPlayerManager g_PlayerManager;
CPlayerManager g_Players;
SH_DECL_HOOK5(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, edict_t *, const char *, const char *, char *, int);
SH_DECL_HOOK2_void(IServerGameClients, ClientPutInServer, SH_NOATTRIB, 0, edict_t *, const char *);
@ -24,6 +24,17 @@ SH_DECL_HOOK1_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, edict_t *)
SH_DECL_HOOK1_void(IServerGameClients, ClientSettingsChanged, SH_NOATTRIB, 0, edict_t *);
SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int);
CPlayerManager::CPlayerManager()
{
m_AuthQueue = NULL;
m_FirstPass = true;
}
CPlayerManager::~CPlayerManager()
{
delete [] m_AuthQueue;
}
void CPlayerManager::OnSourceModAllInitialized()
{
SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientConnect, serverClients, this, &CPlayerManager::OnClientConnect, false);
@ -37,28 +48,17 @@ void CPlayerManager::OnSourceModAllInitialized()
g_ShareSys.AddInterface(NULL, this);
/* Register OnClientConnect */
ParamType p1[] = {Param_Cell, Param_String, Param_Cell};
m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
/* Register OnClientPutInServer */
ParamType p2[] = {Param_Cell};
ParamType p3[] = {Param_Cell, Param_String};
m_clconnect = g_Forwards.CreateForward("OnClientConnect", ET_Event, 3, p1);
m_clputinserver = g_Forwards.CreateForward("OnClientPutInServer", ET_Ignore, 1, p2);
/* Register OnClientDisconnect */
m_cldisconnect = g_Forwards.CreateForward("OnClientDisconnect", ET_Ignore, 1, p2);
/* Register OnClientDisconnect_Post */
m_cldisconnect_post = g_Forwards.CreateForward("OnClientDisconnect_Post", ET_Ignore, 1, p2);
/* Register OnClientCommand */
m_clcommand = g_Forwards.CreateForward("OnClientCommand", ET_Hook, 1, p2);
/* Register OnClientSettingsChanged */
m_clinfochanged = g_Forwards.CreateForward("OnClientSettingsChanged", ET_Ignore, 1, p2);
/* Register OnClientAuthorized */
//:TODO:
m_clauth = g_Forwards.CreateForward("OnClientAuthorized", ET_Ignore, 2, p2);
}
void CPlayerManager::OnSourceModShutdown()
@ -78,6 +78,7 @@ void CPlayerManager::OnSourceModShutdown()
g_Forwards.ReleaseForward(m_cldisconnect_post);
g_Forwards.ReleaseForward(m_clcommand);
g_Forwards.ReleaseForward(m_clinfochanged);
g_Forwards.ReleaseForward(m_clauth);
delete [] m_Players;
}
@ -90,7 +91,79 @@ void CPlayerManager::OnServerActivate(edict_t *pEdictList, int edictCount, int c
m_maxClients = clientMax;
m_PlayerCount = 0;
m_Players = new CPlayer[m_maxClients + 1];
m_AuthQueue = new unsigned int[m_maxClients + 1];
m_FirstPass = false;
memset(m_AuthQueue, 0, sizeof(unsigned int) * (m_maxClients + 1));
}
}
void CPlayerManager::RunAuthChecks()
{
CPlayer *pPlayer;
const char *authstr;
unsigned int removed = 0;
for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
{
pPlayer = GetPlayerByIndex(m_AuthQueue[i]);
authstr = engine->GetPlayerNetworkIDString(pPlayer->m_pEdict);
if (authstr && authstr[0] != '\0'
&& (strcmp(authstr, "STEAM_ID_PENDING") != 0))
{
/* Set authorization */
pPlayer->m_AuthID.assign(authstr);
pPlayer->m_IsAuthorized = true;
/* Send to extensions */
List<IClientListener *>::iterator iter;
IClientListener *pListener;
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
{
pListener = (*iter);
pListener->OnClientAuthorized(m_AuthQueue[i], authstr);
}
/* Send to plugins */
if (m_clauth->GetFunctionCount())
{
m_clauth->PushCell(m_AuthQueue[i]);
m_clauth->PushString(authstr);
m_clauth->Execute(NULL);
}
/* Mark as removed from queue */
m_AuthQueue[i] = 0;
removed++;
}
}
/* Clean up the queue */
if (removed)
{
/* We don't have to compcat the list if it's empty */
if (removed != m_AuthQueue[0])
{
unsigned int diff = 0;
for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
{
/* If this member is removed... */
if (m_AuthQueue[i] == 0)
{
/* Increase the differential */
diff++;
} else {
/* diff cannot increase faster than i+1 */
assert(i > diff);
assert(i - diff >= 1);
/* move this index down */
m_AuthQueue[i - diff] = m_AuthQueue[i];
}
}
m_AuthQueue[0] -= removed;
} else {
m_AuthQueue[0] = 0;
g_SourceMod.SetAuthChecking(false);
}
}
}
@ -117,6 +190,12 @@ bool CPlayerManager::OnClientConnect(edict_t *pEntity, const char *pszName, cons
m_clconnect->PushCell(maxrejectlen);
m_clconnect->Execute(&res, NULL);
if (res)
{
m_AuthQueue[++m_AuthQueue[0]] = client;
g_SourceMod.SetAuthChecking(true);
}
return (res) ? true : false;
}
@ -143,6 +222,25 @@ void CPlayerManager::OnClientPutInServer(edict_t *pEntity, const char *playernam
cell_t res;
int client = engine->IndexOfEdict(pEntity);
CPlayer *pPlayer = GetPlayerByIndex(client);
if (!pPlayer->IsConnected())
{
/* Run manual connection routines */
char error[255];
if (!OnClientConnect(pEntity, playername, "127.0.0.1", error, sizeof(error)))
{
/* :TODO: kick the bot if it's rejected */
return;
}
List<IClientListener *>::iterator iter;
IClientListener *pListener = NULL;
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
{
pListener = (*iter);
pListener->OnClientConnected(client);
}
}
List<IClientListener *>::iterator iter;
IClientListener *pListener = NULL;
for (iter=m_hooks.begin(); iter!=m_hooks.end(); iter++)
@ -186,6 +284,27 @@ void CPlayerManager::OnClientDisconnect(edict_t *pEntity)
pListener->OnClientDisconnecting(client);
}
/**
* Remove client from auth queue if necessary
*/
if (!m_Players[client].IsAuthorized())
{
for (unsigned int i=1; i<=m_AuthQueue[0]; i++)
{
if (m_AuthQueue[i] == client)
{
/* Move everything ahead of us back by one */
for (unsigned int j=i+1; j<=m_AuthQueue[0]; j++)
{
m_AuthQueue[j-1] = m_AuthQueue[j];
}
/* Remove us and break */
m_AuthQueue[0]--;
break;
}
}
}
m_Players[client].Disconnect();
}
@ -275,7 +394,7 @@ CPlayer::CPlayer()
m_IsConnected = false;
m_IsInGame = false;
m_IsAuthorized = false;
m_PlayerEdict = NULL;
m_pEdict = NULL;
}
void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
@ -283,7 +402,7 @@ void CPlayer::Initialize(const char *name, const char *ip, edict_t *pEntity)
m_IsConnected = true;
m_Name.assign(name);
m_Ip.assign(ip);
m_PlayerEdict = pEntity;
m_pEdict = pEntity;
}
void CPlayer::Connect()
@ -305,7 +424,7 @@ void CPlayer::Disconnect()
m_Name.clear();
m_Ip.clear();
m_AuthID.clear();
m_PlayerEdict = NULL;
m_pEdict = NULL;
}
void CPlayer::SetName(const char *name)
@ -330,7 +449,7 @@ const char *CPlayer::GetAuthString() const
edict_t *CPlayer::GetEdict() const
{
return m_PlayerEdict;
return m_pEdict;
}
bool CPlayer::IsInGame() const

View File

@ -21,6 +21,7 @@
#include <IPlayerHelpers.h>
#include <sh_string.h>
#include <sh_list.h>
#include <sh_vector.h>
using namespace SourceHook;
@ -51,7 +52,7 @@ private:
String m_Name;
String m_Ip;
String m_AuthID;
edict_t *m_PlayerEdict;
edict_t *m_pEdict;
};
class CPlayerManager :
@ -59,12 +60,14 @@ class CPlayerManager :
public IPlayerManager
{
public:
CPlayerManager() : m_FirstPass(true) {}
CPlayerManager();
~CPlayerManager();
public: //SMGlobalClass
void OnSourceModAllInitialized();
void OnSourceModShutdown();
public:
CPlayer *GetPlayerByIndex(int client) const;
void RunAuthChecks();
public:
bool OnClientConnect(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
bool OnClientConnect_Post(edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen);
@ -100,12 +103,14 @@ private:
IForward *m_clputinserver;
IForward *m_clcommand;
IForward *m_clinfochanged;
IForward *m_clauth;
CPlayer *m_Players;
int m_maxClients;
int m_PlayerCount;
bool m_FirstPass;
unsigned int *m_AuthQueue;
};
extern CPlayerManager g_PlayerManager;
extern CPlayerManager g_Players;
#endif //_INCLUDE_SOURCEMOD_CPLAYERMANAGER_H_

View File

@ -72,7 +72,7 @@ try_serverlang:
pCtx->ThrowNativeError("Translation failure: English language not found.");
goto error_out;
}
} else if ((target >= 1) && (target <= g_PlayerManager.GetMaxClients())) {
} else if ((target >= 1) && (target <= g_Players.GetMaxClients())) {
langname = "en"; //:TODO: read player's lang
if (!langname || !g_Translator.GetLanguageByCode(langname, &langid))
{

View File

@ -18,37 +18,37 @@ static cell_t sm_GetClientCount(IPluginContext *pCtx, const cell_t *params)
{
if (params[1])
{
return g_PlayerManager.NumPlayers();
return g_Players.NumPlayers();
}
int maxplayers = g_PlayerManager.MaxClients();
int maxplayers = g_Players.MaxClients();
int count = 0;
for (int i=1; i<=maxplayers; ++i)
{
CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(i);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(i);
if ((pPlayer->IsConnected()) && !(pPlayer->IsInGame()))
{
count++;
}
}
return (g_PlayerManager.NumPlayers() + count);
return (g_Players.NumPlayers() + count);
}
static cell_t sm_GetMaxClients(IPluginContext *pCtx, const cell_t *params)
{
return g_PlayerManager.MaxClients();
return g_Players.MaxClients();
}
static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
if (!pPlayer->IsConnected())
{
return pCtx->ThrowNativeError("Client %d is not connected.", index);
@ -61,12 +61,12 @@ static cell_t sm_GetClientName(IPluginContext *pCtx, const cell_t *params)
static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
if (!pPlayer->IsConnected())
{
return pCtx->ThrowNativeError("Client %d is not connected.", index);
@ -87,12 +87,12 @@ static cell_t sm_GetClientIP(IPluginContext *pCtx, const cell_t *params)
static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
if (!pPlayer->IsConnected())
{
return pCtx->ThrowNativeError("Client %d is not connected.", index);
@ -105,45 +105,45 @@ static cell_t sm_GetClientAuthStr(IPluginContext *pCtx, const cell_t *params)
static cell_t sm_IsPlayerConnected(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
return (g_PlayerManager.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0;
return (g_Players.GetPlayerByIndex(index)->IsConnected()) ? 1 : 0;
}
static cell_t sm_IsPlayerIngame(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
return (g_PlayerManager.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0;
return (g_Players.GetPlayerByIndex(index)->IsInGame()) ? 1 : 0;
}
static cell_t sm_IsPlayerAuthorized(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
return (g_PlayerManager.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0;
return (g_Players.GetPlayerByIndex(index)->IsAuthorized()) ? 1 : 0;
}
static cell_t sm_IsPlayerFakeClient(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
if (!pPlayer->IsConnected())
{
return pCtx->ThrowNativeError("Client %d is not connected.", index);
@ -172,12 +172,12 @@ static cell_t sm_PrintToServer(IPluginContext *pCtx, const cell_t *params)
static cell_t sm_PrintToConsole(IPluginContext *pCtx, const cell_t *params)
{
int index = params[1];
if ((index < 1) || (index > g_PlayerManager.GetMaxClients()))
if ((index < 1) || (index > g_Players.GetMaxClients()))
{
return pCtx->ThrowNativeError("Invalid client index %d.", index);
}
CPlayer *pPlayer = g_PlayerManager.GetPlayerByIndex(index);
CPlayer *pPlayer = g_Players.GetPlayerByIndex(index);
if (!pPlayer->IsInGame())
{
return pCtx->ThrowNativeError("Client %d is not in game.", index);

View File

@ -21,6 +21,7 @@ IVEngineServer *engine = NULL;
IServerGameDLL *gamedll = NULL;
IServerGameClients *serverClients = NULL;
ISmmPluginManager *g_pMMPlugins = NULL;
CGlobalVars *gpGlobals = NULL;
PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core);
@ -41,6 +42,8 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen
return false;
}
gpGlobals = ismm->pGlobals();
return g_SourceMod.InitializeSourceMod(error, maxlen, late);
}

View File

@ -45,6 +45,7 @@ extern IVEngineServer *engine;
extern IServerGameDLL *gamedll;
extern IServerGameClients *serverClients;
extern ISmmPluginManager *g_pMMPlugins;
extern CGlobalVars *gpGlobals;
PLUGIN_GLOBALVARS();

View File

@ -23,9 +23,11 @@
#include "ExtensionSys.h"
#include "AdminCache.h"
#include "sm_stringutil.h"
#include "CPlayerManager.h"
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool);
SourcePawnEngine g_SourcePawn;
SourceModBase g_SourceMod;
@ -35,6 +37,8 @@ SourceHook::String g_BaseDir;
ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn;
IVirtualMachine *g_pVM;
IdentityToken_t *g_pCoreIdent = NULL;
float g_LastTime = 0.0f;
float g_LastAuthCheck = 0.0f;
typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *);
typedef unsigned int (*GETEXPORTCOUNT)();
@ -150,6 +154,7 @@ void SourceModBase::StartSourceMod(bool late)
/* First initialize the global hooks we need */
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false);
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false);
/* Notify! */
SMGlobalClass *pBase = SMGlobalClass::head;
@ -178,6 +183,8 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
{
m_IsMapLoading = true;
m_ExecPluginReload = true;
g_LastTime = 0.0f;
g_LastAuthCheck = 0.0f;
g_Logger.MapChange(pMapName);
@ -191,6 +198,25 @@ bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, ch
RETURN_META_VALUE(MRES_IGNORED, true);
}
void SourceModBase::GameFrame(bool simulating)
{
/**
* Note: This is all hardcoded rather than delegated to save
* precious CPU cycles.
*/
float curtime = gpGlobals->curtime;
if (curtime - g_LastTime > 0.1f)
{
if (m_CheckingAuth
&& (gpGlobals->curtime - g_LastAuthCheck > 0.7f))
{
g_LastAuthCheck = gpGlobals->curtime;
g_Players.RunAuthChecks();
}
g_LastTime = curtime;
}
}
void SourceModBase::LevelShutdown()
{
if (m_ExecPluginReload)
@ -280,6 +306,7 @@ void SourceModBase::CloseSourceMod()
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false);
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false);
/* Rest In Peace */
ShutdownJIT();
@ -349,6 +376,11 @@ void SourceModBase::SetGlobalTarget(unsigned int index)
m_target = index;
}
void SourceModBase::SetAuthChecking(bool set)
{
m_CheckingAuth = set;
}
unsigned int SourceModBase::GetGlobalTarget() const
{
return m_target;

View File

@ -37,8 +37,8 @@ public:
void StartSourceMod(bool late);
/**
* @brief Shuts down all SourceMod components
*/
* @brief Shuts down all SourceMod components
*/
void CloseSourceMod();
/**
@ -47,8 +47,8 @@ public:
bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
/**
* @brief Level shutdown hook
*/
* @brief Level shutdown hook
*/
void LevelShutdown();
/**
@ -57,15 +57,14 @@ public:
bool IsMapLoading();
/**
* @brief Stores the global target index.
*/
* @brief Stores the global target index.
*/
void SetGlobalTarget(unsigned int index);
/**
* @brief Returns the global target index.
*/
* @brief Returns the global target index.
*/
unsigned int GetGlobalTarget() const;
public: //ISourceMod
const char *GetModPath();
const char *GetSourceModPath();
@ -73,17 +72,20 @@ public: //ISourceMod
void LogMessage(IExtension *pExt, const char *format, ...);
void LogError(IExtension *pExt, const char *format, ...);
size_t FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param);
void SetAuthChecking(bool set);
private:
/**
* @brief Loading plugins
*/
void DoGlobalPluginLoads();
void GameFrame(bool simulating);
private:
char m_SMBaseDir[PLATFORM_MAX_PATH+1];
char m_SMRelDir[PLATFORM_MAX_PATH+1];
bool m_IsMapLoading;
bool m_ExecPluginReload;
unsigned int m_target;
bool m_CheckingAuth;
};
extern SourceModBase g_SourceMod;

View File

@ -136,6 +136,15 @@ forward OnClientCommand(client);
*/
forward OnClientSettingsChanged(client);
/**
* Called when a client receives a Steam ID.
* @note This is called by bots, but the ID will be "BOT"
*
* @param client Player index.
* @param auth Player auth string.
*/
forward OnClientAuthorized(client, const String:auth[]);
/**
* Returns the maximum number of clients allowed on the server.
*