Remove spectatorClientNum hack
spectatorClientNum was hardcoded to MAX_CLIENTS-1 but the spectator actually connected at a different slot. All skip checks using it were no-ops protecting the wrong slot. Removed entirely: - Zombie slots handle player slot reservation - G_RunFrame recreates the spectator entity via ClientThink_real - PlayerState injection writes all slots (spectator's ps gets overwritten by ClientThink_real anyway) - SVD_SpectatorClientNum accessor removed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4d89d35a6d
commit
b79eb77bb3
2 changed files with 5 additions and 24 deletions
|
|
@ -357,7 +357,6 @@ void SVD_Stop_f( void );
|
||||||
qboolean SVD_PlaybackFrame( void );
|
qboolean SVD_PlaybackFrame( void );
|
||||||
qboolean SVD_IsRecording( void );
|
qboolean SVD_IsRecording( void );
|
||||||
qboolean SVD_IsPlaying( void );
|
qboolean SVD_IsPlaying( void );
|
||||||
int SVD_SpectatorClientNum( void );
|
|
||||||
|
|
||||||
//============================================================
|
//============================================================
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,8 @@ typedef struct {
|
||||||
int playFps; // original sv_fps
|
int playFps; // original sv_fps
|
||||||
char *savedConfigstrings[MAX_CONFIGSTRINGS]; // from demo header, re-applied after map load
|
char *savedConfigstrings[MAX_CONFIGSTRINGS]; // from demo header, re-applied after map load
|
||||||
char playMapName[SVDEMO_MAX_MAPNAME];
|
char playMapName[SVDEMO_MAX_MAPNAME];
|
||||||
int spectatorClientNum; // which client slot is the demo spectator
|
// spectatorClientNum removed — zombie slots handle reservation,
|
||||||
|
// and G_RunFrame recreates the spectator entity each frame.
|
||||||
int nextFrameTime; // serverTime of next frame to read
|
int nextFrameTime; // serverTime of next frame to read
|
||||||
qboolean endOfDemo;
|
qboolean endOfDemo;
|
||||||
qboolean needConfigstrings; // apply saved configstrings on first frame
|
qboolean needConfigstrings; // apply saved configstrings on first frame
|
||||||
|
|
@ -686,11 +687,8 @@ static qboolean SVD_ReadFrame( fileHandle_t f ) {
|
||||||
MSG_Init( &msg, msgBuf, sizeof(msgBuf) );
|
MSG_Init( &msg, msgBuf, sizeof(msgBuf) );
|
||||||
msg.cursize = blockLen;
|
msg.cursize = blockLen;
|
||||||
|
|
||||||
// clear all non-spectator entities
|
// clear all entities (spectator's entity is recreated by ClientThink_real)
|
||||||
for ( i = 0; i < sv.num_entities; i++ ) {
|
for ( i = 0; i < sv.num_entities; i++ ) {
|
||||||
if ( i == demo.spectatorClientNum ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ent = SV_GentityNum( i );
|
ent = SV_GentityNum( i );
|
||||||
if ( ent->r.linked ) {
|
if ( ent->r.linked ) {
|
||||||
SV_UnlinkEntity( ent );
|
SV_UnlinkEntity( ent );
|
||||||
|
|
@ -750,11 +748,6 @@ static qboolean SVD_ReadFrame( fileHandle_t f ) {
|
||||||
demo.playPrevEntities[entNum].es = newEs;
|
demo.playPrevEntities[entNum].es = newEs;
|
||||||
demo.playPrevEntities[entNum].active = qtrue;
|
demo.playPrevEntities[entNum].active = qtrue;
|
||||||
|
|
||||||
// skip the spectator's slot
|
|
||||||
if ( entNum == demo.spectatorClientNum ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply to server entity
|
// apply to server entity
|
||||||
ent = SV_GentityNum( entNum );
|
ent = SV_GentityNum( entNum );
|
||||||
ent->s = newEs;
|
ent->s = newEs;
|
||||||
|
|
@ -774,11 +767,6 @@ static qboolean SVD_ReadFrame( fileHandle_t f ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure spectator slot is counted
|
|
||||||
if ( demo.spectatorClientNum + 1 > sv.num_entities ) {
|
|
||||||
sv.num_entities = demo.spectatorClientNum + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read player states (delta compressed)
|
// read player states (delta compressed)
|
||||||
{
|
{
|
||||||
msg_t psmsg;
|
msg_t psmsg;
|
||||||
|
|
@ -818,14 +806,14 @@ static qboolean SVD_ReadFrame( fileHandle_t f ) {
|
||||||
demo.playPrevPlayers[clientNum].active = qtrue;
|
demo.playPrevPlayers[clientNum].active = qtrue;
|
||||||
|
|
||||||
// inject into game module's client state
|
// inject into game module's client state
|
||||||
if ( clientNum != demo.spectatorClientNum ) {
|
{
|
||||||
playerState_t *gamePs = SV_GameClientNum( clientNum );
|
playerState_t *gamePs = SV_GameClientNum( clientNum );
|
||||||
*gamePs = newPs;
|
*gamePs = newPs;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
demo.playPrevPlayers[clientNum].active = qfalse;
|
demo.playPrevPlayers[clientNum].active = qfalse;
|
||||||
// clear game playerState so G_RunFrame sees commandTime=0
|
// clear game playerState so G_RunFrame sees commandTime=0
|
||||||
if ( clientNum != demo.spectatorClientNum ) {
|
{
|
||||||
playerState_t *gamePs = SV_GameClientNum( clientNum );
|
playerState_t *gamePs = SV_GameClientNum( clientNum );
|
||||||
Com_Memset( gamePs, 0, sizeof(*gamePs) );
|
Com_Memset( gamePs, 0, sizeof(*gamePs) );
|
||||||
}
|
}
|
||||||
|
|
@ -906,9 +894,6 @@ void SVD_Play_f( void ) {
|
||||||
demo.playing = qtrue;
|
demo.playing = qtrue;
|
||||||
demo.endOfDemo = qfalse;
|
demo.endOfDemo = qfalse;
|
||||||
|
|
||||||
// The spectator gets the highest slot: MAX_CLIENTS - 1
|
|
||||||
demo.spectatorClientNum = MAX_CLIENTS - 1;
|
|
||||||
|
|
||||||
Com_Printf( "Playing server demo: map=%s maxclients=%d fps=%d\n",
|
Com_Printf( "Playing server demo: map=%s maxclients=%d fps=%d\n",
|
||||||
demo.playMapName, demo.playMaxClients, demo.playFps );
|
demo.playMapName, demo.playMaxClients, demo.playFps );
|
||||||
|
|
||||||
|
|
@ -1032,6 +1017,3 @@ qboolean SVD_IsPlaying( void ) {
|
||||||
return demo.playing;
|
return demo.playing;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SVD_SpectatorClientNum( void ) {
|
|
||||||
return demo.spectatorClientNum;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue