shithub: choc

Download patch

ref: 440dd9fc2affb98ddd334e118f3a17657965e7be
parent: 481b3391baff23f1682df009df7d3387d62f3d75
author: Simon Howard <fraggle@gmail.com>
date: Fri Sep 29 17:25:13 EDT 2006

Working drone clients!

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 680

--- a/src/d_main.c
+++ b/src/d_main.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: d_main.c 666 2006-09-25 20:47:11Z fraggle $
+// $Id: d_main.c 680 2006-09-29 21:25:13Z fraggle $
 //
 // Copyright(C) 1993-1996 Id Software, Inc.
 // Copyright(C) 2005 Simon Howard
@@ -184,7 +184,7 @@
 //-----------------------------------------------------------------------------
 
 
-static const char rcsid[] = "$Id: d_main.c 666 2006-09-25 20:47:11Z fraggle $";
+static const char rcsid[] = "$Id: d_main.c 680 2006-09-29 21:25:13Z fraggle $";
 
 #define	BGCOLOR		7
 #define	FGCOLOR		8
@@ -277,8 +277,6 @@
 boolean         nomonsters;	// checkparm of -nomonsters
 boolean         respawnparm;	// checkparm of -respawn
 boolean         fastparm;	// checkparm of -fast
-
-boolean         drone;
 
 boolean		singletics = false; // debug flag to cancel adaptiveness
 
--- a/src/d_net.c
+++ b/src/d_net.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: d_net.c 544 2006-05-29 20:55:20Z fraggle $
+// $Id: d_net.c 680 2006-09-29 21:25:13Z 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 544 2006-05-29 20:55:20Z fraggle $";
+static const char rcsid[] = "$Id: d_net.c 680 2006-09-29 21:25:13Z fraggle $";
 
 #include "doomfeatures.h"
 
@@ -249,6 +249,13 @@
         // Always run the menu
 
         M_Ticker ();
+
+        if (drone)
+        {
+            // In drone mode, do not generate any ticcmds.
+
+            continue;
+        }
 	
         if (net_cl_new_sync)
         { 
@@ -324,6 +331,11 @@
     {
         playeringame[i] = false;
        	nettics[i] = 0;
+    }
+
+    if (M_CheckParm("-drone") > 0)
+    {
+        drone = true;
     }
 
     playeringame[0] = true;
--- a/src/net_client.c
+++ b/src/net_client.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_client.c 641 2006-09-21 11:13:28Z rtc_marine $
+// $Id: net_client.c 680 2006-09-29 21:25:13Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -265,6 +265,12 @@
 static int recvwindow_start;
 static net_server_recv_t recvwindow[BACKUPTICS];
 
+// Whether we need to send an acknowledgement and
+// when gamedata was last received.
+
+static boolean need_to_acknowledge;
+static unsigned int gamedata_recv_time;
+
 // Average time between sending our ticcmd and receiving from the server
 
 static fixed_t average_latency;
@@ -273,7 +279,10 @@
 
 boolean net_cl_new_sync = true;
 
+// Connected but not participating in the game (observer)
 
+boolean drone = false;
+
 #define NET_CL_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b))
 
 // Called when a player leaves the game
@@ -384,7 +393,7 @@
     
     for (i=0; i<MAXPLAYERS; ++i)
     {
-        if (i == consoleplayer)
+        if (i == consoleplayer && !drone)
         {
             continue;
         }
@@ -505,6 +514,22 @@
     NET_WriteSettings(packet, &settings);
 }
 
+static void NET_CL_SendGameDataACK(void)
+{
+    net_packet_t *packet;
+
+    packet = NET_NewPacket(10);
+
+    NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_ACK);
+    NET_WriteInt8(packet, gametic & 0xff);
+
+    NET_Conn_SendPacket(&client_connection, packet);
+
+    NET_FreePacket(packet);
+
+    need_to_acknowledge = false;
+}
+
 static void NET_CL_SendTics(int start, int end)
 {
     net_packet_t *packet;
@@ -529,6 +554,7 @@
     // Write the start tic and number of tics.  Send only the low byte
     // of start - it can be inferred by the server.
 
+    NET_WriteInt8(packet, gametic & 0xff);
     NET_WriteInt8(packet, start & 0xff);
     NET_WriteInt8(packet, end - start + 1);
 
@@ -552,6 +578,10 @@
     // All done!
 
     NET_FreePacket(packet);
+
+    // Acknowledgement has been sent as part of the packet
+
+    need_to_acknowledge = false;
 }
 
 // Add a new ticcmd to the send queue
@@ -593,7 +623,7 @@
 {
     unsigned int num_players;
     unsigned int is_controller;
-    unsigned int player_number;
+    signed int player_number;
     char *player_names[MAXPLAYERS];
     char *player_addr[MAXPLAYERS];
     size_t i;
@@ -600,7 +630,7 @@
 
     if (!NET_ReadInt8(packet, &num_players)
      || !NET_ReadInt8(packet, &is_controller)
-     || !NET_ReadInt8(packet, &player_number))
+     || !NET_ReadSInt8(packet, &player_number))
     {
         // invalid packet
 
@@ -607,13 +637,21 @@
         return;
     }
 
-    if (num_players > MAXPLAYERS 
-     || player_number >= num_players)
+    if (num_players > MAXPLAYERS)
     {
         // insane data
 
         return;
     }
+
+    if ((player_number >= 0 && drone)
+     || (player_number < 0 && !drone)
+     || (player_number >= (signed int) num_players))
+    {
+        // Invalid player number
+
+        return;
+    }
  
     // Read the player names
 
@@ -644,11 +682,12 @@
 static void NET_CL_ParseGameStart(net_packet_t *packet)
 {
     net_gamesettings_t settings;
-    unsigned int player_number, num_players;
+    unsigned int num_players;
+    signed int player_number;
     int i;
 
     if (!NET_ReadInt8(packet, &num_players)
-     || !NET_ReadInt8(packet, &player_number)
+     || !NET_ReadSInt8(packet, &player_number)
      || !NET_ReadSettings(packet, &settings))
     {
         return;
@@ -659,15 +698,31 @@
         return;
     }
 
-    if (num_players > MAXPLAYERS || player_number >= num_players)
+    if (num_players > MAXPLAYERS || player_number >= (signed int) num_players)
     {
         // insane values
         return;
     }
 
+    if ((drone && player_number >= 0)
+     || (!drone && player_number < 0))
+    {
+        // Invalid player number: must be positive for real players,
+        // negative for drones
+
+        return;
+    }
+
     // Start the game
 
-    consoleplayer = player_number;
+    if (!drone)
+    {
+        consoleplayer = player_number;
+    }
+    else
+    {
+        consoleplayer = 0;
+    }
     
     for (i=0; i<MAXPLAYERS; ++i) 
     {
@@ -792,6 +847,15 @@
         NET_CL_SendResendRequest(recvwindow_start + resend_start,
                                  recvwindow_start + resend_end);
     }
+
+    // We have received some data from the server and not acknowledged
+    // it yet.  Normally this gets acknowledged when we send our game
+    // data, but if the client is a drone we need to do this.
+
+    if (need_to_acknowledge && nowtime - gamedata_recv_time > 200)
+    {
+        NET_CL_SendGameDataACK();
+    }
 }
 
 
@@ -817,6 +881,15 @@
 
     nowtime = I_GetTimeMS();
 
+    // Whatever happens, we now need to send an acknowledgement of our
+    // current receive point.
+
+    if (!need_to_acknowledge)
+    {
+        need_to_acknowledge = true;
+        gamedata_recv_time = nowtime;
+    }
+
     // Expand byte value into the full tic number
 
     seq = NET_CL_ExpandTicNum(seq);
@@ -1045,6 +1118,7 @@
     NET_WriteInt16(packet, gamemode);
     NET_WriteInt16(packet, gamemission);
     NET_WriteInt8(packet, lowres_turn);
+    NET_WriteInt8(packet, drone);
     NET_WriteString(packet, net_player_name);
     NET_Conn_SendPacket(&client_connection, packet);
     NET_FreePacket(packet);
--- a/src/net_client.h
+++ b/src/net_client.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_client.h 470 2006-04-14 15:25:42Z fraggle $
+// $Id: net_client.h 680 2006-09-29 21:25:13Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -91,6 +91,7 @@
 extern int net_player_number;
 extern char *net_player_name;
 extern boolean net_cl_new_sync;
+extern boolean drone;
 
 #endif /* #ifndef NET_CLIENT_H */
 
--- a/src/net_defs.h
+++ b/src/net_defs.h
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_defs.h 612 2006-09-17 20:37:26Z fraggle $
+// $Id: net_defs.h 680 2006-09-29 21:25:13Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -158,6 +158,7 @@
     NET_PACKET_TYPE_WAITING_DATA,
     NET_PACKET_TYPE_GAMESTART,
     NET_PACKET_TYPE_GAMEDATA,
+    NET_PACKET_TYPE_GAMEDATA_ACK,
     NET_PACKET_TYPE_DISCONNECT,
     NET_PACKET_TYPE_DISCONNECT_ACK,
     NET_PACKET_TYPE_RELIABLE_ACK,
--- a/src/net_server.c
+++ b/src/net_server.c
@@ -1,7 +1,7 @@
 // Emacs style mode select   -*- C++ -*- 
 //-----------------------------------------------------------------------------
 //
-// $Id: net_server.c 641 2006-09-21 11:13:28Z rtc_marine $
+// $Id: net_server.c 680 2006-09-29 21:25:13Z fraggle $
 //
 // Copyright(C) 2005 Simon Howard
 //
@@ -209,6 +209,14 @@
     int sendseq;
     net_full_ticcmd_t sendqueue[BACKUPTICS];
 
+    // Latest acknowledged by the client
+
+    int acknowledged;
+
+    // Observer: receives data but does not participate in the game.
+
+    boolean drone;
+
 } net_client_t;
 
 // structure used for the recv window
@@ -320,9 +328,16 @@
     {
         if (ClientConnected(&clients[i]))
         {
-            sv_players[pl] = &clients[i];
-            sv_players[pl]->player_number = pl;
-            ++pl;
+            if (!clients[i].drone)
+            {
+                sv_players[pl] = &clients[i];
+                sv_players[pl]->player_number = pl;
+                ++pl;
+            }
+            else
+            {
+                clients[i].player_number = -1;
+            }
         }
     }
 
@@ -332,30 +347,29 @@
     }
 }
 
-// returns the number of clients connected
+// Returns the number of players currently connected.
 
-static int NET_SV_NumClients(void)
+static int NET_SV_NumPlayers(void)
 {
-    int count;
     int i;
+    int result;
 
-    count = 0;
+    result = 0;
 
-    for (i=0; i<MAXNETNODES; ++i)
+    for (i=0; i<MAXPLAYERS; ++i)
     {
-        if (ClientConnected(&clients[i]))
+        if (sv_players[i] != NULL && ClientConnected(sv_players[i]))
         {
-            ++count;
+            result += 1;
         }
     }
 
-    return count;
+    return result;
 }
 
-// Returns the index of a particular client in the list of connected
-// clients.
+// returns the number of clients connected
 
-static int NET_SV_ClientIndex(net_client_t *client)
+static int NET_SV_NumClients(void)
 {
     int count;
     int i;
@@ -366,17 +380,14 @@
     {
         if (ClientConnected(&clients[i]))
         {
-            if (client == &clients[i])
-            {
-                return count;
-            }
             ++count;
         }
     }
 
-    return -1;
+    return count;
 }
 
+
 // Possibly advance the recv window if all connected clients have
 // used the data in the window
 
@@ -385,20 +396,18 @@
     int i;
     int lowtic = -1;
 
-    // Find the smallest value of player->sendseq for all connected
-    // players
+    // Find the smallest value of client->acknowledged for all connected
+    // clients
 
-    for (i=0; i<MAXPLAYERS; ++i) 
+    for (i=0; i<MAXNETNODES; ++i) 
     {
-        if (sv_players[i] == NULL || !ClientConnected(sv_players[i]))
+        if (ClientConnected(&clients[i]))
         {
-            continue;
+            if (lowtic < 0 || clients[i].acknowledged < lowtic)
+            {
+                lowtic = clients[i].acknowledged;
+            }
         }
-
-        if (lowtic < 0 || sv_players[i]->sendseq < lowtic)
-        {
-            lowtic = sv_players[i]->sendseq;
-        }
     }
 
     if (lowtic < 0)
@@ -460,7 +469,7 @@
 
     for (i=0; i<MAXNETNODES; ++i)
     {
-        if (ClientConnected(&clients[i]))
+        if (ClientConnected(&clients[i]) && !clients[i].drone)
         {
             return &clients[i];
         }
@@ -514,6 +523,8 @@
     // init the ticcmd send queue
 
     client->sendseq = 0;
+    client->acknowledged = 0;
+    client->drone = false;
     memset(client->sendqueue, 0xff, sizeof(client->sendqueue));
 }
 
@@ -526,6 +537,7 @@
     unsigned int magic;
     unsigned int cl_gamemode, cl_gamemission;
     unsigned int cl_recording_lowres;
+    unsigned int cl_drone;
     char *player_name;
     char *client_version;
     int i;
@@ -545,7 +557,7 @@
     }
 
     // Check the client version is the same as the server
-    //
+
     client_version = NET_ReadString(packet);
 
     if (client_version == NULL)
@@ -563,7 +575,8 @@
 
     if (!NET_ReadInt16(packet, &cl_gamemode) 
      || !NET_ReadInt16(packet, &cl_gamemission)
-     || !NET_ReadInt8(packet, &cl_recording_lowres))
+     || !NET_ReadInt8(packet, &cl_recording_lowres)
+     || !NET_ReadInt8(packet, &cl_drone))
     {
         return;
     }
@@ -627,14 +640,15 @@
 
     if (!client->active)
     {
-        int num_clients;
+        int num_players;
 
         // Before accepting a new client, check that there is a slot
         // free
 
-        num_clients = NET_SV_NumClients();
+        NET_SV_AssignPlayers();
+        num_players = NET_SV_NumPlayers();
 
-        if (num_clients >= MAXPLAYERS)
+        if (num_players >= MAXPLAYERS)
         {
             NET_SV_SendReject(addr, "Server is full!");
             return;
@@ -646,7 +660,7 @@
 
         // Adopt the game mode and mission of the first connecting client
 
-        if (num_clients == 0)
+        if (num_players == 0 && !cl_drone)
         {
             sv_gamemode = cl_gamemode;
             sv_gamemission = cl_gamemission;
@@ -666,6 +680,7 @@
         NET_SV_InitNewClient(client, addr, player_name);
 
         client->recording_lowres = cl_recording_lowres;
+        client->drone = cl_drone;
     }
 
     if (client->connection.state == NET_CONN_STATE_WAITING_ACK)
@@ -733,16 +748,16 @@
 
     // Send start packets to each connected node
 
-    for (i=0; i<MAXPLAYERS; ++i) 
+    for (i=0; i<MAXNETNODES; ++i) 
     {
-        if (sv_players[i] == NULL)
-            break;
+        if (!ClientConnected(&clients[i]))
+            continue;
 
-        startpacket = NET_Conn_NewReliable(&sv_players[i]->connection,
+        startpacket = NET_Conn_NewReliable(&clients[i].connection,
                                            NET_PACKET_TYPE_GAMESTART);
 
-        NET_WriteInt8(startpacket, NET_SV_NumClients());
-        NET_WriteInt8(startpacket, sv_players[i]->player_number);
+        NET_WriteInt8(startpacket, NET_SV_NumPlayers());
+        NET_WriteInt8(startpacket, clients[i].player_number);
         NET_WriteSettings(startpacket, &settings);
     }
 
@@ -867,6 +882,7 @@
 {
     net_client_recv_t *recvobj;
     unsigned int seq;
+    unsigned int ackseq;
     unsigned int num_tics;
     unsigned int nowtime;
     size_t i;
@@ -879,21 +895,26 @@
         return;
     }
 
-    //if (rand() % 8 == 0)
-    //    return;
+    if (client->drone)
+    {
+        // Drones do not contribute any game data.
+        return;
+    }
 
     player = client->player_number;
 
     // Read header
 
-    if (!NET_ReadInt8(packet, &seq)
+    if (!NET_ReadInt8(packet, &ackseq)
+     || !NET_ReadInt8(packet, &seq)
      || !NET_ReadInt8(packet, &num_tics))
     {
         return;
     }
 
-    // Expand 8-bit value to the full sequence number
+    // Expand 8-bit values to the full sequence number
 
+    ackseq = NET_SV_ExpandTicNum(ackseq);
     seq = NET_SV_ExpandTicNum(seq);
 
     // Sanity checks
@@ -924,6 +945,13 @@
         recvobj->latency = latency;
     }
 
+    // Higher acknowledgement point?
+
+    if (ackseq > client->acknowledged)
+    {
+        client->acknowledged = ackseq;
+    }
+
     // 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.
@@ -975,6 +1003,34 @@
     }
 }
 
+static void NET_SV_ParseGameDataACK(net_packet_t *packet, net_client_t *client)
+{
+    unsigned int ackseq;
+
+    if (server_state != SERVER_IN_GAME)
+    {
+        return;
+    }
+
+    // Read header
+
+    if (!NET_ReadInt8(packet, &ackseq))
+    {
+        return;
+    }
+
+    // Expand 8-bit values to the full sequence number
+
+    ackseq = NET_SV_ExpandTicNum(ackseq);
+
+    // Higher acknowledgement point than we already have?
+
+    if (ackseq > client->acknowledged)
+    {
+        client->acknowledged = ackseq;
+    }
+}
+
 static void NET_SV_SendTics(net_client_t *client, int start, int end)
 {
     net_packet_t *packet;
@@ -1075,7 +1131,7 @@
 
     // Number of players/maximum players
 
-    querydata.num_players = NET_SV_NumClients();
+    querydata.num_players = NET_SV_NumPlayers();
     querydata.max_players = MAXPLAYERS;
 
     // Game mode/mission
@@ -1144,6 +1200,9 @@
             case NET_PACKET_TYPE_GAMEDATA:
                 NET_SV_ParseGameData(packet, client);
                 break;
+            case NET_PACKET_TYPE_GAMEDATA_ACK:
+                NET_SV_ParseGameDataACK(packet, client);
+                break;
             case NET_PACKET_TYPE_GAMEDATA_RESEND:
                 NET_SV_ParseResendRequest(packet, client);
                 break;
@@ -1167,41 +1226,43 @@
 static void NET_SV_SendWaitingData(net_client_t *client)
 {
     net_packet_t *packet;
-    int num_clients;
+    int num_players;
     int i;
 
-    num_clients = NET_SV_NumClients();
+    NET_SV_AssignPlayers();
 
+    num_players = NET_SV_NumPlayers();
+
     // time to send the client another status packet
 
     packet = NET_NewPacket(10);
     NET_WriteInt16(packet, NET_PACKET_TYPE_WAITING_DATA);
 
-    // include the number of clients waiting
+    // include the number of players waiting
 
-    NET_WriteInt8(packet, num_clients);
+    NET_WriteInt8(packet, num_players);
 
     // indicate whether the client is the controller
 
     NET_WriteInt8(packet, NET_SV_Controller() == client);
 
-    // send the index of the client
+    // send the player number of this client
 
-    NET_WriteInt8(packet, NET_SV_ClientIndex(client));
+    NET_WriteInt8(packet, client->player_number);
 
     // send the address of all players
 
-    for (i=0; i<num_clients; ++i)
+    for (i=0; i<num_players; ++i)
     {
         char *addr;
 
         // name
 
-        NET_WriteString(packet, clients[i].name);
+        NET_WriteString(packet, sv_players[i]->name);
 
         // address
 
-        addr = NET_AddrToString(clients[i].addr);
+        addr = NET_AddrToString(sv_players[i]->addr);
 
         NET_WriteString(packet, addr);
     }
@@ -1395,6 +1456,8 @@
     {
         clients[i].active = false;
     }
+
+    NET_SV_AssignPlayers();
 
     server_state = SERVER_WAITING_START;
     sv_gamemode = indetermined;