From 0df2cb80cf03d7259746834220d209b306a8c503 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 4 Sep 2008 23:15:36 +0000 Subject: Add GPLed Heretic/Hexen source. Subversion-branch: /branches/raven-branch Subversion-revision: 1195 --- src/hexen/oldd_net.c | 790 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 790 insertions(+) create mode 100644 src/hexen/oldd_net.c (limited to 'src/hexen/oldd_net.c') diff --git a/src/hexen/oldd_net.c b/src/hexen/oldd_net.c new file mode 100644 index 00000000..73bba9c1 --- /dev/null +++ b/src/hexen/oldd_net.c @@ -0,0 +1,790 @@ +// I_pcnet.m + +#include "DoomDef.h" + +#define NCMD_EXIT 0x80000000 +#define NCMD_RETRANSMIT 0x40000000 +#define NCMD_SETUP 0x20000000 +#define NCMD_CHECKSUM 0x0fffffff + +/* +if more space needs to be crunched out of the protocol... + +1 drone +2 player +8 tic +5 numtics + +#define NCMD_EXIT 0x80000000 +#define NCMD_RETRANSMIT 0x40000000 // a retransmit will have 0 tics +#define NCMD_DRONE 0x20000000 +#define NCMD_PLAYER 0x18000000 +#define NCMD_PLAYERSHIFT 27 +#define NCMD_TIC 0x00ff0000 +#define NCMD_TICSHIFT 16 +#define NCMD_NUMTICS 0x0000ff00 +#define NCMD_NUMTICSSHIFT 8 +#define NCMD_CHECKSUM 0x000000ff + +*/ + + + + + +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]; + +int nodeforplayer[MAXPLAYERS]; + +int gametime; +int maketic; +int lastnettic, skiptics; +int ticdup; + +void D_ProcessEvents (void); +void G_BuildTiccmd (ticcmd_t *cmd); +void D_DoAdvanceDemo (void); + +boolean reboundpacket; +doomdata_t reboundstore; + + +int NetbufferSize (void) +{ + return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]); +} + +unsigned NetbufferChecksum (void) +{ + unsigned c; + int i,l; + + c = 0x1234567; + +#ifdef NeXT + return 0; // byte order problems +#endif + + l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4; + for (i=0 ; iretransmitfrom)[i] * (i+1); + + return c & NCMD_CHECKSUM; +} + +int ExpandTics (int low) +{ + int delta; + + delta = low - (maketic&0xff); + + 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; + + I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic); + return 0; +} + + +//============================================================================ + + +/* +============== += += HSendPacket += +============== +*/ + +void HSendPacket (int node, int flags) +{ + netbuffer->checksum = NetbufferChecksum () | flags; + + if (!node) + { + reboundstore = *netbuffer; + reboundpacket = true; + 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 ; idatalength ; i++) + fprintf (debugfile,"%i ",((byte *)netbuffer)[i]); + fprintf (debugfile,"\n"); +} + + I_NetCmd (); +} + +/* +============== += += HGetPacket += += Returns false if no packet is waiting += +============== +*/ + +boolean HGetPacket (void) +{ + if (reboundpacket) + { + *netbuffer = reboundstore; + doomcom->remotenode = 0; + reboundpacket = false; + return true; + } + + if (!netgame) + return false; + + doomcom->command = CMD_GET; + I_NetCmd (); + if (doomcom->remotenode == -1) + return false; + + if (doomcom->datalength != NetbufferSize ()) + { + 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 (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 ; idatalength ; i++) + fprintf (debugfile,"%i ",((byte *)netbuffer)[i]); + fprintf (debugfile,"\n"); + } +} + return true; +} + + +/* +=================== += += GetPackets += +=================== +*/ + +char exitmsg[80]; + +void GetPackets (void) +{ + int netconsole; + int netnode; + int netdrone; + int j; + ticcmd_t *src, *dest; + int dupedstart, dupedend; + int skiptics; + int realstart; + + while (HGetPacket ()) + { + if (netbuffer->checksum & NCMD_SETUP) + continue; // extra setup packet + + netdrone = netbuffer->player & PL_DRONE; + 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); + dupedstart = realstart*doomcom->ticdup; + dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup; + + // + // check for exiting the game + // + if (netbuffer->checksum & NCMD_EXIT) + { + if (!nodeingame[netnode]) + continue; + nodeingame[netnode] = false; + if (!netdrone) + { + playeringame[netconsole] = false; + strcpy (exitmsg, "Player 1 left the game"); + exitmsg[7] += netconsole; + players[consoleplayer].message = exitmsg; + } + continue; + } + + // + // drone packets are just notifications + // + if (netdrone) + { + nettics[netnode] = dupedend; + continue; + } + + 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 (dupedend == nettics[netnode]) + continue; + + if (dupedend < nettics[netnode]) + { +if (debugfile) +fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics); + continue; + } + + // + // check for a missed packet + // + if (dupedstart > nettics[netnode]) + { + // stop processing until the other system resends the missed tics +if (debugfile) +fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]); + remoteresend[netnode] = true; + continue; + } + +// +// update command store from the packet +// + remoteresend[netnode] = false; + + skiptics = nettics[netnode]/doomcom->ticdup - realstart; + src = &netbuffer->cmds[skiptics]; + + while (nettics[netnode] < dupedend) + { + for (j=0 ; jticdup ; j++) + { + dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS]; + nettics[netnode]++; + *dest = *src; + src->chatchar = 0; + if (src->buttons & BT_SPECIAL) + src->buttons = 0; + } + src++; + } + } +} + +/* +============= += += NetUpdate += += Builds ticcmds for console player += sends out a packet +============= +*/ + +void NetUpdate (void) +{ + int nowtime; + int newtics; + int i,j; + int gameticdiv; + int realstart; + + if (singletics) + return; // singletic update is syncronous + +// +// check time +// + nowtime = I_GetTime ()/doomcom->ticdup; + newtics = nowtime - gametime; + gametime = nowtime; + if (newtics <= 0) // nothing new to update + goto listen; + + if (skiptics <= newtics) + { + newtics -= skiptics; + skiptics = 0; + } + else + { + skiptics -= newtics; + newtics = 0; + } + + + netbuffer->player = consoleplayer; + if (doomcom->drone) + netbuffer->player |= PL_DRONE; + +// +// drone packets +// + if (doomcom->drone) + { + I_StartTic (); + D_ProcessEvents (); + goto sendit; + } + +// +// build new ticcmds for console player +// + gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup; + for (i=0 ; i= BACKUPTICS/2 /* /doomcom->ticdup */- 1) + { + newtics = i; + break; // can't hold any more + } +//printf ("mk:%i ",maketic); + G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]); + maketic++; + } + +// +// send the packet to the other nodes +// +sendit: + for (i=0 ; inumnodes ; i++) + if (nodeingame[i]) + { + if (doomcom->drone) + { + netbuffer->starttic = realstart = maketic + BACKUPTICS/2; + netbuffer->numtics = 0; + } + else + { + netbuffer->starttic = realstart = resendto[i]; + netbuffer->numtics = maketic - realstart; + resendto[i] = maketic - doomcom->extratics; + } + + if (netbuffer->numtics > BACKUPTICS) + I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS"); + + for (j=0 ; j< netbuffer->numtics ; j++) + netbuffer->cmds[j] = + localcmds[(realstart+j)%BACKUPTICS]; + + if (remoteresend[i]) + { + netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup; + HSendPacket (i, NCMD_RETRANSMIT); + } + else + { + netbuffer->retransmitfrom = 0; + HSendPacket (i, 0); + } + } + +// +// listen for other packets +// +listen: + + GetPackets (); +} + + +/* +===================== += += CheckAbort += +===================== +*/ + +void CheckAbort (void) +{ + event_t *ev; + + I_WaitVBL(2); + + I_StartTic (); + for ( ; eventtail != eventhead + ; eventtail = (++eventtail)&(MAXEVENTS-1) ) + { + ev = &events[eventtail]; + if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE) + I_Error ("Network game synchronization aborted."); + } +} + +/* +===================== += += D_ArbitrateNetStart += +===================== +*/ + +void D_ArbitrateNetStart (void) +{ + int i; + boolean gotinfo[MAXNETNODES]; + + autostart = true; + memset (gotinfo,0,sizeof(gotinfo)); + + if (doomcom->consoleplayer) + { // listen for setup info from key player + printf ("listening for network start info...\n"); + while (1) + { + CheckAbort (); + if (!HGetPacket ()) + continue; + if (netbuffer->checksum & NCMD_SETUP) + { + if (netbuffer->player != VERSION) + I_Error ("Different DOOM versions cannot play a net game!"); + startskill = netbuffer->retransmitfrom & 15; + deathmatch = (netbuffer->retransmitfrom & 0x80) > 0; + nomonsters = (netbuffer->retransmitfrom & 0x40) > 0; + respawnparm = (netbuffer->retransmitfrom & 0x20) > 0; + startmap = netbuffer->starttic & 15; + startepisode = netbuffer->starttic >> 4; + return; + } + } + } + else + { // key player, send the setup info + printf ("sending network start info...\n"); + do + { + CheckAbort (); + for (i=0 ; inumnodes ; i++) + { + netbuffer->retransmitfrom = startskill; + if (deathmatch) + netbuffer->retransmitfrom |= 0x80; + if (nomonsters) + netbuffer->retransmitfrom |= 0x40; + if (respawnparm) + netbuffer->retransmitfrom |= 0x20; + netbuffer->starttic = startepisode * 16 + startmap; + netbuffer->player = VERSION; + netbuffer->numtics = 0; + HSendPacket (i, NCMD_SETUP); + } + + while (HGetPacket ()) + { + gotinfo[netbuffer->player&0x7f] = true; + } + + for (i=1 ; inumnodes ; i++) + if (!gotinfo[i]) + break; + } while (i < doomcom->numnodes); + } +} + +/* +=================== += += D_CheckNetGame += += Works out player numbers among the net participants +=================== +*/ + +extern int viewangleoffset; + +void D_CheckNetGame (void) +{ + int i; + + for (i=0 ; iid != DOOMCOM_ID) + I_Error ("Doomcom buffer invalid!"); + netbuffer = &doomcom->data; + consoleplayer = displayplayer = doomcom->consoleplayer; + if (netgame) + D_ArbitrateNetStart (); +printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode); + +// read values out of doomcom + ticdup = doomcom->ticdup; + + for (i=0 ; inumplayers ; i++) + playeringame[i] = true; + for (i=0 ; inumnodes ; i++) + nodeingame[i] = true; + +printf ("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) +{ + int i, j; + + if (debugfile) + fclose (debugfile); + + if (!netgame || !usergame || consoleplayer == -1) + return; + +// send a bunch of packets for security + netbuffer->player = consoleplayer; + if (doomcom->drone) + netbuffer->player |= PL_DRONE; + netbuffer->numtics = 0; + for (i=0 ; i<4 ; i++) + { + for (j=1 ; jnumnodes ; j++) + if (nodeingame[j]) + HSendPacket (j, NCMD_EXIT); + I_WaitVBL (1); + } +} + + + +/* +=============== += += TryRunTics += +=============== +*/ + +int frametics[4], frameon; +int frameskip[4]; +int oldnettics; +extern boolean advancedemo; + +void TryRunTics (void) +{ + int i; + int lowtic, nextlowest; + int entertic; + int static oldentertics; + int realtics, availabletics; + int counts; + int numplaying; + +// +// get real tics +// + entertic = I_GetTime (); + realtics = entertic - oldentertics; + oldentertics = entertic; + +// +// get available tics +// + NetUpdate (); + + lowtic = nextlowest = MAXINT; + numplaying = 0; + for (i=0 ; inumnodes ; i++) + if (nodeingame[i]) + { + numplaying++; + if (nettics[i] < lowtic) + { + nextlowest = lowtic; + lowtic = nettics[i]; + } + else if (nettics[i] < nextlowest) + nextlowest = nettics[i]; + } + availabletics = lowtic - gametic; + + +// +// 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; + + frameon++; + +if (debugfile) + fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts); + +//============================================================================= +// +// ideally nettics[0] should be 1 - 3 tics above lowtic +// if we are consistantly slower, speed up time +// drones should never hold up the other players +// + for (i=0 ; i nettics[nodeforplayer[i]]); + oldnettics = nettics[0]; + if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3]) + { + skiptics = 1; +// printf ("+"); + } + } +//============================================================================= + +// +// wait for new tics if needed +// + while (lowtic < gametic + counts) + { + + NetUpdate (); + lowtic = MAXINT; + + for (i=0 ; inumnodes ; i++) + if (nodeingame[i] && nettics[i] < lowtic) + lowtic = nettics[i]; + + if (lowtic < gametic) + I_Error ("TryRunTics: lowtic < gametic"); + + // don't stay in here forever -- give the menu a chance to work + if (I_GetTime () - entertic >= 20) + return; + } + + +// +// run the tics +// + while (counts--) + { + G_Ticker (); + NetUpdate (); // check for new console commands + gametic++; + } +} -- cgit v1.2.3