Fix spectator display and recorded spectator handling
- Set sv_demoplaying before devmap so game module knows during ClientConnect/ClientBegin - Call ClientUserinfoChanged after forcing spectator team so CS_PLAYERS configstring has correct team value for cgame - Record sanitized playerState for spectators (pm_type=PM_SPECTATOR, PERS_TEAM=TEAM_SPECTATOR) so they show correctly on scoreboard instead of appearing as regular players from follow-mode corruption Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d78f5c7aaf
commit
fcd5fc6ce8
2 changed files with 23 additions and 5 deletions
|
|
@ -1013,10 +1013,10 @@ void ClientBegin( int clientNum ) {
|
|||
client->pers.teamState.state = TEAM_BEGIN;
|
||||
|
||||
// demo playback: force all clients to spectator
|
||||
// demo playback: force to spectator and update configstring
|
||||
if ( g_svDemoPlaying.integer ) {
|
||||
client->sess.sessionTeam = TEAM_SPECTATOR;
|
||||
client->ps.pm_type = PM_SPECTATOR;
|
||||
client->ps.persistant[PERS_TEAM] = TEAM_SPECTATOR;
|
||||
ClientUserinfoChanged( ent->client - level.clients );
|
||||
}
|
||||
|
||||
// save eflags around this, because changing teams will
|
||||
|
|
|
|||
|
|
@ -336,6 +336,23 @@ static void SVD_WriteFrame( fileHandle_t f ) {
|
|||
playerState_t *ps = SV_GameClientNum( i );
|
||||
client_t *cl = &svs.clients[i];
|
||||
qboolean active = ( cl->state >= CS_ACTIVE );
|
||||
qboolean isSpectator;
|
||||
playerState_t specPs;
|
||||
|
||||
// detect spectators: free cam or follow mode
|
||||
isSpectator = active && ( ps->pm_type == PM_SPECTATOR || (ps->pm_flags & PMF_FOLLOW) );
|
||||
|
||||
// for spectators, record a sanitized ps so they appear on
|
||||
// the scoreboard as spectators (follow mode corrupts their ps
|
||||
// with the followed player's data)
|
||||
if ( isSpectator ) {
|
||||
Com_Memset( &specPs, 0, sizeof(specPs) );
|
||||
specPs.commandTime = ps->commandTime;
|
||||
specPs.pm_type = PM_SPECTATOR;
|
||||
specPs.persistant[PERS_TEAM] = TEAM_SPECTATOR;
|
||||
specPs.clientNum = i;
|
||||
ps = &specPs;
|
||||
}
|
||||
|
||||
if ( active ) {
|
||||
playerState_t *from = demo.prevPlayers[i].active ? &demo.prevPlayers[i].ps : NULL;
|
||||
|
|
@ -897,14 +914,15 @@ void SVD_Play_f( void ) {
|
|||
Com_Printf( "Playing server demo: map=%s maxclients=%d fps=%d\n",
|
||||
demo.playMapName, demo.playMaxClients, demo.playFps );
|
||||
|
||||
// Signal demo mode BEFORE map load so the game module knows
|
||||
// during ClientConnect/ClientBegin to force spectator team.
|
||||
Cvar_Set( "sv_demoplaying", "1" );
|
||||
|
||||
// Load the map with maxclients = MAX_CLIENTS to avoid entity slot collisions.
|
||||
Cbuf_ExecuteText( EXEC_NOW, va("set sv_maxclients %d\n", MAX_CLIENTS) );
|
||||
Cbuf_ExecuteText( EXEC_NOW, va("set sv_fps %d\n", demo.playFps) );
|
||||
Cbuf_ExecuteText( EXEC_NOW, va("devmap %s\n", demo.playMapName) );
|
||||
|
||||
// Signal demo mode to the game module AFTER map load
|
||||
Cvar_Set( "sv_demoplaying", "1" );
|
||||
|
||||
// Reserve recorded player slots so the connecting spectator
|
||||
// doesn't land in slot 0 (which collides with recorded player 0).
|
||||
// Mark as CS_ZOMBIE (non-free, won't be reused by SV_DirectConnect).
|
||||
|
|
|
|||
Loading…
Reference in a new issue