diff --git a/r5dev/common/global.cpp b/r5dev/common/global.cpp index 0a751fcf..a03a11c8 100644 --- a/r5dev/common/global.cpp +++ b/r5dev/common/global.cpp @@ -104,7 +104,7 @@ ConVar* sv_forceChatToTeamOnly = nullptr; ConVar* sv_single_core_dedi = nullptr; -ConVar* sv_maxunlag_delta = nullptr; +ConVar* sv_maxunlag = nullptr; ConVar* sv_updaterate_sp = nullptr; ConVar* sv_updaterate_mp = nullptr; @@ -328,8 +328,6 @@ void ConVar_StaticInit(void) sv_autoReloadRate = ConVar::StaticCreate("sv_autoReloadRate" , "0" , FCVAR_RELEASE, "Time in seconds between each server auto-reload (disabled if null).", true, 0.f, false, 0.f, nullptr, nullptr); sv_simulateBots = ConVar::StaticCreate("sv_simulateBots", "1", FCVAR_RELEASE, "Simulate user commands for bots on the server.", true, 0.f, false, 0.f, nullptr, nullptr); - sv_maxunlag_delta = ConVar::StaticCreate("sv_maxunlag_delta", "0.3", FCVAR_RELEASE, "Maximum amount of deviation in seconds between server and UserCmd's issue time for unlag (excludes latency).", true, 0.f, true, 1.f, nullptr, nullptr); - sv_rcon_debug = ConVar::StaticCreate("sv_rcon_debug" , "0" , FCVAR_RELEASE, "Show rcon debug information ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); sv_rcon_sendlogs = ConVar::StaticCreate("sv_rcon_sendlogs" , "0" , FCVAR_RELEASE, "Network console logs to connected and authenticated sockets.", false, 0.f, false, 0.f, nullptr, nullptr); //sv_rcon_banpenalty = ConVar::StaticCreate("sv_rcon_banpenalty" , "10", FCVAR_RELEASE, "Number of minutes to ban users who fail rcon authentication.", false, 0.f, false, 0.f, nullptr, nullptr); @@ -520,6 +518,8 @@ void ConVar_InitShipped(void) #ifndef CLIENT_DLL sv_stats = g_pCVar->FindVar("sv_stats"); + sv_maxunlag = g_pCVar->FindVar("sv_maxunlag"); + sv_updaterate_sp = g_pCVar->FindVar("sv_updaterate_sp"); sv_updaterate_mp = g_pCVar->FindVar("sv_updaterate_mp"); diff --git a/r5dev/common/global.h b/r5dev/common/global.h index 848042fe..7a4fbc77 100644 --- a/r5dev/common/global.h +++ b/r5dev/common/global.h @@ -93,7 +93,7 @@ extern ConVar* sv_forceChatToTeamOnly; extern ConVar* sv_single_core_dedi; -extern ConVar* sv_maxunlag_delta; +extern ConVar* sv_maxunlag; extern ConVar* sv_updaterate_sp; extern ConVar* sv_updaterate_mp; diff --git a/r5dev/game/server/player.cpp b/r5dev/game/server/player.cpp index f6d989dc..0e200b6e 100644 --- a/r5dev/game/server/player.cpp +++ b/r5dev/game/server/player.cpp @@ -125,49 +125,64 @@ void CPlayer::ProcessUserCmds(CUserCmd* cmds, int numCmds, int totalCmds, CUserCmd* lastCmd = &m_Commands[MAX_QUEUED_COMMANDS_PROCESS]; - const float latencyAmount = chan->GetLatency(FLOW_OUTGOING); - const float maxCommandDelta = sv_maxunlag_delta->GetFloat(); + const float maxUnlag = sv_maxunlag->GetFloat(); + const float latencyAmount = Clamp(chan->GetLatency(FLOW_OUTGOING), 0.0f, maxUnlag); const float localCurTime = (*g_pGlobals)->m_flCurTime; - const float lastCommandTime = m_LastCmd.command_time; for (int i = totalCmds - 1; i >= 0; i--) { CUserCmd* cmd = &cmds[i]; + const int commandNumber = cmd->command_number; + if (commandNumber <= m_latestCommandQueued) + continue; + + m_latestCommandQueued = commandNumber; + const int lastCommandNumber = lastCmd->command_number; + + if (lastCommandNumber == MAX_QUEUED_COMMANDS_PROCESS) + return; + + // Command issue time from client, note that this value can be altered + // from the client, and therefore be used to exploit lag compensation. const float commandTime = cmd->command_time; - const float commandDelta = fabs(commandTime - localCurTime) - latencyAmount; + const float lastCommandTime = m_LastCmd.command_time; - if (/*commandTime < lastCommandTime ||*/ commandDelta > maxCommandDelta) + if (commandTime < lastCommandTime) // Can never be lower than last !!! { cmd->command_time = localCurTime - latencyAmount; if (IsDebug()) { - Warning(eDLL_T::SERVER, "%s: Command delta of %f exceeded maximum of %f; commandTime=%f, lastCommandTime=%f, localCurTime=%f, latencyAmount=%f\n", - __FUNCTION__, commandDelta, maxCommandDelta, commandTime, lastCommandTime, localCurTime, latencyAmount); + Warning(eDLL_T::SERVER, "%s: cmd->command_time( %f ) < m_LastCmd.command_time( %f ); clamped to %f !!!\n", + __FUNCTION__, commandTime, lastCommandTime, cmd->command_time); + } + } + else + { + const float commandDelta = fabs(commandTime - localCurTime); + + if (commandDelta > maxUnlag) // Too much to unlag, clamp to max !!! + { + cmd->command_time = localCurTime - latencyAmount; + + if (IsDebug()) + { + Warning(eDLL_T::SERVER, "%s: commandDelta( %f ) > maxUnlag( %f ); clamped to %f !!!\n", + __FUNCTION__, commandDelta, maxUnlag, cmd->command_time); + } } } - const int commandNumber = cmd->command_number; + CUserCmd* queuedCmd = &m_Commands[lastCommandNumber]; + queuedCmd->Copy(cmd); - if (commandNumber > m_latestCommandQueued) + if (++lastCmd->command_number > player_userCmdsQueueWarning->GetInt()) { - m_latestCommandQueued = commandNumber; - const int lastCommandNumber = lastCmd->command_number; + const float curTime = float(Plat_FloatTime()); - if (lastCommandNumber == MAX_QUEUED_COMMANDS_PROCESS) - return; - - CUserCmd* queuedCmd = &m_Commands[lastCommandNumber]; - queuedCmd->Copy(cmd); - - if (++lastCmd->command_number > player_userCmdsQueueWarning->GetInt()) - { - const float curTime = float(Plat_FloatTime()); - - if ((curTime - m_lastCommandCountWarnTime) > 0.5f) - m_lastCommandCountWarnTime = curTime; - } + if ((curTime - m_lastCommandCountWarnTime) > 0.5f) + m_lastCommandCountWarnTime = curTime; } }