Add svdemo_seekexact for precise seeking with read-forward
svdemo_seek snaps to the nearest keyframe (fast, ±interval accuracy). svdemo_seekexact reads forward from the keyframe to the exact target time, giving frame-accurate positioning at the cost of a brief processing delay. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a8bfa738b0
commit
d0a4310bad
3 changed files with 72 additions and 0 deletions
|
|
@ -356,6 +356,7 @@ void SVD_CleanupPlayback( void );
|
|||
void SVD_Stop_f( void );
|
||||
void SVD_Pause_f( void );
|
||||
void SVD_Seek_f( void );
|
||||
void SVD_SeekExact_f( void );
|
||||
qboolean SVD_PlaybackFrame( void );
|
||||
qboolean SVD_IsRecording( void );
|
||||
qboolean SVD_IsPlaying( void );
|
||||
|
|
|
|||
|
|
@ -746,6 +746,7 @@ void SV_AddOperatorCommands( void ) {
|
|||
Cmd_AddCommand ("svdemo_play", SVD_Play_f);
|
||||
Cmd_AddCommand ("svdemo_pause", SVD_Pause_f);
|
||||
Cmd_AddCommand ("svdemo_seek", SVD_Seek_f);
|
||||
Cmd_AddCommand ("svdemo_seekexact", SVD_SeekExact_f);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1104,6 +1104,76 @@ void SVD_Seek_f( void ) {
|
|||
Com_Printf( "Seeked to time %d.\n", svs.time );
|
||||
}
|
||||
|
||||
void SVD_SeekExact_f( void ) {
|
||||
int targetTime, i, bestKf;
|
||||
float seconds;
|
||||
|
||||
if ( !demo.playing ) {
|
||||
Com_Printf( "Not playing a server demo.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Cmd_Argc() < 2 ) {
|
||||
Com_Printf( "Usage: svdemo_seekexact <seconds>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( demo.numKeyframes <= 0 ) {
|
||||
Com_Printf( "No keyframes in this demo.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
seconds = atof( Cmd_Argv(1) );
|
||||
targetTime = svs.time + (int)(seconds * 1000);
|
||||
|
||||
// find nearest keyframe at or before target time
|
||||
bestKf = -1;
|
||||
for ( i = 0; i < demo.numKeyframes; i++ ) {
|
||||
if ( demo.keyframeTimes[i] <= targetTime ) {
|
||||
bestKf = i;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( bestKf < 0 ) {
|
||||
bestKf = 0;
|
||||
targetTime = demo.keyframeTimes[0];
|
||||
}
|
||||
|
||||
// seek to keyframe
|
||||
FS_Seek( demo.playFile, demo.keyframeOffsets[bestKf], FS_SEEK_SET );
|
||||
Com_Memset( demo.playPrevEntities, 0, sizeof(demo.playPrevEntities) );
|
||||
Com_Memset( demo.playPrevPlayers, 0, sizeof(demo.playPrevPlayers) );
|
||||
svs.time = demo.keyframeTimes[bestKf];
|
||||
svs.snapFlagServerBit ^= SNAPFLAG_SERVERCOUNT;
|
||||
demo.seeked = qtrue;
|
||||
demo.endOfDemo = qfalse;
|
||||
|
||||
// read forward from keyframe to target time
|
||||
while ( svs.time < targetTime ) {
|
||||
if ( !SVD_ReadFrame( demo.playFile ) ) {
|
||||
demo.endOfDemo = qtrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// reset client snapshot timing
|
||||
{
|
||||
int j;
|
||||
for ( j = 0; j < sv_maxclients->integer; j++ ) {
|
||||
if ( svs.clients[j].state >= CS_ACTIVE ) {
|
||||
svs.clients[j].nextSnapshotTime = svs.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sv.timeResidual = 1000 / sv_fps->integer;
|
||||
|
||||
Com_Printf( "Seeked to time %d (read forward %d ms from keyframe).\n",
|
||||
svs.time, svs.time - demo.keyframeTimes[bestKf] );
|
||||
}
|
||||
|
||||
/*
|
||||
Called from SV_Frame() to advance playback by one frame.
|
||||
Returns qtrue if a frame was read, qfalse if demo ended.
|
||||
|
|
|
|||
Loading…
Reference in a new issue