Added the old clock correction, new one caused flickering

This commit is contained in:
Kamay Xutax 2024-08-27 17:11:24 +02:00
parent a9b7bf8e2f
commit ad3b1ca178
7 changed files with 196 additions and 42 deletions

View file

@ -9,6 +9,7 @@
#include "client.h" #include "client.h"
#include "client_pch.h" #include "client_pch.h"
#include "clockdriftmgr.h"
#include "sound.h" #include "sound.h"
#include <inetchannel.h> #include <inetchannel.h>
#include "checksum_engine.h" #include "checksum_engine.h"
@ -508,6 +509,8 @@ Updates the local time and reads/handles messages on client net connection.
================= =================
*/ */
extern ConVar cl_clock_correction;
void CL_ReadPackets ( bool bFinalTick ) void CL_ReadPackets ( bool bFinalTick )
{ {
VPROF_BUDGET( "CL_ReadPackets", VPROF_BUDGETGROUP_OTHER_NETWORKING ); VPROF_BUDGET( "CL_ReadPackets", VPROF_BUDGETGROUP_OTHER_NETWORKING );
@ -517,26 +520,20 @@ void CL_ReadPackets ( bool bFinalTick )
return; return;
// update client times/tick // update client times/tick
if (!CClockDriftMgr::IsClockCorrectionEnabled()) if (cl_clock_correction.GetInt() <= 1)
{ {
cl.oldtickcount = cl.GetServerTickCount(); cl.oldtickcount = cl.GetServerTickCount();
} if ( !cl.IsPaused() )
// Moved after process socket so we can receive the lastest updates.
if ( !cl.IsPaused() )
{
// While clock correction is off, we have the old behavior of matching the client and server clocks.
if (!CClockDriftMgr::IsClockCorrectionEnabled())
{ {
cl.SetClientTickCount(cl.GetClientTickCount() + 1); cl.SetClientTickCount( cl.GetClientTickCount() + 1 );
cl.SetServerTickCount(cl.GetClientTickCount());
// While clock correction is off, we have the old behavior of matching the client and server clocks.
if ( !CClockDriftMgr::IsClockCorrectionEnabled() )
cl.SetServerTickCount( cl.GetClientTickCount() );
g_ClientGlobalVariables.tickcount = cl.GetClientTickCount(); g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
g_ClientGlobalVariables.curtime = cl.GetTime(); g_ClientGlobalVariables.curtime = cl.GetTime();
} }
}
if (!CClockDriftMgr::IsClockCorrectionEnabled())
{
// 0 or tick_rate if simulating // 0 or tick_rate if simulating
g_ClientGlobalVariables.frametime = cl.GetFrameTime(); g_ClientGlobalVariables.frametime = cl.GetFrameTime();
} }
@ -583,29 +580,31 @@ void CL_ReadPackets ( bool bFinalTick )
} }
#endif #endif
if (CClockDriftMgr::IsClockCorrectionEnabled()) if (cl_clock_correction.GetInt() >= 2)
{ {
cl.oldtickcount = cl.GetServerTickCount();
}
// Moved after process socket so we can receive the lastest updates.
if ( !cl.IsPaused() )
{
// While clock correction is off, we have the old behavior of matching the client and server clocks.
if (CClockDriftMgr::IsClockCorrectionEnabled()) if (CClockDriftMgr::IsClockCorrectionEnabled())
{ {
cl.m_ClockDriftMgr.IncrementCachedTickCount(bFinalTick); cl.oldtickcount = cl.GetServerTickCount();
g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
g_ClientGlobalVariables.curtime = cl.GetTime();
} }
}
if (CClockDriftMgr::IsClockCorrectionEnabled()) // Moved after process socket so we can receive the lastest updates.
{ if ( !cl.IsPaused() )
// 0 or tick_rate if simulating {
g_ClientGlobalVariables.frametime = cl.GetFrameTime(); // While clock correction is off, we have the old behavior of matching the client and server clocks.
} if (CClockDriftMgr::IsClockCorrectionEnabled())
{
cl.m_ClockDriftMgr.IncrementCachedTickCount(bFinalTick);
g_ClientGlobalVariables.tickcount = cl.GetClientTickCount();
g_ClientGlobalVariables.curtime = cl.GetTime();
}
}
if (CClockDriftMgr::IsClockCorrectionEnabled())
{
// 0 or tick_rate if simulating
g_ClientGlobalVariables.frametime = cl.GetFrameTime();
}
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -11,7 +11,7 @@
#include "enginethreads.h" #include "enginethreads.h"
ConVar cl_clock_correction( "cl_clock_correction", "0", FCVAR_CHEAT, "Enable/disable clock correction on the client." ); ConVar cl_clock_correction( "cl_clock_correction", "1", 0, "Enable/disable clock correction on the client." );
ConVar cl_clockdrift_max_ms( "cl_clockdrift_max_ms", "150", FCVAR_CHEAT, "Maximum number of milliseconds the clock is allowed to drift before the client snaps its clock to the server's." ); ConVar cl_clockdrift_max_ms( "cl_clockdrift_max_ms", "150", FCVAR_CHEAT, "Maximum number of milliseconds the clock is allowed to drift before the client snaps its clock to the server's." );
ConVar cl_clockdrift_max_ms_threadmode( "cl_clockdrift_max_ms_threadmode", "0", FCVAR_CHEAT, "Maximum number of milliseconds the clock is allowed to drift before the client snaps its clock to the server's." ); ConVar cl_clockdrift_max_ms_threadmode( "cl_clockdrift_max_ms_threadmode", "0", FCVAR_CHEAT, "Maximum number of milliseconds the clock is allowed to drift before the client snaps its clock to the server's." );
@ -19,7 +19,33 @@ ConVar cl_clockdrift_max_ms_threadmode( "cl_clockdrift_max_ms_threadmode", "0",
ConVar cl_clock_showdebuginfo( "cl_clock_showdebuginfo", "0", FCVAR_CHEAT, "Show debugging info about the clock drift. "); ConVar cl_clock_showdebuginfo( "cl_clock_showdebuginfo", "0", FCVAR_CHEAT, "Show debugging info about the clock drift. ");
ConVar cl_clock_correction_force_server_tick( "cl_clock_correction_force_server_tick", "999", FCVAR_CHEAT, "Force clock correction to match the server tick + this offset (-999 disables it)." ); ConVar cl_clock_correction_force_server_tick( "cl_clock_correction_force_server_tick", "999", FCVAR_CHEAT, "Force clock correction to match the server tick + this offset (-999 disables it)." );
ConVar cl_clock_correction_adjustment_max_amount( "cl_clock_correction_adjustment_max_amount", "200", FCVAR_CHEAT,
"Sets the maximum number of milliseconds per second it is allowed to correct the client clock. "
"It will only correct this amount if the difference between the client and server clock is equal to or larger than cl_clock_correction_adjustment_max_offset." );
ConVar cl_clock_correction_adjustment_min_offset( "cl_clock_correction_adjustment_min_offset", "10", FCVAR_CHEAT,
"If the clock offset is less than this amount (in milliseconds), then no clock correction is applied." );
ConVar cl_clock_correction_adjustment_max_offset( "cl_clock_correction_adjustment_max_offset", "90", FCVAR_CHEAT,
"As the clock offset goes from cl_clock_correction_adjustment_min_offset to this value (in milliseconds), "
"it moves towards applying cl_clock_correction_adjustment_max_amount of adjustment. That way, the response "
"is small when the offset is small." );
// Given the offset (in milliseconds) of the client clock from the server clock,
// returns how much correction we'd like to apply per second (in seconds).
static float GetClockAdjustmentAmount( float flCurDiffInMS )
{
flCurDiffInMS = clamp( flCurDiffInMS, cl_clock_correction_adjustment_min_offset.GetFloat(), cl_clock_correction_adjustment_max_offset.GetFloat() );
float flReturnValue = RemapVal( flCurDiffInMS,
cl_clock_correction_adjustment_min_offset.GetFloat(), cl_clock_correction_adjustment_max_offset.GetFloat(),
0, cl_clock_correction_adjustment_max_amount.GetFloat() / 1000.0f );
return flReturnValue;
}
// -------------------------------------------------------------------------------------------------- / // -------------------------------------------------------------------------------------------------- /
// CClockDriftMgr implementation. // CClockDriftMgr implementation.
@ -39,6 +65,9 @@ void CClockDriftMgr::Clear()
m_nLaggedClientTick = 0; m_nLaggedClientTick = 0;
m_flServerHostFrametime = 0.0f; m_flServerHostFrametime = 0.0f;
m_flServerHostFrametimeStdDeviation = 0.0f; m_flServerHostFrametimeStdDeviation = 0.0f;
m_iCurClockOffset = 0;
memset( m_ClockOffsets, 0, sizeof( m_ClockOffsets ) );
} }
@ -65,8 +94,9 @@ void CClockDriftMgr::SetServerTick( int nTick, int nLaggedTick, float flServerHo
if (cl_clock_correction_force_server_tick.GetInt() == 999) if (cl_clock_correction_force_server_tick.GetInt() == 999)
{ {
if (IsClockCorrectionEnabled()) // TODO_ENHANCED: !!!!!!!!! This needs to be corrected !!!!!!!!!!
if (IsClockCorrectionEnabled() && cl_clock_correction.GetInt() >= 2)
{ {
// Take the difference between last sent client tick and server tick // Take the difference between last sent client tick and server tick
// This will give how much we are shifted from the server perfectly // This will give how much we are shifted from the server perfectly
@ -88,7 +118,14 @@ void CClockDriftMgr::SetServerTick( int nTick, int nLaggedTick, float flServerHo
{ {
// Used for testing.. // Used for testing..
m_nClientTick = (nTick + cl_clock_correction_force_server_tick.GetInt()); m_nClientTick = (nTick + cl_clock_correction_force_server_tick.GetInt());
} }
if (cl_clock_correction.GetInt() <= 1)
{
// adjust the clock offset by the clock with thread mode compensation
m_ClockOffsets[m_iCurClockOffset] = clientTick - m_nServerTick;
m_iCurClockOffset = (m_iCurClockOffset + 1) % NUM_CLOCKDRIFT_SAMPLES;
}
ShowDebugInfo(); ShowDebugInfo();
m_nOldServerTick = m_nServerTick; m_nOldServerTick = m_nServerTick;
@ -105,6 +142,58 @@ void CClockDriftMgr::IncrementCachedTickCount(bool bFinalTick)
m_nClientTick = m_nCachedRealClientTick + m_nLagDiff; m_nClientTick = m_nCachedRealClientTick + m_nLagDiff;
} }
float CClockDriftMgr::AdjustFrameTime( float inputFrameTime )
{
float flAdjustmentThisFrame = 0;
float flAdjustmentPerSec = 0;
if ( IsClockCorrectionEnabled()
#if !defined( _XBOX ) && !defined( SWDS )
&& !demoplayer->IsPlayingBack()
#endif
&& cl_clock_correction.GetInt() <= 1)
{
// Get the clock difference in seconds.
float flCurDiffInSeconds = GetCurrentClockDifference() * host_state.interval_per_tick;
float flCurDiffInMS = flCurDiffInSeconds * 1000.0f;
// Is the server ahead or behind us?
if ( flCurDiffInMS > cl_clock_correction_adjustment_min_offset.GetFloat() )
{
flAdjustmentPerSec = -GetClockAdjustmentAmount( flCurDiffInMS );
flAdjustmentThisFrame = inputFrameTime * flAdjustmentPerSec;
flAdjustmentThisFrame = max( flAdjustmentThisFrame, -flCurDiffInSeconds );
}
else if ( flCurDiffInMS < -cl_clock_correction_adjustment_min_offset.GetFloat() )
{
flAdjustmentPerSec = GetClockAdjustmentAmount( -flCurDiffInMS );
flAdjustmentThisFrame = inputFrameTime * flAdjustmentPerSec;
flAdjustmentThisFrame = min( flAdjustmentThisFrame, -flCurDiffInSeconds );
}
if ( IsEngineThreaded() )
{
flAdjustmentThisFrame = -flCurDiffInSeconds;
}
AdjustAverageDifferenceBy( flAdjustmentThisFrame );
}
return inputFrameTime + flAdjustmentThisFrame;
}
float CClockDriftMgr::GetCurrentClockDifference() const
{
// Note: this could be optimized a little by updating it each time we add
// a sample (subtract the old value from the total and add the new one in).
float total = 0;
for ( int i=0; i < NUM_CLOCKDRIFT_SAMPLES; i++ )
total += m_ClockOffsets[i];
return total / NUM_CLOCKDRIFT_SAMPLES;
}
void CClockDriftMgr::ShowDebugInfo() void CClockDriftMgr::ShowDebugInfo()
{ {
#if !defined( SWDS ) #if !defined( SWDS )
@ -124,6 +213,22 @@ void CClockDriftMgr::ShowDebugInfo()
#endif #endif
} }
void CClockDriftMgr::AdjustAverageDifferenceBy( float flAmountInSeconds )
{
// Don't adjust the average if it's already tiny.
float c = GetCurrentClockDifference();
if ( c < 0.05f )
return;
float flAmountInTicks = flAmountInSeconds / host_state.interval_per_tick;
float factor = 1 + flAmountInTicks / c;
for ( int i=0; i < NUM_CLOCKDRIFT_SAMPLES; i++ )
m_ClockOffsets[i] *= factor;
Assert( fabs( GetCurrentClockDifference() - (c + flAmountInTicks) ) < 0.001f );
}
extern float NET_GetFakeLag(); extern float NET_GetFakeLag();
extern ConVar net_usesocketsforloopback; extern ConVar net_usesocketsforloopback;

View file

@ -29,10 +29,32 @@ public:
void SetServerTick( int iServerTick, int nLaggedTick, float flServerHostFrametime, float flServerHostFrametimeStdDeviation); void SetServerTick( int iServerTick, int nLaggedTick, float flServerHostFrametime, float flServerHostFrametimeStdDeviation);
void IncrementCachedTickCount(bool bFinalTick); void IncrementCachedTickCount(bool bFinalTick);
// Pass in the frametime you would use, and it will drift it towards the server clock.
float AdjustFrameTime( float inputFrameTime );
// Returns how many ticks ahead of the server the client is.
float GetCurrentClockDifference() const;
private: private:
void ShowDebugInfo(); void ShowDebugInfo();
// This scales the offsets so the average produced is equal to the
// current average + flAmount. This way, as we add corrections,
// we lower the average accordingly so we don't keep responding
// as much as we need to after we'd adjusted it a couple times.
void AdjustAverageDifferenceBy( float flAmountInSeconds );
enum
{
// This controls how much it smoothes out the samples from the server.
NUM_CLOCKDRIFT_SAMPLES=16
};
// This holds how many ticks the client is ahead each time we get a server tick.
// We average these together to get our estimate of how far ahead we are.
float m_ClockOffsets[NUM_CLOCKDRIFT_SAMPLES];
int m_iCurClockOffset;
public: public:
int m_nLagDiff; int m_nLagDiff;

View file

@ -1944,6 +1944,11 @@ void Host_AccumulateTime( float dt )
} }
#endif #endif
// Adjust the client clock very slightly to keep it in line with the server clock.
float adj = cl.GetClockDriftMgr().AdjustFrameTime( host_frametime ) - host_frametime;
host_frametime += adj;
host_frametime_unbounded += adj;
if ( g_pSoundServices ) // not present on linux server if ( g_pSoundServices ) // not present on linux server
g_pSoundServices->SetSoundFrametime(dt, host_frametime); g_pSoundServices->SetSoundFrametime(dt, host_frametime);
@ -3050,7 +3055,8 @@ void _Host_RunFrame (float time)
MDLCACHE_COARSE_LOCK_(g_pMDLCache); MDLCACHE_COARSE_LOCK_(g_pMDLCache);
static double host_remainder = 0.0f; static double host_remainder = 0.0f;
double prevremainder; double prevremainder;
bool shouldrender; bool shouldrender;
float angleframetime = 0.0f;
#if defined( RAD_TELEMETRY_ENABLED ) #if defined( RAD_TELEMETRY_ENABLED )
if( g_Telemetry.DemoTickEnd == ( uint32 )-1 ) if( g_Telemetry.DemoTickEnd == ( uint32 )-1 )
@ -3411,6 +3417,9 @@ void _Host_RunFrame (float time)
CL_RunPrediction( PREDICTION_NORMAL ); CL_RunPrediction( PREDICTION_NORMAL );
CL_ApplyAddAngle(); CL_ApplyAddAngle();
// Ensure we get the right frametime
angleframetime = g_ClientGlobalVariables.frametime;
} }
#endif #endif
#if defined( REPLAY_ENABLED ) #if defined( REPLAY_ENABLED )
@ -3498,6 +3507,9 @@ void _Host_RunFrame (float time)
// This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder) // This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
Host_SetClientInSimulation( false ); Host_SetClientInSimulation( false );
// Ensure we get the right frametime
angleframetime = g_ClientGlobalVariables.frametime;
//------------------- //-------------------
// Run prediction if it hasn't been run yet // Run prediction if it hasn't been run yet
//------------------- //-------------------
@ -3666,15 +3678,16 @@ void _Host_RunFrame (float time)
} // Profile scope, protect from setjmp() problems } // Profile scope, protect from setjmp() problems
Host_ShowIPCCallCount(); Host_ShowIPCCallCount();
#ifndef SWDS #ifndef SWDS
// TODO_ENHANCED: // TODO_ENHANCED:
// Update the mouse as last so we can get the right prediction viewangles on a frame // Update the mouse as last so we can get the right viewangles while taking screenshot.
// The mouse is always simulated for the current frame's time // The mouse is always simulated for the current frame's time
// This makes updates smooth in every case // This makes updates smooth in every case
// continuous controllers affecting the view are also simulated this way // continuous controllers affecting the view are also simulated this way
// but they have a cap applied by IN_SetSampleTime() so they are not also // but they have a cap applied by IN_SetSampleTime() so they are not also
// simulated during input gathering // simulated during input gathering
CL_ExtraMouseUpdate( g_ClientGlobalVariables.frametime ); CL_ExtraMouseUpdate( angleframetime );
#endif #endif
} }
/* /*

View file

@ -149,7 +149,7 @@ extern int host_currentframetick;
// PERFORMANCE INFO // PERFORMANCE INFO
#define MIN_FPS 0.1 // Host minimum fps value for maxfps. #define MIN_FPS 0.1 // Host minimum fps value for maxfps.
#define MAX_FPS 1000.0 // Upper limit for maxfps. #define MAX_FPS 100000000.0 // Upper limit for maxfps.
#define MAX_FRAMETIME 0.1 #define MAX_FRAMETIME 0.1
#define MIN_FRAMETIME 0.001 #define MIN_FRAMETIME 0.001

View file

@ -279,6 +279,21 @@ bool CEngine::FilterTime( float dt )
return false; return false;
} }
} }
else if ( fps == 0 )
{
m_flMinFrameTime = 0.0f;
if (
#if !defined(SWDS)
!demoplayer->IsPlayingTimeDemo() &&
#endif
!g_bDedicatedServerBenchmarkMode &&
dt < 0.0f )
{
// framerate is too high
return false;
}
}
return true; return true;
} }

View file

@ -767,7 +767,7 @@ C_CSPlayer::C_CSPlayer() :
{ {
m_angEyeAngles.Init(); m_angEyeAngles.Init();
// AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_ANIMATION_VAR ); // AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
m_iLastAddonBits = m_iAddonBits = 0; m_iLastAddonBits = m_iAddonBits = 0;
m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE; m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE;