]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/d_netbak.c
Optimized blit functions.
[theoddone33/hheretic.git] / base / d_netbak.c
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 }