4 // Modified 12-21-94 by Chris Rhinehart for use with multiple ticdups
5 // actually, it wasn't modified, but rather we are currently using this
6 // older version of D_NET.C, since the new one doesn't seem to work with
7 // ticdup set to greater than one.
13 #define NCMD_EXIT 0x80000000
14 #define NCMD_RETRANSMIT 0x40000000
15 #define NCMD_SETUP 0x20000000
16 #define NCMD_CHECKSUM 0x0fffffff
19 if more space needs to be crunched out of the protocol...
26 #define NCMD_EXIT 0x80000000
27 #define NCMD_RETRANSMIT 0x40000000 // a retransmit will have 0 tics
28 #define NCMD_DRONE 0x20000000
29 #define NCMD_PLAYER 0x18000000
30 #define NCMD_PLAYERSHIFT 27
31 #define NCMD_TIC 0x00ff0000
32 #define NCMD_TICSHIFT 16
33 #define NCMD_NUMTICS 0x0000ff00
34 #define NCMD_NUMTICSSHIFT 8
35 #define NCMD_CHECKSUM 0x000000ff
44 doomdata_t *netbuffer; // points inside doomcom
48 ==============================================================================
52 gametic is the tic about to (or currently being) run
53 maketic is the tick that hasn't had control made for it yet
54 nettics[] has the maketics for all players
56 a gametic cannot be run until nettics[] > gametic for all players
58 ==============================================================================
61 #define RESENDCOUNT 10
62 #define PL_DRONE 0x80 // bit flag in doomdata->player
64 ticcmd_t localcmds[BACKUPTICS];
66 ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
67 int nettics[MAXNETNODES];
68 boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
69 boolean remoteresend[MAXNETNODES]; // set when local needs tics
70 int resendto[MAXNETNODES]; // set when remote needs tics
71 int resendcount[MAXNETNODES];
73 int nodeforplayer[MAXPLAYERS];
77 int lastnettic, skiptics;
80 void D_ProcessEvents (void);
81 void G_BuildTiccmd (ticcmd_t *cmd);
82 void D_DoAdvanceDemo (void);
84 boolean reboundpacket;
85 doomdata_t reboundstore;
88 int NetbufferSize (void)
90 return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
93 unsigned NetbufferChecksum (void)
100 l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
101 for (i=0 ; i<l ; i++)
102 c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
104 return c & NCMD_CHECKSUM;
107 int ExpandTics (int low)
111 delta = low - (maketic&0xff);
113 if (delta >= -64 && delta <= 64)
114 return (maketic&~0xff) + low;
116 return (maketic&~0xff) - 256 + low;
118 return (maketic&~0xff) + 256 + low;
120 I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
125 //============================================================================
136 void HSendPacket (int node, int flags)
138 netbuffer->checksum = NetbufferChecksum () | flags;
142 reboundstore = *netbuffer;
143 reboundpacket = true;
148 I_Error ("Tried to transmit to another node");
150 doomcom->command = CMD_SEND;
151 doomcom->remotenode = node;
152 doomcom->datalength = NetbufferSize ();
158 if (netbuffer->checksum & NCMD_RETRANSMIT)
159 realretrans = ExpandTics (netbuffer->retransmitfrom);
162 fprintf (debugfile,"send (%i + %i, R %i) [%i] "
163 ,ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
164 for (i=0 ; i<doomcom->datalength ; i++)
165 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
166 fprintf (debugfile,"\n");
177 = Returns false if no packet is waiting
182 boolean HGetPacket (void)
186 *netbuffer = reboundstore;
187 doomcom->remotenode = 0;
188 reboundpacket = false;
195 doomcom->command = CMD_GET;
197 if (doomcom->remotenode == -1)
200 if (doomcom->datalength != NetbufferSize ())
203 fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
207 if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
210 fprintf (debugfile,"bad packet checksum\n");
219 if (netbuffer->checksum & NCMD_SETUP)
220 fprintf (debugfile,"setup packet\n");
223 if (netbuffer->checksum & NCMD_RETRANSMIT)
224 realretrans = ExpandTics (netbuffer->retransmitfrom);
227 fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",doomcom->remotenode,
228 ExpandTics(netbuffer->starttic),netbuffer->numtics, realretrans, doomcom->datalength);
229 for (i=0 ; i<doomcom->datalength ; i++)
230 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
231 fprintf (debugfile,"\n");
248 void GetPackets (void)
254 ticcmd_t *src, *dest;
255 int dupedstart, dupedend;
259 while (HGetPacket ())
261 if (netbuffer->checksum & NCMD_SETUP)
262 continue; // extra setup packet
264 netdrone = netbuffer->player & PL_DRONE;
265 netconsole = netbuffer->player & ~PL_DRONE;
266 netnode = doomcom->remotenode;
268 // to save bytes, only the low byte of tic numbers are sent
269 // Figure out what the rest of the bytes are
271 realstart = ExpandTics (netbuffer->starttic);
272 dupedstart = realstart*doomcom->ticdup;
273 dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup;
276 // check for exiting the game
278 if (netbuffer->checksum & NCMD_EXIT)
280 if (!nodeingame[netnode])
282 nodeingame[netnode] = false;
285 playeringame[netconsole] = false;
286 strcpy (exitmsg, "PLAYER 1 HAS LEFT THE GAME");
287 exitmsg[7] += netconsole;
288 P_SetMessage(&players[consoleplayer], exitmsg, true);
289 UpdateState |= I_MESSAGES;
290 S_StartSound(NULL, sfx_chat);
296 // drone packets are just notifications
300 nettics[netnode] = dupedend;
304 nodeforplayer[netconsole] = netnode;
307 // check for retransmit request
309 if ( resendcount[netnode] <= 0
310 && (netbuffer->checksum & NCMD_RETRANSMIT) )
312 resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
314 fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
315 resendcount[netnode] = RESENDCOUNT;
318 resendcount[netnode]--;
321 // check for out of order / duplicated packet
323 if (dupedend == nettics[netnode])
326 if (dupedend < nettics[netnode])
329 fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
334 // check for a missed packet
336 if (dupedstart > nettics[netnode])
338 // stop processing until the other system resends the missed tics
340 fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]);
341 remoteresend[netnode] = true;
346 // update command store from the packet
348 remoteresend[netnode] = false;
350 skiptics = nettics[netnode]/doomcom->ticdup - realstart;
351 src = &netbuffer->cmds[skiptics];
353 while (nettics[netnode] < dupedend)
355 for (j=0 ; j<doomcom->ticdup ; j++)
357 dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
361 if (src->buttons & BT_SPECIAL)
374 = Builds ticcmds for console player
379 void NetUpdate (void)
388 return; // singletic update is syncronous
393 nowtime = I_GetTime ()/doomcom->ticdup;
394 newtics = nowtime - gametime;
396 if (newtics <= 0) // nothing new to update
399 if (skiptics <= newtics)
411 netbuffer->player = consoleplayer;
413 netbuffer->player |= PL_DRONE;
426 // build new ticcmds for console player
428 gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup;
429 for (i=0 ; i<newtics ; i++)
433 if (maketic - gameticdiv >= BACKUPTICS/2 /* /doomcom->ticdup */- 1)
436 break; // can't hold any more
438 //printf ("mk:%i ",maketic);
439 G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
444 // send the packet to the other nodes
447 for (i=0 ; i<doomcom->numnodes ; i++)
452 netbuffer->starttic = realstart = maketic + BACKUPTICS/2;
453 netbuffer->numtics = 0;
457 netbuffer->starttic = realstart = resendto[i];
458 netbuffer->numtics = maketic - realstart;
459 resendto[i] = maketic - doomcom->extratics;
462 if (netbuffer->numtics > BACKUPTICS)
463 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
465 for (j=0 ; j< netbuffer->numtics ; j++)
467 localcmds[(realstart+j)%BACKUPTICS];
471 netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup;
472 HSendPacket (i, NCMD_RETRANSMIT);
476 netbuffer->retransmitfrom = 0;
482 // listen for other packets
491 =====================
495 =====================
498 void CheckAbort (void)
505 for ( ; eventtail != eventhead
506 ; eventtail = (++eventtail)&(MAXEVENTS-1) )
508 ev = &events[eventtail];
509 if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
510 I_Error ("Network game synchronization aborted.");
515 =====================
517 = D_ArbitrateNetStart
519 =====================
522 void D_ArbitrateNetStart (void)
525 boolean gotinfo[MAXNETNODES];
528 memset (gotinfo,0,sizeof(gotinfo));
530 if (doomcom->consoleplayer)
531 { // listen for setup info from key player
532 //printf ("listening for network start info...\n");
538 if (netbuffer->checksum & NCMD_SETUP)
540 if (netbuffer->player != VERSION)
541 I_Error ("Different HERETIC versions cannot play a net game!");
542 startskill = netbuffer->retransmitfrom & 15;
543 deathmatch = (netbuffer->retransmitfrom & 0x80) > 0;
544 startmap = netbuffer->starttic & 15;
545 startepisode = netbuffer->starttic >> 4;
551 { // key player, send the setup info
552 // printf ("sending network start info...\n");
556 for (i=0 ; i<doomcom->numnodes ; i++)
558 netbuffer->retransmitfrom = startskill;
560 netbuffer->retransmitfrom |= 0x80;
561 netbuffer->starttic = startepisode * 16 + startmap;
562 netbuffer->player = VERSION;
563 netbuffer->numtics = 0;
564 HSendPacket (i, NCMD_SETUP);
567 while (HGetPacket ())
569 //printf ("got packet\n");
570 gotinfo[netbuffer->player&0x7f] = true;
573 for (i=1 ; i<doomcom->numnodes ; i++)
576 } while (i < doomcom->numnodes);
585 = Works out player numbers among the net participants
589 extern int viewangleoffset;
591 void D_CheckNetGame (void)
595 for (i=0 ; i<MAXNETNODES ; i++)
597 nodeingame[i] = false;
599 remoteresend[i] = false; // set when local needs tics
600 resendto[i] = 0; // which tic to start sending
603 // I_InitNetwork sets doomcom and netgame
605 if (doomcom->id != DOOMCOM_ID)
606 I_Error ("Doomcom buffer invalid!");
607 netbuffer = &doomcom->data;
608 consoleplayer = displayplayer = doomcom->consoleplayer;
610 D_ArbitrateNetStart ();
611 //printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
613 // read values out of doomcom
614 ticdup = doomcom->ticdup;
616 for (i=0 ; i<doomcom->numplayers ; i++)
617 playeringame[i] = true;
618 for (i=0 ; i<doomcom->numnodes ; i++)
619 nodeingame[i] = true;
621 //printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
630 = Called before quitting to leave a net game without hanging the
636 void D_QuitNetGame (void)
643 if (!netgame || !usergame || consoleplayer == -1)
646 // send a bunch of packets for security
647 netbuffer->player = consoleplayer;
649 netbuffer->player |= PL_DRONE;
650 netbuffer->numtics = 0;
651 for (i=0 ; i<4 ; i++)
653 for (j=1 ; j<doomcom->numnodes ; j++)
655 HSendPacket (j, NCMD_EXIT);
670 int frametics[4], frameon;
673 extern boolean advancedemo;
675 void TryRunTics (void)
678 int lowtic, nextlowest;
680 int static oldentertics;
681 int realtics, availabletics;
688 entertic = I_GetTime ();
689 realtics = entertic - oldentertics;
690 oldentertics = entertic;
693 // get available tics
697 lowtic = nextlowest = MAXINT;
699 for (i=0 ; i<doomcom->numnodes ; i++)
703 if (nettics[i] < lowtic)
708 else if (nettics[i] < nextlowest)
709 nextlowest = nettics[i];
711 availabletics = lowtic - gametic;
715 // decide how many tics to run
717 if (realtics < availabletics-1)
719 else if (realtics < availabletics)
722 counts = availabletics;
729 fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
731 //=============================================================================
733 // ideally nettics[0] should be 1 - 3 tics above lowtic
734 // if we are consistantly slower, speed up time
735 // drones should never hold up the other players
737 for (i=0 ; i<MAXPLAYERS ; i++)
740 if (consoleplayer == i)
741 { // the key player does not adapt
745 if (nettics[0] <= nettics[nodeforplayer[i]])
750 frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
751 oldnettics = nettics[0];
752 if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
758 //=============================================================================
761 // wait for new tics if needed
763 while (lowtic < gametic + counts)
769 for (i=0 ; i<doomcom->numnodes ; i++)
770 if (nodeingame[i] && nettics[i] < lowtic)
773 if (lowtic < gametic)
774 I_Error ("TryRunTics: lowtic < gametic");
776 // don't stay in here forever -- give the menu a chance to work
777 if (I_GetTime () - entertic >= 20)
794 NetUpdate (); // check for new console commands