set the include directory
[AROS-Contrib.git] / Games / Doom / d_net.c
blob4c3667d469700a9c47a8ea3991c266d8f61e27e8
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
17 // $Log$
18 // Revision 1.1 2000/02/29 18:21:04 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
22 // DESCRIPTION:
23 // DOOM Network game communication and protocol,
24 // all OS independend parts.
26 //-----------------------------------------------------------------------------
29 static const char rcsid[] = "$Id$";
31 #include <stdlib.h>
32 #ifdef __SASC
33 #include <dos.h>
34 #endif
35 #ifdef AROS
36 #include <proto/exec.h>
37 #endif
39 #include "m_menu.h"
40 #include "i_system.h"
41 #include "i_video.h"
42 #include "i_net.h"
43 #include "g_game.h"
44 #include "doomdef.h"
45 #include "doomstat.h"
46 #include "m_argv.h"
47 #ifdef __BIG_ENDIAN__
48 #include "m_swap.h"
49 #endif
51 #define NCMD_EXIT 0x80000000
52 #define NCMD_RETRANSMIT 0x40000000
53 #define NCMD_SETUP 0x20000000
54 #define NCMD_KILL 0x10000000 // kill game
55 #define NCMD_CHECKSUM 0x0fffffff
58 doomcom_t* doomcom;
59 doomdata_t* netbuffer; // points inside doomcom
63 // NETWORKING
65 // gametic is the tic about to (or currently being) run
66 // maketic is the tick that hasn't had control made for it yet
67 // nettics[] has the maketics for all players
69 // a gametic cannot be run until nettics[] > gametic for all players
71 #define RESENDCOUNT 10
72 #define PL_DRONE 0x80 // bit flag in doomdata->player
74 ticcmd_t localcmds[BACKUPTICS];
76 ticcmd_t netcmds[MAXPLAYERS][BACKUPTICS];
77 int nettics[MAXNETNODES];
78 boolean nodeingame[MAXNETNODES]; // set false as nodes leave game
79 boolean remoteresend[MAXNETNODES]; // set when local needs tics
80 int resendto[MAXNETNODES]; // set when remote needs tics
81 int resendcount[MAXNETNODES];
83 int nodeforplayer[MAXPLAYERS];
85 int maketic;
86 int lastnettic;
87 int skiptics;
88 int ticdup;
89 int maxsend; // BACKUPTICS/(2*ticdup)-1
92 void D_ProcessEvents (void);
93 void G_BuildTiccmd (ticcmd_t *cmd);
94 void D_DoAdvanceDemo (void);
96 boolean reboundpacket;
97 doomdata_t reboundstore;
99 static int use_pcchecksum = 0;
105 int NetbufferSize (void)
107 return (int)&(((doomdata_t *)0)->cmds[netbuffer->numtics]);
111 // Checksum
113 unsigned NetbufferChecksum (void)
115 unsigned c;
116 int i;
117 #ifdef AROS
118 int l;
119 #endif
120 #ifdef __BIG_ENDIAN__
121 ticcmd_t *t;
122 #endif
124 c = 0x1234567;
126 // FIXME -endianess?
127 #ifdef NORMALUNIX
128 if (!use_pcchecksum)
129 return 0; // byte order problems
130 #endif
132 #ifdef __BIG_ENDIAN__
133 c += SWAPLONG(*(unsigned *)&netbuffer->retransmitfrom);
134 for (i = 0; i < netbuffer->numtics; i++) {
135 t = &netbuffer->cmds[i];
136 c += ((i << 1) + 2) * (((unsigned char)t->forwardmove) +
137 (((unsigned char)t->sidemove) << 8) +
138 (((unsigned short)t->angleturn) << 16));
139 c += ((i << 1) + 3) * (((unsigned short)t->consistancy) +
140 (((unsigned char)t->chatchar) << 16) +
141 (((unsigned char)t->buttons) << 24));
143 return c & NCMD_CHECKSUM;
144 #else
146 l = (NetbufferSize () - (int)&(((doomdata_t *)0)->retransmitfrom))/4;
147 for (i=0 ; i<l ; i++)
148 c += ((unsigned *)&netbuffer->retransmitfrom)[i] * (i+1);
150 return c & NCMD_CHECKSUM;
151 #endif
157 int ExpandTics (int low)
159 int delta;
161 delta = low - (maketic&0xff);
163 if (delta >= -64 && delta <= 64)
164 return (maketic&~0xff) + low;
165 if (delta > 64)
166 return (maketic&~0xff) - 256 + low;
167 if (delta < -64)
168 return (maketic&~0xff) + 256 + low;
170 I_Error ("ExpandTics: strange value %i at maketic %i",low,maketic);
171 return 0;
177 // HSendPacket
179 void
180 HSendPacket
181 (int node,
182 int flags )
184 netbuffer->checksum = NetbufferChecksum () | flags;
186 if (!node)
188 reboundstore = *netbuffer;
189 reboundpacket = true;
190 return;
193 if (demoplayback)
194 return;
196 if (!netgame)
197 I_Error ("Tried to transmit to another node");
199 doomcom->command = CMD_SEND;
200 doomcom->remotenode = node;
201 doomcom->datalength = NetbufferSize ();
203 if (debugfile)
205 int i;
206 int realretrans;
207 if (netbuffer->checksum & NCMD_RETRANSMIT)
208 realretrans = ExpandTics (netbuffer->retransmitfrom);
209 else
210 realretrans = -1;
212 fprintf (debugfile,"send (%i + %i, R %i) [%i] ",
213 ExpandTics(netbuffer->starttic),
214 netbuffer->numtics, realretrans, doomcom->datalength);
216 for (i=0 ; i<doomcom->datalength ; i++)
217 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
219 fprintf (debugfile,"\n");
222 I_NetCmd ();
226 // HGetPacket
227 // Returns false if no packet is waiting
229 boolean HGetPacket (void)
231 if (reboundpacket)
233 *netbuffer = reboundstore;
234 doomcom->remotenode = 0;
235 reboundpacket = false;
236 return true;
239 if (!netgame)
240 return false;
242 if (demoplayback)
243 return false;
245 doomcom->command = CMD_GET;
246 I_NetCmd ();
248 if (doomcom->remotenode == -1)
249 return false;
251 if (doomcom->datalength != NetbufferSize ())
253 if (debugfile)
254 fprintf (debugfile,"bad packet length %i\n",doomcom->datalength);
255 return false;
258 if (NetbufferChecksum () != (netbuffer->checksum&NCMD_CHECKSUM) )
260 int i;
262 if (debugfile)
263 fprintf (debugfile,"bad packet checksum\n");
264 fprintf (stderr, "Net Packet Checksum error, %08x != %08x\n",
265 NetbufferChecksum(),
266 netbuffer->checksum&NCMD_CHECKSUM);
267 fprintf (stderr, "%08x",
268 ((int *)&netbuffer->retransmitfrom)[0]);
269 for (i = 0; i < netbuffer->numtics; i++)
270 fprintf (stderr, " %08x %08x",
271 ((int *)&netbuffer->cmds[0])[2*i],
272 ((int *)&netbuffer->cmds[0])[2*i+1]);
273 fprintf (stderr, "\n");
274 return false;
277 if (debugfile)
279 int realretrans;
280 int i;
282 if (netbuffer->checksum & NCMD_SETUP)
283 fprintf (debugfile,"setup packet\n");
284 else
286 if (netbuffer->checksum & NCMD_RETRANSMIT)
287 realretrans = ExpandTics (netbuffer->retransmitfrom);
288 else
289 realretrans = -1;
291 fprintf (debugfile,"get %i = (%i + %i, R %i)[%i] ",
292 doomcom->remotenode,
293 ExpandTics(netbuffer->starttic),
294 netbuffer->numtics, realretrans, doomcom->datalength);
296 for (i=0 ; i<doomcom->datalength ; i++)
297 fprintf (debugfile,"%i ",((byte *)netbuffer)[i]);
298 fprintf (debugfile,"\n");
301 return true;
306 // GetPackets
308 char exitmsg[80];
310 void GetPackets (void)
312 int netconsole;
313 int netnode;
314 ticcmd_t *src, *dest;
315 int realend;
316 int realstart;
318 while ( HGetPacket() )
320 if (netbuffer->checksum & NCMD_SETUP)
321 continue; // extra setup packet
323 netconsole = netbuffer->player & ~PL_DRONE;
324 netnode = doomcom->remotenode;
326 // to save bytes, only the low byte of tic numbers are sent
327 // Figure out what the rest of the bytes are
328 realstart = ExpandTics (netbuffer->starttic);
329 realend = (realstart+netbuffer->numtics);
331 // check for exiting the game
332 if (netbuffer->checksum & NCMD_EXIT)
334 if (!nodeingame[netnode])
335 continue;
336 nodeingame[netnode] = false;
337 playeringame[netconsole] = false;
338 strcpy (exitmsg, "Player 1 left the game");
339 exitmsg[7] += netconsole;
340 players[consoleplayer].message = exitmsg;
341 if (demorecording)
342 G_CheckDemoStatus ();
343 continue;
346 // check for a remote game kill
347 if (netbuffer->checksum & NCMD_KILL)
348 I_Error ("Killed by network driver");
350 nodeforplayer[netconsole] = netnode;
352 // check for retransmit request
353 if ( resendcount[netnode] <= 0
354 && (netbuffer->checksum & NCMD_RETRANSMIT) )
356 resendto[netnode] = ExpandTics(netbuffer->retransmitfrom);
357 if (debugfile)
358 fprintf (debugfile,"retransmit from %i\n", resendto[netnode]);
359 resendcount[netnode] = RESENDCOUNT;
361 else
362 resendcount[netnode]--;
364 // check for out of order / duplicated packet
365 if (realend == nettics[netnode])
366 continue;
368 if (realend < nettics[netnode])
370 if (debugfile)
371 fprintf (debugfile,
372 "out of order packet (%i + %i)\n" ,
373 realstart,netbuffer->numtics);
374 continue;
377 // check for a missed packet
378 if (realstart > nettics[netnode])
380 // stop processing until the other system resends the missed tics
381 if (debugfile)
382 fprintf (debugfile,
383 "missed tics from %i (%i - %i)\n",
384 netnode, realstart, nettics[netnode]);
385 remoteresend[netnode] = true;
386 continue;
389 // update command store from the packet
391 int start;
393 remoteresend[netnode] = false;
395 start = nettics[netnode] - realstart;
396 src = &netbuffer->cmds[start];
398 while (nettics[netnode] < realend)
400 dest = &netcmds[netconsole][nettics[netnode]%BACKUPTICS];
401 nettics[netnode]++;
402 *dest = *src;
403 src++;
411 // NetUpdate
412 // Builds ticcmds for console player,
413 // sends out a packet
415 int gametime;
417 void NetUpdate (void)
419 int nowtime;
420 int newtics;
421 int i,j;
422 int realstart;
423 int gameticdiv;
425 // check time
426 nowtime = I_GetTime ()/ticdup;
427 newtics = nowtime - gametime;
428 gametime = nowtime;
430 if (newtics <= 0) // nothing new to update
431 goto listen;
433 if (skiptics <= newtics)
435 newtics -= skiptics;
436 skiptics = 0;
438 else
440 skiptics -= newtics;
441 newtics = 0;
445 netbuffer->player = consoleplayer;
447 // build new ticcmds for console player
448 gameticdiv = gametic/ticdup;
449 for (i=0 ; i<newtics ; i++)
451 I_StartTic ();
452 D_ProcessEvents ();
453 if (maketic - gameticdiv >= BACKUPTICS/2-1)
454 break; // can't hold any more
456 //printf ("mk:%i ",maketic);
457 G_BuildTiccmd (&localcmds[maketic%BACKUPTICS]);
458 maketic++;
462 if (singletics)
463 return; // singletic update is syncronous
465 // send the packet to the other nodes
466 for (i=0 ; i<doomcom->numnodes ; i++)
467 if (nodeingame[i])
469 netbuffer->starttic = realstart = resendto[i];
470 netbuffer->numtics = maketic - realstart;
471 if (netbuffer->numtics > BACKUPTICS)
472 I_Error ("NetUpdate: netbuffer->numtics > BACKUPTICS");
474 resendto[i] = maketic - doomcom->extratics;
476 for (j=0 ; j< netbuffer->numtics ; j++)
477 netbuffer->cmds[j] =
478 localcmds[(realstart+j)%BACKUPTICS];
480 if (remoteresend[i])
482 netbuffer->retransmitfrom = nettics[i];
483 HSendPacket (i, NCMD_RETRANSMIT);
485 else
487 netbuffer->retransmitfrom = 0;
488 HSendPacket (i, 0);
492 // listen for other packets
493 listen:
494 GetPackets ();
500 // CheckAbort
502 void CheckAbort (void)
504 event_t *ev;
505 int stoptic;
507 stoptic = I_GetTime () + 2;
508 while (I_GetTime() < stoptic)
509 I_StartTic ();
511 I_StartTic ();
512 for ( ; eventtail != eventhead
513 ; eventtail++, eventtail = (eventtail)&(MAXEVENTS-1) )
515 ev = &events[eventtail];
516 if (ev->type == ev_keydown && ev->data1 == KEY_ESCAPE)
517 I_Error ("Network game synchronization aborted.");
519 #ifdef __SASC
520 chkabort ();
521 #endif
526 // D_ArbitrateNetStart
528 void D_ArbitrateNetStart (void)
530 int i;
531 boolean gotinfo[MAXNETNODES];
533 autostart = true;
534 memset (gotinfo,0,sizeof(gotinfo));
536 if (doomcom->consoleplayer)
538 // listen for setup info from key player
539 printf ("listening for network start info...\n");
540 while (1)
542 #ifdef AROS
543 SetTaskPri(FindTask(NULL), -1);
544 SetTaskPri(FindTask(NULL), 0);
545 #endif
546 CheckAbort ();
547 if (!HGetPacket ())
548 continue;
549 if (netbuffer->checksum & NCMD_SETUP)
551 if (netbuffer->player != VERSION)
552 I_Error ("Different DOOM versions cannot play a net game!");
553 startskill = netbuffer->retransmitfrom & 15;
554 deathmatch = (netbuffer->retransmitfrom & 0xc0) >> 6;
555 nomonsters = (netbuffer->retransmitfrom & 0x20) > 0;
556 respawnparm = (netbuffer->retransmitfrom & 0x10) > 0;
557 startmap = netbuffer->starttic & 0x3f;
558 startepisode = netbuffer->starttic >> 6;
559 return;
563 else
565 // key player, send the setup info
566 printf ("sending network start info...\n");
569 CheckAbort ();
571 //printf("network start info loop: sending packets \n");
572 for (i=0 ; i<doomcom->numnodes ; i++)
574 netbuffer->retransmitfrom = startskill;
575 if (deathmatch)
576 netbuffer->retransmitfrom |= (deathmatch<<6);
577 if (nomonsters)
578 netbuffer->retransmitfrom |= 0x20;
579 if (respawnparm)
580 netbuffer->retransmitfrom |= 0x10;
581 netbuffer->starttic = startepisode * 64 + startmap;
582 netbuffer->player = VERSION;
583 netbuffer->numtics = 0;
584 HSendPacket (i, NCMD_SETUP);
587 //printf("network start info loop: getting packets \n");
589 #if 1
590 for(i = 10 ; i && HGetPacket(); --i)
592 if((netbuffer->player&0x7f) < MAXNETNODES)
594 //printf("Got Info from Player %d\n",netbuffer->player&0x7f);
595 gotinfo[netbuffer->player&0x7f] = true;
596 } else {;
597 //printf("Bad Info from Player %d\n",netbuffer->player&0x7f);
600 #else
601 while (HGetPacket ())
603 gotinfo[netbuffer->player&0x7f] = true;
605 #endif
607 for (i=1 ; i<doomcom->numnodes ; i++)
608 if (!gotinfo[i])
609 break;
611 #ifdef AROS
612 SetTaskPri(FindTask(NULL), -1);
613 SetTaskPri(FindTask(NULL), 0);
614 #endif
615 } while (i < doomcom->numnodes);
617 //printf("network start info okay for all nodes\n");
623 // D_CheckNetGame
624 // Works out player numbers among the net participants
626 extern int viewangleoffset;
628 void D_CheckNetGame (void)
630 int i;
632 use_pcchecksum = M_CheckParm ("-pcchecksum");
634 for (i=0 ; i<MAXNETNODES ; i++)
636 nodeingame[i] = false;
637 nettics[i] = 0;
638 remoteresend[i] = false; // set when local needs tics
639 resendto[i] = 0; // which tic to start sending
642 // I_InitNetwork sets doomcom and netgame
643 I_InitNetwork ();
644 if (doomcom->id != DOOMCOM_ID)
645 I_Error ("Doomcom buffer invalid!");
647 netbuffer = &doomcom->data;
648 consoleplayer = displayplayer = doomcom->consoleplayer;
649 if (netgame)
650 D_ArbitrateNetStart ();
652 printf ("startskill %i deathmatch: %i startmap: %i startepisode: %i\n",
653 startskill, deathmatch, startmap, startepisode);
655 // read values out of doomcom
656 ticdup = doomcom->ticdup;
657 maxsend = BACKUPTICS/(2*ticdup)-1;
658 if (maxsend<1)
659 maxsend = 1;
661 for (i=0 ; i<doomcom->numplayers ; i++)
662 playeringame[i] = true;
663 for (i=0 ; i<doomcom->numnodes ; i++)
664 nodeingame[i] = true;
666 printf ("player %i of %i (%i nodes)\n",
667 consoleplayer+1, doomcom->numplayers, doomcom->numnodes);
673 // D_QuitNetGame
674 // Called before quitting to leave a net game
675 // without hanging the other players
677 void D_QuitNetGame (void)
679 int i, j;
681 if (debugfile)
682 fclose (debugfile);
684 if (!netgame || !usergame || consoleplayer == -1 || demoplayback)
685 return;
687 // send a bunch of packets for security
688 netbuffer->player = consoleplayer;
689 netbuffer->numtics = 0;
690 for (i=0 ; i<4 ; i++)
692 for (j=1 ; j<doomcom->numnodes ; j++)
693 if (nodeingame[j])
694 HSendPacket (j, NCMD_EXIT);
695 I_WaitVBL (1);
702 // TryRunTics
704 int frametics[4];
705 int frameon;
706 int frameskip[4];
707 int oldnettics;
709 extern boolean advancedemo;
711 void TryRunTics (void)
713 int i;
714 int lowtic;
715 int entertic;
716 static int oldentertics;
717 int realtics;
718 int availabletics;
719 int counts;
720 int numplaying;
722 // get real tics
723 entertic = I_GetTime ()/ticdup;
724 realtics = entertic - oldentertics;
725 oldentertics = entertic;
727 // get available tics
728 NetUpdate ();
730 lowtic = MAXINT;
731 numplaying = 0;
732 for (i=0 ; i<doomcom->numnodes ; i++)
734 if (nodeingame[i])
736 numplaying++;
737 if (nettics[i] < lowtic)
738 lowtic = nettics[i];
741 availabletics = lowtic - gametic/ticdup;
743 // decide how many tics to run
744 if (realtics < availabletics-1)
745 counts = realtics+1;
746 else if (realtics < availabletics)
747 counts = realtics;
748 else
749 counts = availabletics;
751 if (counts < 1)
752 counts = 1;
754 frameon++;
756 if (debugfile)
757 fprintf (debugfile,
758 "=======real: %i avail: %i game: %i\n",
759 realtics, availabletics,counts);
761 if (!demoplayback)
763 // ideally nettics[0] should be 1 - 3 tics above lowtic
764 // if we are consistantly slower, speed up time
765 for (i=0 ; i<MAXPLAYERS ; i++)
766 if (playeringame[i])
767 break;
768 if (consoleplayer == i)
770 // the key player does not adapt
772 else
774 if (nettics[0] <= nettics[nodeforplayer[i]])
776 gametime--;
777 // printf ("-");
779 frameskip[frameon&3] = (oldnettics > nettics[nodeforplayer[i]]);
780 oldnettics = nettics[0];
781 if (frameskip[0] && frameskip[1] && frameskip[2] && frameskip[3])
783 skiptics = 1;
784 // printf ("+");
787 }// demoplayback
789 // wait for new tics if needed
790 while (lowtic < gametic/ticdup + counts)
792 NetUpdate ();
793 lowtic = MAXINT;
795 for (i=0 ; i<doomcom->numnodes ; i++)
796 if (nodeingame[i] && nettics[i] < lowtic)
797 lowtic = nettics[i];
799 if (lowtic < gametic/ticdup)
800 I_Error ("TryRunTics: lowtic < gametic");
802 // don't stay in here forever -- give the menu a chance to work
803 if (I_GetTime ()/ticdup - entertic >= 20)
805 M_Ticker ();
806 return;
810 // run the count * ticdup dics
811 while (counts--)
813 for (i=0 ; i<ticdup ; i++)
815 if (gametic/ticdup > lowtic)
816 I_Error ("gametic>lowtic");
817 if (advancedemo)
818 D_DoAdvanceDemo ();
819 M_Ticker ();
820 G_Ticker ();
821 gametic++;
823 // modify command for duplicated tics
824 if (i != ticdup-1)
826 ticcmd_t *cmd;
827 int buf;
828 int j;
830 buf = (gametic/ticdup)%BACKUPTICS;
831 for (j=0 ; j<MAXPLAYERS ; j++)
833 cmd = &netcmds[j][buf];
834 cmd->chatchar = 0;
835 if (cmd->buttons & BT_SPECIAL)
836 cmd->buttons = 0;
840 NetUpdate (); // check for new console commands