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