Subversion Repositories Kolibri OS

Rev

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