1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4
5 This file is part of Shadow Warrior version 1.2
6
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #include "build.h"
27
28 #include "keys.h"
29 #include "game.h"
30 #include "tags.h"
31 #include "names2.h"
32 #include "network.h"
33 #include "menus.h"
34
35 SWBOOL SyncPrintMode = TRUE;
36 short NumSyncBytes = 1;
37 char sync_first[MAXSYNCBYTES][60];
38 int sync_found = FALSE;
39
40 static int crctable[256];
41 #define updatecrc(dcrc,xz) (dcrc = (crctable[((dcrc)>>8)^((xz)&255)]^((dcrc)<<8)))
42
initsynccrc(void)43 void initsynccrc(void)
44 {
45 int i, j, k, a;
46
47 for (j=0; j<256; j++) //Calculate CRC table
48 {
49 k = (j<<8); a = 0;
50 for (i=7; i>=0; i--)
51 {
52 if (((k^a)&0x8000) > 0)
53 a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly
54 else
55 a = ((a<<1)&65535);
56 k = ((k<<1)&65535);
57 }
58 crctable[j] = (a&65535);
59 }
60 }
61
62 #if SYNC_TEST
63 uint8_t
PlayerSync(void)64 PlayerSync(void)
65 {
66 short i;
67 unsigned short crc = 0;
68 PLAYERp pp;
69
70 for (i = connecthead; i >= 0; i = connectpoint2[i])
71 {
72 pp = Player + i;
73 updatecrc(crc, pp->posx & 255);
74 updatecrc(crc, pp->posy & 255);
75 updatecrc(crc, pp->posz & 255);
76 updatecrc(crc, fix16_to_int(pp->q16ang) & 255);
77 }
78
79 return (uint8_t) crc & 255;
80 }
81
82 uint8_t
PlayerSync2(void)83 PlayerSync2(void)
84 {
85 short i;
86 unsigned short crc = 0;
87 PLAYERp pp;
88
89 for (i = connecthead; i >= 0; i = connectpoint2[i])
90 {
91 pp = Player + i;
92
93 updatecrc(crc, fix16_to_int(pp->q16horiz) & 255);
94 updatecrc(crc, User[pp->PlayerSprite]->Health & 255);
95 updatecrc(crc, pp->bcnt & 255);
96 }
97
98 return (uint8_t) crc & 255;
99 }
100
101 uint8_t
SOSync(void)102 SOSync(void)
103 {
104 unsigned short crc = 0;
105 SECTOR_OBJECTp sop;
106
107 for (sop = SectorObject; sop < &SectorObject[MAX_SECTOR_OBJECTS]; sop++)
108 {
109 updatecrc(crc, (sop->xmid) & 255);
110 updatecrc(crc, (sop->ymid) & 255);
111 updatecrc(crc, (sop->zmid) & 255);
112 updatecrc(crc, (sop->vel) & 255);
113 updatecrc(crc, (sop->ang) & 255);
114 updatecrc(crc, (sop->ang_moving) & 255);
115 updatecrc(crc, (sop->spin_ang) & 255);
116 }
117
118 return (uint8_t) crc & 255;
119 }
120
121
122 uint8_t
EnemySync(void)123 EnemySync(void)
124 {
125 unsigned short crc = 0;
126 short j, nextj;
127 SPRITEp spr;
128
129 TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], j, nextj)
130 {
131 spr = &sprite[j];
132 updatecrc(crc, (spr->x) & 255);
133 updatecrc(crc, (spr->y) & 255);
134 updatecrc(crc, (spr->z) & 255);
135 updatecrc(crc, (spr->ang) & 255);
136 }
137
138 #if 0
139 extern char DemoTmpName[];
140 //DSPRINTF(ds, "Demo Tmp Name %s", DemoTmpName);
141 MONO_PRINT(ds);
142
143 {
144 if (Once < 1 && DemoTmpName[0] != '\0')
145 {
146 FILE *fout;
147
148 Once++;
149 fout = fopen(DemoTmpName, "wb");
150
151 //DSPRINTF(ds, "Demo Tmp Name %s", DemoTmpName);
152 MONO_PRINT(ds);
153
154 TRAVERSE_SPRITE_STAT(headspritestat[STAT_ENEMY], j, nextj)
155 {
156 spr = &sprite[j];
157
158 fprintf(fout, "num %d, spr->x %d, spr->y %d, spr->z %d, spr->ang %d, spr->picnum %d\n", j, spr->x, spr->y, spr->z, spr->ang, spr->picnum);
159 }
160 fclose(fout);
161 }
162 }
163 #endif
164
165 return (uint8_t) crc & 255;
166 }
167
168 uint8_t
MissileSync(void)169 MissileSync(void)
170 {
171 unsigned short crc = 0;
172 short j, nextj;
173 SPRITEp spr;
174
175 TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISSILE], j, nextj)
176 {
177 spr = &sprite[j];
178 updatecrc(crc, (spr->x) & 255);
179 updatecrc(crc, (spr->y) & 255);
180 updatecrc(crc, (spr->z) & 255);
181 updatecrc(crc, (spr->ang) & 255);
182 }
183
184 return (uint8_t) crc & 255;
185 }
186
187 uint8_t
MissileSkip4Sync(void)188 MissileSkip4Sync(void)
189 {
190 unsigned short crc = 0;
191 short j, nextj;
192 SPRITEp spr;
193
194 TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISSILE_SKIP4], j, nextj)
195 {
196 spr = &sprite[j];
197 updatecrc(crc, (spr->x) & 255);
198 updatecrc(crc, (spr->y) & 255);
199 updatecrc(crc, (spr->z) & 255);
200 updatecrc(crc, (spr->ang) & 255);
201 }
202
203 return (uint8_t) crc & 255;
204 }
205
206 uint8_t
ShrapSync(void)207 ShrapSync(void)
208 {
209 unsigned short crc = 0;
210 short j, nextj;
211 SPRITEp spr;
212
213 TRAVERSE_SPRITE_STAT(headspritestat[STAT_SHRAP], j, nextj)
214 {
215 spr = &sprite[j];
216 updatecrc(crc, (spr->x) & 255);
217 updatecrc(crc, (spr->y) & 255);
218 updatecrc(crc, (spr->z) & 255);
219 updatecrc(crc, (spr->ang) & 255);
220 }
221
222 return (uint8_t) crc & 255;
223 }
224
225 uint8_t
MiscSync(void)226 MiscSync(void)
227 {
228 unsigned short crc = 0;
229 short j, nextj;
230 SPRITEp spr;
231
232 TRAVERSE_SPRITE_STAT(headspritestat[STAT_MISC], j, nextj)
233 {
234 spr = &sprite[j];
235 updatecrc(crc, (spr->x) & 255);
236 updatecrc(crc, (spr->y) & 255);
237 updatecrc(crc, (spr->z) & 255);
238 updatecrc(crc, (spr->ang) & 255);
239 }
240
241 return (uint8_t) crc & 255;
242 }
243
244 uint8_t
RandomSync(void)245 RandomSync(void)
246 {
247 unsigned short crc = 0;
248
249 updatecrc(crc, randomseed & 255);
250 updatecrc(crc, (randomseed >> 8) & 255);
251
252 if (NumSyncBytes == 1)
253 {
254 updatecrc(crc,PlayerSync() & 255);
255 updatecrc(crc,PlayerSync2() & 255);
256 updatecrc(crc,MissileSync() & 255);
257 }
258
259 return (uint8_t) crc & 255;
260 }
261
262 /*
263 #define STAT_SKIP2_START 2
264 #define STAT_ENEMY 2
265 #define STAT_DEAD_ACTOR 3 //misc actor stuff - dead guys etc
266 #define STAT_MISSILE 4
267 #define STAT_SKIP2_END 4
268
269 #define STAT_SKIP4_START 5
270 #define STAT_ITEM 5
271 #define STAT_SKIP4 6
272 #define STAT_MISSILE_SKIP4 7
273 #define STAT_ENEMY_SKIP4 8
274 #define STAT_SKIP4_END 8
275 */
276
277 const char *SyncNames[] =
278 {
279 "RandomSync",
280 "PlayerSync",
281 "PlayerSync2",
282 "SOSync",
283 "EnemySync",
284 "MissileSync",
285 "ShrapSync",
286 "MiscSync",
287 "MissileSkip4Sync",
288 NULL
289 };
290
291 static uint8_t(*SyncFunc[MAXSYNCBYTES + 1]) (void) =
292 {
293 RandomSync,
294 PlayerSync,
295 PlayerSync2,
296 SOSync,
297 EnemySync,
298 MissileSync,
299 ShrapSync,
300 MiscSync,
301 MissileSkip4Sync,
302 NULL
303 };
304
305 void
getsyncstat(void)306 getsyncstat(void)
307 {
308 int i;
309 PLAYERp pp = Player + myconnectindex;
310 unsigned int val;
311 static unsigned int count;
312
313 if (!CommEnabled)
314 return;
315
316 if (numplayers < 2)
317 return;
318
319 for (i = 0; SyncFunc[i]; i++)
320 {
321 pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][i] = (*SyncFunc[i])();
322 }
323
324 val = pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][0];
325 count += val;
326
327 pp->syncvalhead++;
328 }
329
330 ////////////////////////////////////////////////////////////////////////
331 //
332 // Sync Message print
333 //
334 ////////////////////////////////////////////////////////////////////////
335
336
337 void
SyncStatMessage(void)338 SyncStatMessage(void)
339 {
340 int i, j;
341 static unsigned int MoveCount = 0;
342 extern unsigned int MoveThingsCount;
343
344 if (!CommEnabled)
345 return;
346
347 if (!SyncPrintMode)
348 return;
349
350 if (numplayers <= 1)
351 return;
352
353 for (i = 0; i < NumSyncBytes; i++)
354 {
355 // syncstat is NON 0 - out of sync
356 if (syncstat[i] != 0)
357 {
358 if (NumSyncBytes > 1)
359 {
360 sprintf(ds, "GAME OUT OF SYNC - %s", SyncNames[i]);
361 printext256(68L, 68L + (i * 8), 1, 31, ds, 0);
362 }
363
364 if (!sync_found && sync_first[i][0] == '\0')
365 {
366 // sync_found one so test all of them and then never test again
367 sync_found = TRUE;
368
369 // save off loop count
370 MoveCount = MoveThingsCount;
371
372 for (j = 0; j < NumSyncBytes; j++)
373 {
374 if (syncstat[j] != 0 && sync_first[j][0] == '\0')
375 {
376 sprintf(ds, "OUT OF SYNC - %s", SyncNames[j]);
377 strcpy(sync_first[j], ds);
378 }
379 }
380 }
381 }
382 }
383
384 // print out the sync_first message you got
385 for (i = 0; i < NumSyncBytes; i++)
386 {
387 if (sync_first[i][0] != '\0')
388 {
389 if (NumSyncBytes > 1)
390 {
391 sprintf(ds, "FIRST %s", sync_first[i]);
392 printext256(50L, 0L, 1, 31, ds, 0);
393 sprintf(ds, "MoveCount %u",MoveCount);
394 printext256(50L, 10L, 1, 31, ds, 0);
395 }
396 else
397 {
398 short w,h;
399 // production out of sync error
400
401 sprintf(ds,"GAME OUT OF SYNC!");
402 MNU_MeasureString(ds, &w, &h);
403 MNU_DrawString(TEXT_TEST_COL(w), 20, ds, 0, 19);
404
405 sprintf(ds,"Restart the game.");
406 MNU_MeasureString(ds, &w, &h);
407 MNU_DrawString(TEXT_TEST_COL(w), 30, ds, 0, 19);
408 }
409 }
410 }
411
412 if (syncstate != 0)
413 printext256(68L, 92L, 1, 31, "Missed Network packet!", 0);
414 }
415
416
417 void
GetSyncInfoFromPacket(uint8_t * packbuf,int packbufleng,int * j,int otherconnectindex)418 GetSyncInfoFromPacket(uint8_t *packbuf, int packbufleng, int *j, int otherconnectindex)
419 {
420 int sb, i;
421 extern int syncvaltottail;
422 PLAYERp ppo = &Player[otherconnectindex];
423 SWBOOL found = FALSE;
424
425 // have had problems with this routine crashing when players quit
426 // games.
427
428 // if ready2send is not set then don't try to get sync info
429
430 if (!ready2send)
431 return;
432
433 // Suspect that its trying to traverse the connect list
434 // for a player that does not exist. This tries to take care of that
435
436 TRAVERSE_CONNECT(i)
437 {
438 if (otherconnectindex == i)
439 found = TRUE;
440 }
441
442 if (!found)
443 return;
444
445 // sync testing
446 //while ((*j) != packbufleng) // changed this on Kens suggestion
447 while ((*j) < packbufleng)
448 {
449 for (sb = 0; sb < NumSyncBytes; sb++)
450 {
451 ppo->syncval[ppo->syncvalhead & (SYNCFIFOSIZ - 1)][sb] = packbuf[(*j)++];
452 }
453 ppo->syncvalhead++;
454 }
455
456 // update syncstat
457 // if any of the syncstat vars is non-0 then there is a problem
458 TRAVERSE_CONNECT(i)
459 {
460 if (Player[i].syncvalhead == syncvaltottail)
461 return;
462 }
463
464 //for (sb = 0; sb < NumSyncBytes; sb++)
465 // syncstat[sb] = 0;
466
467 while (TRUE)
468 {
469 for (i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i])
470 {
471 for (sb = 0; sb < NumSyncBytes; sb++)
472 {
473 if (Player[i].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb] != Player[connecthead].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb])
474 {
475 syncstat[sb] = 1;
476 }
477 }
478 }
479
480 syncvaltottail++;
481
482 TRAVERSE_CONNECT(i)
483 {
484 if (Player[i].syncvalhead == syncvaltottail)
485 return;
486 }
487 }
488 }
489
490
491 ////////////////////////////////////////////////////////////////////////
492 //
493 // Demo Sync recording and testing
494 //
495 ////////////////////////////////////////////////////////////////////////
496
497 extern FILE *DemoSyncFile;
498
499 void
demosync_record(void)500 demosync_record(void)
501 {
502 int i;
503 uint8_t sync_val;
504
505 for (i = 0; SyncFunc[i]; i++)
506 {
507 sync_val = (*SyncFunc[i])();
508 fwrite(&sync_val, sizeof(sync_val), 1, DemoSyncFile);
509 }
510 }
511
512 void
demosync_test(int cnt)513 demosync_test(int cnt)
514 {
515 int i;
516 uint8_t sync_val;
517
518 for (i = 0; SyncFunc[i]; i++)
519 {
520 fread(&sync_val, sizeof(sync_val), 1, DemoSyncFile);
521
522 if (sync_val != (*SyncFunc[i])())
523 {
524 TerminateLevel();
525 TerminateGame();
526 printf("Demo out of sync - Sync Byte Number %d - Iteration %d.", i, cnt);
527 exit(0);
528 }
529 }
530 }
531
532
533
534 /*
535 getsyncbyte()
536 {
537 int i, j;
538 char ch;
539 SPRITEp spr;
540 PLAYERp pp;
541 USERp u;
542
543 ch = (char) (randomseed & 255);
544
545 for (i = connecthead; i >= 0; i = connectpoint2[i])
546 {
547 pp = Player + i;
548 u = User[pp->SpriteP - sprite];
549 ch ^= (pp->posx ^ pp->posy ^ pp->posz ^ fix16_to_int(pp->q16ang) ^ fix16_to_int(pp->q16horiz) ^ u->Health);
550 }
551
552 for (j = headspritestat[STAT_ENEMY]; j >= 0; j = nextspritestat[j])
553 {
554 spr = &sprite[j];
555 ch ^= spr->x ^ spr->y ^ spr->z ^ spr->ang;
556 }
557
558 return (ch);
559 }
560 */
561 #endif
562
563