3 // This version has the fixed ticdup code
7 #define NCMD_EXIT 0x80000000
8 #define NCMD_RETRANSMIT 0x40000000
9 #define NCMD_SETUP 0x20000000
10 #define NCMD_KILL 0x10000000 // kill game
11 #define NCMD_CHECKSUM 0x0fffffff
15 doomdata_t *netbuffer; // points inside doomcom
19 ==============================================================================
23 gametic is the tic about to (or currently being) run
24 maketic is the tick that hasn't had control made for it yet
25 nettics[] has the maketics for all players
27 a gametic cannot be run until nettics[] > gametic for all players
29 ==============================================================================
32 #define RESENDCOUNT 10
33 #define PL_DRONE 0x80 // bit flag in doomdata->player
35 ticcmd_t localcmds[BACKUPTICS];
37 ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
38 int nettics[MAXNETNODES];
39 boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
40 boolean remoteresend[MAXNETNODES]; // set when local needs tics
41 int resendto[MAXNETNODES]; // set when remote needs tics
42 int resendcount[MAXNETNODES];
44 int nodeforplayer[MAXPLAYERS];
47 int lastnettic, skiptics;
49 int maxsend; // BACKUPTICS/(2*ticdup)-1
51 void D_ProcessEvents (void);
52 void G_BuildTiccmd (ticcmd_t *cmd);
53 void D_DoAdvanceDemo (void);
55 boolean reboundpacket;
56 doomdata_t reboundstore;
59 int NetbufferSize (void)
61 return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
64 unsigned NetbufferChecksum (void)
71 #if defined(NeXT) || defined(NORMALUNIX)
72 return 0; // byte order problems
75 l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
77 c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
79 return c & NCMD_CHECKSUM;
82 int ExpandTics (int low)
86 delta = low - (maketic&0xff);
88 if (delta >= -64 && delta <= 64)
89 return (maketic&~0xff) + low;
91 return (maketic&~0xff) - 256 + low;
93 return (maketic&~0xff) + 256 + low;
95 I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
100 //============================================================================
111 void HSendPacket (int node, int flags)
113 netbuffer->checksum = NetbufferChecksum () | flags;
117 reboundstore = *netbuffer;
118 reboundpacket = true;
126 I_Error ("Tried to transmit to another node");
128 doomcom->command = CMD_SEND;
129 doomcom->remotenode = node;
130 doomcom->datalength = NetbufferSize ();
136 if (netbuffer->checksum & NCMD_RETRANSMIT)
137 realretrans = ExpandTics (netbuffer->retransmitfrom);
140 fprintf (debugfile,"send (%i + %i, R %i) [%i] "
141 ,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
142 for (i=0 ; i<doomcom->datalength ; i++)
143 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
144 fprintf (debugfile,"\n");
155 = Returns false if no packet is waiting
160 boolean HGetPacket (void)
164 *netbuffer = reboundstore;
165 doomcom->remotenode = 0;
166 reboundpacket = false;
175 doomcom->command = CMD_GET;
177 if (doomcom->remotenode == -1)
180 if (doomcom->datalength != NetbufferSize ())
183 fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
187 if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
190 fprintf (debugfile,"bad packet checksum\n");
199 if (netbuffer->checksum & NCMD_SETUP)
200 fprintf (debugfile,"setup packet\n");
203 if (netbuffer->checksum & NCMD_RETRANSMIT)
204 realretrans = ExpandTics (netbuffer->retransmitfrom);
207 fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
208 ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
209 for (i=0 ; i<doomcom->datalength ; i++)
210 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
211 fprintf (debugfile,"\n");
228 void GetPackets (void)
232 ticcmd_t *src, *dest;
236 while (HGetPacket ())
238 if (netbuffer->checksum & NCMD_SETUP)
239 continue; // extra setup packet
241 netconsole = netbuffer->player & ~PL_DRONE;
242 netnode = doomcom->remotenode;
244 // to save bytes, only the low byte of tic numbers are sent
245 // Figure out what the rest of the bytes are
247 realstart = ExpandTics (netbuffer->starttic);
248 realend = (realstart+netbuffer->numtics);
251 // check for exiting the game
253 if (netbuffer->checksum & NCMD_EXIT)
255 if (!nodeingame[netnode])
257 nodeingame[netnode] = false;
258 playeringame[netconsole] = false;
259 strcpy (exitmsg, "PLAYER 1 LEFT THE GAME");
260 exitmsg[7] += netconsole;
261 players[consoleplayer].message = exitmsg;
262 // if (demorecording)
263 // G_CheckDemoStatus ();
268 // check for a remote game kill
270 if (netbuffer->checksum & NCMD_KILL)
271 I_Error ("Killed by network driver");
273 nodeforplayer[netconsole] = netnode;
276 // check for retransmit request
278 if ( resendcount[netnode] <= 0
279 && (netbuffer->checksum & NCMD_RETRANSMIT) )
281 resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
283 fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
284 resendcount[netnode] = RESENDCOUNT;
287 resendcount[netnode]--;
290 // check for out of order / duplicated packet
292 if (realend == nettics[netnode])
295 if (realend < nettics[netnode])
298 fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
303 // check for a missed packet
305 if (realstart > nettics[netnode])
307 // stop processing until the other system resends the missed tics
309 fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
310 remoteresend[netnode] = true;
315 // update command store from the packet
320 remoteresend[netnode] = false;
322 start = nettics[netnode] - realstart;
323 src = &netbuffer->cmds[start];
325 while (nettics[netnode] < realend)
327 dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
342 = Builds ticcmds for console player
349 void NetUpdate (void)
360 nowtime = I_GetTime ()/ticdup;
361 newtics = nowtime - gametime;
364 if (newtics <= 0) // nothing new to update
367 if (skiptics <= newtics)
379 netbuffer->player = consoleplayer;
382 // build new ticcmds for console player
384 gameticdiv = gametic/ticdup;
385 for (i=0 ; i<newtics ; i++)
389 if (maketic - gameticdiv >= BACKUPTICS/2-1)
390 break; // can't hold any more
391 //printf ("mk:%i ",maketic);
392 G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
398 return; // singletic update is syncronous
401 // send the packet to the other nodes
403 for (i=0 ; i<doomcom->numnodes ; i++)
406 netbuffer->starttic = realstart = resendto[i];
407 netbuffer->numtics = maketic - realstart;
408 if (netbuffer->numtics > BACKUPTICS)
409 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
411 resendto[i] = maketic - doomcom->extratics;
413 for (j=0 ; j< netbuffer->numtics ; j++)
415 localcmds[(realstart+j)%BACKUPTICS];
419 netbuffer->retransmitfrom = nettics[i];
420 HSendPacket (i, NCMD_RETRANSMIT);
424 netbuffer->retransmitfrom = 0;
430 // listen for other packets
439 =====================
443 =====================
446 void CheckAbort (void)
451 stoptic = I_GetTime () + 2;
452 while (I_GetTime() < stoptic)
456 for ( ; eventtail != eventhead
457 ; eventtail = (++eventtail)&(MAXEVENTS-1) )
459 ev = &events[eventtail];
460 if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
461 I_Error ("Network game synchronization aborted.");
466 =====================
468 = D_ArbitrateNetStart
470 =====================
473 void D_ArbitrateNetStart (void)
476 boolean gotinfo[MAXNETNODES];
479 memset (gotinfo,0,sizeof(gotinfo));
481 if (doomcom->consoleplayer)
482 { // listen for setup info from key player
483 // mprintf ("listening for network start info...\n");
489 if (netbuffer->checksum & NCMD_SETUP)
491 if (netbuffer->player != VERSION)
492 I_Error ("Different DOOM versions cannot play a net game!");
493 startskill = netbuffer->retransmitfrom & 15;
494 deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
495 nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
496 respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
497 //startmap = netbuffer->starttic & 0x3f;
498 //startepisode = netbuffer->starttic >> 6;
499 startmap = netbuffer->starttic&15;
500 startepisode = netbuffer->starttic>>4;
506 { // key player, send the setup info
507 // mprintf ("sending network start info...\n");
511 for (i=0 ; i<doomcom->numnodes ; i++)
513 netbuffer->retransmitfrom = startskill;
515 netbuffer->retransmitfrom |= (deathmatch<<6);
517 netbuffer->retransmitfrom |= 0x20;
519 netbuffer->retransmitfrom |= 0x10;
520 //netbuffer->starttic = startepisode * 64 + startmap;
521 netbuffer->starttic = (startepisode<<4)+startmap;
522 netbuffer->player = VERSION;
523 netbuffer->numtics = 0;
524 HSendPacket (i, NCMD_SETUP);
528 for(i = 10 ; i && HGetPacket(); --i)
530 if((netbuffer->player&0x7f) < MAXNETNODES)
531 gotinfo[netbuffer->player&0x7f] = true;
534 while (HGetPacket ())
536 gotinfo[netbuffer->player&0x7f] = true;
540 for (i=1 ; i<doomcom->numnodes ; i++)
543 } while (i < doomcom->numnodes);
552 = Works out player numbers among the net participants
556 extern int viewangleoffset;
558 void D_CheckNetGame (void)
562 for (i=0 ; i<MAXNETNODES ; i++)
564 nodeingame[i] = false;
566 remoteresend[i] = false; // set when local needs tics
567 resendto[i] = 0; // which tic to start sending
570 // I_InitNetwork sets doomcom and netgame
572 if (doomcom->id != DOOMCOM_ID)
573 I_Error ("Doomcom buffer invalid!");
574 netbuffer = &doomcom->data;
575 consoleplayer = displayplayer = doomcom->consoleplayer;
577 D_ArbitrateNetStart ();
578 //printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
580 // read values out of doomcom
581 ticdup = doomcom->ticdup;
582 maxsend = BACKUPTICS/(2*ticdup)-1;
586 for (i=0 ; i<doomcom->numplayers ; i++)
587 playeringame[i] = true;
588 for (i=0 ; i<doomcom->numnodes ; i++)
589 nodeingame[i] = true;
591 //printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
600 = Called before quitting to leave a net game without hanging the
606 void D_QuitNetGame (void)
613 if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
616 // send a bunch of packets for security
617 netbuffer->player = consoleplayer;
618 netbuffer->numtics = 0;
619 for (i=0 ; i<4 ; i++)
621 for (j=1 ; j<doomcom->numnodes ; j++)
623 HSendPacket (j, NCMD_EXIT);
638 int frametics[4], frameon;
641 extern boolean advancedemo;
643 void TryRunTics (void)
648 static int oldentertics;
649 int realtics, availabletics;
656 entertic = I_GetTime ()/ticdup;
657 realtics = entertic - oldentertics;
658 oldentertics = entertic;
661 // get available tics
667 for (i=0 ; i<doomcom->numnodes ; i++)
671 if (nettics[i] < lowtic)
674 availabletics = lowtic - gametic/ticdup;
678 // decide how many tics to run
680 if (realtics < availabletics-1)
682 else if (realtics < availabletics)
685 counts = availabletics;
692 fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
696 //=============================================================================
698 // ideally nettics[0] should be 1 - 3 tics above lowtic
699 // if we are consistantly slower, speed up time
701 for (i=0 ; i<MAXPLAYERS ; i++)
704 if (consoleplayer == i)
705 { // the key player does not adapt
709 if (nettics[0] <= nettics[nodeforplayer[i]])
714 frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
715 oldnettics = nettics[0];
716 if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
722 //=============================================================================
726 // wait for new tics if needed
728 while (lowtic < gametic/ticdup + counts)
734 for (i=0 ; i<doomcom->numnodes ; i++)
735 if (nodeingame[i] && nettics[i] < lowtic)
738 if (lowtic < gametic/ticdup)
739 I_Error ("TryRunTics: lowtic < gametic");
741 // don't stay in here forever -- give the menu a chance to work
742 if (I_GetTime ()/ticdup - entertic >= 20)
750 // run the count * ticdup dics
754 for (i=0 ; i<ticdup ; i++)
756 if (gametic/ticdup > lowtic)
757 I_Error ("gametic>lowtic");
764 // modify command for duplicated tics
772 buf = (gametic/ticdup)%BACKUPTICS;
773 for (j=0 ; j<MAXPLAYERS ; j++)
775 cmd = &netcmds[j][buf];
777 if (cmd->buttons & BT_SPECIAL)
782 NetUpdate (); // check for new console commands