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;