diff options
Diffstat (limited to 'src/net_client.c')
-rw-r--r-- | src/net_client.c | 427 |
1 files changed, 122 insertions, 305 deletions
diff --git a/src/net_client.c b/src/net_client.c index 24fb7f6c..239691c8 100644 --- a/src/net_client.c +++ b/src/net_client.c @@ -22,17 +22,19 @@ // #include <ctype.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include "config.h" -#include "doomdef.h" -#include "doomstat.h" +#include "doomtype.h" #include "deh_main.h" -#include "g_game.h" +#include "deh_str.h" #include "i_system.h" #include "i_timer.h" #include "m_argv.h" +#include "m_fixed.h" +#include "m_config.h" #include "m_misc.h" #include "net_client.h" #include "net_common.h" @@ -45,8 +47,14 @@ #include "w_checksum.h" #include "w_wad.h" +extern void D_ReceiveTic(ticcmd_t *ticcmds, boolean *playeringame); + typedef enum { + // waiting for the game to launch + + CLIENT_STATE_WAITING_LAUNCH, + // waiting for the game to start CLIENT_STATE_WAITING_START, @@ -69,10 +77,10 @@ typedef struct unsigned int resend_time; - // Tic data from server + // Tic data from server net_full_ticcmd_t cmd; - + } net_server_recv_t; // Type of structure used in the send window @@ -103,53 +111,32 @@ static net_clientstate_t client_state; static net_addr_t *server_addr; static net_context_t *client_context; +// game settings, as received from the server when the game started + +static net_gamesettings_t settings; + // true if the client code is in use boolean net_client_connected; -// true if we have received waiting data from the server +// true if we have received waiting data from the server, +// and the wait data that was received. boolean net_client_received_wait_data; +net_waitdata_t net_client_wait_data; -// if true, this client is the controller of the game - -boolean net_client_controller = false; - -// Number of clients currently connected to the server - -unsigned int net_clients_in_game; - -// Number of drone players connected to the server - -unsigned int net_drones_in_game; - -// Names of all players - -char net_player_addresses[MAXPLAYERS][MAXPLAYERNAME]; -char net_player_names[MAXPLAYERS][MAXPLAYERNAME]; - -// SHA1 checksums of the wad directory and dehacked data that the server -// has sent to us. - -sha1_digest_t net_server_wad_sha1sum; -sha1_digest_t net_server_deh_sha1sum; - -// Is the server a freedoom game? +// Waiting at the initial wait screen for the game to be launched? -unsigned int net_server_is_freedoom; - -// Player number - -int net_player_number; - -// Waiting for the game to start? - -boolean net_waiting_for_start = false; +boolean net_waiting_for_launch = false; // Name that we send to the server char *net_player_name = NULL; +// Connected but not participating in the game (observer) + +boolean drone = false; + // The last ticcmd constructed static ticcmd_t last_ticcmd; @@ -160,7 +147,7 @@ static net_server_send_t send_queue[BACKUPTICS]; // Receive window -static ticcmd_t recvwindow_cmd_base[MAXPLAYERS]; +static ticcmd_t recvwindow_cmd_base[NET_MAXPLAYERS]; static int recvwindow_start; static net_server_recv_t recvwindow[BACKUPTICS]; @@ -185,53 +172,11 @@ static fixed_t average_latency; #define NET_CL_ExpandTicNum(b) NET_ExpandTicNum(recvwindow_start, (b)) -// Called when a player leaves the game - -static void NET_CL_PlayerQuitGame(player_t *player) -{ - static char exitmsg[80]; - - // Do this the same way as Vanilla Doom does, to allow dehacked - // replacements of this message - - strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg)); - exitmsg[sizeof(exitmsg) - 1] = '\0'; - - exitmsg[7] += player - players; - - players[consoleplayer].message = exitmsg; - - // TODO: check if it is sensible to do this: - - if (demorecording) - { - G_CheckDemoStatus (); - } -} - // Called when we become disconnected from the server static void NET_CL_Disconnected(void) { - int i; - - // In drone mode, the game cannot continue once disconnected. - - if (drone) - { - I_Error("Disconnected from server in drone mode."); - } - - // disconnected from server - - players[consoleplayer].message = "Disconnected from server"; - printf("Disconnected from server.\n"); - - for (i=0; i<MAXPLAYERS; ++i) - { - if (i != consoleplayer) - playeringame[i] = false; - } + D_ReceiveTic(NULL, NULL); } // Expand a net_full_ticcmd_t, applying the diffs in cmd->cmds as @@ -239,7 +184,8 @@ static void NET_CL_Disconnected(void) // 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, unsigned int seq) +static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq, + ticcmd_t *ticcmds) { int latency; fixed_t adjustment; @@ -299,40 +245,27 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq) // Expand tic diffs for all players - for (i=0; i<MAXPLAYERS; ++i) + for (i=0; i<NET_MAXPLAYERS; ++i) { - if (i == consoleplayer && !drone) + if (i == settings.consoleplayer && !drone) { continue; } - if (playeringame[i] && !cmd->playeringame[i]) - { - NET_CL_PlayerQuitGame(&players[i]); - } - - playeringame[i] = cmd->playeringame[i]; - - if (playeringame[i]) + if (cmd->playeringame[i]) { net_ticdiff_t *diff; - ticcmd_t ticcmd; diff = &cmd->cmds[i]; // Use the ticcmd diff to patch the previous ticcmd to // the new ticcmd - NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmd); - - // Save in d_net.c structures - - netcmds[i][nettics[i] % BACKUPTICS] = ticcmd; - ++nettics[i]; + NET_TiccmdPatch(&recvwindow_cmd_base[i], diff, &ticcmds[i]); // Store a copy for next time - recvwindow_cmd_base[i] = ticcmd; + recvwindow_cmd_base[i] = ticcmds[i]; } } } @@ -341,11 +274,15 @@ static void NET_CL_ExpandFullTiccmd(net_full_ticcmd_t *cmd, unsigned int seq) static void NET_CL_AdvanceWindow(void) { + ticcmd_t ticcmds[NET_MAXPLAYERS]; + while (recvwindow[0].active) { // Expand tic diff data into d_net.c structures - NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start); + NET_CL_ExpandFullTiccmd(&recvwindow[0].cmd, recvwindow_start, + ticcmds); + D_ReceiveTic(ticcmds, recvwindow[0].cmd.playeringame); // Advance the window @@ -373,66 +310,14 @@ static void NET_CL_Shutdown(void) } } -void NET_CL_StartGame(void) +void NET_CL_LaunchGame(void) { - net_packet_t *packet; - net_gamesettings_t settings; - int i; - - // Fill in game settings structure with appropriate parameters - // for the new game - - settings.deathmatch = deathmatch; - settings.episode = startepisode; - settings.map = startmap; - settings.skill = startskill; - settings.loadgame = startloadgame; - settings.gameversion = gameversion; - settings.nomonsters = nomonsters; - settings.fast_monsters = fastparm; - settings.respawn_monsters = respawnparm; - settings.timelimit = timelimit; - - //! - // @category net - // - // Use original game sync code. - // - - if (M_CheckParm("-oldsync") > 0) - settings.new_sync = 0; - else - settings.new_sync = 1; - - //! - // @category net - // @arg <n> - // - // Send n extra tics in every packet as insurance against dropped - // packets. - // - - i = M_CheckParmWithArgs("-extratics", 1); - - if (i > 0) - settings.extratics = atoi(myargv[i+1]); - else - settings.extratics = 1; - - //! - // @category net - // @arg <n> - // - // Reduce the resolution of the game by a factor of n, reducing - // the amount of network bandwidth needed. - // - - i = M_CheckParmWithArgs("-dup", 1); + NET_Conn_NewReliable(&client_connection, NET_PACKET_TYPE_LAUNCH); +} - if (i > 0) - settings.ticdup = atoi(myargv[i+1]); - else - settings.ticdup = 1; +void NET_CL_StartGame(net_gamesettings_t *settings) +{ + net_packet_t *packet; // Start from a ticcmd of all zeros @@ -443,7 +328,7 @@ void NET_CL_StartGame(void) packet = NET_Conn_NewReliable(&client_connection, NET_PACKET_TYPE_GAMESTART); - NET_WriteSettings(packet, &settings); + NET_WriteSettings(packet, settings); } static void NET_CL_SendGameDataACK(void) @@ -453,7 +338,7 @@ static void NET_CL_SendGameDataACK(void) packet = NET_NewPacket(10); NET_WriteInt16(packet, NET_PACKET_TYPE_GAMEDATA_ACK); - NET_WriteInt8(packet, (gametic / ticdup) & 0xff); + NET_WriteInt8(packet, recvwindow_start & 0xff); NET_Conn_SendPacket(&client_connection, packet); @@ -485,7 +370,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 / ticdup) & 0xff); + NET_WriteInt8(packet, recvwindow_start & 0xff); NET_WriteInt8(packet, start & 0xff); NET_WriteInt8(packet, end - start + 1); @@ -499,7 +384,7 @@ static void NET_CL_SendTics(int start, int end) NET_WriteInt16(packet, average_latency / FRACUNIT); - NET_WriteTiccmdDiff(packet, &sendobj->cmd, lowres_turn); + NET_WriteTiccmdDiff(packet, &sendobj->cmd, settings.lowres_turn); } // Send the packet @@ -539,7 +424,7 @@ void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic) // Send to server. - starttic = maketic - extratics; + starttic = maketic - settings.extratics; endtic = maketic; if (starttic < 0) @@ -552,92 +437,61 @@ void NET_CL_SendTiccmd(ticcmd_t *ticcmd, int maketic) static void NET_CL_ParseWaitingData(net_packet_t *packet) { - unsigned int num_players; - unsigned int num_drones; - unsigned int is_controller; - signed int player_number; - char *player_names[MAXPLAYERS]; - char *player_addr[MAXPLAYERS]; - sha1_digest_t wad_sha1sum, deh_sha1sum; - unsigned int server_is_freedoom; - size_t i; + net_waitdata_t wait_data; - if (!NET_ReadInt8(packet, &num_players) - || !NET_ReadInt8(packet, &num_drones) - || !NET_ReadInt8(packet, &is_controller) - || !NET_ReadSInt8(packet, &player_number)) + if (!NET_ReadWaitData(packet, &wait_data)) { - // invalid packet - + // Invalid packet? return; } - if (num_players > MAXPLAYERS) + if (wait_data.num_players > wait_data.max_players + || wait_data.ready_players > wait_data.num_players + || wait_data.max_players > NET_MAXPLAYERS) { // insane data return; } - if ((player_number >= 0 && drone) - || (player_number < 0 && !drone) - || (player_number >= (signed int) num_players)) + if ((wait_data.consoleplayer >= 0 && drone) + || (wait_data.consoleplayer < 0 && !drone) + || (wait_data.consoleplayer >= wait_data.num_players)) { // Invalid player number return; } - - // Read the player names - for (i=0; i<num_players; ++i) - { - player_names[i] = NET_ReadString(packet); - player_addr[i] = NET_ReadString(packet); + memcpy(&net_client_wait_data, &wait_data, sizeof(net_waitdata_t)); + net_client_received_wait_data = true; +} - if (player_names[i] == NULL || player_addr[i] == NULL) - { - return; - } - } +static void NET_CL_ParseLaunch(net_packet_t *packet) +{ + unsigned int num_players; - if (!NET_ReadSHA1Sum(packet, wad_sha1sum) - || !NET_ReadSHA1Sum(packet, deh_sha1sum) - || !NET_ReadInt8(packet, &server_is_freedoom)) + if (client_state != CLIENT_STATE_WAITING_LAUNCH) { return; } - net_clients_in_game = num_players; - net_drones_in_game = num_drones; - net_client_controller = is_controller != 0; - net_player_number = player_number; + // The launch packet contains the number of players that will be + // in the game when it starts, so that we can do the startup + // progress indicator (the wait data is unreliable). - for (i=0; i<num_players; ++i) + if (!NET_ReadInt8(packet, &num_players)) { - strncpy(net_player_names[i], player_names[i], MAXPLAYERNAME); - net_player_names[i][MAXPLAYERNAME-1] = '\0'; - strncpy(net_player_addresses[i], player_addr[i], MAXPLAYERNAME); - net_player_addresses[i][MAXPLAYERNAME-1] = '\0'; + return; } - memcpy(net_server_wad_sha1sum, wad_sha1sum, sizeof(sha1_digest_t)); - memcpy(net_server_deh_sha1sum, deh_sha1sum, sizeof(sha1_digest_t)); - net_server_is_freedoom = server_is_freedoom; - - net_client_received_wait_data = true; + net_client_wait_data.num_players = num_players; + client_state = CLIENT_STATE_WAITING_START; } static void NET_CL_ParseGameStart(net_packet_t *packet) { - net_gamesettings_t settings; - unsigned int num_players; - signed int player_number; - unsigned int i; - - if (!NET_ReadInt8(packet, &num_players) - || !NET_ReadSInt8(packet, &player_number) - || !NET_ReadSettings(packet, &settings)) + if (!NET_ReadSettings(packet, &settings)) { return; } @@ -647,14 +501,15 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) return; } - if (num_players > MAXPLAYERS || player_number >= (signed int) num_players) + if (settings.num_players > NET_MAXPLAYERS + || settings.consoleplayer >= (signed int) settings.num_players) { // insane values return; } - if ((drone && player_number >= 0) - || (!drone && player_number < 0)) + if ((drone && settings.consoleplayer >= 0) + || (!drone && settings.consoleplayer < 0)) { // Invalid player number: must be positive for real players, // negative for drones @@ -662,49 +517,8 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) return; } - // Start the game - - if (!drone) - { - consoleplayer = player_number; - } - else - { - consoleplayer = 0; - } - - for (i=0; i<MAXPLAYERS; ++i) - { - playeringame[i] = i < num_players; - } - client_state = CLIENT_STATE_IN_GAME; - deathmatch = settings.deathmatch; - ticdup = settings.ticdup; - extratics = settings.extratics; - startepisode = settings.episode; - startmap = settings.map; - startskill = settings.skill; - startloadgame = settings.loadgame; - lowres_turn = settings.lowres_turn; - nomonsters = settings.nomonsters; - fastparm = settings.fast_monsters; - respawnparm = settings.respawn_monsters; - net_cl_new_sync = settings.new_sync != 0; - timelimit = settings.timelimit; - - if (net_cl_new_sync == false) - { - printf("Syncing netgames like Vanilla Doom.\n"); - } - - if (lowres_turn) - { - printf("NOTE: Turning resolution is reduced; this is probably " - "because there is a client recording a Vanilla demo.\n"); - } - // Clear the receive window memset(recvwindow, 0, sizeof(recvwindow)); @@ -714,9 +528,6 @@ static void NET_CL_ParseGameStart(net_packet_t *packet) // Clear the send queue memset(&send_queue, 0x00, sizeof(send_queue)); - - netgame = true; - autostart = true; } static void NET_CL_SendResendRequest(int start, int end) @@ -863,7 +674,7 @@ static void NET_CL_ParseGameData(net_packet_t *packet) index = seq - recvwindow_start + i; - if (!NET_ReadFullTiccmd(packet, &cmd, lowres_turn)) + if (!NET_ReadFullTiccmd(packet, &cmd, settings.lowres_turn)) { return; } @@ -1026,6 +837,10 @@ static void NET_CL_ParsePacket(net_packet_t *packet) NET_CL_ParseWaitingData(packet); break; + case NET_PACKET_TYPE_LAUNCH: + NET_CL_ParseLaunch(packet); + break; + case NET_PACKET_TYPE_GAMESTART: NET_CL_ParseGameStart(packet); break; @@ -1085,12 +900,13 @@ void NET_CL_Run(void) || client_connection.state == NET_CONN_STATE_DISCONNECTED_SLEEP) { NET_CL_Disconnected(); - + NET_CL_Shutdown(); } - - net_waiting_for_start = client_connection.state == NET_CONN_STATE_CONNECTED - && client_state == CLIENT_STATE_WAITING_START; + + net_waiting_for_launch = + client_connection.state == NET_CONN_STATE_CONNECTED + && client_state == CLIENT_STATE_WAITING_LAUNCH; if (client_state == CLIENT_STATE_IN_GAME) { @@ -1104,7 +920,7 @@ void NET_CL_Run(void) } } -static void NET_CL_SendSYN(void) +static void NET_CL_SendSYN(net_connect_data_t *data) { net_packet_t *packet; @@ -1112,13 +928,7 @@ static void NET_CL_SendSYN(void) NET_WriteInt16(packet, NET_PACKET_TYPE_SYN); NET_WriteInt32(packet, NET_MAGIC_NUMBER); NET_WriteString(packet, PACKAGE_STRING); - NET_WriteInt16(packet, gamemode); - NET_WriteInt16(packet, gamemission); - NET_WriteInt8(packet, lowres_turn); - NET_WriteInt8(packet, drone); - NET_WriteSHA1Sum(packet, net_local_wad_sha1sum); - NET_WriteSHA1Sum(packet, net_local_deh_sha1sum); - NET_WriteInt8(packet, net_local_is_freedoom); + NET_WriteConnectData(packet, data); NET_WriteString(packet, net_player_name); NET_Conn_SendPacket(&client_connection, packet); NET_FreePacket(packet); @@ -1126,34 +936,22 @@ static void NET_CL_SendSYN(void) // connect to a server -boolean NET_CL_Connect(net_addr_t *addr) +boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data) { int start_time; int last_send_time; server_addr = addr; - // Are we recording a demo? Possibly set lowres turn mode - - if (M_CheckParm("-record") > 0 && M_CheckParm("-longtics") == 0) - { - lowres_turn = true; - } - - // Read checksums of our WAD directory and dehacked information - - W_Checksum(net_local_wad_sha1sum); - DEH_Checksum(net_local_deh_sha1sum); - - // Are we playing with the Freedoom IWAD? - - net_local_is_freedoom = W_CheckNumForName("FREEDOOM") >= 0; + memcpy(net_local_wad_sha1sum, data->wad_sha1sum, sizeof(sha1_digest_t)); + memcpy(net_local_deh_sha1sum, data->deh_sha1sum, sizeof(sha1_digest_t)); + net_local_is_freedoom = data->is_freedoom; // create a new network I/O context and add just the // necessary module client_context = NET_NewContext(); - + // initialize module for client mode if (!addr->module->InitClient()) @@ -1171,7 +969,7 @@ boolean NET_CL_Connect(net_addr_t *addr) NET_Conn_InitClient(&client_connection, addr); // try to connect - + start_time = I_GetTimeMS(); last_send_time = -1; @@ -1183,11 +981,11 @@ boolean NET_CL_Connect(net_addr_t *addr) if (nowtime - last_send_time > 1000 || last_send_time < 0) { - NET_CL_SendSYN(); + NET_CL_SendSYN(data); last_send_time = nowtime; } - - // time out after 5 seconds + + // time out after 5 seconds if (nowtime - start_time > 5000) { @@ -1197,7 +995,7 @@ boolean NET_CL_Connect(net_addr_t *addr) // run client code NET_CL_Run(); - + // run the server, just incase we are doing a loopback // connect @@ -1212,7 +1010,8 @@ boolean NET_CL_Connect(net_addr_t *addr) { // connected ok! - client_state = CLIENT_STATE_WAITING_START; + client_state = CLIENT_STATE_WAITING_LAUNCH; + drone = data->drone; return true; } @@ -1221,9 +1020,23 @@ boolean NET_CL_Connect(net_addr_t *addr) // failed to connect NET_CL_Shutdown(); - + + return false; + } +} + +// read game settings received from server + +boolean NET_CL_GetSettings(net_gamesettings_t *_settings) +{ + if (client_state != CLIENT_STATE_IN_GAME) + { return false; } + + memcpy(_settings, &settings, sizeof(net_gamesettings_t)); + + return true; } // disconnect from the server @@ -1294,3 +1107,7 @@ void NET_Init(void) NET_CL_Init(); } +void NET_BindVariables(void) +{ + M_BindVariable("player_name", &net_player_name); +} |