Add FileTransfer Hooks to SDKTools (r=Drifter).
This commit is contained in:
parent
8777d0d0da
commit
274e7bd329
@ -44,6 +44,7 @@
|
||||
#include <ISDKTools.h>
|
||||
#include "clientnatives.h"
|
||||
#include "teamnatives.h"
|
||||
#include "filesystem.h"
|
||||
/**
|
||||
* @file extension.cpp
|
||||
* @brief Implements SDK Tools extension code.
|
||||
@ -68,6 +69,7 @@ IVoiceServer *voiceserver = NULL;
|
||||
IPlayerInfoManager *playerinfomngr = NULL;
|
||||
ICvar *icvar = NULL;
|
||||
IServer *iserver = NULL;
|
||||
IBaseFileSystem *basefilesystem = NULL;
|
||||
CGlobalVars *gpGlobals;
|
||||
ISoundEmitterSystemBase *soundemitterbase = NULL;
|
||||
|
||||
@ -258,6 +260,7 @@ bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool
|
||||
GET_V_IFACE_ANY(GetEngineFactory, voiceserver, IVoiceServer, INTERFACEVERSION_VOICESERVER);
|
||||
GET_V_IFACE_ANY(GetServerFactory, playerinfomngr, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER);
|
||||
GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
|
||||
GET_V_IFACE_CURRENT(GetFileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION);
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
GET_V_IFACE_ANY(GetServerFactory, servertools, IServerTools, VSERVERTOOLS_INTERFACE_VERSION);
|
||||
@ -466,9 +469,10 @@ const char *SDKTools::GetExtensionDateString()
|
||||
return SOURCEMOD_BUILD_TIME;
|
||||
}
|
||||
|
||||
void SDKTools::OnClientPutInServer(int client)
|
||||
bool SDKTools::InterceptClientConnect(int client, char *error, size_t maxlength)
|
||||
{
|
||||
g_Hooks.OnClientPutInServer(client);
|
||||
g_Hooks.OnClientConnect(client);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_CSGO
|
||||
@ -487,6 +491,11 @@ void SDKTools::OnSendClientCommand(edict_t *pPlayer, const char *szFormat)
|
||||
}
|
||||
#endif
|
||||
|
||||
void SDKTools::OnClientPutInServer(int client)
|
||||
{
|
||||
g_Hooks.OnClientPutInServer(client);
|
||||
}
|
||||
|
||||
class SDKTools_API : public ISDKTools
|
||||
{
|
||||
public:
|
||||
|
@ -89,6 +89,7 @@ public:
|
||||
public: //IConCommandBaseAccessor
|
||||
bool RegisterConCommandBase(ConCommandBase *pVar);
|
||||
public: //IClientListner
|
||||
bool InterceptClientConnect(int client, char *error, size_t maxlength);
|
||||
void OnClientPutInServer(int client);
|
||||
void OnClientDisconnecting(int client);
|
||||
public: // IVoiceServer
|
||||
@ -129,6 +130,7 @@ extern IVoiceServer *voiceserver;
|
||||
extern IPlayerInfoManager *playerinfomngr;
|
||||
extern ICvar *icvar;
|
||||
extern IServer *iserver;
|
||||
extern IBaseFileSystem *basefilesystem;
|
||||
extern CGlobalVars *gpGlobals;
|
||||
#if SOURCE_ENGINE >= SE_ORANGEBOX
|
||||
extern IServerTools *servertools;
|
||||
|
@ -37,18 +37,32 @@
|
||||
#include "utlvector.h"
|
||||
#include <shareddefs.h>
|
||||
#include "usercmd.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
#define FEATURECAP_PLAYERRUNCMD_11PARAMS "SDKTools PlayerRunCmd 11Params"
|
||||
|
||||
CHookManager g_Hooks;
|
||||
static bool PRCH_enabled = false;
|
||||
static bool PRCH_used = false;
|
||||
static bool FILE_used = false;
|
||||
|
||||
SH_DECL_MANUALHOOK2_void(PlayerRunCmdHook, 0, 0, 0, CUserCmd *, IMoveHelper *);
|
||||
SH_DECL_HOOK2(IBaseFileSystem, FileExists, SH_NOATTRIB, 0, bool, const char*, const char *);
|
||||
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
SH_DECL_HOOK3(INetChannel, SendFile, SH_NOATTRIB, 0, bool, const char *, unsigned int, bool);
|
||||
#else
|
||||
SH_DECL_HOOK2(INetChannel, SendFile, SH_NOATTRIB, 0, bool, const char *, unsigned int);
|
||||
#endif
|
||||
SH_DECL_HOOK2_void(INetChannel, ProcessPacket, SH_NOATTRIB, 0, struct netpacket_s *, bool);
|
||||
|
||||
SourceHook::CallClass<IBaseFileSystem> *basefilesystemPatch = NULL;
|
||||
|
||||
CHookManager::CHookManager()
|
||||
{
|
||||
m_usercmdsFwd = NULL;
|
||||
m_netFileSendFwd = NULL;
|
||||
m_netFileReceiveFwd = NULL;
|
||||
m_pActiveNetChannel = NULL;
|
||||
}
|
||||
|
||||
void CHookManager::Initialize()
|
||||
@ -65,6 +79,13 @@ void CHookManager::Initialize()
|
||||
PRCH_enabled = false;
|
||||
}
|
||||
|
||||
SH_ADD_HOOK(IBaseFileSystem, FileExists, basefilesystem, SH_MEMBER(this, &CHookManager::FileExists), false);
|
||||
|
||||
basefilesystemPatch = SH_GET_CALLCLASS(basefilesystem);
|
||||
|
||||
m_netFileSendFwd = forwards->CreateForward("OnFileSend", ET_Event, 2, NULL, Param_Cell, Param_String);
|
||||
m_netFileReceiveFwd = forwards->CreateForward("OnFileReceive", ET_Event, 2, NULL, Param_Cell, Param_String);
|
||||
|
||||
plsys->AddPluginsListener(this);
|
||||
sharesys->AddCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS);
|
||||
|
||||
@ -85,16 +106,25 @@ void CHookManager::Initialize()
|
||||
void CHookManager::Shutdown()
|
||||
{
|
||||
forwards->ReleaseForward(m_usercmdsFwd);
|
||||
forwards->ReleaseForward(m_netFileSendFwd);
|
||||
forwards->ReleaseForward(m_netFileReceiveFwd);
|
||||
|
||||
plsys->RemovePluginsListener(this);
|
||||
sharesys->DropCapabilityProvider(myself, this, FEATURECAP_PLAYERRUNCMD_11PARAMS);
|
||||
}
|
||||
|
||||
void CHookManager::OnClientConnect(int client)
|
||||
{
|
||||
NetChannelHook(client);
|
||||
}
|
||||
|
||||
void CHookManager::OnClientPutInServer(int client)
|
||||
{
|
||||
if (!PRCH_enabled)
|
||||
return;
|
||||
PlayerRunCmdHook(client);
|
||||
}
|
||||
|
||||
void CHookManager::PlayerRunCmdHook(int client)
|
||||
{
|
||||
if (!PRCH_used)
|
||||
return;
|
||||
|
||||
@ -193,47 +223,194 @@ void CHookManager::PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper)
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
void CHookManager::NetChannelHook(int client)
|
||||
{
|
||||
if (!FILE_used)
|
||||
return;
|
||||
|
||||
INetChannel *pNetChannel = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
|
||||
if (pNetChannel == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Normal NetChannel Hooks. */
|
||||
{
|
||||
CVTableHook hook(pNetChannel);
|
||||
size_t iter;
|
||||
for (iter = 0; iter < m_netChannelHooks.length(); ++iter)
|
||||
{
|
||||
/* We can technically skip 2; even technical-ier, this could be a bool; but Valve. */
|
||||
if (hook == m_netChannelHooks[iter])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter == m_netChannelHooks.length())
|
||||
{
|
||||
int hookid = SH_ADD_VPHOOK(INetChannel, SendFile, pNetChannel, SH_MEMBER(this, &CHookManager::SendFile), false);
|
||||
hook.SetHookID(hookid);
|
||||
m_netChannelHooks.append(new CVTableHook(hook));
|
||||
|
||||
hookid = SH_ADD_VPHOOK(INetChannel, ProcessPacket, pNetChannel, SH_MEMBER(this, &CHookManager::ProcessPacket), false);
|
||||
hook.SetHookID(hookid);
|
||||
m_netChannelHooks.append(new CVTableHook(hook));
|
||||
|
||||
hookid = SH_ADD_VPHOOK(INetChannel, ProcessPacket, pNetChannel, SH_MEMBER(this, &CHookManager::ProcessPacket_Post), true);
|
||||
hook.SetHookID(hookid);
|
||||
m_netChannelHooks.append(new CVTableHook(hook));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CHookManager::ProcessPacket(struct netpacket_s *packet, bool bHasHeader)
|
||||
{
|
||||
if (m_netFileReceiveFwd->GetFunctionCount() == 0)
|
||||
{
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
m_pActiveNetChannel = META_IFACEPTR(INetChannel);
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
bool CHookManager::FileExists(const char *filename, const char *pathID)
|
||||
{
|
||||
if (m_pActiveNetChannel == NULL || m_netFileReceiveFwd->GetFunctionCount() == 0)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
bool ret = SH_CALL(basefilesystemPatch, &IBaseFileSystem::FileExists)(filename, pathID);
|
||||
if (ret == true) /* If the File Exists, the engine historically bails out. */
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
int userid = 0;
|
||||
IClient *pClient = (IClient *)m_pActiveNetChannel->GetMsgHandler();
|
||||
if (pClient != NULL)
|
||||
{
|
||||
userid = pClient->GetUserID();
|
||||
}
|
||||
|
||||
cell_t res = Pl_Continue;
|
||||
m_netFileReceiveFwd->PushCell(playerhelpers->GetClientOfUserId(userid));
|
||||
m_netFileReceiveFwd->PushString(filename);
|
||||
m_netFileReceiveFwd->Execute(&res);
|
||||
|
||||
if (res != Pl_Continue)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, true);
|
||||
}
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
void CHookManager::ProcessPacket_Post(struct netpacket_s* packet, bool bHasHeader)
|
||||
{
|
||||
m_pActiveNetChannel = NULL;
|
||||
RETURN_META(MRES_IGNORED);
|
||||
}
|
||||
|
||||
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
bool CHookManager::SendFile(const char *filename, unsigned int transferID, bool isReplayDemo)
|
||||
#else
|
||||
bool CHookManager::SendFile(const char *filename, unsigned int transferID)
|
||||
#endif
|
||||
{
|
||||
if (m_netFileSendFwd->GetFunctionCount() == 0)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
INetChannel *pNetChannel = META_IFACEPTR(INetChannel);
|
||||
if (pNetChannel == NULL)
|
||||
{
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
int userid = 0;
|
||||
IClient *pClient = (IClient *)m_pActiveNetChannel->GetMsgHandler();
|
||||
if (pClient != NULL)
|
||||
{
|
||||
userid = pClient->GetUserID();
|
||||
}
|
||||
|
||||
cell_t res = Pl_Continue;
|
||||
m_netFileSendFwd->PushCell(playerhelpers->GetClientOfUserId(userid));
|
||||
m_netFileSendFwd->PushString(filename);
|
||||
m_netFileSendFwd->Execute(&res);
|
||||
|
||||
if (res != Pl_Continue)
|
||||
{
|
||||
/* Mimic the Engine. */
|
||||
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
pNetChannel->DenyFile(filename, transferID, isReplayDemo);
|
||||
#else
|
||||
pNetChannel->DenyFile(filename, transferID);
|
||||
#endif
|
||||
RETURN_META_VALUE(MRES_SUPERCEDE, false);
|
||||
}
|
||||
|
||||
RETURN_META_VALUE(MRES_IGNORED, false);
|
||||
}
|
||||
|
||||
void CHookManager::OnPluginLoaded(IPlugin *plugin)
|
||||
{
|
||||
if (!PRCH_enabled)
|
||||
return;
|
||||
|
||||
if (PRCH_used)
|
||||
return;
|
||||
|
||||
if (!m_usercmdsFwd->GetFunctionCount())
|
||||
return;
|
||||
|
||||
PRCH_used = true;
|
||||
|
||||
int MaxClients = playerhelpers->GetMaxClients();
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
if (PRCH_enabled && !PRCH_used && m_usercmdsFwd->GetFunctionCount())
|
||||
{
|
||||
if (playerhelpers->GetGamePlayer(i)->IsInGame())
|
||||
PRCH_used = true;
|
||||
|
||||
int MaxClients = playerhelpers->GetMaxClients();
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
OnClientPutInServer(i);
|
||||
if (playerhelpers->GetGamePlayer(i)->IsInGame())
|
||||
{
|
||||
OnClientPutInServer(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!FILE_used && (m_netFileSendFwd->GetFunctionCount() || m_netFileReceiveFwd->GetFunctionCount()))
|
||||
{
|
||||
FILE_used = true;
|
||||
|
||||
int MaxClients = playerhelpers->GetMaxClients();
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (playerhelpers->GetGamePlayer(i)->IsConnected())
|
||||
{
|
||||
OnClientConnect(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CHookManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
if (!PRCH_enabled)
|
||||
return;
|
||||
|
||||
if (!PRCH_used)
|
||||
return;
|
||||
|
||||
if (m_usercmdsFwd->GetFunctionCount())
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < m_runUserCmdHooks.length(); ++i)
|
||||
if (PRCH_used && !m_usercmdsFwd->GetFunctionCount())
|
||||
{
|
||||
delete m_runUserCmdHooks[i];
|
||||
for (size_t i = 0; i < m_runUserCmdHooks.length(); ++i)
|
||||
{
|
||||
delete m_runUserCmdHooks[i];
|
||||
}
|
||||
|
||||
m_runUserCmdHooks.clear();
|
||||
PRCH_used = false;
|
||||
}
|
||||
|
||||
m_runUserCmdHooks.clear();
|
||||
PRCH_used = false;
|
||||
if (FILE_used && !m_netFileSendFwd->GetFunctionCount() && !m_netFileReceiveFwd->GetFunctionCount())
|
||||
{
|
||||
for (size_t i = 0; i < m_netChannelHooks.length(); ++i)
|
||||
{
|
||||
delete m_netChannelHooks[i];
|
||||
}
|
||||
|
||||
m_netChannelHooks.clear();
|
||||
FILE_used = false;
|
||||
}
|
||||
}
|
||||
|
||||
FeatureStatus CHookManager::GetFeatureStatus(FeatureType type, const char *name)
|
||||
|
@ -36,6 +36,8 @@ class CUserCmd;
|
||||
|
||||
#include "extension.h"
|
||||
#include <am-vector.h>
|
||||
#include "inetchannel.h"
|
||||
#include "iclient.h"
|
||||
#include "vtable_hook_helper.h"
|
||||
|
||||
class CHookManager : IPluginsListener, IFeatureProvider
|
||||
@ -44,17 +46,35 @@ public:
|
||||
CHookManager();
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
void OnClientConnect(int client);
|
||||
void OnClientPutInServer(int client);
|
||||
void PlayerRunCmd(CUserCmd *ucmd, IMoveHelper *moveHelper);
|
||||
public: /* NetChannel/Related Hooks */
|
||||
bool FileExists(const char *filename, const char *pathID);
|
||||
#if SOURCE_ENGINE >= SE_ALIENSWARM || SOURCE_ENGINE == SE_LEFT4DEAD || SOURCE_ENGINE == SE_LEFT4DEAD2
|
||||
bool SendFile(const char *filename, unsigned int transferID, bool isReplayDemo);
|
||||
#else
|
||||
bool SendFile(const char *filename, unsigned int transferID);
|
||||
#endif
|
||||
void ProcessPacket(struct netpacket_s *packet, bool bHasHeader);
|
||||
void ProcessPacket_Post(struct netpacket_s *packet, bool bHasHeader);
|
||||
public: //IPluginsListener
|
||||
void OnPluginLoaded(IPlugin *plugin);
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public: //IFeatureProvider
|
||||
virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
|
||||
|
||||
private:
|
||||
void PlayerRunCmdHook(int client);
|
||||
void NetChannelHook(int client);
|
||||
|
||||
private:
|
||||
IForward *m_usercmdsFwd;
|
||||
IForward *m_netFileSendFwd;
|
||||
IForward *m_netFileReceiveFwd;
|
||||
ke::Vector<CVTableHook *> m_runUserCmdHooks;
|
||||
ke::Vector<CVTableHook *> m_netChannelHooks;
|
||||
INetChannel *m_pActiveNetChannel;
|
||||
};
|
||||
|
||||
extern CHookManager g_Hooks;
|
||||
|
@ -57,3 +57,23 @@
|
||||
* FEATURECAP_PLAYERRUNCMD_11PARAMS.
|
||||
*/
|
||||
forward Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon, &subtype, &cmdnum, &tickcount, &seed, mouse[2]);
|
||||
|
||||
/**
|
||||
* @brief Called when a client requests a file from the server.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param sFile Requested file path.
|
||||
*
|
||||
* @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed.
|
||||
*/
|
||||
forward Action:OnFileSend(client, const String:sFile[]);
|
||||
|
||||
/**
|
||||
* @brief Called when a client sends a file to the server.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param sFile Requested file path.
|
||||
*
|
||||
* @return Plugin_Handled to block the transfer, Plugin_Continue to let it proceed.
|
||||
*/
|
||||
forward Action:OnFileReceive(client, const String:sFile[]);
|
||||
|
Loading…
Reference in New Issue
Block a user