foxygit / doom Log in
commit 41cdd5785305a28912fa2d6231ec8f518a850ec9
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon Feb 27 16:31:08 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon Feb 27 16:31:08 2006 +0000

    Working client sync: adjust the clock to try to match the latency of other
    players. Allow the menu ticker to run even if the main game ticker
    doesn't run. Remove time request/response code (now using game latency).

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 394
---
 src/d_net.c        |  48 ++++++++++++++------
 src/net_client.c   |  96 +++++++++++++++++++++++++++-------------
 src/net_defs.h     |   5 +--
 src/net_server.c   | 125 +++++++++--------------------------------------------
 src/net_structrw.c |  13 +++++-
 5 files changed, 135 insertions(+), 152 deletions(-)

diff --git a/src/d_net.c b/src/d_net.c
index df66e693..ea39ace1 100644
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: d_net.c 388 2006-02-24 19:14:22Z fraggle $
+// $Id: d_net.c 394 2006-02-27 16:31:08Z fraggle $
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
@@ -117,7 +117,7 @@
 //-----------------------------------------------------------------------------


-static const char rcsid[] = "$Id: d_net.c 388 2006-02-24 19:14:22Z fraggle $";
+static const char rcsid[] = "$Id: d_net.c 394 2006-02-27 16:31:08Z fraggle $";


 #include "d_main.h"
@@ -137,6 +137,8 @@ static const char rcsid[] = "$Id: d_net.c 388 2006-02-24 19:14:22Z fraggle $";
 #include "net_loop.h"


+#define FPS 35
+
 //
 // NETWORKING
 //
@@ -155,6 +157,7 @@ int             maketic;
 int		lastnettic;
 int		ticdup;
 int             extratics;
+fixed_t         offsetms;


 void D_ProcessEvents (void);
@@ -162,12 +165,23 @@ void G_BuildTiccmd (ticcmd_t *cmd);
 void D_DoAdvanceDemo (void);


+// 35 fps clock adjusted by offsetms milliseconds
+
+static int GetAdjustedTime(void)
+{
+    int time_ms;
+
+    time_ms = I_GetTimeMS() + (offsetms / FRACUNIT);
+
+    return (time_ms * FPS) / 1000;
+}
+
 //
 // NetUpdate
 // Builds ticcmds for console player,
 // sends out a packet
 //
-int      gametime;
+int      lasttime;

 void NetUpdate (void)
 {
@@ -183,9 +197,9 @@ void NetUpdate (void)
     NET_SV_Run();

     // check time
-    nowtime = I_GetTime ()/ticdup;
-    newtics = nowtime - gametime;
-    gametime = nowtime;
+    nowtime = GetAdjustedTime()/ticdup;
+    newtics = nowtime - lasttime;
+    lasttime = nowtime;

     if (newtics <= 0) 	// nothing new to update
         return;
@@ -196,7 +210,14 @@ void NetUpdate (void)
     for (i=0 ; i<newtics ; i++)
     {
         ticcmd_t cmd;
-
+
+	I_StartTic ();
+	D_ProcessEvents ();
+
+        // Always run the menu
+
+        M_Ticker ();
+
         // If playing single player, do not allow tics to buffer
         // up very far

@@ -208,9 +229,6 @@ void NetUpdate (void)
         if (maketic - gameticdiv > 35)
             break;

-	I_StartTic ();
-	D_ProcessEvents ();
-
 	//printf ("mk:%i ",maketic);
 	G_BuildTiccmd(&cmd);

@@ -247,6 +265,7 @@ void D_CheckNetGame (void)
     ticdup = 1;
     extratics = 1;
     lowres_turn = false;
+    offsetms = 0;

     for (i=0; i<MAXPLAYERS; i++)
     {
@@ -384,6 +403,8 @@ void TryRunTics (void)
     else
 	counts = availabletics;

+    counts = availabletics;
+
     if (counts < 1)
 	counts = 1;

@@ -402,10 +423,11 @@ void TryRunTics (void)
 	if (lowtic < gametic/ticdup)
 	    I_Error ("TryRunTics: lowtic < gametic");

-	// don't stay in here forever -- give the menu a chance to work
-	if (I_GetTime ()/ticdup - entertic >= 20)
+        // Don't stay in this loop forever.  The menu is still running,
+        // so return to update the screen
+
+	if (I_GetTime ()/ticdup - entertic > 0)
 	{
-	    M_Ticker ();
 	    return;
 	}

diff --git a/src/net_client.c b/src/net_client.c
index 4a52c62b..110c458f 100644
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_client.c 389 2006-02-24 19:14:59Z fraggle $
+// $Id: net_client.c 394 2006-02-27 16:31:08Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -213,6 +213,8 @@ typedef struct
     net_ticdiff_t cmd;
 } net_server_send_t;

+extern fixed_t offsetms;
+
 static net_connection_t client_connection;
 static net_clientstate_t client_state;
 static net_addr_t *server_addr;
@@ -261,6 +263,10 @@ static ticcmd_t recvwindow_cmd_base[MAXPLAYERS];
 static int recvwindow_start;
 static net_server_recv_t recvwindow[BACKUPTICS];

+// Average time between sending our ticcmd and receiving from the server
+
+static fixed_t average_latency;
+
 #define NET_CL_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b))

 // Called when a player leaves the game
@@ -308,10 +314,66 @@ static void NET_CL_Disconnected(void)
 // the d_net.c structures (netcmds/nettics) and save the new ticcmd
 // back into recvwindow_cmd_base.

-static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd)
+static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, int seq)
 {
+    int latency;
+    fixed_t adjustment;
     int i;

+    // Update average_latency
+
+    if (seq == send_queue[seq % NET_TICCMD_QUEUE_SIZE].seq)
+    {
+        latency = I_GetTimeMS() - send_queue[seq % NET_TICCMD_QUEUE_SIZE].time;
+    }
+    else if (seq > send_queue[seq % NET_TICCMD_QUEUE_SIZE].seq)
+    {
+        // We have received the ticcmd from the server before we have
+        // even sent ours
+
+        latency = 0;
+    }
+    else
+    {
+        latency = -1;
+    }
+
+    if (latency >= 0)
+    {
+        if (seq <= 20)
+        {
+            average_latency = latency * FRACUNIT;
+        }
+        else
+        {
+            // Low level filter
+
+            average_latency = (average_latency * 0.9)
+                            + (latency * FRACUNIT * 0.1);
+        }
+    }
+
+    //printf("latency: %i\tremote:%i\n", average_latency / FRACUNIT,
+    //                                   cmd->latency);
+
+    // Possibly adjust offsetms in d_net.c, try to make players all have
+    // the same lag.  Don't adjust in the first few tics of play, as
+    // we don't have an accurate value for average_latency yet.
+
+    if (seq > 35)
+    {
+        adjustment = (cmd->latency * FRACUNIT) - average_latency;
+
+        // Only adjust very slightly; the cumulative effect over
+        // multiple tics will sort it out.
+
+        adjustment = adjustment / 100;
+
+        offsetms += adjustment;
+    }
+
+    // Expand tic diffs for all players
+
     for (i=0; i<MAXPLAYERS; ++i)
     {
         if (i == consoleplayer)
@@ -358,7 +420,7 @@ static void NET_CL_AdvanceWindow(void)
     {
         // Expand tic diff data into d_net.c structures

-        NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd);
+        NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start);

         // Advance the window

@@ -454,7 +516,7 @@ static void NET_CL_SendTics(int start, int end)

         sendobj = &send_queue[i % NET_TICCMD_QUEUE_SIZE];

-        NET_WriteInt16(packet, sendobj->time);
+        NET_WriteInt16(packet, average_latency / FRACUNIT);

         NET_WriteTiccmdDiff(packet, &sendobj->cmd, lowres_turn);
     }
@@ -800,28 +862,6 @@ static void NET_CL_ParseGameData(net_packet_t *packet)
     }
 }

-static void NET_CL_ParseTimeRequest(net_packet_t *packet)
-{
-    net_packet_t *reply;
-    unsigned int seq;
-
-    // Received a request from the server for our current time.
-
-    if (!NET_ReadInt32(packet, &seq))
-    {
-	return;
-    }
-
-    // Send a response with our current time.
-
-    reply = NET_NewPacket(10);
-    NET_WriteInt16(reply, NET_PACKET_TYPE_TIME_RESP);
-    NET_WriteInt32(reply, seq);
-    NET_WriteInt32(reply, I_GetTimeMS());
-    NET_Conn_SendPacket(&client_connection, reply);
-    NET_FreePacket(reply);
-}
-
 // Parse a resend request from the server due to a dropped packet

 static void NET_CL_ParseResendRequest(net_packet_t *packet)
@@ -873,10 +913,6 @@ static void NET_CL_ParsePacket(net_packet_t *packet)
                 NET_CL_ParseGameData(packet);
                 break;

-	    case NET_PACKET_TYPE_TIME_REQ:
-		NET_CL_ParseTimeRequest(packet);
-		break;
-
             case NET_PACKET_TYPE_GAMEDATA_RESEND:
                 NET_CL_ParseResendRequest(packet);
                 break;
diff --git a/src/net_defs.h b/src/net_defs.h
index ee6c790d..8854317c 100644
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_defs.h 376 2006-02-23 18:19:05Z fraggle $
+// $Id: net_defs.h 394 2006-02-27 16:31:08Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -165,8 +165,6 @@ typedef enum
     NET_PACKET_TYPE_DISCONNECT,
     NET_PACKET_TYPE_DISCONNECT_ACK,
     NET_PACKET_TYPE_RELIABLE_ACK,
-    NET_PACKET_TYPE_TIME_REQ,
-    NET_PACKET_TYPE_TIME_RESP,
     NET_PACKET_TYPE_GAMEDATA_RESEND,
 } net_packet_type_t;

@@ -199,6 +197,7 @@ typedef struct

 typedef struct
 {
+    signed int latency;
     unsigned int seq;
     boolean playeringame[MAXPLAYERS];
     net_ticdiff_t cmds[MAXPLAYERS];
diff --git a/src/net_server.c b/src/net_server.c
index ba64422d..02ac1926 100644
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_server.c 389 2006-02-24 19:14:59Z fraggle $
+// $Id: net_server.c 394 2006-02-27 16:31:08Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -200,12 +200,6 @@ typedef struct

     boolean recording_lowres;

-    // time query variables
-
-    int last_time_req_time;
-    int time_req_seq;
-    signed int time_offset;
-
     // send queue: items to send to the client
     // this is a circular buffer

@@ -222,10 +216,9 @@ typedef struct

     boolean active;

-    // Time this tic was generated (adjusted for time offset between
-    // client and server
-
-    unsigned int time;
+    // Latency value received from the client
+
+    signed int latency;

     // Last time we sent a resend request for this tic

@@ -470,9 +463,6 @@ static void NET_SV_InitNewClient(net_client_t *client,
     client->addr = addr;
     client->last_send_time = -1;
     client->name = strdup(player_name);
-    client->last_time_req_time = -1;
-    client->time_req_seq = 0;
-    client->time_offset = 0;

     // init the ticcmd send queue

@@ -700,60 +690,6 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client)
     recvwindow_start = 0;
 }

-static void NET_SV_ParseTimeResponse(net_packet_t *packet, net_client_t *client)
-{
-    unsigned int seq;
-    unsigned int remote_time;
-    unsigned int rtt;
-    unsigned int nowtime;
-    signed int time_offset;
-
-    if (!NET_ReadInt32(packet, &seq)
-     || !NET_ReadInt32(packet, &remote_time))
-    {
-	return;
-    }
-
-    if (seq != client->time_req_seq)
-    {
-	// Not the time response we are expecting
-
-	return;
-    }
-
-    // Calculate the round trip time
-
-    nowtime = I_GetTimeMS();
-    rtt = nowtime - client->last_time_req_time;
-
-    // Adjust the remote time based on the round trip time
-
-    remote_time += rtt / 2;
-
-    // Calculate the offset to our own time
-
-    time_offset = remote_time - nowtime;
-
-    // Update the time offset
-
-    if (client->time_req_seq == 1)
-    {
-	// This is the first reply, so this is the only sample we have
-	// so far
-
-	client->time_offset = time_offset;
-    }
-    else
-    {
-	// Apply a low level filter to the time offset adjustments
-
-	client->time_offset = ((client->time_offset * 3) / 4)
-	                    + (time_offset / 4);
-    }
-
-    //printf("SV: 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)
@@ -900,9 +836,9 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client)
     for (i=0; i<num_tics; ++i)
     {
         net_ticdiff_t diff;
-        unsigned int time;
+        signed int latency;

-        if (!NET_ReadInt16(packet, &time)
+        if (!NET_ReadSInt16(packet, &latency)
          || !NET_ReadTiccmdDiff(packet, &diff, sv_settings.lowres_turn))
         {
             return;
@@ -920,6 +856,7 @@ static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client)
         recvobj = &recvwindow[index][player];
         recvobj->active = true;
         recvobj->diff = diff;
+        recvobj->latency = latency;
     }

     // Has this been received out of sequence, ie. have we not received
@@ -1082,9 +1019,6 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
             case NET_PACKET_TYPE_GAMEDATA_RESEND:
                 NET_SV_ParseResendRequest(packet, client);
                 break;
-	    case NET_PACKET_TYPE_TIME_RESP:
-		NET_SV_ParseTimeResponse(packet, client);
-		break;
             default:
                 // unknown packet type

@@ -1150,25 +1084,6 @@ static void NET_SV_SendWaitingData(net_client_t *client)
     NET_FreePacket(packet);
 }

-static void NET_SV_SendTimeRequest(net_client_t *client)
-{
-    net_packet_t *packet;
-
-    ++client->time_req_seq;
-
-    // Transmit the request packet
-
-    packet = NET_NewPacket(10);
-    NET_WriteInt16(packet, NET_PACKET_TYPE_TIME_REQ);
-    NET_WriteInt32(packet, client->time_req_seq);
-    NET_Conn_SendPacket(&client->connection, packet);
-    NET_FreePacket(packet);
-
-    // Save the time we send the request
-
-    client->last_time_req_time = I_GetTimeMS();
-}
-
 static void NET_SV_PumpSendQueue(net_client_t *client)
 {
     net_full_ticcmd_t cmd;
@@ -1217,8 +1132,12 @@ static void NET_SV_PumpSendQueue(net_client_t *client)

     // 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
@@ -1234,9 +1153,17 @@ static void NET_SV_PumpSendQueue(net_client_t *client)
         }

         cmd.playeringame[i] = true;
-        cmd.cmds[i] = recvwindow[recv_index][i].diff;
+
+        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;
@@ -1294,18 +1221,6 @@ static void NET_SV_RunClient(net_client_t *client)
         }
     }

-    if (client->last_time_req_time < 0)
-    {
-	client->last_time_req_time = I_GetTimeMS() - 5000;
-    }
-
-    if (I_GetTimeMS() - client->last_time_req_time > 10000)
-    {
-	// Query the clients' times once every ten seconds.
-
-	NET_SV_SendTimeRequest(client);
-    }
-
     if (server_state == SERVER_IN_GAME)
     {
         NET_SV_PumpSendQueue(client);
diff --git a/src/net_structrw.c b/src/net_structrw.c
index 6567c01c..0fdf0245 100644
--- a/src/net_structrw.c
+++ b/src/net_structrw.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*-
 //-----------------------------------------------------------------------------
 //
-// $Id: net_structrw.c 378 2006-02-23 19:12:02Z fraggle $
+// $Id: net_structrw.c 394 2006-02-27 16:31:08Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -242,6 +242,13 @@ boolean NET_ReadFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean
     unsigned int bitfield;
     int i;

+    // Latency
+
+    if (!NET_ReadSInt16(packet, &cmd->latency))
+    {
+        return false;
+    }
+
     // Regenerate playeringame from the "header" bitfield

     if (!NET_ReadInt8(packet, &bitfield))
@@ -275,6 +282,10 @@ void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd, boolean l
     unsigned int bitfield;
     int i;

+    // Write the latency
+
+    NET_WriteInt16(packet, cmd->latency);
+
     // Write "header" byte indicating which players are active
     // in this ticcmd