|
|
1.1 root 1:
2: // I_pcnet.m
3: //
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.
8:
9: #include "DoomDef.h"
10: #include "P_local.h"
11: #include "soundst.h"
12:
13: #define NCMD_EXIT 0x80000000
14: #define NCMD_RETRANSMIT 0x40000000
15: #define NCMD_SETUP 0x20000000
16: #define NCMD_CHECKSUM 0x0fffffff
17:
18: /*
19: if more space needs to be crunched out of the protocol...
20:
21: 1 drone
22: 2 player
23: 8 tic
24: 5 numtics
25:
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
36:
37: */
38:
39:
40:
41:
42:
43: doomcom_t *doomcom;
44: doomdata_t *netbuffer; // points inside doomcom
45:
46:
47: /*
48: ==============================================================================
49:
50: NETWORKING
51:
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
55:
56: a gametic cannot be run until nettics[] > gametic for all players
57:
58: ==============================================================================
59: */
60:
61: #define RESENDCOUNT 10
62: #define PL_DRONE 0x80 // bit flag in doomdata->player
63:
64: ticcmd_t localcmds[BACKUPTICS];
65:
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];
72:
73: int nodeforplayer[MAXPLAYERS];
74:
75: int gametime;
76: int maketic;
77: int lastnettic, skiptics;
78: int ticdup;
79:
80: void D_ProcessEvents (void);
81: void G_BuildTiccmd (ticcmd_t *cmd);
82: void D_DoAdvanceDemo (void);
83:
84: boolean reboundpacket;
85: doomdata_t reboundstore;
86:
87:
88: int NetbufferSize (void)
89: {
90: return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
91: }
92:
93: unsigned NetbufferChecksum (void)
94: {
95: unsigned c;
96: int i,l;
97:
98: c = 0x1234567;
99:
100: l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
101: for (i=0 ; i<l ; i++)
102: c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
103:
104: return c & NCMD_CHECKSUM;
105: }
106:
107: int ExpandTics (int low)
108: {
109: int delta;
110:
111: delta = low - (maketic&0xff);
112:
113: if (delta >= -64 && delta <= 64)
114: return (maketic&~0xff) + low;
115: if (delta > 64)
116: return (maketic&~0xff) - 256 + low;
117: if (delta < -64)
118: return (maketic&~0xff) + 256 + low;
119:
120: I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
121: return 0;
122: }
123:
124:
125: //============================================================================
126:
127:
128: /*
129: ==============
130: =
131: = HSendPacket
132: =
133: ==============
134: */
135:
136: void HSendPacket (int node, int flags)
137: {
138: netbuffer->checksum = NetbufferChecksum () | flags;
139:
140: if (!node)
141: {
142: reboundstore = *netbuffer;
143: reboundpacket = true;
144: return;
145: }
146:
147: if (!netgame)
148: I_Error ("Tried to transmit to another node");
149:
150: doomcom->command = CMD_SEND;
151: doomcom->remotenode = node;
152: doomcom->datalength = NetbufferSize ();
153:
154: if (debugfile)
155: {
156: int i;
157: int realretrans;
158: if (netbuffer->checksum & NCMD_RETRANSMIT)
159: realretrans = ExpandTics (netbuffer->retransmitfrom);
160: else
161: realretrans = -1;
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");
167: }
168:
169: I_NetCmd ();
170: }
171:
172: /*
173: ==============
174: =
175: = HGetPacket
176: =
177: = Returns false if no packet is waiting
178: =
179: ==============
180: */
181:
182: boolean HGetPacket (void)
183: {
184: if (reboundpacket)
185: {
186: *netbuffer = reboundstore;
187: doomcom->remotenode = 0;
188: reboundpacket = false;
189: return true;
190: }
191:
192: if (!netgame)
193: return false;
194:
195: doomcom->command = CMD_GET;
196: I_NetCmd ();
197: if (doomcom->remotenode == -1)
198: return false;
199:
200: if (doomcom->datalength != NetbufferSize ())
201: {
202: if (debugfile)
203: fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
204: return false;
205: }
206:
207: if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
208: {
209: if (debugfile)
210: fprintf (debugfile,"bad packet checksum\n");
211: return false;
212: }
213:
214: if (debugfile)
215: {
216: int realretrans;
217: int i;
218:
219: if (netbuffer->checksum & NCMD_SETUP)
220: fprintf (debugfile,"setup packet\n");
221: else
222: {
223: if (netbuffer->checksum & NCMD_RETRANSMIT)
224: realretrans = ExpandTics (netbuffer->retransmitfrom);
225: else
226: realretrans = -1;
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");
232: }
233: }
234: return true;
235: }
236:
237:
238: /*
239: ===================
240: =
241: = GetPackets
242: =
243: ===================
244: */
245:
246: char exitmsg[80];
247:
248: void GetPackets (void)
249: {
250: int netconsole;
251: int netnode;
252: int netdrone;
253: int j;
254: ticcmd_t *src, *dest;
255: int dupedstart, dupedend;
256: int skiptics;
257: int realstart;
258:
259: while (HGetPacket ())
260: {
261: if (netbuffer->checksum & NCMD_SETUP)
262: continue; // extra setup packet
263:
264: netdrone = netbuffer->player & PL_DRONE;
265: netconsole = netbuffer->player & ~PL_DRONE;
266: netnode = doomcom->remotenode;
267: //
268: // to save bytes, only the low byte of tic numbers are sent
269: // Figure out what the rest of the bytes are
270: //
271: realstart = ExpandTics (netbuffer->starttic);
272: dupedstart = realstart*doomcom->ticdup;
273: dupedend = (realstart+netbuffer->numtics)*doomcom->ticdup;
274:
275: //
276: // check for exiting the game
277: //
278: if (netbuffer->checksum & NCMD_EXIT)
279: {
280: if (!nodeingame[netnode])
281: continue;
282: nodeingame[netnode] = false;
283: if (!netdrone)
284: {
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);
291: }
292: continue;
293: }
294:
295: //
296: // drone packets are just notifications
297: //
298: if (netdrone)
299: {
300: nettics[netnode] = dupedend;
301: continue;
302: }
303:
304: nodeforplayer[netconsole] = netnode;
305:
306: //
307: // check for retransmit request
308: //
309: if ( resendcount[netnode] <= 0
310: && (netbuffer->checksum & NCMD_RETRANSMIT) )
311: {
312: resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
313: if (debugfile)
314: fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
315: resendcount[netnode] = RESENDCOUNT;
316: }
317: else
318: resendcount[netnode]--;
319:
320: //
321: // check for out of order / duplicated packet
322: //
323: if (dupedend == nettics[netnode])
324: continue;
325:
326: if (dupedend < nettics[netnode])
327: {
328: if (debugfile)
329: fprintf (debugfile,"out of order packet (%i + %i)\n" ,realstart,netbuffer->numtics);
330: continue;
331: }
332:
333: //
334: // check for a missed packet
335: //
336: if (dupedstart > nettics[netnode])
337: {
338: // stop processing until the other system resends the missed tics
339: if (debugfile)
340: fprintf (debugfile,"missed tics from %i (%i - %i)\n", netnode, dupedstart, nettics[netnode]);
341: remoteresend[netnode] = true;
342: continue;
343: }
344:
345: //
346: // update command store from the packet
347: //
348: remoteresend[netnode] = false;
349:
350: skiptics = nettics[netnode]/doomcom->ticdup - realstart;
351: src = &netbuffer->cmds[skiptics];
352:
353: while (nettics[netnode] < dupedend)
354: {
355: for (j=0 ; j<doomcom->ticdup ; j++)
356: {
357: dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
358: nettics[netnode]++;
359: *dest = *src;
360: src->chatchar = 0;
361: if (src->buttons & BT_SPECIAL)
362: src->buttons = 0;
363: }
364: src++;
365: }
366: }
367: }
368:
369: /*
370: =============
371: =
372: = NetUpdate
373: =
374: = Builds ticcmds for console player
375: = sends out a packet
376: =============
377: */
378:
379: void NetUpdate (void)
380: {
381: int nowtime;
382: int newtics;
383: int i,j;
384: int gameticdiv;
385: int realstart;
386:
387: if (singletics)
388: return; // singletic update is syncronous
389:
390: //
391: // check time
392: //
393: nowtime = I_GetTime ()/doomcom->ticdup;
394: newtics = nowtime - gametime;
395: gametime = nowtime;
396: if (newtics <= 0) // nothing new to update
397: goto listen;
398:
399: if (skiptics <= newtics)
400: {
401: newtics -= skiptics;
402: skiptics = 0;
403: }
404: else
405: {
406: skiptics -= newtics;
407: newtics = 0;
408: }
409:
410:
411: netbuffer->player = consoleplayer;
412: if (doomcom->drone)
413: netbuffer->player |= PL_DRONE;
414:
415: //
416: // drone packets
417: //
418: if (doomcom->drone)
419: {
420: I_StartTic ();
421: D_ProcessEvents ();
422: goto sendit;
423: }
424:
425: //
426: // build new ticcmds for console player
427: //
428: gameticdiv = (gametic+doomcom->ticdup-1)/doomcom->ticdup;
429: for (i=0 ; i<newtics ; i++)
430: {
431: I_StartTic ();
432: D_ProcessEvents ();
433: if (maketic - gameticdiv >= BACKUPTICS/2 /* /doomcom->ticdup */- 1)
434: {
435: newtics = i;
436: break; // can't hold any more
437: }
438: //printf ("mk:%i ",maketic);
439: G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
440: maketic++;
441: }
442:
443: //
444: // send the packet to the other nodes
445: //
446: sendit:
447: for (i=0 ; i<doomcom->numnodes ; i++)
448: if (nodeingame[i])
449: {
450: if (doomcom->drone)
451: {
452: netbuffer->starttic = realstart = maketic + BACKUPTICS/2;
453: netbuffer->numtics = 0;
454: }
455: else
456: {
457: netbuffer->starttic = realstart = resendto[i];
458: netbuffer->numtics = maketic - realstart;
459: resendto[i] = maketic - doomcom->extratics;
460: }
461:
462: if (netbuffer->numtics > BACKUPTICS)
463: I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
464:
465: for (j=0 ; j< netbuffer->numtics ; j++)
466: netbuffer->cmds[j] =
467: localcmds[(realstart+j)%BACKUPTICS];
468:
469: if (remoteresend[i])
470: {
471: netbuffer->retransmitfrom = nettics[i]/doomcom->ticdup;
472: HSendPacket (i, NCMD_RETRANSMIT);
473: }
474: else
475: {
476: netbuffer->retransmitfrom = 0;
477: HSendPacket (i, 0);
478: }
479: }
480:
481: //
482: // listen for other packets
483: //
484: listen:
485:
486: GetPackets ();
487: }
488:
489:
490: /*
491: =====================
492: =
493: = CheckAbort
494: =
495: =====================
496: */
497:
498: void CheckAbort (void)
499: {
500: event_t *ev;
501:
502: I_WaitVBL(2);
503:
504: I_StartTic ();
505: for ( ; eventtail != eventhead
506: ; eventtail = (++eventtail)&(MAXEVENTS-1) )
507: {
508: ev = &events[eventtail];
509: if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
510: I_Error ("Network game synchronization aborted.");
511: }
512: }
513:
514: /*
515: =====================
516: =
517: = D_ArbitrateNetStart
518: =
519: =====================
520: */
521:
522: void D_ArbitrateNetStart (void)
523: {
524: int i;
525: boolean gotinfo[MAXNETNODES];
526:
527: autostart = true;
528: memset (gotinfo,0,sizeof(gotinfo));
529:
530: if (doomcom->consoleplayer)
531: { // listen for setup info from key player
532: //printf ("listening for network start info...\n");
533: while (1)
534: {
535: CheckAbort ();
536: if (!HGetPacket ())
537: continue;
538: if (netbuffer->checksum & NCMD_SETUP)
539: {
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;
546: return;
547: }
548: }
549: }
550: else
551: { // key player, send the setup info
552: // printf ("sending network start info...\n");
553: do
554: {
555: CheckAbort ();
556: for (i=0 ; i<doomcom->numnodes ; i++)
557: {
558: netbuffer->retransmitfrom = startskill;
559: if (deathmatch)
560: netbuffer->retransmitfrom |= 0x80;
561: netbuffer->starttic = startepisode * 16 + startmap;
562: netbuffer->player = VERSION;
563: netbuffer->numtics = 0;
564: HSendPacket (i, NCMD_SETUP);
565: }
566:
567: while (HGetPacket ())
568: {
569: //printf ("got packet\n");
570: gotinfo[netbuffer->player&0x7f] = true;
571: }
572:
573: for (i=1 ; i<doomcom->numnodes ; i++)
574: if (!gotinfo[i])
575: break;
576: } while (i < doomcom->numnodes);
577: }
578: }
579:
580: /*
581: ===================
582: =
583: = D_CheckNetGame
584: =
585: = Works out player numbers among the net participants
586: ===================
587: */
588:
589: extern int viewangleoffset;
590:
591: void D_CheckNetGame (void)
592: {
593: int i;
594:
595: for (i=0 ; i<MAXNETNODES ; i++)
596: {
597: nodeingame[i] = false;
598: nettics[i] = 0;
599: remoteresend[i] = false; // set when local needs tics
600: resendto[i] = 0; // which tic to start sending
601: }
602:
603: // I_InitNetwork sets doomcom and netgame
604: I_InitNetwork ();
605: if (doomcom->id != DOOMCOM_ID)
606: I_Error ("Doomcom buffer invalid!");
607: netbuffer = &doomcom->data;
608: consoleplayer = displayplayer = doomcom->consoleplayer;
609: if (netgame)
610: D_ArbitrateNetStart ();
611: //printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n", startskill, deathmatch, startmap, startepisode);
612:
613: // read values out of doomcom
614: ticdup = doomcom->ticdup;
615:
616: for (i=0 ; i<doomcom->numplayers ; i++)
617: playeringame[i] = true;
618: for (i=0 ; i<doomcom->numnodes ; i++)
619: nodeingame[i] = true;
620:
621: //printf ("player %i of %i (%i nodes)\n", consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
622:
623: }
624:
625: /*
626: ==================
627: =
628: = D_QuitNetGame
629: =
630: = Called before quitting to leave a net game without hanging the
631: = other players
632: =
633: ==================
634: */
635:
636: void D_QuitNetGame (void)
637: {
638: int i, j;
639:
640: if (debugfile)
641: fclose (debugfile);
642:
643: if (!netgame || !usergame || consoleplayer == -1)
644: return;
645:
646: // send a bunch of packets for security
647: netbuffer->player = consoleplayer;
648: if (doomcom->drone)
649: netbuffer->player |= PL_DRONE;
650: netbuffer->numtics = 0;
651: for (i=0 ; i<4 ; i++)
652: {
653: for (j=1 ; j<doomcom->numnodes ; j++)
654: if (nodeingame[j])
655: HSendPacket (j, NCMD_EXIT);
656: I_WaitVBL (1);
657: }
658: }
659:
660:
661:
662: /*
663: ===============
664: =
665: = TryRunTics
666: =
667: ===============
668: */
669:
670: int frametics[4], frameon;
671: int frameskip[4];
672: int oldnettics;
673: extern boolean advancedemo;
674:
675: void TryRunTics (void)
676: {
677: int i;
678: int lowtic, nextlowest;
679: int entertic;
680: int static oldentertics;
681: int realtics, availabletics;
682: int counts;
683: int numplaying;
684:
685: //
686: // get real tics
687: //
688: entertic = I_GetTime ();
689: realtics = entertic - oldentertics;
690: oldentertics = entertic;
691:
692: //
693: // get available tics
694: //
695: NetUpdate ();
696:
697: lowtic = nextlowest = MAXINT;
698: numplaying = 0;
699: for (i=0 ; i<doomcom->numnodes ; i++)
700: if (nodeingame[i])
701: {
702: numplaying++;
703: if (nettics[i] < lowtic)
704: {
705: nextlowest = lowtic;
706: lowtic = nettics[i];
707: }
708: else if (nettics[i] < nextlowest)
709: nextlowest = nettics[i];
710: }
711: availabletics = lowtic - gametic;
712:
713:
714: //
715: // decide how many tics to run
716: //
717: if (realtics < availabletics-1)
718: counts = realtics+1;
719: else if (realtics < availabletics)
720: counts = realtics;
721: else
722: counts = availabletics;
723: if (counts < 1)
724: counts = 1;
725:
726: frameon++;
727:
728: if (debugfile)
729: fprintf (debugfile,"=======real: %i avail: %i game: %i\n",realtics, availabletics,counts);
730:
731: //=============================================================================
732: //
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
736: //
737: for (i=0 ; i<MAXPLAYERS ; i++)
738: if (playeringame[i])
739: break;
740: if (consoleplayer == i)
741: { // the key player does not adapt
742: }
743: else
744: {
745: if (nettics[0] <= nettics[nodeforplayer[i]])
746: {
747: gametime--;
748: // printf ("-");
749: }
750: frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
751: oldnettics = nettics[0];
752: if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
753: {
754: skiptics = 1;
755: // printf ("+");
756: }
757: }
758: //=============================================================================
759:
760: //
761: // wait for new tics if needed
762: //
763: while (lowtic < gametic + counts)
764: {
765:
766: NetUpdate ();
767: lowtic = MAXINT;
768:
769: for (i=0 ; i<doomcom->numnodes ; i++)
770: if (nodeingame[i] && nettics[i] < lowtic)
771: lowtic = nettics[i];
772:
773: if (lowtic < gametic)
774: I_Error ("TryRunTics: lowtic < gametic");
775:
776: // don't stay in here forever -- give the menu a chance to work
777: if (I_GetTime () - entertic >= 20)
778: {
779: MN_Ticker ();
780: return;
781: }
782: }
783:
784:
785: //
786: // run the tics
787: //
788: while (counts--)
789: {
790: if (advancedemo)
791: D_DoAdvanceDemo ();
792: MN_Ticker ();
793: G_Ticker ();
794: NetUpdate (); // check for new console commands
795: gametic++;
796: }
797: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.