static void NET_SV_AdvanceWindow(void) { unsigned int lowtic; int i; if (NET_SV_NumPlayers() <= 0) { return; } lowtic = NET_SV_LatestAcknowledged(); // Advance the recv window until it catches up with lowtic while (recvwindow_start < lowtic) { boolean should_advance; // Check we have tics from all players for first tic in // the recv window should_advance = true; for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] == NULL || !ClientConnected(sv_players[i])) { continue; } if (!recvwindow[0][i].active) { should_advance = false; break; } } if (!should_advance) { // The first tic is not complete: ie. we have not // received tics from all connected players. This can // happen if only one player is in the game. break; } // Advance the window memmove(recvwindow, recvwindow + 1, sizeof(*recvwindow) * (BACKUPTICS - 1)); memset(&recvwindow[BACKUPTICS-1], 0, sizeof(*recvwindow)); ++recvwindow_start; //printf("SV: advanced to %i\n", recvwindow_start); } }
static void NET_SV_PumpSendQueue(net_client_t *client) { net_full_ticcmd_t cmd; int recv_index; int i; int starttic, endtic; // If a client has not sent any acknowledgments for a while, // wait until they catch up. if (client->sendseq - NET_SV_LatestAcknowledged() > 40) { return; } // Work out the index into the receive window recv_index = client->sendseq - recvwindow_start; if (recv_index < 0 || recv_index >= BACKUPTICS) { return; } // Check if we can generate a new entry for the send queue // using the data in recvwindow. for (i=0; i<MAXPLAYERS; ++i) { if (sv_players[i] == client) { // Client does not rely on itself for data continue; } if (sv_players[i] == NULL || !ClientConnected(sv_players[i])) { continue; } if (!recvwindow[recv_index][i].active) { // We do not have this player's ticcmd, so we cannot // generate a complete command yet. return; } } //printf("SV: have complete ticcmd for %i\n", client->sendseq); // We have all data we need to generate a command for this tic. cmd.seq = client->sendseq; // Add ticcmds from all players cmd.latency = 0; for (i=0; i<MAXPLAYERS; ++i) { net_client_recv_t *recvobj; if (sv_players[i] == client) { // Not the player we are sending to cmd.playeringame[i] = false; continue; } if (sv_players[i] == NULL || !recvwindow[recv_index][i].active) { cmd.playeringame[i] = false; continue; } cmd.playeringame[i] = true; recvobj = &recvwindow[recv_index][i]; cmd.cmds[i] = recvobj->diff; if (recvobj->latency > cmd.latency) cmd.latency = recvobj->latency; } //printf("SV: %i: latency %i\n", client->player_number, cmd.latency); // Add into the queue client->sendqueue[client->sendseq % BACKUPTICS] = cmd; // Transmit the new tic to the client starttic = client->sendseq - sv_settings.extratics; endtic = client->sendseq; if (starttic < 0) starttic = 0; NET_SV_SendTics(client, starttic, endtic); ++client->sendseq; }
static void NET_SV_PumpSendQueue(net_client_t *client) { net_full_ticcmd_t cmd; int recv_index; int num_players; int i; int starttic, endtic; // If a client has not sent any acknowledgments for a while, // wait until they catch up. if (client->sendseq - NET_SV_LatestAcknowledged() > 40) { return; } // Work out the index into the receive window recv_index = client->sendseq - recvwindow_start; if (recv_index < 0 || recv_index >= BACKUPTICS) { return; } // Check if we can generate a new entry for the send queue // using the data in recvwindow. num_players = 0; for (i=0; i<NET_MAXPLAYERS; ++i) { if (sv_players[i] == client) { // Client does not rely on itself for data continue; } if (sv_players[i] == NULL || !ClientConnected(sv_players[i])) { continue; } if (!recvwindow[recv_index][i].active) { // We do not have this player's ticcmd, so we cannot // generate a complete command yet. return; } ++num_players; } // If this is a game with only a single player in it, we might // be sending a ticcmd set containing 0 ticcmds. This is fine; // however, there's nothing to stop the game running on ahead // and never stopping. Don't let the server get too far ahead // of the client. if (num_players == 0 && client->sendseq > recvwindow_start + 10) { return; } // We have all data we need to generate a command for this tic. cmd.seq = client->sendseq; // Add ticcmds from all players cmd.latency = 0; for (i=0; i<NET_MAXPLAYERS; ++i) { net_client_recv_t *recvobj; if (sv_players[i] == client) { // Not the player we are sending to cmd.playeringame[i] = false; continue; } if (sv_players[i] == NULL || !recvwindow[recv_index][i].active) { cmd.playeringame[i] = false; continue; } cmd.playeringame[i] = true; recvobj = &recvwindow[recv_index][i]; cmd.cmds[i] = recvobj->diff; if (recvobj->latency > cmd.latency) cmd.latency = recvobj->latency; } //printf("SV: %i: latency %i\n", client->player_number, cmd.latency); // Add into the queue client->sendqueue[client->sendseq % BACKUPTICS] = cmd; // Transmit the new tic to the client starttic = client->sendseq - sv_settings.extratics; endtic = client->sendseq; if (starttic < 0) starttic = 0; NET_Log("server: send tics %d-%d to %s", starttic, endtic, NET_AddrToString(client->addr)); NET_SV_SendTics(client, starttic, endtic); ++client->sendseq; }