Skip to content

Commit

Permalink
server: handle dropped gamestate after UDP download
Browse files Browse the repository at this point in the history
Adds an extra check for dropped gamestate for clients that just finished a UDP download, based on detecting missing move commands. Fixes potential "awaiting gamestate" freeze after UDP download completes.
  • Loading branch information
Chomenor committed Jun 1, 2024
1 parent 38c37ea commit a875f25
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 0 deletions.
2 changes: 2 additions & 0 deletions code/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ typedef struct client_s {
int downloadBlockSize[MAX_DOWNLOAD_WINDOW];
qboolean downloadEOF; // We have sent the EOF block
int downloadSendTime; // time we last got an ack from the client
qboolean downloadGamestateDropCheck; // perform extra dropped gamestate check after downloads
int downloadGamestateDropTime; // wait for 2nd client message ~750ms later

int deltaMessage; // frame last client usercmd message
int lastPacketTime; // svs.time when packet was last received
Expand Down
35 changes: 35 additions & 0 deletions code/server/sv_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,10 @@ static void SV_DoneDownload_f( client_t *cl ) {

// resend the game state to update any clients that entered during the download
SV_SendClientGameState( cl );

// activate protection to resend gamestate if previous one was dropped
cl->downloadGamestateDropCheck = qtrue;
cl->downloadGamestateDropTime = 0;
}


Expand Down Expand Up @@ -2297,4 +2301,35 @@ void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) {
// if ( msg->readcount != msg->cursize ) {
// Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients );
// }

// following UDP downloads, the client expects a new gamestate, but the usual check to
// detect if it was dropped may not work because the client has the correct serverid,
// so do an extra check based on missing move commands
if ( cl->downloadGamestateDropCheck && !*cl->downloadName ) {
if ( cl->state == CS_ACTIVE ) {
// this means client sent a move command, which means they have gamestate
Com_Printf( "%s: clearing gamestate drop check\n", cl->name );
cl->downloadGamestateDropCheck = qfalse;
} else if ( cl->state == CS_PRIMED && cl->messageAcknowledge - cl->gamestateMessageNum > 0 ) {
// likely dropped gamestate, but wait for 2 messages at least 750ms apart to be safer
// for client compatibility (client should send messages 1s apart without gamestate)
int time = Sys_Milliseconds();
if ( !cl->downloadGamestateDropTime ) {
Com_DPrintf( "%s: potential dropped post-download gamestate (ack=%i)\n",
cl->name, cl->messageAcknowledge - cl->gamestateMessageNum );
cl->downloadGamestateDropTime = time;
} else if ( time - cl->downloadGamestateDropTime < 750 ) {
Com_DPrintf( "%s: potential dropped post-download gamestate bad time (time=%i, ack=%i)\n",
cl->name, time - cl->downloadGamestateDropTime,
cl->messageAcknowledge - cl->gamestateMessageNum );
cl->downloadGamestateDropTime = time;
} else {
Com_DPrintf( "%s: resending post-download gamestate (time=%i, ack=%i)\n",
cl->name, time - cl->downloadGamestateDropTime,
cl->messageAcknowledge - cl->gamestateMessageNum );
SV_SendClientGameState( cl );
cl->downloadGamestateDropTime = 0;
}
}
}
}

0 comments on commit a875f25

Please sign in to comment.