shithub: choc

Download patch

ref: 41cdd5785305a28912fa2d6231ec8f518a850ec9
parent: a747cf67119b5934147093aea150043403ffb4d2
author: Simon Howard <fraggle@gmail.com>
date: Mon Feb 27 11:31:08 EST 2006

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

--- 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 @@
 #include "net_loop.h"
 
 
+#define FPS 35
+
 //
 // NETWORKING
 //
@@ -155,6 +157,7 @@
 int		lastnettic;
 int		ticdup;		
 int             extratics;
+fixed_t         offsetms;
 
 
 void D_ProcessEvents (void); 
@@ -162,12 +165,23 @@
 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 @@
     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 @@
     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 @@
         if (maketic - gameticdiv > 35)
             break;
 
-	I_StartTic ();
-	D_ProcessEvents ();
-	
 	//printf ("mk:%i ",maketic);
 	G_BuildTiccmd(&cmd);
 
@@ -247,6 +265,7 @@
     ticdup = 1;
     extratics = 1;
     lowres_turn = false;
+    offsetms = 0;
     
     for (i=0; i<MAXPLAYERS; i++)
     {
@@ -384,6 +403,8 @@
     else
 	counts = availabletics;
     
+    counts = availabletics;
+
     if (counts < 1)
 	counts = 1;
 		
@@ -402,10 +423,11 @@
 	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;
 	} 
 
--- 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 @@
     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 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 @@
 // 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 @@
     {
         // 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 @@
 
         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_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)
@@ -872,10 +912,6 @@
             case NET_PACKET_TYPE_GAMEDATA:
                 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);
--- 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 @@
     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 
 {
+    signed int latency;
     unsigned int seq;
     boolean playeringame[MAXPLAYERS];
     net_ticdiff_t cmds[MAXPLAYERS];
--- 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 @@
 
     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,11 +216,10 @@
 
     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
 
     unsigned int resend_time;
@@ -470,9 +463,6 @@
     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 @@
     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 @@
     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 @@
         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 @@
             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 @@
     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 @@
 
     // 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 @@
         }
 
         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;
@@ -1292,18 +1219,6 @@
             NET_SV_SendWaitingData(client);
             client->last_send_time = I_GetTimeMS();
         }
-    }
-
-    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)
--- 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 @@
     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))
@@ -274,6 +281,10 @@
 {
     unsigned int bitfield;
     int i;
+
+    // Write the latency
+
+    NET_WriteInt16(packet, cmd->latency);
 
     // Write "header" byte indicating which players are active
     // in this ticcmd