foxygit / doom Log in
commit 440dd9fc2affb98ddd334e118f3a17657965e7be
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Sep 29 21:25:13 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Sep 29 21:25:13 2006 +0000

    Working drone clients!

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 680
---
 src/d_main.c     |   6 +-
 src/d_net.c      |  16 ++++-
 src/net_client.c |  94 +++++++++++++++++++++++++----
 src/net_client.h |   3 +-
 src/net_defs.h   |   3 +-
 src/net_server.c | 177 +++++++++++++++++++++++++++++++++++++------------------
 6 files changed, 224 insertions(+), 75 deletions(-)

diff --git a/src/d_main.c b/src/d_main.c
index e2c88e45..f68113cb 100644
--- 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
@@ -278,8 +278,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


diff --git a/src/d_net.c b/src/d_net.c
index 3fec28b5..76693b89 100644
--- 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 @@ void NetUpdate (void)
         // Always run the menu

         M_Ticker ();
+
+        if (drone)
+        {
+            // In drone mode, do not generate any ticcmds.
+
+            continue;
+        }

         if (net_cl_new_sync)
         {
@@ -326,6 +333,11 @@ void D_CheckNetGame (void)
        	nettics[i] = 0;
     }

+    if (M_CheckParm("-drone") > 0)
+    {
+        drone = true;
+    }
+
     playeringame[0] = true;

 #ifdef FEATURE_MULTIPLAYER
diff --git a/src/net_client.c b/src/net_client.c
index 1c5b7a28..e13b8ea3 100644
--- 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 ticcmd_t recvwindow_cmd_base[MAXPLAYERS];
 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,6 +279,9 @@ static fixed_t average_latency;

 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))

@@ -384,7 +393,7 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, int seq)

     for (i=0; i<MAXPLAYERS; ++i)
     {
-        if (i == consoleplayer)
+        if (i == consoleplayer && !drone)
         {
             continue;
         }
@@ -505,6 +514,22 @@ void NET_CL_StartGame(void)
     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 @@ static void NET_CL_SendTics(int start, int end)
     // 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 @@ static void NET_CL_SendTics(int start, int end)
     // 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,27 +623,35 @@ static void NET_CL_ParseWaitingData(net_packet_t *packet)
 {
     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;

     if (!NET_ReadInt8(packet, &num_players)
      || !NET_ReadInt8(packet, &is_controller)
-     || !NET_ReadInt8(packet, &player_number))
+     || !NET_ReadSInt8(packet, &player_number))
     {
         // invalid packet

         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_ParseWaitingData(net_packet_t *packet)
 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 @@ static void NET_CL_ParseGameStart(net_packet_t *packet)
         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 @@ static void NET_CL_CheckResends(void)
         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 @@ static void NET_CL_ParseGameData(net_packet_t *packet)

     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 @@ static void NET_CL_SendSYN(void)
     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);
diff --git a/src/net_client.h b/src/net_client.h
index 7440e4f7..56c327c8 100644
--- 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 char net_player_addresses[MAXPLAYERS][MAXPLAYERNAME];
 extern int net_player_number;
 extern char *net_player_name;
 extern boolean net_cl_new_sync;
+extern boolean drone;

 #endif /* #ifndef NET_CLIENT_H */

diff --git a/src/net_defs.h b/src/net_defs.h
index 978cfba5..f8bca1d8 100644
--- 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 @@ typedef enum
     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,
diff --git a/src/net_server.c b/src/net_server.c
index 394dc6c2..af794d02 100644
--- 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 @@ typedef struct
     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 @@ static void NET_SV_AssignPlayers(void)
     {
         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 @@ static void NET_SV_AssignPlayers(void)
     }
 }

-// 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 @@ static int NET_SV_ClientIndex(net_client_t *client)
     {
         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,19 +396,17 @@ static void NET_SV_AdvanceWindow(void)
     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]))
-        {
-            continue;
-        }
-
-        if (lowtic < 0 || sv_players[i]->sendseq < lowtic)
+        if (ClientConnected(&clients[i]))
         {
-            lowtic = sv_players[i]->sendseq;
+            if (lowtic < 0 || clients[i].acknowledged < lowtic)
+            {
+                lowtic = clients[i].acknowledged;
+            }
         }
     }

@@ -460,7 +469,7 @@ static net_client_t *NET_SV_Controller(void)

     for (i=0; i<MAXNETNODES; ++i)
     {
-        if (ClientConnected(&clients[i]))
+        if (ClientConnected(&clients[i]) && !clients[i].drone)
         {
             return &clients[i];
         }
@@ -514,6 +523,8 @@ static void NET_SV_InitNewClient(net_client_t *client,
     // 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 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
     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 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
     }

     // Check the client version is the same as the server
-    //
+
     client_version = NET_ReadString(packet);

     if (client_version == NULL)
@@ -563,7 +575,8 @@ static void NET_SV_ParseSYN(net_packet_t *packet,

     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 @@ static void NET_SV_ParseSYN(net_packet_t *packet,

     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 @@ static void NET_SV_ParseSYN(net_packet_t *packet,

         // 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 @@ static void NET_SV_ParseSYN(net_packet_t *packet,
         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 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client)

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

+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 @@ void NET_SV_SendQueryResponse(net_addr_t *addr)

     // 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 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr)
             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_Packet(net_packet_t *packet, net_addr_t *addr)
 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);
     }
@@ -1396,6 +1457,8 @@ void NET_SV_Init(void)
         clients[i].active = false;
     }

+    NET_SV_AssignPlayers();
+
     server_state = SERVER_WAITING_START;
     sv_gamemode = indetermined;
     server_initialised = true;