From 94ff5879178213863265b6128b403560e429a438 Mon Sep 17 00:00:00 2001 From: neyoneit Date: Tue, 3 Mar 2026 21:30:19 +0100 Subject: [PATCH] cl_localTime: PLL-based local rendering clock for smooth gameplay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase-locked loop for cl.serverTime: instead of jumping to network-derived values each frame (causing micro-stutters from snapshot arrival jitter), serverTime advances at a constant local rate and softly tracks the server (max 2% rate adjustment). Hard clamp at 100ms prevents excessive drift. cl_localTime 0 = standard network-synced time (default) cl_localTime 1 = smooth local clock, eliminates rendering jitter Based on clean oDFe (origin/main) with no other modifications. Only client-side change — server needs no modification. Files: code/client/cl_cgame.c, cl_main.c, client.h Co-Authored-By: Claude Opus 4.6 --- code/client/cl_cgame.c | 32 +++++++++++++++++++++++++++++++- code/client/cl_main.c | 5 +++++ code/client/client.h | 1 + 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/code/client/cl_cgame.c b/code/client/cl_cgame.c index ccbe3c079a..0e5f3b6b1b 100644 --- a/code/client/cl_cgame.c +++ b/code/client/cl_cgame.c @@ -1162,7 +1162,37 @@ void CL_SetCGameTime( void ) { // cl_timeNudge is a user adjustable cvar that allows more // or less latency to be added in the interest of better // smoothness or better responsiveness. - cl.serverTime = cls.realtime + cl.serverTimeDelta - CL_TimeNudge(); + + if ( cl_localTime->integer && !clc.demoplaying ) { + // PLL: advance serverTime at constant local rate instead of + // jumping to network-derived value each frame. Eliminates + // rendering jitter from snapshot arrival variance. + static int lastRealtime = 0; + int frameDelta, targetTime, error; + + if ( lastRealtime == 0 || lastRealtime > cls.realtime ) + lastRealtime = cls.realtime; + + frameDelta = cls.realtime - lastRealtime; + lastRealtime = cls.realtime; + + targetTime = cls.realtime + cl.serverTimeDelta - CL_TimeNudge(); + error = targetTime - cl.serverTime; + + // soft rate adjustment: speed up/slow down max 2% to track server + if ( error > 2 ) + cl.serverTime += (int)( frameDelta * 1.02f ); + else if ( error < -2 ) + cl.serverTime += (int)( frameDelta * 0.98f ); + else + cl.serverTime += frameDelta; + + // hard clamp: never diverge more than 100ms from server + if ( error > 100 || error < -100 ) + cl.serverTime = targetTime; + } else { + cl.serverTime = cls.realtime + cl.serverTimeDelta - CL_TimeNudge(); + } // guarantee that time will never flow backwards, even if // serverTimeDelta made an adjustment or cl_timeNudge was changed diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 7ca80f2cf4..e5a87a6d7f 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -39,6 +39,7 @@ cvar_t *cl_timeout; cvar_t *cl_autoNudge; cvar_t *cl_timeNudge; cvar_t *cl_showTimeDelta; +cvar_t *cl_localTime; cvar_t *cl_shownet; cvar_t *cl_autoRecordDemo; @@ -3908,6 +3909,10 @@ void CL_Init( void ) { Cvar_CheckRange( cl_timeNudge, "-250", "250", CV_INTEGER ); Cvar_SetDescription( cl_timeNudge, "Allows more or less latency to be added in the interest of better smoothness or better responsiveness." ); + cl_localTime = Cvar_Get( "cl_localTime", "0", CVAR_ARCHIVE_ND ); + Cvar_CheckRange( cl_localTime, "0", "1", CV_INTEGER ); + Cvar_SetDescription( cl_localTime, "Local time mode: cl.serverTime advances at constant local rate instead of jumping to network-derived values.\n 0 - standard network-synced time (default)\n 1 - smooth local clock, eliminates rendering jitter from network\n" ); + cl_shownet = Cvar_Get ("cl_shownet", "0", CVAR_TEMP ); Cvar_SetDescription( cl_shownet, "Toggle the display of current network status." ); cl_showTimeDelta = Cvar_Get ("cl_showTimeDelta", "0", CVAR_TEMP ); diff --git a/code/client/client.h b/code/client/client.h index 48e980c9c2..c3fe86dad5 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -392,6 +392,7 @@ extern cvar_t *cl_shownet; extern cvar_t *cl_autoNudge; extern cvar_t *cl_timeNudge; extern cvar_t *cl_showTimeDelta; +extern cvar_t *cl_localTime; extern cvar_t *com_timedemo; extern cvar_t *cl_aviFrameRate;