123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- // 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 ; i<l ; i++)
- c += ((unsigned *)&netbuffer->retransmitfrom)[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 ; i<doomcom->datalength ; 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 ; i<doomcom->datalength ; 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 ; j<doomcom->ticdup ; 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<newtics ; i++)
- {
- I_StartTic ();
- D_ProcessEvents ();
- if (maketic - gameticdiv >= 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 ; i<doomcom->numnodes ; 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 ; i<doomcom->numnodes ; 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 ; i<doomcom->numnodes ; 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 ; 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
- }
-
- // 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;
- 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 ; i<doomcom->numplayers ; i++)
- playeringame[i] = true;
- for (i=0 ; i<doomcom->numnodes ; 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 ; j<doomcom->numnodes ; 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 ; i<doomcom->numnodes ; 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<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 ("+");
- }
- }
- //=============================================================================
- //
- // wait for new tics if needed
- //
- while (lowtic < gametic + counts)
- {
- NetUpdate ();
- lowtic = MAXINT;
-
- for (i=0 ; i<doomcom->numnodes ; 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++;
- }
- }
|