From 4af352a213431e577a48dd8b3ece7822cb7168bc Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 16 Feb 2006 01:12:28 +0000 Subject: Define a new type net_full_ticcmd_t, a structure containing all ticcmds for a given tic. Store received game data in a receive window. Add send queues for clients and add data from the receive window to generate complete sets of ticcmds. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 369 --- src/net_defs.h | 18 +++- src/net_server.c | 297 +++++++++++++++++++++++++++++++++++++++++++++++++---- src/net_structrw.c | 78 +++++++++++++- src/net_structrw.h | 12 ++- 4 files changed, 384 insertions(+), 21 deletions(-) diff --git a/src/net_defs.h b/src/net_defs.h index 906ad91a..ffb84152 100644 --- a/src/net_defs.h +++ b/src/net_defs.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_defs.h 323 2006-01-22 22:29:42Z fraggle $ +// $Id: net_defs.h 369 2006-02-16 01:12:28Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,12 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.12 2006/02/16 01:12:28 fraggle +// Define a new type net_full_ticcmd_t, a structure containing all ticcmds +// for a given tic. Store received game data in a receive window. Add +// send queues for clients and add data from the receive window to +// generate complete sets of ticcmds. +// // Revision 1.11 2006/01/22 22:29:42 fraggle // Periodically request the time from clients to estimate their offset to // the server time. @@ -69,6 +75,7 @@ #ifndef NET_DEFS_H #define NET_DEFS_H +#include "doomdef.h" #include "doomtype.h" #include "d_ticcmd.h" @@ -180,5 +187,14 @@ typedef struct ticcmd_t cmd; } net_ticdiff_t; +// Complete set of ticcmds from all players + +typedef struct +{ + unsigned int seq; + boolean playeringame[MAXPLAYERS]; + net_ticdiff_t cmds[MAXPLAYERS]; +} net_full_ticcmd_t; + #endif /* #ifndef NET_DEFS_H */ diff --git a/src/net_server.c b/src/net_server.c index b9a15594..7922596e 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_server.c 323 2006-01-22 22:29:42Z fraggle $ +// $Id: net_server.c 369 2006-02-16 01:12:28Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,12 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.24 2006/02/16 01:12:28 fraggle +// Define a new type net_full_ticcmd_t, a structure containing all ticcmds +// for a given tic. Store received game data in a receive window. Add +// send queues for clients and add data from the receive window to +// generate complete sets of ticcmds. +// // Revision 1.23 2006/01/22 22:29:42 fraggle // Periodically request the time from clients to estimate their offset to // the server time. @@ -141,6 +147,7 @@ typedef enum typedef struct { boolean active; + int player_number; net_addr_t *addr; net_connection_t connection; int last_send_time; @@ -151,16 +158,56 @@ typedef struct 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 + + int sendseq; + net_full_ticcmd_t sendqueue[BACKUPTICS]; + } net_client_t; +// structure used for the recv window + +typedef struct +{ + boolean active; + unsigned int time; + net_ticdiff_t diff; +} net_client_recv_t; + static net_server_state_t server_state; static boolean server_initialised = false; static net_client_t clients[MAXNETNODES]; +static net_client_t *sv_players[MAXPLAYERS]; static net_context_t *server_context; static int sv_gamemode; static int sv_gamemission; static net_gamesettings_t sv_settings; +// receive window + +static unsigned int recvwindow_start; +static net_client_recv_t recvwindow[BACKUPTICS][MAXPLAYERS]; + +static unsigned int NET_SV_ExpandTicNum(int i) +{ + int l, h; + unsigned int result; + + h = recvwindow_start & ~0xff; + l = recvwindow_start & 0xff; + + result = h | i; + + if (i - l > 0x80) + result -= 0x100; + else if (l - i > 0x80) + result += 0x100; + + return result; +} + static void NET_SV_DisconnectClient(net_client_t *client) { if (client->active) @@ -178,6 +225,29 @@ static boolean ClientConnected(net_client_t *client) && client->connection.state == NET_CONN_STATE_CONNECTED; } +static void NET_SV_AssignPlayers(void) +{ + int i; + int pl; + + pl = 0; + + for (i=0; iplayer_number = pl; + ++pl; + } + } + + for (; plsendseq for all connected + // players + + for (i=0; isendseq < lowtic) + { + lowtic = sv_players[i]->sendseq; + } + } + + if (lowtic < 0) + { + return; + } + + // Advance the recv window until it catches up with lowtic + + while (recvwindow_start < lowtic) + { + memcpy(recvwindow, recvwindow + 1, sizeof(*recvwindow) * (BACKUPTICS - 1)); + memset(&recvwindow[BACKUPTICS-1], 0, sizeof(*recvwindow)); + ++recvwindow_start; + } +} + // returns a pointer to the client which controls the server static net_client_t *NET_SV_Controller(void) @@ -274,6 +383,25 @@ static void NET_SV_SendReject(net_addr_t *addr, char *msg) NET_FreePacket(packet); } +static void NET_SV_InitNewClient(net_client_t *client, + net_addr_t *addr, + char *player_name) +{ + client->active = true; + NET_Conn_InitServer(&client->connection, addr); + 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 + + client->sendseq = 0; + memset(client->sendqueue, 0xff, sizeof(client->sendqueue)); +} + // parse a SYN from a client(initiating a connection) static void NET_SV_ParseSYN(net_packet_t *packet, @@ -406,14 +534,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, // Activate, initialise connection - client->active = true; - NET_Conn_InitServer(&client->connection, addr); - 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; + NET_SV_InitNewClient(client, addr, player_name); } if (client->connection.state == NET_CONN_STATE_WAITING_ACK) @@ -459,18 +580,23 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) // Send start packets to each connected node - for (i=0; iconnection, + NET_PACKET_TYPE_GAMESTART); + + NET_WriteInt8(startpacket, NET_SV_NumClients()); + NET_WriteInt8(startpacket, sv_players[i]->player_number); + NET_WriteSettings(startpacket, &settings); } + + memset(recvwindow, 0, sizeof(recvwindow)); + recvwindow_start = 0; } static void NET_SV_ParseTimeResponse(net_packet_t *packet, net_client_t *client) @@ -527,6 +653,62 @@ static void NET_SV_ParseTimeResponse(net_packet_t *packet, net_client_t *client) printf("client %p time offset: %i(%i)->%i\n", client, time_offset, rtt, client->time_offset); } +// Process game data from a client + +static void NET_SV_ParseGameData(net_packet_t *packet, net_client_t *client) +{ + net_client_recv_t *recvobj; + unsigned int seq; + unsigned int num_tics; + int i; + int player; + + if (server_state != SERVER_IN_GAME) + { + return; + } + + player = client->player_number; + + // Read header + + if (!NET_ReadInt8(packet, &seq) + || !NET_ReadInt8(packet, &num_tics)) + { + return; + } + + // Expand 8-bit value to the full sequence number + + seq = NET_SV_ExpandTicNum(seq); + + // Sanity checks + + for (i=0; i= BACKUPTICS) + { + // Not in range of the recv window + + continue; + } + + recvobj = &recvwindow[index][player]; + recvobj->active = true; + recvobj->diff = diff; + } +} + // Process a packet received by the server static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) @@ -568,6 +750,9 @@ static void NET_SV_Packet(net_packet_t *packet, net_addr_t *addr) case NET_PACKET_TYPE_GAMESTART: NET_SV_ParseGameStart(packet, client); break; + case NET_PACKET_TYPE_GAMEDATA: + NET_SV_ParseGameData(packet, client); + break; case NET_PACKET_TYPE_TIME_RESP: NET_SV_ParseTimeResponse(packet, client); break; @@ -655,6 +840,72 @@ static void NET_SV_SendTimeRequest(net_client_t *client) client->last_time_req_time = I_GetTimeMS(); } +static void NET_SV_PumpSendQueue(net_client_t *client) +{ + net_full_ticcmd_t cmd; + int recv_index; + int i; + + recv_index = client->sendseq - recvwindow_start; + + if (recv_index < 0 || recv_index >= BACKUPTICS) + { + return; + } + + // Check if we can generate a new entry for the send queue + // using the data in recvwindow. + + for (i=0; isendseq); + + // We have all data we need to generate a command for this tic. + + cmd.seq = client->sendseq; + + // Add ticcmds from all players + + for (i=0; isendqueue[client->sendseq % BACKUPTICS] = cmd; + + ++client->sendseq; +} + // Perform any needed action on a client static void NET_SV_RunClient(net_client_t *client) @@ -706,6 +957,11 @@ static void NET_SV_RunClient(net_client_t *client) NET_SV_SendTimeRequest(client); } + + if (server_state == SERVER_IN_GAME) + { + NET_SV_PumpSendQueue(client); + } } // Initialise server and wait for connections @@ -762,6 +1018,11 @@ void NET_SV_Run(void) NET_SV_RunClient(&clients[i]); } } + + if (server_state == SERVER_IN_GAME) + { + NET_SV_AdvanceWindow(); + } } void NET_SV_Shutdown(void) diff --git a/src/net_structrw.c b/src/net_structrw.c index a2662023..f57a9091 100644 --- a/src/net_structrw.c +++ b/src/net_structrw.c @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_structrw.c 295 2006-01-14 02:06:48Z fraggle $ +// $Id: net_structrw.c 369 2006-02-16 01:12:28Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,12 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.6 2006/02/16 01:12:28 fraggle +// Define a new type net_full_ticcmd_t, a structure containing all ticcmds +// for a given tic. Store received game data in a receive window. Add +// send queues for clients and add data from the receive window to +// generate complete sets of ticcmds. +// // Revision 1.5 2006/01/14 02:06:48 fraggle // Include the game version in the settings structure. // @@ -47,6 +53,8 @@ #include #include +#include "doomdef.h" + #include "net_packet.h" #include "net_structrw.h" @@ -213,3 +221,71 @@ void NET_TiccmdPatch(ticcmd_t *src, net_ticdiff_t *diff, ticcmd_t *dest) dest->chatchar = 0; } +// +// net_full_ticcmd_t +// + +boolean NET_ReadFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd) +{ + unsigned int bitfield; + int i; + + // Regenerate playeringame from the "header" bitfield + + if (!NET_ReadInt8(packet, &bitfield)) + { + return false; + } + + for (i=0; iplayeringame[i] = (bitfield & (1 << i)) != 0; + } + + // Read cmds + + for (i=0; iplayeringame[i]) + { + if (!NET_ReadTiccmdDiff(packet, &cmd->cmds[i], false)) + { + return false; + } + } + } + + return true; +} + +void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd) +{ + unsigned int bitfield; + int i; + + // Write "header" byte indicating which players are active + // in this ticcmd + + bitfield = 0; + + for (i=0; iplayeringame[i]) + { + bitfield |= 1 << i; + } + } + + NET_WriteInt8(packet, bitfield); + + // Write player ticcmds + + for (i=0; iplayeringame[i]) + { + NET_WriteTiccmdDiff(packet, &cmd->cmds[i], false); + } + } +} + diff --git a/src/net_structrw.h b/src/net_structrw.h index 3d835b65..5f458445 100644 --- a/src/net_structrw.h +++ b/src/net_structrw.h @@ -1,7 +1,7 @@ // Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // -// $Id: net_structrw.h 288 2006-01-13 02:22:47Z fraggle $ +// $Id: net_structrw.h 369 2006-02-16 01:12:28Z fraggle $ // // Copyright(C) 2005 Simon Howard // @@ -21,6 +21,12 @@ // 02111-1307, USA. // // $Log$ +// Revision 1.4 2006/02/16 01:12:28 fraggle +// Define a new type net_full_ticcmd_t, a structure containing all ticcmds +// for a given tic. Store received game data in a receive window. Add +// send queues for clients and add data from the receive window to +// generate complete sets of ticcmds. +// // Revision 1.3 2006/01/13 02:22:47 fraggle // Update prototypes to match header. Make sure we include the header in the // source file. @@ -49,5 +55,9 @@ extern boolean NET_ReadTiccmdDiff(net_packet_t *packet, net_ticdiff_t *diff, boo extern void NET_TiccmdDiff(ticcmd_t *tic1, ticcmd_t *tic2, net_ticdiff_t *diff); extern void NET_TiccmdPatch(ticcmd_t *src, net_ticdiff_t *diff, ticcmd_t *dest); +boolean NET_ReadFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd); +void NET_WriteFullTiccmd(net_packet_t *packet, net_full_ticcmd_t *cmd); + + #endif /* #ifndef NET_STRUCTRW_H */ -- cgit v1.2.3