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)
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 S_StartSound(NULL, sfx_chat);
261 exitmsg[7] += netconsole;
262 //players[consoleplayer].message = exitmsg;
263 P_SetMessage(&players[consoleplayer], exitmsg, true);
264 /* if (demorecording)
265 G_CheckDemoStatus ();
271 // check for a remote game kill
273 if (netbuffer->checksum & NCMD_KILL)
274 I_Error ("Killed by network driver");
276 nodeforplayer[netconsole] = netnode;
279 // check for retransmit request
281 if ( resendcount[netnode] <= 0
282 && (netbuffer->checksum & NCMD_RETRANSMIT) )
284 resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
286 fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
287 resendcount[netnode] = RESENDCOUNT;
290 resendcount[netnode]--;
293 // check for out of order / duplicated packet
295 if (realend == nettics[netnode])
298 if (realend < nettics[netnode])
301 fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
306 // check for a missed packet
308 if (realstart > nettics[netnode])
310 // stop processing until the other system resends the missed tics
312 fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, realstart, nettics[netnode]);
313 remoteresend[netnode] = true;
318 // update command store from the packet
323 remoteresend[netnode] = false;
325 start = nettics[netnode] - realstart;
326 src = &netbuffer->cmds[start];
328 while (nettics[netnode] < realend)
330 dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
345 = Builds ticcmds for console player
352 void NetUpdate (void)
363 nowtime = I_GetTime ()/ticdup;
364 newtics = nowtime - gametime;
367 if (newtics <= 0) // nothing new to update
370 if (skiptics <= newtics)
382 netbuffer->player = consoleplayer;
385 // build new ticcmds for console player
387 gameticdiv = gametic/ticdup;
388 for (i=0 ; i<newtics ; i++)
392 if (maketic - gameticdiv >= BACKUPTICS/2-1)
393 break; // can't hold any more
394 //printf ("mk:%i ",maketic);
395 G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
401 return; // singletic update is syncronous
404 // send the packet to the other nodes
406 for (i=0 ; i<doomcom->numnodes ; i++)
409 netbuffer->starttic = realstart = resendto[i];
410 netbuffer->numtics = maketic - realstart;
411 if (netbuffer->numtics > BACKUPTICS)
412 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
414 resendto[i] = maketic - doomcom->extratics;
417 for (j=0 ; j< netbuffer->numtics ; j++)
419 localcmds[(realstart+j)%BACKUPTICS];
423 netbuffer->retransmitfrom = nettics[i];
424 HSendPacket (i, NCMD_RETRANSMIT);
428 netbuffer->retransmitfrom = 0;
434 // listen for other packets
443 =====================
447 =====================
450 void CheckAbort (void)
455 stoptic = I_GetTime () + 2;
456 while (I_GetTime() < stoptic)
460 for ( ; eventtail != eventhead
461 ; eventtail = (++eventtail)&(MAXEVENTS-1) )
463 ev = &events[eventtail];
464 if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
465 I_Error ("Network game synchronization aborted.");
470 =====================
472 = D_ArbitrateNetStart
474 =====================
477 void D_ArbitrateNetStart (void)
480 boolean gotinfo[MAXNETNODES];
483 memset (gotinfo,0,sizeof(gotinfo));
485 if (doomcom->consoleplayer)
486 { // listen for setup info from key player
492 if (netbuffer->checksum & NCMD_SETUP)
494 if (netbuffer->player != VERSION)
495 I_Error ("Different DOOM versions cannot play a net game!");
496 startskill = netbuffer->retransmitfrom & 15;
497 deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
498 nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
499 respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
500 startmap = netbuffer->starttic & 0x3f;
501 startepisode = netbuffer->starttic >> 6;
507 { // key player, send the setup info
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->player = VERSION;
522 netbuffer->numtics = 0;
523 HSendPacket (i, NCMD_SETUP);
527 for(i = 10 ; i && HGetPacket(); --i)
529 if((netbuffer->player&0x7f) < MAXNETNODES)
530 gotinfo[netbuffer->player&0x7f] = true;
533 while (HGetPacket ())
535 gotinfo[netbuffer->player&0x7f] = true;
539 for (i=1 ; i<doomcom->numnodes ; i++)
542 } while (i < doomcom->numnodes);
551 = Works out player numbers among the net participants
555 extern int viewangleoffset;
557 void D_CheckNetGame (void)
561 for (i=0 ; i<MAXNETNODES ; i++)
563 nodeingame[i] = false;
565 remoteresend[i] = false; // set when local needs tics
566 resendto[i] = 0; // which tic to start sending
569 // I_InitNetwork sets doomcom and netgame
571 if (doomcom->id != DOOMCOM_ID)
572 I_Error ("Doomcom buffer invalid!");
573 netbuffer = &doomcom->data;
574 consoleplayer = displayplayer = doomcom->consoleplayer;
576 D_ArbitrateNetStart ();
577 //printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
579 // read values out of doomcom
580 ticdup = doomcom->ticdup;
581 maxsend = BACKUPTICS/2-1;
585 for (i=0 ; i<doomcom->numplayers ; i++)
586 playeringame[i] = true;
587 for (i=0 ; i<doomcom->numnodes ; i++)
588 nodeingame[i] = true;
590 //printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
599 = Called before quitting to leave a net game without hanging the
605 void D_QuitNetGame (void)
612 if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
615 // send a bunch of packets for security
616 netbuffer->player = consoleplayer;
617 netbuffer->numtics = 0;
618 for (i=0 ; i<4 ; i++)
620 for (j=1 ; j<doomcom->numnodes ; j++)
622 HSendPacket (j, NCMD_EXIT);
637 int frametics[4], frameon;
640 extern boolean advancedemo;
642 void TryRunTics (void)
647 static int oldentertics;
648 int realtics, availabletics;
655 entertic = I_GetTime ()/ticdup;
656 realtics = entertic - oldentertics;
657 oldentertics = entertic;
660 // get available tics
666 for (i=0 ; i<doomcom->numnodes ; i++)
670 if (nettics[i] < lowtic)
673 availabletics = lowtic - gametic/ticdup;
677 // decide how many tics to run
679 if (realtics < availabletics-1)
681 else if (realtics < availabletics)
684 counts = availabletics;
691 fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
695 //=============================================================================
697 // ideally nettics[0] should be 1 - 3 tics above lowtic
698 // if we are consistantly slower, speed up time
700 for (i=0 ; i<MAXPLAYERS ; i++)
703 if (consoleplayer == i)
704 { // the key player does not adapt
708 if (nettics[0] <= nettics[nodeforplayer[i]])
713 frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
714 oldnettics = nettics[0];
715 if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
721 //=============================================================================
725 // wait for new tics if needed
727 while (lowtic < gametic/ticdup + counts)
733 for (i=0 ; i<doomcom->numnodes ; i++)
734 if (nodeingame[i] && nettics[i] < lowtic)
737 if (lowtic < gametic/ticdup)
738 I_Error ("TryRunTics: lowtic < gametic");
740 // don't stay in here forever -- give the menu a chance to work
741 if (I_GetTime ()/ticdup - entertic >= 20)
749 // run the count * ticdup dics
753 for (i=0 ; i<ticdup ; i++)
755 if (gametic/ticdup > lowtic)
756 I_Error ("gametic>lowtic");
763 // modify command for duplicated tics
771 buf = (gametic/ticdup)%BACKUPTICS;
772 for (j=0 ; j<MAXPLAYERS ; j++)
774 cmd = &netcmds[j][buf];
776 if (cmd->buttons & BT_SPECIAL)
781 NetUpdate (); // check for new console commands