Demo pause: freeze svs.time, hold demo data consumption
svdemo_pause toggles playback pause. When paused: - svs.time frozen so entity trajectories freeze correctly - No demo frames consumed (SVD_PlaybackFrame returns early) - Game frame still runs at frozen time for spectator movement - No time jump on unpause — svs.time resumes from where it was Spectator movement degrades during pause (200ms PmoveSingle cap) — will be resolved by client-owned camera in a future change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9799952b34
commit
7141d941a3
4 changed files with 1087 additions and 1056 deletions
|
|
@ -353,9 +353,11 @@ void SVD_CaptureServerCommand( const char *cmd );
|
|||
void SVD_Play_f( void );
|
||||
void SVD_StopPlay_f( void );
|
||||
void SVD_Stop_f( void );
|
||||
void SVD_Pause_f( void );
|
||||
qboolean SVD_PlaybackFrame( void );
|
||||
qboolean SVD_IsRecording( void );
|
||||
qboolean SVD_IsPlaying( void );
|
||||
qboolean SVD_IsPaused( void );
|
||||
qboolean SVD_ShouldPause( void );
|
||||
|
||||
//============================================================
|
||||
|
|
|
|||
|
|
@ -744,6 +744,7 @@ void SV_AddOperatorCommands( void ) {
|
|||
Cmd_AddCommand ("svdemo_record", SVD_Record_f);
|
||||
Cmd_AddCommand ("svdemo_stop", SVD_Stop_f);
|
||||
Cmd_AddCommand ("svdemo_play", SVD_Play_f);
|
||||
Cmd_AddCommand ("svdemo_pause", SVD_Pause_f);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -831,6 +831,15 @@ void SV_Frame( int msec ) {
|
|||
// run the game simulation in chunks
|
||||
while ( sv.timeResidual >= frameMsec ) {
|
||||
sv.timeResidual -= frameMsec;
|
||||
|
||||
if ( SVD_IsPaused() ) {
|
||||
// demo paused: freeze svs.time so trajectories freeze
|
||||
// and client doesn't see time jumps on unpause.
|
||||
// still run game frame for spectator movement (at frozen time).
|
||||
VM_Call( gvm, GAME_RUN_FRAME, svs.time );
|
||||
continue;
|
||||
}
|
||||
|
||||
svs.time += frameMsec;
|
||||
|
||||
if ( SVD_IsPlaying() ) {
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ typedef struct {
|
|||
char playMapName[SVDEMO_MAX_MAPNAME];
|
||||
qboolean endOfDemo;
|
||||
qboolean needConfigstrings; // apply saved configstrings on first frame
|
||||
qboolean paused;
|
||||
svdEntityState_t playPrevEntities[MAX_GENTITIES]; // previous frame for delta read
|
||||
svdPlayerState_t playPrevPlayers[MAX_CLIENTS]; // previous frame player states
|
||||
} svDemo_t;
|
||||
|
|
@ -987,6 +988,15 @@ void SVD_Stop_f( void ) {
|
|||
}
|
||||
}
|
||||
|
||||
void SVD_Pause_f( void ) {
|
||||
if ( !demo.playing ) {
|
||||
Com_Printf( "Not playing a server demo.\n" );
|
||||
return;
|
||||
}
|
||||
demo.paused = !demo.paused;
|
||||
Com_Printf( "Demo playback %s.\n", demo.paused ? "paused" : "resumed" );
|
||||
}
|
||||
|
||||
/*
|
||||
Called from SV_Frame() to advance playback by one frame.
|
||||
Returns qtrue if a frame was read, qfalse if demo ended.
|
||||
|
|
@ -996,6 +1006,11 @@ qboolean SVD_PlaybackFrame( void ) {
|
|||
return qfalse;
|
||||
}
|
||||
|
||||
// manual pause — don't consume demo data
|
||||
if ( demo.paused ) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// wait for a spectator to be fully in-game before starting playback.
|
||||
// the server keeps running frames (so the connection handshake completes)
|
||||
// but no demo data is consumed until someone is CS_ACTIVE.
|
||||
|
|
@ -1034,6 +1049,10 @@ qboolean SVD_IsPlaying( void ) {
|
|||
return demo.playing;
|
||||
}
|
||||
|
||||
qboolean SVD_IsPaused( void ) {
|
||||
return demo.playing && demo.paused;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns qtrue if demo playback should pause (no active spectators).
|
||||
Controlled by svdemo_pauseEmpty cvar.
|
||||
|
|
|
|||
Loading…
Reference in a new issue