From 490fcd9bde873a9e81b220079e32106c711b4ace Mon Sep 17 00:00:00 2001 From: serge_shubin Date: Tue, 24 Mar 2026 03:59:44 +0800 Subject: [PATCH] Smooth unpause: reset client time delta and entity interpolation On unpause, toggle SNAPFLAG_SERVERCOUNT and set SNAPFLAG_RESET_ENTITIES. In CL_ParseSnapshot, detect SERVERCOUNT toggle and hard-reset cl.serverTimeDelta instead of letting CL_AdjustTimeDelta slowly drift. During pause, the delta drifted because snapshots had frozen serverTime while cls.realtime advanced. Without the hard reset, it took 1-2 seconds of choppy interpolation to re-sync. Co-Authored-By: Claude Opus 4.6 (1M context) --- code/client/cl_parse.c | 30 +++++++++++++++++++++--------- code/server/sv_netdemo.c | 8 ++++++++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index 9de3588..6c55476 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -288,17 +288,29 @@ void CL_ParseSnapshot( msg_t *msg ) { cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse; } - // copy to the current good spot - cl.snap = newSnap; - cl.snap.ping = 999; - // calculate ping time - for ( i = 0 ; i < PACKET_BACKUP ; i++ ) { - packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK; - if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) { - cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime; - break; + { + int oldSnapFlags = cl.snap.snapFlags; + + // copy to the current good spot + cl.snap = newSnap; + cl.snap.ping = 999; + // calculate ping time + for ( i = 0 ; i < PACKET_BACKUP ; i++ ) { + packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK; + if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) { + cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime; + break; + } + } + // if server count changed (map_restart or demo unpause), force-reset + // the time delta so the client doesn't slowly drift back to sync + if ( ( oldSnapFlags ^ newSnap.snapFlags ) & SNAPFLAG_SERVERCOUNT ) { + cl.serverTimeDelta = cl.snap.serverTime - cls.realtime; + cl.oldServerTime = cl.snap.serverTime; + cl.serverTime = cl.snap.serverTime; } } + // save the frame off in the backup array for later delta comparisons cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap; diff --git a/code/server/sv_netdemo.c b/code/server/sv_netdemo.c index 1ef536f..143a856 100644 --- a/code/server/sv_netdemo.c +++ b/code/server/sv_netdemo.c @@ -994,6 +994,14 @@ void SVD_Pause_f( void ) { return; } demo.paused = !demo.paused; + if ( !demo.paused ) { + // resuming — reset entities so client doesn't interpolate + // from frozen positions to post-pause positions. + // also toggle SERVERCOUNT to reset client snapshot timing + // (drifted during pause from identical serverTimes). + svs.snapFlagServerBit |= SNAPFLAG_RESET_ENTITIES; + svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT; + } Com_Printf( "Demo playback %s.\n", demo.paused ? "paused" : "resumed" ); }