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