Proper demo playback cleanup and state reset

- Extract SVD_CleanupPlayback for shared cleanup logic
- Called on demo end (SVD_PlaybackFrame) and manual stop
- Frees zombie client slots, saved configstrings, file handle
- Clears sv_demoplaying cvar so game module exits demo mode
- Hook into SV_Shutdown to clean up on server shutdown/map change
- Allows playing another demo after one finishes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
serge_shubin 2026-03-23 04:55:12 +08:00
parent 0bd116982a
commit b48a0575f1
2 changed files with 27 additions and 4 deletions

View file

@ -667,6 +667,14 @@ void SV_Shutdown( char *finalmsg ) {
Com_Printf( "----- Server Shutdown -----\n" );
// clean up any active demo recording/playback
if ( SVD_IsRecording() ) {
SVD_StopRecord_f();
}
if ( SVD_IsPlaying() ) {
SVD_StopPlay_f();
}
if ( svs.clients && !com_errorEntered ) {
SV_FinalMessage( finalmsg );
}

View file

@ -735,11 +735,10 @@ void SVD_Play_f( void ) {
demo.needConfigstrings = qtrue;
}
void SVD_StopPlay_f( void ) {
static void SVD_CleanupPlayback( void ) {
int i;
if ( !demo.playing ) {
Com_Printf( "Not playing a server demo.\n" );
return;
}
@ -751,9 +750,25 @@ void SVD_StopPlay_f( void ) {
Z_Free( demo.savedConfigstrings[i] );
}
}
memset( &demo, 0, sizeof(demo) );
// free zombie client slots
for ( i = 0; i < demo.playMaxClients; i++ ) {
if ( svs.clients[i].state == CS_ZOMBIE ) {
svs.clients[i].state = CS_FREE;
}
}
memset( &demo, 0, sizeof(demo) );
Cvar_Set( "sv_demoplaying", "0" );
}
void SVD_StopPlay_f( void ) {
if ( !demo.playing ) {
Com_Printf( "Not playing a server demo.\n" );
return;
}
SVD_CleanupPlayback();
Com_Printf( "Server demo playback stopped.\n" );
}
@ -773,8 +788,8 @@ qboolean SVD_PlaybackFrame( void ) {
}
if ( !SVD_ReadFrame( demo.playFile ) ) {
demo.endOfDemo = qtrue;
Com_Printf( "Server demo playback finished.\n" );
SVD_CleanupPlayback();
return qfalse;
}