Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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