]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/netold.c
More 64bit fixes
[theoddone33/hheretic.git] / base / netold.c
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 }