foxygit / doom Log in
commit 65ba9ecd3c61235e618a208e0595d71bcefcf9f4
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Feb 17 20:15:16 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Feb 17 20:15:16 2006 +0000

    Request resends for missed packets

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 370
---
 src/net_client.c |  72 +++++++++++++++++--------
 src/net_defs.h   |   6 ++-
 src/net_server.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 210 insertions(+), 26 deletions(-)

diff --git a/src/net_client.c b/src/net_client.c
index b1f14c20..c5bb5ed1 100644
--- 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 @@ void NET_CL_StartGame(void)
     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 @@ void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic)
     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 @@ static void NET_CL_ParseTimeRequest(net_packet_t *packet)
     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)
@@ -433,6 +456,9 @@ static void NET_CL_ParsePacket(net_packet_t *packet)
 		NET_CL_ParseTimeRequest(packet);
 		break;

+            case NET_PACKET_TYPE_GAMEDATA_RESEND:
+                NET_CL_ParseResendRequest(packet);
+
             default:
                 break;
         }
diff --git a/src/net_defs.h b/src/net_defs.h
index ffb84152..9dc12d8d 100644
--- 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 @@ typedef enum
     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
diff --git a/src/net_server.c b/src/net_server.c
index 7922596e..c8bdad4a 100644
--- 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

 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 @@ static void NET_SV_ParseTimeResponse(net_packet_t *packet, net_client_t *client)
     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 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client)
     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 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client)

     // 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 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client)
         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 @@ static void NET_SV_SendTimeRequest(net_client_t *client)
     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;
@@ -903,6 +1052,11 @@ static void NET_SV_PumpSendQueue(net_client_t *client)

     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;
 }