ref: 65ba9ecd3c61235e618a208e0595d71bcefcf9f4
parent: 4af352a213431e577a48dd8b3ece7822cb7168bc
author: Simon Howard <fraggle@gmail.com>
date: Fri Feb 17 15:15:16 EST 2006
Request resends for missed packets Subversion-branch: /trunk/chocolate-doom Subversion-revision: 370
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
-// $Id: net_client.c 323 2006-01-22 22:29:42Z fraggle $
+// $Id: net_client.c 370 2006-02-17 20:15:16Z fraggle $
//
// Copyright(C) 2005 Simon Howard
//
@@ -21,6 +21,9 @@
// 02111-1307, USA.
//
// $Log$
+// Revision 1.24 2006/02/17 20:15:16 fraggle
+// Request resends for missed packets
+//
// Revision 1.23 2006/01/22 22:29:42 fraggle
// Periodically request the time from clients to estimate their offset to
// the server time.
@@ -217,34 +220,13 @@
NET_WriteSettings(packet, &settings);
}
-// Add a new ticcmd to the send queue
-
-void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic)
+static void NET_CL_SendTics(int start, int end)
{
- net_ticdiff_t diff;
net_packet_t *packet;
- int start, end;
int i;
-
- // Calculate the difference to the last ticcmd
- NET_TiccmdDiff(&last_ticcmd, ticcmd, &diff);
-
- // Store in the send queue
-
- ticcmd_send_queue[maketic % NET_TICCMD_QUEUE_SIZE] = diff;
-
- last_ticcmd = *ticcmd;
-
- // We need to generate a new packet containing the new ticcmd to send
- // to the server. Work out which ticcmds we are sending.
-
-// start = maketic - extratics;
-
if (start < 0)
start = 0;
-
- end = maketic;
// Build a new packet to send to the server
@@ -277,6 +259,27 @@
NET_FreePacket(packet);
}
+// Add a new ticcmd to the send queue
+
+void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic)
+{
+ net_ticdiff_t diff;
+
+ // Calculate the difference to the last ticcmd
+
+ NET_TiccmdDiff(&last_ticcmd, ticcmd, &diff);
+
+ // Store in the send queue
+
+ ticcmd_send_queue[maketic % NET_TICCMD_QUEUE_SIZE] = diff;
+
+ last_ticcmd = *ticcmd;
+
+ // Send to server.
+
+ NET_CL_SendTics(maketic, maketic);
+}
+
// data received while we are waiting for the game to start
static void NET_CL_ParseWaitingData(net_packet_t *packet)
@@ -399,6 +402,26 @@
NET_FreePacket(reply);
}
+// Parse a resend request from the server due to a dropped packet
+
+static void NET_CL_ParseResendRequest(net_packet_t *packet)
+{
+ static unsigned int start;
+ static unsigned int num_tics;
+
+ if (!NET_ReadInt32(packet, &start)
+ || !NET_ReadInt8(packet, &num_tics))
+ {
+ return;
+ }
+
+ // Resend those tics
+
+ printf("CL: resend %i-%i\n", start, start+num_tics-1);
+
+ NET_CL_SendTics(start, start + num_tics - 1);
+}
+
// parse a received packet
static void NET_CL_ParsePacket(net_packet_t *packet)
@@ -432,6 +455,9 @@
case NET_PACKET_TYPE_TIME_REQ:
NET_CL_ParseTimeRequest(packet);
break;
+
+ case NET_PACKET_TYPE_GAMEDATA_RESEND:
+ NET_CL_ParseResendRequest(packet);
default:
break;
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
-// $Id: net_defs.h 369 2006-02-16 01:12:28Z fraggle $
+// $Id: net_defs.h 370 2006-02-17 20:15:16Z fraggle $
//
// Copyright(C) 2005 Simon Howard
//
@@ -21,6 +21,9 @@
// 02111-1307, USA.
//
// $Log$
+// Revision 1.13 2006/02/17 20:15:16 fraggle
+// Request resends for missed packets
+//
// Revision 1.12 2006/02/16 01:12:28 fraggle
// Define a new type net_full_ticcmd_t, a structure containing all ticcmds
// for a given tic. Store received game data in a receive window. Add
@@ -161,6 +164,7 @@
NET_PACKET_TYPE_RELIABLE_ACK,
NET_PACKET_TYPE_TIME_REQ,
NET_PACKET_TYPE_TIME_RESP,
+ NET_PACKET_TYPE_GAMEDATA_RESEND,
} net_packet_type_t;
typedef struct
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
-// $Id: net_server.c 369 2006-02-16 01:12:28Z fraggle $
+// $Id: net_server.c 370 2006-02-17 20:15:16Z fraggle $
//
// Copyright(C) 2005 Simon Howard
//
@@ -21,6 +21,9 @@
// 02111-1307, USA.
//
// $Log$
+// Revision 1.25 2006/02/17 20:15:16 fraggle
+// Request resends for missed packets
+//
// Revision 1.24 2006/02/16 01:12:28 fraggle
// Define a new type net_full_ticcmd_t, a structure containing all ticcmds
// for a given tic. Store received game data in a receive window. Add
@@ -171,8 +174,21 @@
typedef struct
{
+ // Whether this tic has been received yet
+
boolean active;
+
+ // Time this tic was generated (adjusted for time offset between
+ // client and server
+
unsigned int time;
+
+ // Last time we sent a resend request for this tic
+
+ unsigned int resend_time;
+
+ // Tic data itself
+
net_ticdiff_t diff;
} net_client_recv_t;
@@ -653,6 +669,48 @@
printf("client %p time offset: %i(%i)->%i\n", client, time_offset, rtt, client->time_offset);
}
+// Send a resend request to a client
+
+static void NET_SV_SendResendRequest(net_client_t *client, int start, int end)
+{
+ net_packet_t *packet;
+ net_client_recv_t *recvobj;
+ int i;
+ unsigned int nowtime;
+ int index;
+
+ printf("SV: send resend for %i-%i\n", start, end);
+
+ packet = NET_NewPacket(20);
+
+ NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_RESEND);
+ NET_WriteInt32(packet, start);
+ NET_WriteInt8(packet, end - start + 1);
+
+ NET_Conn_SendPacket(&client->connection, packet);
+ NET_FreePacket(packet);
+
+ // Store the time we send the resend request
+
+ nowtime = I_GetTimeMS();
+
+ for (i=start; i<=end; ++i)
+ {
+ index = i - recvwindow_start;
+
+ if (index >= BACKUPTICS)
+ {
+ // Outside the range
+
+ continue;
+ }
+
+ recvobj = &recvwindow[index][client->player_number];
+
+ recvobj->resend_time = nowtime;
+ }
+}
+
// Process game data from a client
static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client)
@@ -660,8 +718,11 @@
net_client_recv_t *recvobj;
unsigned int seq;
unsigned int num_tics;
+ unsigned int nowtime;
int i;
int player;
+ int resend_start;
+ int index;
if (server_state != SERVER_IN_GAME)
{
@@ -680,14 +741,19 @@
// Expand 8-bit value to the full sequence number
+ printf("SV: expanding %i ", seq);
+
seq = NET_SV_ExpandTicNum(seq);
+ printf("to %i(%i)\n", seq, recvwindow_start);
+
// Sanity checks
+ printf("SV: data %i-%i\n", seq, seq+num_tics-1);
+
for (i=0; i<num_tics; ++i)
{
net_ticdiff_t diff;
- int index;
if (!NET_ReadTiccmdDiff(packet, &diff, false))
{
@@ -707,6 +773,50 @@
recvobj->active = true;
recvobj->diff = diff;
}
+
+ // Has this been received out of sequence, ie. have we not received
+ // all tics before the first tic in this packet? If so, send a
+ // resend request.
+
+ nowtime = I_GetTimeMS();
+ resend_start = seq;
+
+ for (i = seq - 1; i >= recvwindow_start; --i)
+ {
+ index = i - recvwindow_start;
+
+ if (index >= recvwindow_start + BACKUPTICS)
+ {
+ // Outside of the range of the recv window
+
+ continue;
+ }
+
+ recvobj = &recvwindow[index][player];
+
+ if (recvobj->active)
+ {
+ // ended our run of unreceived tics
+
+ break;
+ }
+
+ if (recvobj->resend_time != 0)
+ {
+ // Already sent a resend request for this tic
+
+ break;
+ }
+
+ resend_start = i;
+ }
+
+ // Possibly send a resend request
+
+ if (resend_start < seq)
+ {
+ NET_SV_SendResendRequest(client, resend_start, seq - 1);
+ }
}
// Process a packet received by the server
@@ -840,6 +950,45 @@
client->last_time_req_time = I_GetTimeMS();
}
+static void NET_SV_SendTics(net_client_t *client, int start, int end)
+{
+ net_packet_t *packet;
+ int i;
+
+ packet = NET_NewPacket(500);
+
+ NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA);
+
+ // Send the start tic and number of tics
+
+ NET_WriteInt8(packet, start & 0xff);
+ NET_WriteInt8(packet, end-start + 1);
+
+ // Write the tics
+
+ for (i=start; i<=end; ++i)
+ {
+ net_full_ticcmd_t *cmd;
+
+ cmd = &client->sendqueue[i % BACKUPTICS];
+
+ if (i != cmd->seq)
+ {
+ I_Error("Wanted to send %i, but %i is in its place", i, cmd->seq);
+ }
+
+ // Add command
+
+ NET_WriteFullTiccmd(packet, cmd);
+ }
+
+ // Send packet
+
+ NET_Conn_SendPacket(&client->connection, packet);
+
+ NET_FreePacket(packet);
+}
+
static void NET_SV_PumpSendQueue(net_client_t *client)
{
net_full_ticcmd_t cmd;
@@ -902,6 +1051,11 @@
// Add into the queue
client->sendqueue[client->sendseq % BACKUPTICS] = cmd;
+
+ // Transmit the new tic to the client
+ // TODO: extratics
+
+ NET_SV_SendTics(client, client->sendseq, client->sendseq);
++client->sendseq;
}