mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
UserCmd: limit command backlog to prevent exploitation
Implement UserCmd command backlog limiting (the new convar 'sv_maxUserCmdProcessTicks' dictates how many ticks can be processed per second). Defaulted to 10, which is (default tick interval (0.05) * default cvar val (10) = 0.5ms window), which is equal to the default of cvar 'sv_maxunlag'. Before this patch, you could stuff several seconds worth of usercmd's in one second and achieve speed hacking.
This commit is contained in:
parent
824b5098b3
commit
42e02b4569
@ -85,7 +85,13 @@ ConVar* sv_voiceEcho = nullptr;
|
||||
ConVar* sv_voiceenable = nullptr;
|
||||
ConVar* sv_alltalk = nullptr;
|
||||
|
||||
ConVar* sv_clampPlayerFrameTime = nullptr;
|
||||
|
||||
ConVar* playerframetimekick_margin = nullptr;
|
||||
ConVar* playerframetimekick_decayrate = nullptr;
|
||||
|
||||
ConVar* player_userCmdsQueueWarning = nullptr;
|
||||
ConVar* player_disallow_negative_frametime = nullptr;
|
||||
|
||||
#endif // !CLIENT_DLL
|
||||
ConVar* sv_cheats = nullptr;
|
||||
@ -208,7 +214,14 @@ void ConVar_InitShipped(void)
|
||||
sv_voiceenable = g_pCVar->FindVar("sv_voiceenable");
|
||||
sv_voiceEcho = g_pCVar->FindVar("sv_voiceEcho");
|
||||
sv_alltalk = g_pCVar->FindVar("sv_alltalk");
|
||||
|
||||
sv_clampPlayerFrameTime = g_pCVar->FindVar("sv_clampPlayerFrameTime");
|
||||
|
||||
playerframetimekick_margin = g_pCVar->FindVar("playerframetimekick_margin");
|
||||
playerframetimekick_decayrate = g_pCVar->FindVar("playerframetimekick_decayrate");
|
||||
|
||||
player_userCmdsQueueWarning = g_pCVar->FindVar("player_userCmdsQueueWarning");
|
||||
player_disallow_negative_frametime = g_pCVar->FindVar("player_disallow_negative_frametime");
|
||||
|
||||
sv_updaterate_sp->RemoveFlags(FCVAR_DEVELOPMENTONLY);
|
||||
sv_updaterate_mp->RemoveFlags(FCVAR_DEVELOPMENTONLY);
|
||||
|
@ -72,7 +72,13 @@ extern ConVar* sv_voiceEcho;
|
||||
extern ConVar* sv_voiceenable;
|
||||
extern ConVar* sv_alltalk;
|
||||
|
||||
extern ConVar* sv_clampPlayerFrameTime;
|
||||
|
||||
extern ConVar* playerframetimekick_margin;
|
||||
extern ConVar* playerframetimekick_decayrate;
|
||||
|
||||
extern ConVar* player_userCmdsQueueWarning;
|
||||
extern ConVar* player_disallow_negative_frametime;
|
||||
|
||||
#endif // CLIENT_DLL
|
||||
extern ConVar* sv_cheats;
|
||||
|
@ -135,6 +135,8 @@
|
||||
#include "game/server/detour_impl.h"
|
||||
#include "game/server/gameinterface.h"
|
||||
#include "game/server/movehelper_server.h"
|
||||
#include "game/server/player.h"
|
||||
#include "game/server/player_command.h"
|
||||
#include "game/server/physics_main.h"
|
||||
#include "game/server/vscript_server.h"
|
||||
#endif // !CLIENT_DLL
|
||||
@ -663,6 +665,7 @@ void DetourRegister() // Register detour classes to be searched and hooked.
|
||||
REGISTER(VBaseEntity);
|
||||
REGISTER(VBaseAnimating);
|
||||
REGISTER(VPlayer);
|
||||
REGISTER(VPlayerMove);
|
||||
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
|
@ -524,6 +524,48 @@ bool CClient::VProcessSetConVar(CClient* pClient, NET_SetConVar* pMsg)
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: set UserCmd time buffer
|
||||
// Input : numUserCmdProcessTicksMax -
|
||||
// tickInterval -
|
||||
//---------------------------------------------------------------------------------
|
||||
void CClientExtended::InitializeMovementTimeForUserCmdProcessing(const int numUserCmdProcessTicksMax, const float tickInterval)
|
||||
{
|
||||
// Grant the client some time buffer to execute user commands
|
||||
m_flMovementTimeForUserCmdProcessingRemaining += tickInterval;
|
||||
|
||||
// but never accumulate more than N ticks
|
||||
if (m_flMovementTimeForUserCmdProcessingRemaining > numUserCmdProcessTicksMax * tickInterval)
|
||||
m_flMovementTimeForUserCmdProcessingRemaining = numUserCmdProcessTicksMax * tickInterval;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: consume UserCmd time buffer
|
||||
// Input : flTimeNeeded -
|
||||
// Output : max time allowed for processing
|
||||
//---------------------------------------------------------------------------------
|
||||
float CClientExtended::ConsumeMovementTimeForUserCmdProcessing(const float flTimeNeeded)
|
||||
{
|
||||
if (m_flMovementTimeForUserCmdProcessingRemaining <= 0.0f)
|
||||
return 0.0f;
|
||||
else if (flTimeNeeded > m_flMovementTimeForUserCmdProcessingRemaining + FLT_EPSILON)
|
||||
{
|
||||
const float flResult = m_flMovementTimeForUserCmdProcessingRemaining;
|
||||
m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
|
||||
|
||||
return flResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flMovementTimeForUserCmdProcessingRemaining -= flTimeNeeded;
|
||||
|
||||
if (m_flMovementTimeForUserCmdProcessingRemaining < 0.0f)
|
||||
m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
|
||||
|
||||
return flTimeNeeded;
|
||||
}
|
||||
}
|
||||
|
||||
void VClient::Detour(const bool bAttach) const
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
|
@ -230,6 +230,7 @@ public:
|
||||
m_flNetProcessTimeBase = 0.0;
|
||||
m_flStringCommandQuotaTimeStart = 0.0;
|
||||
m_nStringCommandQuotaCount = NULL;
|
||||
m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
|
||||
m_bInitialConVarsSet = false;
|
||||
}
|
||||
|
||||
@ -247,6 +248,12 @@ public: // Inlines:
|
||||
inline void SetStringCommandQuotaCount(const int iCount) { m_nStringCommandQuotaCount = iCount; }
|
||||
inline int GetStringCommandQuotaCount(void) const { return m_nStringCommandQuotaCount; }
|
||||
|
||||
inline void SetRemainingMovementTimeForUserCmdProcessing(const float flValue) { m_flMovementTimeForUserCmdProcessingRemaining = flValue; }
|
||||
inline float GetRemainingMovementTimeForUserCmdProcessing() const { return m_flMovementTimeForUserCmdProcessingRemaining; }
|
||||
|
||||
void InitializeMovementTimeForUserCmdProcessing(const int numUserCmdProcessTicksMax, const float tickInterval);
|
||||
float ConsumeMovementTimeForUserCmdProcessing(const float flTimeNeeded);
|
||||
|
||||
private:
|
||||
// Measure how long this client's packets took to process.
|
||||
double m_flNetProcessingTimeMsecs;
|
||||
@ -256,6 +263,9 @@ private:
|
||||
double m_flStringCommandQuotaTimeStart;
|
||||
int m_nStringCommandQuotaCount;
|
||||
|
||||
// How much of a movement time buffer can we process from this user?
|
||||
float m_flMovementTimeForUserCmdProcessingRemaining;
|
||||
|
||||
bool m_bInitialConVarsSet; // Whether or not the initial ConVar KV's are set
|
||||
};
|
||||
|
||||
|
@ -73,6 +73,8 @@ add_sources( SOURCE_GROUP "Network"
|
||||
add_sources( SOURCE_GROUP "Player"
|
||||
"server/player.cpp"
|
||||
"server/player.h"
|
||||
"server/player_command.cpp"
|
||||
"server/player_command.h"
|
||||
"server/playerlocaldata.h"
|
||||
)
|
||||
|
||||
|
@ -22,10 +22,10 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// This is called when a new game is started. (restart, map)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CServerGameDLL::GameInit(void)
|
||||
bool CServerGameDLL::GameInit(void)
|
||||
{
|
||||
const static int index = 1;
|
||||
CallVFunc<void>(index, this);
|
||||
return CallVFunc<bool>(index, this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -19,7 +19,7 @@ class ServerClass;
|
||||
class CServerGameDLL
|
||||
{
|
||||
public:
|
||||
void GameInit(void);
|
||||
bool GameInit(void);
|
||||
void PrecompileScriptsJob(void);
|
||||
void LevelShutdown(void);
|
||||
void GameShutdown(void);
|
||||
@ -48,11 +48,15 @@ class CServerGameEnts : public IServerGameEnts
|
||||
};
|
||||
|
||||
inline void(*CServerGameDLL__OnReceivedSayTextMessage)(void* thisptr, int senderId, const char* text, bool isTeamChat);
|
||||
inline bool(*CServerGameDLL__GameInit)(void);
|
||||
|
||||
inline void(*CServerGameClients__ProcessUserCmds)(CServerGameClients* thisp, edict_t edict, bf_read* buf,
|
||||
int numCmds, int totalCmds, int droppedPackets, bool ignore, bool paused);
|
||||
|
||||
inline void(*v_RunFrameServer)(double flFrameTime, bool bRunOverlays, bool bUniformUpdate);
|
||||
|
||||
inline float* g_pflServerFrameTimeBase = nullptr;
|
||||
|
||||
extern CServerGameDLL* g_pServerGameDLL;
|
||||
extern CServerGameClients* g_pServerGameClients;
|
||||
extern CServerGameEnts* g_pServerGameEntities;
|
||||
@ -65,8 +69,10 @@ class VServerGameDLL : public IDetour
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("CServerGameDLL::OnReceivedSayTextMessage", CServerGameDLL__OnReceivedSayTextMessage);
|
||||
LogFunAdr("CServerGameDLL::GameInit", CServerGameDLL__GameInit);
|
||||
LogFunAdr("CServerGameClients::ProcessUserCmds", CServerGameClients__ProcessUserCmds);
|
||||
LogFunAdr("RunFrameServer", v_RunFrameServer);
|
||||
LogVarAdr("g_flServerFrameTimeBase", g_pflServerFrameTimeBase);
|
||||
LogVarAdr("g_pServerGameDLL", g_pServerGameDLL);
|
||||
LogVarAdr("g_pServerGameClients", g_pServerGameClients);
|
||||
LogVarAdr("g_pServerGameEntities", g_pServerGameEntities);
|
||||
@ -75,12 +81,14 @@ class VServerGameDLL : public IDetour
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("85 D2 0F 8E ?? ?? ?? ?? 4C 8B DC").GetPtr(CServerGameDLL__OnReceivedSayTextMessage);
|
||||
g_GameDll.FindPatternSIMD("48 83 EC 28 48 8B 0D ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 8B 01 FF 90 ?? ?? ?? ?? 48 8B 0D ?? ?? ?? ?? 48 8B 01").GetPtr(CServerGameDLL__GameInit);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 55 41 55 41 57").GetPtr(CServerGameClients__ProcessUserCmds);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 30 0F 29 74 24 ?? 48 8D 0D ?? ?? ?? ??").GetPtr(v_RunFrameServer);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
g_pGlobals = g_GameDll.FindPatternSIMD("4C 8B 0D ?? ?? ?? ?? 48 8B D1").ResolveRelativeAddressSelf(0x3, 0x7).RCast<CGlobalVars**>();
|
||||
g_pflServerFrameTimeBase = CMemory(CServerGameDLL__GameInit).FindPatternSelf("F3 0F 11 0D").ResolveRelativeAddressSelf(0x4, 0x8).RCast<float*>();
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
|
@ -13,6 +13,9 @@
|
||||
|
||||
#include "engine/server/server.h"
|
||||
|
||||
// NOTE[ AMOS ]: default tick interval (0.05) * default cvar value (10) = total time buffer of 0.5, which is the default of cvar 'sv_maxunlag'.
|
||||
static ConVar sv_maxUserCmdProcessTicks("sv_maxUserCmdProcessTicks", "10", FCVAR_NONE, "Maximum number of client-issued UserCmd ticks that can be replayed in packet loss conditions, 0 to allow no restrictions.");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: executes a null command for this player
|
||||
//------------------------------------------------------------------------------
|
||||
@ -64,7 +67,7 @@ inline void CPlayer::SetTimeBase(float flTimeBase)
|
||||
|
||||
SetLastUCmdSimulationRemainderTime(flTime);
|
||||
|
||||
float flSimulationTime = flTimeBase - m_lastUCmdSimulationRemainderTime * (*g_pGlobals)->m_flTickInterval;
|
||||
float flSimulationTime = flTimeBase - m_lastUCmdSimulationRemainderTime * TICK_INTERVAL;
|
||||
if (flSimulationTime >= 0.0f)
|
||||
{
|
||||
flTime = flSimulationTime;
|
||||
@ -241,6 +244,25 @@ void CPlayer::SetLastUserCommand(CUserCmd* pUserCmd)
|
||||
m_LastCmd.Copy(pUserCmd);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose: run physics simulation for player
|
||||
// Input : *player (this) -
|
||||
// numPerIteration -
|
||||
// adjustTimeBase -
|
||||
//------------------------------------------------------------------------------
|
||||
bool Player_PhysicsSimulate(CPlayer* player, int numPerIteration, bool adjustTimeBase)
|
||||
{
|
||||
CClientExtended* const cle = g_pServer->GetClientExtended(player->GetEdict() - 1);
|
||||
const int numUserCmdProcessTicksMax = sv_maxUserCmdProcessTicks.GetInt();
|
||||
|
||||
if (numUserCmdProcessTicksMax && (*g_pGlobals)->m_nGameMode != GameMode_t::SP_MODE) // don't apply this filter in SP games
|
||||
cle->InitializeMovementTimeForUserCmdProcessing(numUserCmdProcessTicksMax, TICK_INTERVAL);
|
||||
else // Otherwise we don't care to track time
|
||||
cle->SetRemainingMovementTimeForUserCmdProcessing(FLT_MAX);
|
||||
|
||||
return CPlayer__PhysicsSimulate(player, numPerIteration, adjustTimeBase);
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CC_CreateFakePlayer_f
|
||||
@ -286,3 +308,8 @@ static void CC_CreateFakePlayer_f(const CCommand& args)
|
||||
}
|
||||
|
||||
static ConCommand sv_addbot("sv_addbot", CC_CreateFakePlayer_f, "Creates a bot on the server", FCVAR_RELEASE);
|
||||
|
||||
void VPlayer::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&CPlayer__PhysicsSimulate, &Player_PhysicsSimulate, bAttach);
|
||||
}
|
||||
|
@ -241,6 +241,7 @@ struct SpeedChangeHistoryEntry
|
||||
|
||||
class CPlayer : public CBaseCombatCharacter
|
||||
{
|
||||
friend class CPlayerMove;
|
||||
public:
|
||||
void RunNullCommand(void);
|
||||
QAngle* EyeAngles(QAngle* pAngles);
|
||||
@ -260,6 +261,8 @@ public:
|
||||
inline bool IsConnected() const { return m_iConnected != PlayerDisconnected; }
|
||||
inline bool IsDisconnecting() const { return m_iConnected == PlayerDisconnecting; }
|
||||
|
||||
inline bool IsBot() const { return (GetFlags() & FL_FAKECLIENT) != 0; }
|
||||
|
||||
private:
|
||||
int m_StuckLast;
|
||||
char gap_5a8c[4];
|
||||
@ -796,6 +799,7 @@ static_assert(sizeof(CPlayer) == 0x7EF0); // !TODO: backwards compatibility.
|
||||
|
||||
inline QAngle*(*CPlayer__EyeAngles)(CPlayer* pPlayer, QAngle* pAngles);
|
||||
inline void(*CPlayer__PlayerRunCommand)(CPlayer* pPlayer, CUserCmd* pUserCmd, IMoveHelper* pMover);
|
||||
inline bool(*CPlayer__PhysicsSimulate)(CPlayer* pPlayer, int numPerIteration, bool adjustTimeBase);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class VPlayer : public IDetour
|
||||
@ -804,15 +808,17 @@ class VPlayer : public IDetour
|
||||
{
|
||||
LogFunAdr("CPlayer::EyeAngles", CPlayer__EyeAngles);
|
||||
LogFunAdr("CPlayer::PlayerRunCommand", CPlayer__PlayerRunCommand);
|
||||
LogFunAdr("CPlayer::PhysicsSimulate", CPlayer__PhysicsSimulate);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("40 53 48 83 EC 30 F2 0F 10 05 ?? ?? ?? ??").GetPtr(CPlayer__EyeAngles);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 8B 03 49 81 C6 ?? ?? ?? ??").FollowNearCallSelf().GetPtr(CPlayer__PlayerRunCommand);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 84 C0 74 06").FollowNearCallSelf().GetPtr(CPlayer__PhysicsSimulate);
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
60
r5dev/game/server/player_command.cpp
Normal file
60
r5dev/game/server/player_command.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "engine/server/server.h"
|
||||
#include "engine/client/client.h"
|
||||
|
||||
#include "player_command.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerMove::CPlayerMove(void)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Runs movement commands for the player
|
||||
// Input : *player -
|
||||
// *ucmd -
|
||||
// *moveHelper -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerMove::StaticRunCommand(CPlayerMove* thisp, CPlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper)
|
||||
{
|
||||
CClientExtended* const cle = g_pServer->GetClientExtended(player->GetEdict() - 1);
|
||||
|
||||
const float playerCurTime = (player->m_lastUCmdSimulationRemainderTime * TICK_INTERVAL) + player->m_totalExtraClientCmdTimeAttempted;
|
||||
float playerFrameTime;
|
||||
|
||||
// Always default to clamped UserCmd frame time if this cvar is set
|
||||
if (player_disallow_negative_frametime->GetBool())
|
||||
playerFrameTime = fmaxf(ucmd->frametime, 0.0f);
|
||||
else
|
||||
{
|
||||
if (player->m_bGamePaused)
|
||||
playerFrameTime = 0.0f;
|
||||
else
|
||||
playerFrameTime = TICK_INTERVAL;
|
||||
|
||||
if (ucmd->frametime)
|
||||
playerFrameTime = ucmd->frametime;
|
||||
}
|
||||
|
||||
if (sv_clampPlayerFrameTime->GetBool() && player->m_joinFrameTime > ((*g_pflServerFrameTimeBase) + playerframetimekick_margin->GetFloat()))
|
||||
playerFrameTime = 0.0f;
|
||||
|
||||
const float timeAllowedForProcessing = cle->ConsumeMovementTimeForUserCmdProcessing(playerFrameTime);
|
||||
|
||||
if (!player->IsBot() && (timeAllowedForProcessing < playerFrameTime))
|
||||
return; // Don't process this command
|
||||
|
||||
CPlayerMove__RunCommand(thisp, player, ucmd, moveHelper);
|
||||
}
|
||||
|
||||
void VPlayerMove::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&CPlayerMove__RunCommand, &CPlayerMove::StaticRunCommand, bAttach);
|
||||
}
|
67
r5dev/game/server/player_command.h
Normal file
67
r5dev/game/server/player_command.h
Normal file
@ -0,0 +1,67 @@
|
||||
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef PLAYER_COMMAND_H
|
||||
#define PLAYER_COMMAND_H
|
||||
|
||||
#include "edict.h"
|
||||
#include "game/shared/usercmd.h"
|
||||
#include "game/server/player.h"
|
||||
|
||||
class IMoveHelper;
|
||||
class CMoveData;
|
||||
class CBasePlayer;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Server side player movement
|
||||
//-----------------------------------------------------------------------------
|
||||
class CPlayerMove
|
||||
{
|
||||
public:
|
||||
//DECLARE_CLASS_NOBASE(CPlayerMove);
|
||||
|
||||
// Construction/destruction
|
||||
CPlayerMove(void);
|
||||
virtual ~CPlayerMove(void) {}
|
||||
|
||||
// Hook statics:
|
||||
static void StaticRunCommand(CPlayerMove* thisp, CPlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper);
|
||||
|
||||
// Public interfaces:
|
||||
// Run a movement command from the player
|
||||
virtual void RunCommand(CPlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper) = 0;
|
||||
|
||||
protected:
|
||||
// Prepare for running movement
|
||||
virtual void SetupMove(CPlayer* player, CUserCmd* ucmd, CMoveData* move) = 0;
|
||||
|
||||
// Finish movement
|
||||
virtual void FinishMove(CPlayer* player, CUserCmd* ucmd, CMoveData* move) = 0;
|
||||
|
||||
// Called before and after any movement processing
|
||||
virtual void StartCommand(CPlayer* player, IMoveHelper* pHelper, CUserCmd* cmd) = 0;
|
||||
};
|
||||
|
||||
inline void (*CPlayerMove__RunCommand)(CPlayerMove* thisp, CPlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class VPlayerMove : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("CPlayerMove::RunCommand", CPlayerMove__RunCommand);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 8B C4 55 53 56 57 41 57 48 8D A8 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 50 ??").GetPtr(CPlayerMove__RunCommand);
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // PLAYER_COMMAND_H
|
Loading…
x
Reference in New Issue
Block a user