1 /*
2 This program is free software; you can redistribute it and/or
3 modify it under the terms of the GNU General Public License
4 as published by the Free Software Foundation; either version 2
5 of the License, or (at your option) any later version.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
11 See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
17 $Id$
18 */
19
20 #include "defs.h"
21
22 void ReadPackets (void);
23
24 typedef struct
25 {
26 int running;
27 float time;
28 float diff;
29 float ratio;
30 qbool synced;
31 } info_t;
32
33 static info_t info[MAX_CLIENTS];
34 static sizebuf_t dummy;
35
36 enum {T_ENT, T_CL};
37
FindEntity(int type,frame_t * f,int num,int frame)38 void *FindEntity(int type, frame_t *f, int num, int frame)
39 {
40 //f = &d->frames[frame&UPDATE_MASK];
41 f += frame&UPDATE_MASK;
42
43 switch (type)
44 {
45 case T_ENT:
46 {
47 packet_entities_t *p;
48 int i;
49
50 if (f->invalid)
51 return NULL;
52
53 p = &f->packet_entities;
54 for (i = 0; i < p->num_entities; i++)
55 if (p->entities[i].number == num)
56 return &p->entities[i];
57
58 return NULL;
59 }
60
61 case T_CL:
62 if (f->playerstate[num].messagenum == frame)
63 return &f->playerstate[num];
64
65 return NULL;
66 default:
67 return NULL;
68 }
69 }
70
app(vec3_t o1,vec3_t po1,vec3_t o2,vec3_t po2,float * sec,float t1,float t2)71 qbool app (vec3_t o1, vec3_t po1, vec3_t o2, vec3_t po2, float *sec, float t1, float t2)
72 {
73 int i,j;
74
75 for (i = 0; i < 3; i++)
76 if (o1[i] - po1[i] != 0)
77 break;
78
79 for (j = 0; j < 3; j++)
80 if (o2[j] - po2[j] != 0)
81 break;
82
83 if (i == 3)
84 return false;
85
86 if (j == 3)
87 return false;
88
89 if (po1[i] >= o2[i] && o1[i] <= o2[i] && po1[i] <= po2[i])
90 {
91 *sec = (o2[i] - o1[i])*t1/(po1[i] - o1[i]);
92 //Sys_Printf("app:%f, %f, %f %f (%f %f)\n", o1[i], o2[i], po1[i], po2[i], t1, t2);
93 return true;
94 }
95
96 if (po1[i] <= o2[i] && o1[i] >= o2[i] && po1[i] >= po2[i])
97 {
98 *sec = (o2[i] - o1[i])*t1/(o1[i] - po1[i]);
99 //Sys_Printf("app:%f, %f, %f %f (%f %f)\n", o1[i], o2[i], po1[i], po2[i], t1, t2);
100 return true;
101 }
102
103 if (po2[j] >= o1[j] && o2[j] <= o1[j] && po2[j] <= po1[j])
104 {
105 *sec = (o1[j] - o2[j])*t2/(po2[j] - o2[j]);
106 //Sys_Printf("app:%f, %f, %f %f (%f %f)\n", o1[i], o2[i], po1[i], po2[i], t1, t2);
107 return true;
108 }
109
110 if (po2[j] <= o1[j] && o2[j] >= o1[j] && po2[j] >= po1[j])
111 {
112 *sec = (o1[j] - o2[j])*t2/(o2[j] - po2[j]);
113 //Sys_Printf("app:%f, %f, %f %f (%f %f)\n", o1[i], o2[i], po1[i], po2[i], t1, t2);
114 return true;
115 }
116
117 //Sys_Printf("false\n");
118
119 return false;
120 }
121
122 #define depth 3
demcmp(source_t * d1,source_t * d2)123 float demcmp(source_t *d1, source_t *d2)
124 {
125 frame_t *f1, *f2;
126 packet_entities_t *e1, *e2;
127 player_state_t *p1, *p2, *op1, *op2;
128 entity_state_t *pe1, *pe2;
129 int i,j, c, k, p;
130 float sr;
131 vec3_t vec;
132
133 if (!d1->running)
134 return -1;
135 if (!d2->running)
136 return -1;
137
138 f1 = &d1->frames[d1->parsecount&UPDATE_MASK];
139 f2 = &d2->frames[d2->parsecount&UPDATE_MASK];
140
141 if (f1->invalid)
142 return -1;
143 if (f2->invalid)
144 return -1;
145
146 c = 0;
147 sr = 0;
148 p = 0;
149 // compare players
150 p1 = f1->playerstate;
151 p2 = f2->playerstate;
152 for (i = 0; i < MAX_CLIENTS; i++, p1++, p2++)
153 {
154 if (p1->messagenum != d1->parsecount)
155 continue;
156 if (p2->messagenum != d2->parsecount)
157 continue;
158
159 //VectorSubtract(p1->origin, p2->origin, vec);
160
161 for (k = 1; k < depth; k++)
162 {
163 op1 = (player_state_t*)FindEntity(T_CL, d1->frames, i, d1->parsecount - k);
164
165 if (!op1)
166 continue;
167
168 VectorSubtract(p1->origin, op1->origin, vec);
169 if (VectorLength(vec) > 0 && VectorLength(vec) < 100)
170 break;
171 }
172
173 if (k == depth)
174 op1 = NULL;
175
176 for (k = 1; k < depth; k++)
177 {
178 op2 = (player_state_t*)FindEntity(T_CL, d2->frames, i, d2->parsecount - k);
179
180 if (!op2)
181 continue;
182
183 VectorSubtract(p2->origin, op2->origin, vec);
184 if (VectorLength(vec) > 0 && VectorLength(vec) < 100)
185 break;
186 }
187
188 if (k == depth)
189 op2 = NULL;
190
191 if (op1 && op2)
192 {
193 vec3_t vec2;
194
195 VectorSubtract(p1->origin, p2->origin, vec);
196 VectorSubtract(p1->origin, op1->origin, vec2);
197 //Sys_Printf("ent:%d %f\n",e1->entities[i].number, VectorLength(vec)/VectorLength(vec2));
198 //return VectorLength(vec)/VectorLength(vec2);
199 sr += VectorLength(vec)/VectorLength(vec2);
200 c++;
201 }
202
203 //sr += VectorLength(vec);
204 //c++;
205 //p++;
206 //if (VectorLength(vec))
207 // Sys_Printf("cl:%d %f %s\n", i, VectorLength(vec), d1->players[i].name);
208 }
209
210 // compare entities
211 i = 0;
212 j = 0;
213
214 e1 = &f1->packet_entities;
215 e2 = &f2->packet_entities;
216
217 while (i < e1->num_entities && j < e2->num_entities)
218 {
219 if (e1->entities[i].number < e2->entities[j].number)
220 i++;
221 else if (e1->entities[i].number > e2->entities[j].number)
222 j++;
223 else
224 {
225 for (k = 1; k < depth; k++)
226 {
227 pe1 = (entity_state_t*)FindEntity(T_ENT, d1->frames, e1->entities[i].number, d1->parsecount - k);
228
229 if (!pe1)
230 continue;
231
232 VectorSubtract(e1->entities[i].origin, pe1->origin, vec);
233 if (VectorLength(vec) > 0)
234 break;
235 }
236
237 if (k == depth)
238 pe1 = NULL;
239
240 for (k = 1; k < depth; k++)
241 {
242 pe2 = (entity_state_t*)FindEntity(T_ENT, d2->frames, e2->entities[j].number, d2->parsecount - k);
243
244 if (!pe2)
245 continue;
246
247 VectorSubtract(e2->entities[j].origin, pe2->origin, vec);
248 if (VectorLength(vec) > 0)
249 break;
250 }
251 if (k == depth)
252 pe2 = NULL;
253
254 if (pe1 && pe2)
255 {
256 vec3_t vec2;
257
258 VectorSubtract(e1->entities[i].origin, e2->entities[j].origin, vec);
259 VectorSubtract(e1->entities[i].origin, pe1->origin, vec2);
260 //Sys_Printf("ent:%d %f\n",e1->entities[i].number, VectorLength(vec)/VectorLength(vec2));
261 //return VectorLength(vec)/VectorLength(vec2);
262 sr += VectorLength(vec)/VectorLength(vec2);
263 c++;
264 }
265
266 i++;
267 j++;
268 }
269 }
270
271 if (!c)
272 return -1;
273
274 return sr/c;
275 }
276
SetComparisionDemo(source_t * dem,float time1)277 qbool SetComparisionDemo(source_t *dem, float time1)
278 {
279 int num;
280
281 from = dem;
282 num = from - sources;
283
284 dem->running = (1 << (dem - sources));
285 if (from->lastframe > time1) // rewind
286 {
287 from->netchan.incoming_sequence = 0;
288 from->netchan.incoming_acknowledged= 0;
289 from->netchan.incoming_reliable_acknowledged = 0;
290 from->prevtime = 0;
291 from->time = from->worldtime = from->lastframe = from->lasttime = 0;
292 from->latency = 0;
293 from->parsecount = 0;
294 rewind(sworld.from[from-sources].file);
295 from->lastframe = -1;
296 ReadPackets();
297 }
298
299 if (time1 > (from->lastframe))
300 from->lastframe = time1;
301
302 ReadPackets();
303
304 return from->running != 0;
305 }
306
307
Synchronize(void)308 qbool Synchronize (void)
309 {
310 int i, j, bad;
311 info_t *p;
312 source_t *dem1, *dem2;
313 float prevdesync = 0.0, before = 0.0, after = 0.0, diff, desync = 0.0, f = 0.0, newdesync = 0.0, x = 0.0, y = 0.0, mindiff = 0.0, m = 0.0, sr = 0.0, c = 0.0, sr2 = 0.0, sec2 = 0.0, test = 0.0, test2 = 0.0;
314 byte buf[15*MAX_MSGLEN];
315 qbool done;
316
317 if (sworld.fromcount == 1)
318 return true;
319
320 sworld.options |= O_QWDSYNC;
321
322 memset(&dummy, 0, sizeof(dummy));
323 dummy.data = buf;
324 dummy.maxsize = sizeof(buf);
325
326 msgbuf = &dummy;
327 world.time = 0;
328
329 // get starting info about demos
330 for (p = info, from = sources; from - sources < sworld.fromcount; from++, p++)
331 {
332 if (!from->running)
333 continue;
334
335 rewind(sworld.from[from-sources].file);
336 memset(&from->netchan, 0, sizeof(from->netchan));
337 from->latency = from->worldtime = from->lastframe = from->lasttime = 0.0; // float
338 from->prevtime = 0; // long
339 from->parsecount = 0; // int
340
341 p->running = from->running;
342 p->diff = 0;
343 p->synced = false;
344 from->lastframe = -1;
345 ReadPackets();
346 p->time = from->time;
347 p->ratio = 1;
348 }
349
350 dem1 = sources;
351 info[0].synced = true;
352
353 // now read another demo and try to compare
354 for (i = 1, dem2 = sources + 1; i < sworld.fromcount; dem2++, i++)
355 {
356 if (!dem2->running)
357 continue;
358
359 // initial guess for time desync
360 x = 1;
361 y = info[i].time - info[0].time;
362 // rewind dem1
363 if (!SetComparisionDemo(dem1, info->time))
364 {
365 sworld.options -= O_QWDSYNC;
366 return false;
367 }
368
369 // read 10 sec from dem2
370 while (dem1->running)
371 {
372 j = 0;
373 diff = 0;
374 if (!dem2->running)
375 SetComparisionDemo(dem2, info[i].time);
376
377 while (dem1->running && dem2->running && dem2->time - dem1->time < x + y)
378 {
379 if (diff <0)
380 {
381 f = dem2->time - dem1->time;
382
383 from = dem1;
384 from->lastframe += 1;
385 ReadPackets();
386
387 from = dem2;
388 while (from->running && from->time < dem1->time + f)
389 ReadPackets();
390 }
391 else
392 {
393 from = dem2;
394 ReadPackets();
395 }
396
397 diff = demcmp(dem1, dem2);
398
399 //Sys_Printf("diff:%f, %f, %f %f\n", diff, dem2->worldtime - dem1->worldtime, dem1->worldtime, dem2->worldtime);
400
401 if (diff < 0 || diff > 5)
402 continue;
403
404 f = dem2->time + 1;
405 desync = dem1->time - dem2->time;
406 from = dem2;
407
408 //Sys_Printf("diff:%f, desync:%f\n", diff, desync);
409 while (from->running && from->time < f)
410 {
411 ReadPackets();
412 m = demcmp(dem1, dem2);
413 if (m < 0 || m >= diff)
414 continue;
415
416 diff = m;
417 desync = dem1->time - dem2->time;
418 }
419
420 //Sys_Printf("diff:%f, desync:%f\n", diff, desync);
421
422 bad = 0;
423 j = 0;
424 sr = 0;
425 c = 0;
426 sr2 = 0;
427
428 //dem1->lastframe += 1;
429 test = desync;
430
431 while (dem1->running && dem2->running && bad < 5 && j < 30)
432 {
433 from = dem1;
434 //from->lastframe += 0.5;
435 f = from->time + 0.5;
436 while (from->running && from->time < f)
437 ReadPackets();
438
439 from = dem2;
440 f = -1;
441 m = -1;
442 while (from->running && from->time + desync < dem1->time + 0.25)
443 {
444 ReadPackets();
445 m = demcmp(dem1, dem2);
446 if ( m < 0)
447 continue;
448
449 if (f < 0 || f > m)
450 {
451 f = m;
452 newdesync = dem1->time - dem2->time;
453 }
454 }
455
456 //m = demcmp(dem1, dem2);
457
458 if (f < 0)
459 continue;
460
461 //Sys_Printf("diff:%f\n", f);
462 if (f > 1)
463 {
464 bad++;
465 continue;
466 }
467
468 m = newdesync - test;
469 test += m < 0 ? max(-0.025, m) : min(0.025, m);
470
471 if (!f)
472 f = 0.01f;
473
474 f = 1;
475 sr2 += 1/(f*f);
476 sr += newdesync/(f*f);
477 c++;
478
479 desync = test;
480
481 if (c > 10)
482 desync = sr/sr2;
483
484 j++;
485 }
486
487 //Sys_Printf("\n%f %d %d, %d, %f\n",desync, j , bad, c, x);
488
489 if (bad == 5)
490 {
491 diff = 0;
492 continue;
493 }
494
495 if (j == 30)
496 break;
497 }
498
499 if (j == 30)
500 {
501 Sys_Printf("sync1:%f %f\n", desync, sr/sr2);
502 if (c)
503 desync = sr/sr2;
504
505 desync = test;
506 before = dem2->time;
507 prevdesync = desync;
508
509
510 sr = 0;
511 c = 0;
512 sr2 = 0;
513 j = 0;
514 #if 1
515 //desync = 0.5;
516 if (desync < 0)
517 {
518 SetComparisionDemo(dem1, info->time - desync + 2);
519 SetComparisionDemo(dem2, 0);
520 }
521 else
522 {
523 SetComparisionDemo(dem1, info->time + 2);
524 SetComparisionDemo(dem2, info[i].time + desync);
525 }
526
527 test = desync;
528
529 while (dem1->running && dem2->running && j < 800)
530 {
531 from = dem1;
532 f = from->time + 2;
533 while (from->running && from->time < f)
534 ReadPackets();
535 //from->lastframe += 1;
536 //ReadPackets();
537
538 from = dem2;
539 f = -999;
540 m = -999;
541 sec2 = 0;
542 while (from->running && from->time + desync < dem1->time + 1)
543 {
544 ReadPackets();
545 sec2 = 0;
546
547 m = demcmp(dem1, dem2);
548 if ( m < 0)
549 continue;
550
551 if (f < 0 || f > m)
552 {
553 f = m;
554 newdesync = dem1->time - dem2->time;
555 }
556
557 }
558
559 if (fabs(f) < 1)
560 {
561 test2 = 0;
562 m = newdesync - test;
563 test += m < 0 ? max(-0.025, m) : min(0.025, m);
564
565 //Sys_Printf("%f %f %f %f, %f %f\n",newdesync, f, desync, test, dem1->time, dem1->time - newdesync);
566 if (!f)
567 f = 0.1f;
568 f = 1;
569 sr2 += 1/(f*f);
570 sr += newdesync/(f*f);
571 c++;
572 }
573 else if (f > 4)
574 {
575 test2++;
576 if (test2 == 5)
577 Sys_Printf("lag:%f, %d\n", dem1->worldtime, dem2-sources);
578
579 }
580
581 if (f < 0)
582 continue;
583
584 if (c > 10)
585 //desync = sr/sr2;
586 desync = test;
587
588 after = dem2->time;
589 j++;
590 }
591 //Sys_Printf("j:%d sync:%f\n", j, desync);
592
593 if (c)
594 {
595 //desync = sr/sr2;
596 desync = test;
597 //Sys_Printf("time:%f, b:%f, a:%f, p:%f, d:%f\n", info[i].time, before, after, prevdesync, desync);
598 info[i].ratio = (after - before + desync - prevdesync)/(after - before);
599 //Sys_Printf("ratio:%f\n", info[i].ratio);
600 f = (desync - prevdesync)/(after - before);
601 desync += f*(info[i].time - after);
602 }
603
604
605 #endif
606 info[i].diff = desync;
607 info[i].synced = true;
608 if (mindiff > desync)
609 mindiff = desync;
610 break;
611 }
612
613 //Sys_Printf("another try\n");
614 x *= 2;
615 SetComparisionDemo(dem1, info->time + x);
616 SetComparisionDemo(dem2, info[i].time);
617 }
618
619 }
620
621 done = true;
622 diff = -1;
623 for (i = 0, p = info, from = sources; i < sworld.fromcount; i++, p++, from++)
624 {
625 if (!p->running)
626 continue;
627
628 from->running = p->running;
629 rewind(sworld.from[i].file);
630 from->netchan.incoming_sequence = 0;
631 from->netchan.incoming_acknowledged = 0;
632 from->sync = p->diff - mindiff;
633 from->worldtime = from->latency = from->time = from->lasttime = from->lastframe = 0;
634 from->prevtime = 0;
635 from->parsecount = 0;
636 from->ratio = p->ratio;
637 if (!p->synced)
638 {
639 Sys_Printf(" couldn't synchronize %s\n", sworld.from[i].name);
640 done = false;
641 }
642 else
643 Sys_Printf(" time offset:%f, time ratio:%f\n", from->sync, from->ratio);
644
645 from->lastframe = -1;
646 ReadPackets();
647 if (diff < from->worldtime)
648 diff = from->worldtime;
649 }
650
651 world.signonstats = true;
652 for (from = sources; from - sources < sworld.fromcount; from++)
653 {
654 while (from->running && from->worldtime < diff)
655 ReadPackets();
656 }
657
658 world.signonstats = false;
659 sworld.options -= O_QWDSYNC;
660
661 return done;
662 }
663