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