diff --git a/rehlds/dlls/player.h b/rehlds/dlls/player.h index 5046a512b..59f4cb0fa 100644 --- a/rehlds/dlls/player.h +++ b/rehlds/dlls/player.h @@ -322,6 +322,31 @@ class CBasePlayer : public CBaseMonster float m_flNextChatTime; + float GetRemainingMovementTimeForUserCmdProcessing() const { return m_flMovementTimeForUserCmdProcessingRemaining; } + float ConsumeMovementTimeForUserCmdProcessing( float flTimeNeeded ) + { + if ( m_flMovementTimeForUserCmdProcessingRemaining <= 0.0f ) + return 0.0f; + + const float DIST_EPSILON = 0.03125f; + else if ( flTimeNeeded > m_flMovementTimeForUserCmdProcessingRemaining + FLT_EPSILON ) + { + 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; + } + } + +private: + // How much of a movement time buffer can we process from this user? + float m_flMovementTimeForUserCmdProcessingRemaining; }; #define AUTOAIM_2DEGREES 0.0348994967025 diff --git a/rehlds/engine/server.h b/rehlds/engine/server.h index d44414074..d779b6463 100644 --- a/rehlds/engine/server.h +++ b/rehlds/engine/server.h @@ -378,6 +378,7 @@ extern cvar_t sv_rehlds_attachedentities_playeranimationspeed_fix; extern cvar_t sv_rehlds_local_gametime; extern cvar_t sv_rehlds_send_mapcycle; extern cvar_t sv_usercmd_custom_random_seed; +extern cvar_t sv_maxusrcmdprocessticks_warning; #endif extern int sv_playermodel; diff --git a/rehlds/engine/sv_main.cpp b/rehlds/engine/sv_main.cpp index 74a285fea..f4083e3e5 100644 --- a/rehlds/engine/sv_main.cpp +++ b/rehlds/engine/sv_main.cpp @@ -210,6 +210,7 @@ cvar_t sv_rehlds_send_mapcycle = { "sv_rehlds_send_mapcycle", "0", 0, 0.0f, null cvar_t sv_rehlds_maxclients_from_single_ip = { "sv_rehlds_maxclients_from_single_ip", "5", 0, 5.0f, nullptr }; cvar_t sv_use_entity_file = { "sv_use_entity_file", "0", 0, 0.0f, nullptr }; cvar_t sv_usercmd_custom_random_seed = { "sv_usercmd_custom_random_seed", "0", 0, 0.0f, nullptr }; +cvar_t sv_maxusrcmdprocessticks_warning = { "sv_maxusrcmdprocessticks_warning", "0", 0, 0.0f, nullptr }; #endif delta_t *SV_LookupDelta(char *name) @@ -8025,6 +8026,7 @@ void SV_Init(void) Cvar_RegisterVariable(&sv_rollangle); Cvar_RegisterVariable(&sv_use_entity_file); Cvar_RegisterVariable(&sv_usercmd_custom_random_seed); + Cvar_RegisterVariable(&sv_maxusrcmdprocessticks_warning); #endif for (int i = 0; i < MAX_MODELS; i++) diff --git a/rehlds/engine/sv_user.cpp b/rehlds/engine/sv_user.cpp index 5e2c0018b..5647afc90 100644 --- a/rehlds/engine/sv_user.cpp +++ b/rehlds/engine/sv_user.cpp @@ -754,6 +754,27 @@ void SV_ForceFullClientsUpdate(void) void SV_RunCmd(usercmd_t *ucmd, int random_seed) { + const float playerFrameTime = (1.0f / sys_ticrate.value); + const float flTimeAllowedForProcessing = host_client->ConsumeMovementTimeForUserCmdProcessing( playerFrameTime ); + bool isBot = host_client->fakeclient; + if ( !isBot && ( flTimeAllowedForProcessing < playerFrameTime ) ) + { + // Make sure that the activity in command is erased because player cheated or dropped too many packets + double dblWarningFrequencyThrottle = sv_maxusrcmdprocessticks_warning.value; + if ( dblWarningFrequencyThrottle >= 0.0 ) + { + static double s_dblLastWarningTime = 0.0; + double dblTimeNow = Sys_FloatTime(); + if ( !s_dblLastWarningTime || ( dblTimeNow - s_dblLastWarningTime >= dblWarningFrequencyThrottle ) ) + { + s_dblLastWarningTime = dblTimeNow; + Con_Printf( "sv_maxusrcmdprocessticks_warning at server tick %u: Ignored client %s usrcmd (%.6f < %.6f)!\n", + m_system->GetTick(), host_client->name, flTimeAllowedForProcessing, playerFrameTime ); + } + } + return; // Don't process this command + } + usercmd_t cmd = *ucmd; int i; edict_t *ent;