diff options
author | Simon Howard | 2011-10-14 18:14:34 +0000 |
---|---|---|
committer | Simon Howard | 2011-10-14 18:14:34 +0000 |
commit | 2344223e648ca693945fe014bb3162c272bf27ec (patch) | |
tree | 53269b0822b53fbef073bd4c4bea180d48d7907c | |
parent | 031c8ff2d2dcb1a94d730d28555989722aeffdea (diff) | |
download | chocolate-doom-2344223e648ca693945fe014bb3162c272bf27ec.tar.gz chocolate-doom-2344223e648ca693945fe014bb3162c272bf27ec.tar.bz2 chocolate-doom-2344223e648ca693945fe014bb3162c272bf27ec.zip |
Convert Hexen to use common main loop code. Working multiplayer!
Subversion-branch: /branches/v2-branch
Subversion-revision: 2423
-rw-r--r-- | src/Makefile.am | 28 | ||||
-rw-r--r-- | src/hexen/d_net.c | 1028 | ||||
-rw-r--r-- | src/hexen/g_game.c | 8 | ||||
-rw-r--r-- | src/hexen/h2_main.c | 46 | ||||
-rw-r--r-- | src/hexen/h2def.h | 65 | ||||
-rw-r--r-- | src/net_client.c | 2 | ||||
-rw-r--r-- | src/net_defs.h | 8 | ||||
-rw-r--r-- | src/net_server.c | 20 | ||||
-rw-r--r-- | src/net_structrw.c | 63 |
9 files changed, 263 insertions, 1005 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 06bbf7f4..af7a43a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,6 +51,7 @@ d_event.c d_event.h \ doomfeatures.h \ doomtype.h \ d_iwad.c d_iwad.h \ +d_loop.c d_loop.h \ d_mode.c d_mode.h \ d_ticcmd.h \ deh_str.c deh_str.h \ @@ -127,7 +128,8 @@ mus2mid.c mus2mid.h SOURCE_FILES = $(COMMON_SOURCE_FILES) \ $(GAME_SOURCE_FILES) \ $(FEATURE_WAD_MERGE_SOURCE_FILES) \ - $(FEATURE_SOUND_SOURCE_FILES) + $(FEATURE_SOUND_SOURCE_FILES) \ + $(FEATURE_MULTIPLAYER_SOURCE_FILES) SOURCE_FILES_WITH_DEH = $(SOURCE_FILES) \ $(FEATURE_DEHACKED_SOURCE_FILES) @@ -143,25 +145,17 @@ EXTRA_LIBS = \ @SDLNET_LIBS@ if HAVE_WINDRES -@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc \ - d_loop.c d_loop.h \ - $(FEATURE_MULTIPLAYER_SOURCE_FILES) +@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else -@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) \ - d_loop.c d_loop.h \ - $(FEATURE_MULTIPLAYER_SOURCE_FILES) +@PROGRAM_PREFIX@doom_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@doom_LDADD = doom/libdoom.a $(EXTRA_LIBS) if HAVE_WINDRES -@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc \ - d_loop.c d_loop.h \ - $(FEATURE_MULTIPLAYER_SOURCE_FILES) +@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else -@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) \ - d_loop.c d_loop.h \ - $(FEATURE_MULTIPLAYER_SOURCE_FILES) +@PROGRAM_PREFIX@heretic_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@heretic_LDADD = heretic/libheretic.a $(EXTRA_LIBS) @@ -175,13 +169,9 @@ endif @PROGRAM_PREFIX@hexen_LDADD = hexen/libhexen.a $(EXTRA_LIBS) if HAVE_WINDRES -@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc \ - d_loop.c d_loop.h \ - $(FEATURE_MULTIPLAYER_SOURCE_FILES) +@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) resource.rc else -@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) \ - d_loop.c d_loop.h \ - $(FEATURE_MULTIPLAYER_SOURCE_FILES) +@PROGRAM_PREFIX@strife_SOURCES=$(SOURCE_FILES_WITH_DEH) endif @PROGRAM_PREFIX@strife_LDADD = strife/libstrife.a $(EXTRA_LIBS) diff --git a/src/hexen/d_net.c b/src/hexen/d_net.c index 87afd626..21499881 100644 --- a/src/hexen/d_net.c +++ b/src/hexen/d_net.c @@ -2,8 +2,7 @@ //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. -// Copyright(C) 1993-2008 Raven Software -// Copyright(C) 2008 Simon Howard +// Copyright(C) 2005 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License @@ -20,968 +19,259 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. // +// DESCRIPTION: +// DOOM Network game communication and protocol, +// all OS independend parts. +// //----------------------------------------------------------------------------- +#include <stdlib.h> -#include "h2def.h" -#include "s_sound.h" -#include "doomkeys.h" -#include "i_video.h" +#include "doomfeatures.h" + +#include "m_argv.h" #include "i_system.h" #include "i_timer.h" -#include "m_argv.h" -#include "p_local.h" -#include <stdlib.h> // for atoi() - -#define NCMD_EXIT 0x80000000 -#define NCMD_RETRANSMIT 0x40000000 -#define NCMD_SETUP 0x20000000 -#define NCMD_KILL 0x10000000 // kill game -#define NCMD_CHECKSUM 0x0fffffff - - -doomcom_t *doomcom; -doomdata_t *netbuffer; // points inside doomcom - - -/* -============================================================================== - - NETWORKING - -gametic is the tic about to (or currently being) run -maketic is the tick that hasn't had control made for it yet -nettics[] has the maketics for all players - -a gametic cannot be run until nettics[] > gametic for all players - -============================================================================== -*/ - -#define RESENDCOUNT 10 -#define PL_DRONE 0x80 // bit flag in doomdata->player - -ticcmd_t localcmds[BACKUPTICS]; - -ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; -int nettics[MAXNETNODES]; -boolean nodeingame[MAXNETNODES]; // set false as nodes leave game -boolean remoteresend[MAXNETNODES]; // set when local needs tics -int resendto[MAXNETNODES]; // set when remote needs tics -int resendcount[MAXNETNODES]; +#include "i_video.h" +#include "h2def.h" -int nodeforplayer[MAXPLAYERS]; +#include "deh_main.h" -int maketic; -int lastnettic, skiptics; -int ticdup; -int maxsend; // BACKUPTICS/(2*ticdup)-1 +#include "d_loop.h" -void H2_ProcessEvents(void); -void G_BuildTiccmd(ticcmd_t * cmd); -void H2_DoAdvanceDemo(void); -extern void ST_NetProgress(void); -extern void ST_NetDone(void); +ticcmd_t *netcmds; -boolean reboundpacket; -doomdata_t reboundstore; +extern void H2_DoAdvanceDemo(void); +extern void H2_ProcessEvents(void); +extern void G_BuildTiccmd(ticcmd_t *cmd, int maketic); +extern boolean G_CheckDemoStatus(void); +extern boolean demorecording; -int NetbufferSize(void) -{ - return (int) &(((doomdata_t *) 0)->cmds[netbuffer->numtics]); -} +// Called when a player leaves the game -unsigned NetbufferChecksum(void) +static void PlayerQuitGame(player_t *player) { - unsigned c; - int i, l; - - c = 0x1234567; - -#if defined(NORMALUNIX) - return 0; // byte order problems -#endif - - l = (NetbufferSize() - (int) &(((doomdata_t *) 0)->retransmitfrom)) / 4; - for (i = 0; i < l; i++) - c += ((unsigned *) &netbuffer->retransmitfrom)[i] * (i + 1); + static char exitmsg[80]; + unsigned int player_num; - return c & NCMD_CHECKSUM; -} - -int ExpandTics(int low) -{ - int delta; + player_num = player - players; - delta = low - (maketic & 0xff); + /* TODO + // Do this the same way as Vanilla Doom does, to allow dehacked + // replacements of this message - if (delta >= -64 && delta <= 64) - return (maketic & ~0xff) + low; - if (delta > 64) - return (maketic & ~0xff) - 256 + low; - if (delta < -64) - return (maketic & ~0xff) + 256 + low; + strncpy(exitmsg, DEH_String("Player 1 left the game"), sizeof(exitmsg)); + exitmsg[sizeof(exitmsg) - 1] = '\0'; - I_Error("ExpandTics: strange value %i at maketic %i", low, maketic); - return 0; -} - - -//============================================================================ - - -/* -============== -= -= HSendPacket -= -============== + exitmsg[7] += player_num; + players[consoleplayer].message = exitmsg; */ -void HSendPacket(int node, int flags) -{ - netbuffer->checksum = NetbufferChecksum() | flags; - - if (!node) - { - reboundstore = *netbuffer; - reboundpacket = true; - return; - } - - if (demoplayback) - return; - - if (!netgame) - I_Error("Tried to transmit to another node"); - - doomcom->command = CMD_SEND; - doomcom->remotenode = node; - doomcom->datalength = NetbufferSize(); - - if (debugfile) - { - int i; - int realretrans; - if (netbuffer->checksum & NCMD_RETRANSMIT) - realretrans = ExpandTics(netbuffer->retransmitfrom); - else - realretrans = -1; - fprintf(debugfile, "send (%i + %i, R %i) [%i] ", - ExpandTics(netbuffer->starttic), netbuffer->numtics, - realretrans, doomcom->datalength); - for (i = 0; i < doomcom->datalength; i++) - fprintf(debugfile, "%i ", ((byte *) netbuffer)[i]); - fprintf(debugfile, "\n"); - } - -#ifdef I_NET - I_NetCmd(); -#endif -} - -//========================================================================== -// -// NET_SendFrags -// -//========================================================================== - -void NET_SendFrags(player_t * player) -{ - int i; - int frags; - - netbuffer->checksum = NetbufferChecksum(); + playeringame[player_num] = false; - if (demoplayback) - { - return; - } - if (!netgame) - { - I_Error("Tried to transmit to another node"); - } + // TODO: check if it is sensible to do this: - frags = 0; - for (i = 0; i < MAXPLAYERS; i++) + if (demorecording) { - frags += player->frags[i]; + G_CheckDemoStatus (); } - doomcom->command = CMD_FRAG; - doomcom->remotenode = frags; - doomcom->datalength = NetbufferSize(); - -#ifdef I_NET - I_NetCmd(); -#endif } -/* -============== -= -= HGetPacket -= -= Returns false if no packet is waiting -= -============== -*/ - -boolean HGetPacket(void) +static void RunTic(ticcmd_t *cmds, boolean *ingame) { - if (reboundpacket) - { - *netbuffer = reboundstore; - doomcom->remotenode = 0; - reboundpacket = false; - return true; - } - - if (!netgame) - return false; - if (demoplayback) - return false; + extern boolean advancedemo; + unsigned int i; - doomcom->command = CMD_GET; -#ifdef I_NET - I_NetCmd(); -#endif - if (doomcom->remotenode == -1) - return false; + // Check for player quits. - if (doomcom->datalength != NetbufferSize()) + for (i = 0; i < MAXPLAYERS; ++i) { - if (debugfile) - fprintf(debugfile, "bad packet length %i\n", doomcom->datalength); - return false; - } - - if (NetbufferChecksum() != (netbuffer->checksum & NCMD_CHECKSUM)) - { - if (debugfile) - fprintf(debugfile, "bad packet checksum\n"); - return false; - } - - if (debugfile) - { - int realretrans; - int i; - - if (netbuffer->checksum & NCMD_SETUP) - fprintf(debugfile, "setup packet\n"); - else + if (playeringame[i] && !ingame[i]) { - if (netbuffer->checksum & NCMD_RETRANSMIT) - realretrans = ExpandTics(netbuffer->retransmitfrom); - else - realretrans = -1; - fprintf(debugfile, "get %i = (%i + %i, R %i)[%i] ", - doomcom->remotenode, ExpandTics(netbuffer->starttic), - netbuffer->numtics, realretrans, doomcom->datalength); - for (i = 0; i < doomcom->datalength; i++) - fprintf(debugfile, "%i ", ((byte *) netbuffer)[i]); - fprintf(debugfile, "\n"); + PlayerQuitGame(&players[i]); } } - return true; -} - - -/* -=================== -= -= GetPackets -= -=================== -*/ - -char exitmsg[80]; -void GetPackets(void) -{ - int netconsole; - int netnode; - ticcmd_t *src, *dest; - int realend; - int realstart; + netcmds = cmds; - while (HGetPacket()) - { - if (netbuffer->checksum & NCMD_SETUP) - continue; // extra setup packet - - netconsole = netbuffer->player & ~PL_DRONE; - netnode = doomcom->remotenode; - // - // to save bytes, only the low byte of tic numbers are sent - // Figure out what the rest of the bytes are - // - realstart = ExpandTics(netbuffer->starttic); - realend = (realstart + netbuffer->numtics); - - // - // check for exiting the game - // - if (netbuffer->checksum & NCMD_EXIT) - { - if (!nodeingame[netnode]) - continue; - nodeingame[netnode] = false; - playeringame[netconsole] = false; - strcpy(exitmsg, "PLAYER 1 LEFT THE GAME"); - exitmsg[7] += netconsole; - P_SetMessage(&players[consoleplayer], exitmsg, true); - S_StartSound(NULL, SFX_CHAT); -// players[consoleplayer].message = exitmsg; -// if (demorecording) -// G_CheckDemoStatus (); - continue; - } + // check that there are players in the game. if not, we cannot + // run a tic. - // - // check for a remote game kill - // - if (netbuffer->checksum & NCMD_KILL) - I_Error("Killed by network driver"); - - nodeforplayer[netconsole] = netnode; - - // - // check for retransmit request - // - if (resendcount[netnode] <= 0 - && (netbuffer->checksum & NCMD_RETRANSMIT)) - { - resendto[netnode] = ExpandTics(netbuffer->retransmitfrom); - if (debugfile) - fprintf(debugfile, "retransmit from %i\n", resendto[netnode]); - resendcount[netnode] = RESENDCOUNT; - } - else - resendcount[netnode]--; - - // - // check for out of order / duplicated packet - // - if (realend == nettics[netnode]) - continue; - - if (realend < nettics[netnode]) - { - if (debugfile) - fprintf(debugfile, "out of order packet (%i + %i)\n", - realstart, netbuffer->numtics); - continue; - } - - // - // check for a missed packet - // - if (realstart > nettics[netnode]) - { - // stop processing until the other system resends the missed tics - if (debugfile) - fprintf(debugfile, "missed tics from %i (%i - %i)\n", netnode, - realstart, nettics[netnode]); - remoteresend[netnode] = true; - continue; - } - -// -// update command store from the packet -// - { - int start; - - remoteresend[netnode] = false; - - start = nettics[netnode] - realstart; - src = &netbuffer->cmds[start]; - - while (nettics[netnode] < realend) - { - dest = &netcmds[netconsole][nettics[netnode] % BACKUPTICS]; - nettics[netnode]++; - *dest = *src; - src++; - } - } - } + if (advancedemo) + H2_DoAdvanceDemo (); + G_Ticker (); } -/* -============= -= -= NetUpdate -= -= Builds ticcmds for console player -= sends out a packet -============= -*/ - -int gametime; - -void NetUpdate(void) -{ - int nowtime; - int newtics; - int i, j; - int realstart; - int gameticdiv; +static loop_interface_t hexen_loop_interface = { + H2_ProcessEvents, + G_BuildTiccmd, + RunTic, + MN_Ticker +}; -// -// check time -// - nowtime = I_GetTime() / ticdup; - newtics = nowtime - gametime; - gametime = nowtime; - if (newtics <= 0) // nothing new to update - goto listen; +// Load game settings from the specified structure and +// set global variables. - if (skiptics <= newtics) +static void LoadGameSettings(net_gamesettings_t *settings, + net_connect_data_t *connect_data) +{ + unsigned int i; + + deathmatch = settings->deathmatch; + ticdup = settings->ticdup; + startepisode = settings->episode; + startmap = settings->map; + startskill = settings->skill; + // TODO startloadgame = settings->loadgame; + nomonsters = settings->nomonsters; + respawnparm = settings->respawn_monsters; + + if (!connect_data->drone) { - newtics -= skiptics; - skiptics = 0; + consoleplayer = settings->consoleplayer; } else { - skiptics -= newtics; - newtics = 0; + consoleplayer = 0; } - - netbuffer->player = consoleplayer; - -// -// build new ticcmds for console player -// - gameticdiv = gametic / ticdup; - for (i = 0; i < newtics; i++) + for (i=0; i<MAXPLAYERS; ++i) { - I_StartTic(); - H2_ProcessEvents(); - if (maketic - gameticdiv >= BACKUPTICS / 2 - 1) - break; // can't hold any more -//printf ("mk:%i ",maketic); - G_BuildTiccmd(&localcmds[maketic % BACKUPTICS]); - maketic++; - } - + playeringame[i] = i < settings->num_players; + PlayerClass[i] = settings->player_classes[i]; - if (singletics) - return; // singletic update is syncronous - -// -// send the packet to the other nodes -// - for (i = 0; i < doomcom->numnodes; i++) - if (nodeingame[i]) + if (PlayerClass[i] >= NUMCLASSES) { - netbuffer->starttic = realstart = resendto[i]; - netbuffer->numtics = maketic - realstart; - if (netbuffer->numtics > BACKUPTICS) - I_Error("NetUpdate: netbuffer->numtics > BACKUPTICS"); - - resendto[i] = maketic - doomcom->extratics; - - for (j = 0; j < netbuffer->numtics; j++) - netbuffer->cmds[j] = localcmds[(realstart + j) % BACKUPTICS]; - - if (remoteresend[i]) - { - netbuffer->retransmitfrom = nettics[i]; - HSendPacket(i, NCMD_RETRANSMIT); - } - else - { - netbuffer->retransmitfrom = 0; - HSendPacket(i, 0); - } + PlayerClass[i] = PCLASS_FIGHTER; } - -// -// listen for other packets -// - listen: - - GetPackets(); -} - - -/* -===================== -= -= CheckAbort -= -===================== -*/ - -void CheckAbort(void) -{ - event_t *ev; - int stoptic; - - stoptic = I_GetTime() + 2; - while (I_GetTime() < stoptic) - I_StartTic(); - - I_StartTic(); - for (;;) - { - ev = D_PopEvent(); - - if (ev == NULL) - { - break; - } - - if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE) - I_Error("Network game synchronization aborted."); } } -/* -===================== -= -= D_ArbitrateNetStart -= -===================== -*/ +// Save the game settings from global variables to the specified +// game settings structure. -void D_ArbitrateNetStart(void) +static void SaveGameSettings(net_gamesettings_t *settings, + net_connect_data_t *connect_data) { int i; - boolean gotinfo[MAXNETNODES]; - boolean gotClass[MAXNETNODES]; - // haleyjd FIXME: important somehow? -#ifdef __WATCOMC__ - int nextTic; - extern volatile int ticcount; - - nextTic = ticcount + 8; -#endif - - autostart = true; - - memset(gotClass, 0, sizeof(gotClass)); - memset(gotinfo, 0, sizeof(gotinfo)); - gotClass[doomcom->consoleplayer] = true; - do - { - i = 0; - - CheckAbort(); - while (HGetPacket()) - { // Check for any incoming packets - if (netbuffer->checksum & NCMD_SETUP && netbuffer->starttic >= 64) - { - - PlayerClass[netbuffer->player] = netbuffer->starttic & 0x3f; - if (!gotClass[netbuffer->player]) - { - gotClass[netbuffer->player] = true; - ST_NetProgress(); - ST_Message("\n"); - } - if (netbuffer->retransmitfrom) - { // that node has received info from all other nodes - gotinfo[netbuffer->player] = true; - } - } - } - // haleyjd FIXME: important somehow? -#ifdef __WATCOMC__ - if (ticcount <= nextTic) - { // only send packets every half second - continue; - } - nextTic = ticcount + 8; -#endif - // Keep sending out packets containing the console class - for (i = 0; i < doomcom->numnodes; i++) - { - netbuffer->player = doomcom->consoleplayer; - netbuffer->starttic = PlayerClass[doomcom->consoleplayer] + 64; - netbuffer->retransmitfrom = gotinfo[doomcom->consoleplayer]; - netbuffer->numtics = 0; - HSendPacket(i, NCMD_SETUP); - } - for (i = 0; i < doomcom->numnodes; i++) - { // Make sure that all nodes have sent class info - if (!gotClass[i]) - { - ST_Message("."); - break; - } - } - if (i < doomcom->numnodes) - { - continue; - } - else - { // consoleplayer has received all player classes - if (gotinfo[doomcom->consoleplayer]) - { - CheckAbort(); - } - else - { - gotinfo[doomcom->consoleplayer] = true; - ST_Message("All player classes received, ready to proceed\n"); - ST_NetDone(); - } - } - for (i = 0; i < doomcom->numnodes; i++) - { // Make sure that all nodes are ready to proceed - if (!gotinfo[i]) - { - break; - } - } - } - while (i < doomcom->numnodes); - memset(gotinfo, 0, sizeof(gotinfo)); + // Fill in game settings structure with appropriate parameters + // for the new game - if (doomcom->consoleplayer) - { // listen for setup info from key player -// ST_Message ("listening for network start info...\n"); - while (1) - { - CheckAbort(); - if (!HGetPacket()) - continue; - if (netbuffer->checksum & NCMD_SETUP && netbuffer->starttic < 64) - { - if (netbuffer->player != HEXEN_VERSION) - I_Error - ("Different HEXEN versions cannot play a net game!"); - startskill = netbuffer->retransmitfrom & 15; - deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6; - nomonsters = (netbuffer->retransmitfrom & 0x20) > 0; - respawnparm = (netbuffer->retransmitfrom & 0x10) > 0; - startmap = netbuffer->starttic & 0x3f; - startepisode = 1; - return; - } - } - } - else - { // key player, send the setup info -// ST_Message ("sending network start info...\n"); - do - { - CheckAbort(); - for (i = 0; i < doomcom->numnodes; i++) - { - netbuffer->retransmitfrom = startskill; - if (deathmatch) - netbuffer->retransmitfrom |= (deathmatch << 6); - if (nomonsters) - netbuffer->retransmitfrom |= 0x20; - if (respawnparm) - netbuffer->retransmitfrom |= 0x10; - netbuffer->starttic = startmap & 0x3f; - netbuffer->player = HEXEN_VERSION; - netbuffer->numtics = 0; - HSendPacket(i, NCMD_SETUP); - } - -#if 1 - for (i = 10; i && HGetPacket(); --i) - { - if ((netbuffer->player & 0x7f) < MAXNETNODES) - gotinfo[netbuffer->player & 0x7f] = true; - } -#else - while (HGetPacket()) - { - gotinfo[netbuffer->player & 0x7f] = true; - } -#endif - - for (i = 1; i < doomcom->numnodes; i++) - if (!gotinfo[i]) - break; - } - while (i < doomcom->numnodes); - } -} + settings->deathmatch = deathmatch; + settings->episode = startepisode; + settings->map = startmap; + settings->skill = startskill; + // TODO settings->loadgame = startloadgame; + settings->gameversion = exe_hexen_1_1; + settings->nomonsters = nomonsters; + settings->respawn_monsters = respawnparm; + settings->timelimit = 0; -// Dummy version of I_InitNetwork; netgames are currently broken. + settings->lowres_turn = false; -void I_InitNetwork(void) -{ // - // single player game + // Connect data // - doomcom = malloc(sizeof(*doomcom)); - memset(doomcom, 0, sizeof(*doomcom)); - netgame = false; - doomcom->id = DOOMCOM_ID; - doomcom->numplayers = doomcom->numnodes = 1; - doomcom->deathmatch = false; - doomcom->consoleplayer = 0; - doomcom->ticdup = 1; - doomcom->extratics = 0; -} -/* -=================== -= -= D_CheckNetGame -= -= Works out player numbers among the net participants -=================== -*/ + // Game type fields: -extern int viewangleoffset; + connect_data->gamemode = gamemode; + connect_data->gamemission = gamemission; -void D_CheckNetGame(void) -{ - int i; - int pClass; + connect_data->lowres_turn = false; + connect_data->drone = false; - for (i = 0; i < MAXNETNODES; i++) - { - nodeingame[i] = false; - nettics[i] = 0; - remoteresend[i] = false; // set when local needs tics - resendto[i] = 0; // which tic to start sending - } + //! + // @category net + // @arg <n> + // + // Specify player class: 0=fighter, 1=cleric, 2=mage, 3=pig. + // -// I_InitNetwork sets doomcom and netgame - I_InitNetwork(); - if (doomcom->id != DOOMCOM_ID) - I_Error("Doomcom buffer invalid!"); - netbuffer = &doomcom->data; - consoleplayer = displayplayer = doomcom->consoleplayer; - pClass = PCLASS_FIGHTER; - i = M_CheckParm("-class"); + i = M_CheckParmWithArgs("-class", 1); if (i > 0) { - pClass = atoi(myargv[i + 1]); - if (pClass > PCLASS_MAGE || pClass < PCLASS_FIGHTER) - { - I_Error("Invalid player class: %d\n", pClass); - } - ST_Message("\nPlayer Class: %d\n", pClass); + connect_data->player_class = atoi(myargv[i + 1]); + } + else + { + connect_data->player_class = PCLASS_FIGHTER; } - PlayerClass[consoleplayer] = pClass; - if (netgame) - D_ArbitrateNetStart(); -//ST_Message ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode); - -// read values out of doomcom - ticdup = doomcom->ticdup; - maxsend = BACKUPTICS / (2 * ticdup) - 1; - if (maxsend < 1) - maxsend = 1; - - for (i = 0; i < doomcom->numplayers; i++) - playeringame[i] = true; - for (i = 0; i < doomcom->numnodes; i++) - nodeingame[i] = true; - -//ST_Message ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes); - } -/* -================== -= -= D_QuitNetGame -= -= Called before quitting to leave a net game without hanging the -= other players -= -================== -*/ - -void D_QuitNetGame(void) +void D_InitSinglePlayerGame(net_gamesettings_t *settings) { - int i, j; + // default values for single player + + settings->consoleplayer = 0; + settings->num_players = 1; - if (debugfile) - fclose(debugfile); + netgame = false; - if (!netgame || !usergame || consoleplayer == -1 || demoplayback) - return; + //! + // @category net + // + // Start the game playing as though in a netgame with a single + // player. This can also be used to play back single player netgame + // demos. + // -// send a bunch of packets for security - netbuffer->player = consoleplayer; - netbuffer->numtics = 0; - for (i = 0; i < 4; i++) + if (M_CheckParm("-solo-net") > 0) { - for (j = 1; j < doomcom->numnodes; j++) - if (nodeingame[j]) - HSendPacket(j, NCMD_EXIT); - I_WaitVBL(1); + netgame = true; } } - - -/* -=============== -= -= TryRunTics -= -=============== -*/ - -int frametics[4], frameon; -int frameskip[4]; -int oldnettics; -extern boolean advancedemo; - -void TryRunTics(void) -{ - int i; - int lowtic; - int entertic; - static int oldentertics; - int realtics, availabletics; - int counts; - int numplaying; - -// -// get real tics -// - entertic = I_GetTime() / ticdup; - realtics = entertic - oldentertics; - oldentertics = entertic; - // -// get available tics +// D_CheckNetGame +// Works out player numbers among the net participants // - NetUpdate(); - lowtic = INT_MAX; - numplaying = 0; - for (i = 0; i < doomcom->numnodes; i++) - if (nodeingame[i]) - { - numplaying++; - if (nettics[i] < lowtic) - lowtic = nettics[i]; - } - availabletics = lowtic - gametic / ticdup; +void D_CheckNetGame (void) +{ + net_connect_data_t connect_data; + net_gamesettings_t settings; + D_RegisterLoopCallbacks(&hexen_loop_interface); -// -// decide how many tics to run -// - if (realtics < availabletics - 1) - counts = realtics + 1; - else if (realtics < availabletics) - counts = realtics; - else - counts = availabletics; - if (counts < 1) - counts = 1; + // Call D_QuitNetGame on exit - frameon++; + I_AtExit(D_QuitNetGame, true); - if (debugfile) - fprintf(debugfile, "=======real: %i avail: %i game: %i\n", realtics, - availabletics, counts); + SaveGameSettings(&settings, &connect_data); - if (!demoplayback) + if (D_InitNetGame(&connect_data, &settings)) { - //============================================================================= - // - // ideally nettics[0] should be 1 - 3 tics above lowtic - // if we are consistantly slower, speed up time - // - for (i = 0; i < MAXPLAYERS; i++) - if (playeringame[i]) - break; - if (consoleplayer == i) - { // the key player does not adapt - } - else - { - if (nettics[0] <= nettics[nodeforplayer[i]]) - { - gametime--; - // printf ("-"); - } - frameskip[frameon & 3] = (oldnettics > nettics[nodeforplayer[i]]); - oldnettics = nettics[0]; - if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) - { - skiptics = 1; - // printf ("+"); - } - } - //============================================================================= - } // demoplayback - - // - // wait for new tics if needed - // - while (lowtic < gametic / ticdup + counts) + netgame = true; + autostart = true; + } + else { + D_InitSinglePlayerGame(&settings); + } - NetUpdate(); - lowtic = INT_MAX; - - for (i = 0; i < doomcom->numnodes; i++) - if (nodeingame[i] && nettics[i] < lowtic) - lowtic = nettics[i]; + LoadGameSettings(&settings, &connect_data); +} - if (lowtic < gametic / ticdup) - I_Error("TryRunTics: lowtic < gametic"); +//========================================================================== +// +// NET_SendFrags +// +//========================================================================== - // don't stay in here forever -- give the menu a chance to work - if (I_GetTime() / ticdup - entertic >= 20) - { - MN_Ticker(); - return; - } +void NET_SendFrags(player_t * player) +{ + // Not sure what this is intended for. Unused? +} - // Don't hog the CPU - I_Sleep(1); - } +// TODO: This is a temporary hack! -// -// run the count * ticdup dics -// - while (counts--) - { - for (i = 0; i < ticdup; i++) - { - if (gametic / ticdup > lowtic) - I_Error("gametic>lowtic"); - if (advancedemo) - H2_DoAdvanceDemo(); - MN_Ticker(); - G_Ticker(); - gametic++; - // - // modify command for duplicated tics - // - if (i != ticdup - 1) - { - ticcmd_t *cmd; - int buf; - int j; - - buf = (gametic / ticdup) % BACKUPTICS; - for (j = 0; j < MAXPLAYERS; j++) - { - cmd = &netcmds[j][buf]; - cmd->chatchar = 0; - if (cmd->buttons & BT_SPECIAL) - cmd->buttons = 0; - } - } - } - NetUpdate(); // check for new console commands - } +void DEH_Checksum(md5_digest_t digest) +{ + memset(digest, 0, sizeof(digest)); } diff --git a/src/hexen/g_game.c b/src/hexen/g_game.c index b83a439b..1560c05f 100644 --- a/src/hexen/g_game.c +++ b/src/hexen/g_game.c @@ -109,7 +109,8 @@ boolean singledemo; // quit after playing a demo from cmdline boolean precache = true; // if true, load all graphics at start -short consistancy[MAXPLAYERS][BACKUPTICS]; +// TODO: Hexen uses 16-bit shorts for consistancy? +byte consistancy[MAXPLAYERS][BACKUPTICS]; int mouseSensitivity = 5; @@ -195,9 +196,8 @@ extern int curpos; extern int inv_ptr; boolean usearti = true; -void I_ReadCyberCmd(ticcmd_t * cmd); -void G_BuildTiccmd(ticcmd_t * cmd) +void G_BuildTiccmd(ticcmd_t *cmd, int maketic) { int i; boolean strafe, bstrafe; @@ -888,7 +888,7 @@ void G_Ticker(void) { cmd = &players[i].cmd; - memcpy(cmd, &netcmds[i][buf], sizeof(ticcmd_t)); + memcpy(cmd, &netcmds[i], sizeof(ticcmd_t)); if (demoplayback) G_ReadDemoTiccmd(cmd); diff --git a/src/hexen/h2_main.c b/src/hexen/h2_main.c index 20720e4e..d66e27e1 100644 --- a/src/hexen/h2_main.c +++ b/src/hexen/h2_main.c @@ -31,6 +31,7 @@ #include <time.h> #include "config.h" +#include "doomfeatures.h" #include "h2def.h" #include "ct_chat.h" @@ -44,6 +45,7 @@ #include "m_argv.h" #include "m_config.h" #include "m_controls.h" +#include "net_client.h" #include "p_local.h" #include "v_video.h" #include "w_main.h" @@ -66,7 +68,6 @@ typedef struct void R_ExecuteSetViewSize(void); void D_CheckNetGame(void); -void G_BuildTiccmd(ticcmd_t * cmd); void F_Drawer(void); boolean F_Responder(event_t * ev); void I_StartupKeyboard(void); @@ -314,6 +315,11 @@ void D_DoomMain(void) ST_Message("MN_Init: Init menu system.\n"); MN_Init(); +#ifdef FEATURE_MULTIPLAYER + ST_Message("NET_Init: Init networking subsystem.\n"); + NET_Init(); +#endif + ST_Message("CT_Init: Init chat mode data.\n"); CT_Init(); @@ -350,20 +356,21 @@ void D_DoomMain(void) // MAPINFO.TXT script must be already processed. WarpCheck(); + ST_Message("SB_Init: Loading patches.\n"); + SB_Init(); + + ST_Done(); + + // Netgame start must be here, after the splash screen has finished. + ST_Message("D_CheckNetGame: Checking network game status.\n"); + D_CheckNetGame(); + if (autostart) { ST_Message("Warp to Map %d (\"%s\":%d), Skill %d\n", WarpMap, P_GetMapName(startmap), startmap, startskill + 1); } - ST_Message("D_CheckNetGame: Checking network game status.\n"); - D_CheckNetGame(); - - ST_Message("SB_Init: Loading patches.\n"); - SB_Init(); - - ST_Done(); - CheckRecordFrom(); p = M_CheckParm("-record"); @@ -566,24 +573,8 @@ void H2_GameLoop(void) I_StartFrame(); // Process one or more tics - if (singletics) - { - I_StartTic(); - H2_ProcessEvents(); - G_BuildTiccmd(&netcmds[consoleplayer][maketic % BACKUPTICS]); - if (advancedemo) - { - H2_DoAdvanceDemo(); - } - G_Ticker(); - gametic++; - maketic++; - } - else - { - // Will run at least one tic - TryRunTics(); - } + // Will run at least one tic + TryRunTics(); // Move positional sounds S_UpdateSounds(players[displayplayer].mo); @@ -887,4 +878,3 @@ static void CreateSavePath(void) { M_MakeDirectory(SavePath); } - diff --git a/src/hexen/h2def.h b/src/hexen/h2def.h index faa2d3f8..644c19e8 100644 --- a/src/hexen/h2def.h +++ b/src/hexen/h2def.h @@ -53,6 +53,9 @@ #include "tables.h" +#include "d_loop.h" +#include "net_defs.h" + #define HEXEN_VERSION 110 #define HEXEN_VERSION_TEXT "v1.1" @@ -95,7 +98,6 @@ */ //#define NUMARTIFCTS 28 -#define MAXPLAYERS 8 #define BT_ATTACK 1 #define BT_USE 2 @@ -575,59 +577,6 @@ typedef struct player_s #define CF_GODMODE 2 #define CF_NOMOMENTUM 4 // not really a cheat, just a debug aid - -#define BACKUPTICS 12 - -typedef struct -{ - unsigned checksum; // high bit is retransmit request - byte retransmitfrom; // only valid if NCMD_RETRANSMIT - byte starttic; - byte player, numtics; - ticcmd_t cmds[BACKUPTICS]; -} doomdata_t; - -typedef struct -{ - int id; - short intnum; // DOOM executes an int to execute commands - -// communication between DOOM and the driver - short command; // CMD_SEND or CMD_GET - short remotenode; // dest for send, set by get (-1 = no packet) - short datalength; // bytes in doomdata to be sent - -// info common to all nodes - short numnodes; // console is allways node 0 - short ticdup; // 1 = no duplication, 2-5 = dup for slow nets - short extratics; // 1 = send a backup tic in every packet - short deathmatch; // 1 = deathmatch - short savegame; // -1 = new game, 0-5 = load savegame - short episode; // 1-3 - short map; // 1-9 - short skill; // 1-5 - -// info specific to this node - short consoleplayer; - short numplayers; - short angleoffset; // 1 = left, 0 = center, -1 = right - short drone; // 1 = drone - -// packet data to be sent - doomdata_t data; -} doomcom_t; - -#define DOOMCOM_ID 0x12345678l - -extern doomcom_t *doomcom; -extern doomdata_t *netbuffer; // points inside doomcom - -#define MAXNETNODES 16 // max computers in a game - -#define CMD_SEND 1 -#define CMD_GET 2 -#define CMD_FRAG 3 - #define SBARHEIGHT 39 // status bar height at bottom of screen void NET_SendFrags(player_t * player); @@ -705,15 +654,9 @@ extern int prevmap; extern int levelstarttic; // gametic at level start extern int leveltime; // tics in game play for par -extern ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS]; -extern int ticdup; - -//#define MAXNETNODES 8 +extern ticcmd_t *netcmds; -extern ticcmd_t localcmds[BACKUPTICS]; extern int rndindex; -extern int gametic, maketic; -extern int nettics[MAXNETNODES]; #define MAXDEATHMATCHSTARTS 16 extern mapthing_t *deathmatch_p; diff --git a/src/net_client.c b/src/net_client.c index ffc9b49b..e84eb47c 100644 --- a/src/net_client.c +++ b/src/net_client.c @@ -984,6 +984,7 @@ boolean NET_CL_Connect(net_addr_t *addr, net_connect_data_t *data) server_addr = addr; + // TODO: Move into net_connect_data_t // Read checksums of our WAD directory and dehacked information W_Checksum(net_local_wad_md5sum); @@ -1146,4 +1147,3 @@ void NET_BindVariables(void) { M_BindVariable("player_name", &net_player_name); } - diff --git a/src/net_defs.h b/src/net_defs.h index 1fa9a9af..0d2516b6 100644 --- a/src/net_defs.h +++ b/src/net_defs.h @@ -145,8 +145,7 @@ typedef struct int lowres_turn; int drone; // TODO: is_freedoom in here? WAD/DEH checksums? - // TODO: [Hexen] Requested player class - + int player_class; } net_connect_data_t; // Game settings sent by client to server when initiating game start, @@ -175,7 +174,9 @@ typedef struct int num_players; int consoleplayer; - // TODO: [Hexen] Array of player classes, one for each player. + // Hexen player classes: + + int player_classes[MAXPLAYERS]; } net_gamesettings_t; @@ -218,4 +219,3 @@ typedef struct } net_querydata_t; #endif /* #ifndef NET_DEFS_H */ - diff --git a/src/net_server.c b/src/net_server.c index 24a50bd0..4d6d96fd 100644 --- a/src/net_server.c +++ b/src/net_server.c @@ -106,6 +106,10 @@ typedef struct unsigned int is_freedoom; + // Player class (for Hexen) + + int player_class; + } net_client_t; // structure used for the recv window @@ -640,6 +644,7 @@ static void NET_SV_ParseSYN(net_packet_t *packet, client->recording_lowres = data.lowres_turn; client->drone = data.drone; + client->player_class = data.player_class; } if (client->connection.state == NET_CONN_STATE_WAITING_ACK) @@ -704,6 +709,20 @@ static void NET_SV_ParseGameStart(net_packet_t *packet, net_client_t *client) settings.num_players = NET_SV_NumPlayers(); + // Copy player classes: + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (sv_players[i] != NULL) + { + settings.player_classes[i] = sv_players[i]->player_class; + } + else + { + settings.player_classes[i] = 0; + } + } + nowtime = I_GetTimeMS(); // Send start packets to each connected node @@ -1716,4 +1735,3 @@ void NET_SV_Shutdown(void) I_Sleep(1); } } - diff --git a/src/net_structrw.c b/src/net_structrw.c index 7ed61c24..6e748b6b 100644 --- a/src/net_structrw.c +++ b/src/net_structrw.c @@ -37,6 +37,7 @@ void NET_WriteConnectData(net_packet_t *packet, net_connect_data_t *data) NET_WriteInt8(packet, data->gamemission); NET_WriteInt8(packet, data->lowres_turn); NET_WriteInt8(packet, data->drone); + NET_WriteInt8(packet, data->player_class); } boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data) @@ -44,11 +45,14 @@ boolean NET_ReadConnectData(net_packet_t *packet, net_connect_data_t *data) return NET_ReadInt8(packet, (unsigned int *) &data->gamemode) && NET_ReadInt8(packet, (unsigned int *) &data->gamemission) && NET_ReadInt8(packet, (unsigned int *) &data->lowres_turn) - && NET_ReadInt8(packet, (unsigned int *) &data->drone); + && NET_ReadInt8(packet, (unsigned int *) &data->drone) + && NET_ReadInt8(packet, (unsigned int *) &data->player_class); } void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings) { + int i; + NET_WriteInt8(packet, settings->ticdup); NET_WriteInt8(packet, settings->extratics); NET_WriteInt8(packet, settings->deathmatch); @@ -65,26 +69,50 @@ void NET_WriteSettings(net_packet_t *packet, net_gamesettings_t *settings) NET_WriteInt8(packet, settings->loadgame); NET_WriteInt8(packet, settings->num_players); NET_WriteInt8(packet, settings->consoleplayer); + + for (i = 0; i < settings->num_players; ++i) + { + NET_WriteInt8(packet, settings->player_classes[i]); + } } boolean NET_ReadSettings(net_packet_t *packet, net_gamesettings_t *settings) { - return NET_ReadInt8(packet, (unsigned int *) &settings->ticdup) - && NET_ReadInt8(packet, (unsigned int *) &settings->extratics) - && NET_ReadInt8(packet, (unsigned int *) &settings->deathmatch) - && NET_ReadInt8(packet, (unsigned int *) &settings->nomonsters) - && NET_ReadInt8(packet, (unsigned int *) &settings->fast_monsters) - && NET_ReadInt8(packet, (unsigned int *) &settings->respawn_monsters) - && NET_ReadInt8(packet, (unsigned int *) &settings->episode) - && NET_ReadInt8(packet, (unsigned int *) &settings->map) - && NET_ReadSInt8(packet, &settings->skill) - && NET_ReadInt8(packet, (unsigned int *) &settings->gameversion) - && NET_ReadInt8(packet, (unsigned int *) &settings->lowres_turn) - && NET_ReadInt8(packet, (unsigned int *) &settings->new_sync) - && NET_ReadInt32(packet, (unsigned int *) &settings->timelimit) - && NET_ReadSInt8(packet, (signed int *) &settings->loadgame) - && NET_ReadInt8(packet, (unsigned int *) &settings->num_players) - && NET_ReadSInt8(packet, (signed int *) &settings->consoleplayer); + boolean success; + int i; + + success = NET_ReadInt8(packet, (unsigned int *) &settings->ticdup) + && NET_ReadInt8(packet, (unsigned int *) &settings->extratics) + && NET_ReadInt8(packet, (unsigned int *) &settings->deathmatch) + && NET_ReadInt8(packet, (unsigned int *) &settings->nomonsters) + && NET_ReadInt8(packet, (unsigned int *) &settings->fast_monsters) + && NET_ReadInt8(packet, (unsigned int *) &settings->respawn_monsters) + && NET_ReadInt8(packet, (unsigned int *) &settings->episode) + && NET_ReadInt8(packet, (unsigned int *) &settings->map) + && NET_ReadSInt8(packet, &settings->skill) + && NET_ReadInt8(packet, (unsigned int *) &settings->gameversion) + && NET_ReadInt8(packet, (unsigned int *) &settings->lowres_turn) + && NET_ReadInt8(packet, (unsigned int *) &settings->new_sync) + && NET_ReadInt32(packet, (unsigned int *) &settings->timelimit) + && NET_ReadSInt8(packet, (signed int *) &settings->loadgame) + && NET_ReadInt8(packet, (unsigned int *) &settings->num_players) + && NET_ReadSInt8(packet, (signed int *) &settings->consoleplayer); + + if (!success) + { + return false; + } + + for (i = 0; i < settings->num_players; ++i) + { + if (!NET_ReadInt8(packet, + (unsigned int *) &settings->player_classes[i])) + { + return false; + } + } + + return true; } boolean NET_ReadQueryData(net_packet_t *packet, net_querydata_t *query) @@ -426,4 +454,3 @@ void NET_SafePuts(char *s) putchar('\n'); } - |