1 /*
2 	Relay -- a tool to record and play Quake2 demos
3 	Copyright (C) 2000 Conor Davis
4 
5 	This program is free software; you can redistribute it and/or
6 	modify it under the terms of the GNU General Public License
7 	as published by the Free Software Foundation; either version 2
8 	of the License, or (at your option) any later version.
9 
10 	This program is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program; if not, write to the Free Software
17 	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 	Conor Davis
20 	cedavis@planetquake.com
21 */
22 
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "block.h"
28 #include "cmd.h"
29 #include "dm2.h"
30 #include "endian.h"
31 #include "pak.h"
32 #include "q2defines.h"
33 #include "shared.h"
34 #include "utils.h"
35 
36 //
37 // DM2_Init
38 // Initializes a dm2_t struct so that it can
39 // be properly read or written to.
40 //
41 
DM2_Init(dm2_t * dm2)42 void DM2_Init(dm2_t *dm2)
43 {
44 	int i;
45 
46 	memset(dm2, 0, sizeof(dm2_t));
47 	for (i = 1; i < MAX_EDICTS; i++)
48 		dm2->baselines.entities[i].number = i;
49 	for (i = 0; i < UPDATE_BACKUP; i++)
50 		dm2->states[i].frame = BASELINES_FRAME;
51 	dm2->baselines.frame = BASELINES_FRAME;
52 }
53 
54 // pre-0.4 relay demos could leave gaps in the model table (bad);
55 // this attempts to fix it
DM2_FillConfigstrings(char (* configstrings)[64])56 void DM2_FillConfigstrings(char (*configstrings)[64])
57 {
58 	int i;
59 
60 	for (i = 2; i < MAX_MODELS; i++)
61 	{
62 		if (configstrings[CS_MODELS+i][0] && configstrings[CS_MODELS+i][0] != '*')
63 			break;
64 
65 		if (!configstrings[CS_MODELS+i][0])
66 			sprintf(configstrings[CS_MODELS+i], "*%d", i - 1);
67 	}
68 }
69 
70 //
71 // DM2_ReadBlock
72 // Reads a dm2 block from a file.
73 //
74 
DM2_ReadBlock(block_t * block,PFILE * fd)75 int DM2_ReadBlock(block_t *block, PFILE *fd)
76 {
77 	if (!pfread(&block->writeoffset, 4, 1, fd))
78 		block->writeoffset = 0xffffffff;
79 	else
80 		block->writeoffset = LittleLong(block->writeoffset);
81 
82 	if (block->writeoffset == 0xffffffff)
83 		return 0;
84 
85 	if (WriteOverflow(block))
86 		return -1;
87 
88 	if (!pfread(block->buffer, block->writeoffset, 1, fd))
89 	{
90 		block->writeoffset = 0;
91 		return -1;
92 	}
93 	block->readoffset = 0;
94 
95 	return 0;
96 }
97 
98 //
99 // DM2_WriteBlock
100 // Writes a demo block to a file.
101 //
102 
DM2_WriteBlock(block_t * block,PFILE * fd)103 int DM2_WriteBlock(block_t *block, PFILE *fd)
104 {
105 	int len;
106 
107 	len = LittleLong(block->writeoffset);
108 	if (!pfwrite(&len, 4, 1, fd))
109 		return -1;
110 
111 	if (!pfwrite(block->buffer, block->writeoffset, 1, fd))
112 		return -1;
113 
114 	return 0;
115 }
116 
117 //
118 // functions to read/write dm2 messages
119 // they should return the number of bytes read, or -1
120 // on error
121 //
122 
123 #define SET(a,b)		((a) ? *(a) = (b) : (b))
124 #define SETSTR(a,b) 	((a) ? strcpy((a), (b)) : (b))
125 #define SETSTRN(a,b,c)	((a) ? ( (a)[(c)-1] = 0, strncpy((a), (b), (c)) ) : (b))
126 
127 // for SVC_LAYOUT, SVC_CENTERPRINT, and SVC_STUFFTEXT
DM2_ReadGenericString(block_t * block,char * p,size_t len)128 int DM2_ReadGenericString(block_t *block, char *p, size_t len)
129 {
130 	const char	*s;
131 	size_t		start;
132 
133 	start = block->readoffset;
134 	s = ReadString(block);
135 
136 	if (ReadOverflow(block))
137 		return -1;
138 
139 	if (p)
140 	{
141 		strncpy(p, s, len-1);
142 		p[len-1] = 0;
143 	}
144 
145 	return block->readoffset - start;
146 }
147 
DM2_WriteGenericString(block_t * block,const char * p)148 int DM2_WriteGenericString(block_t *block, const char *p)
149 {
150 	size_t	start;
151 
152 	start = block->writeoffset;
153 	WriteString(block, p);
154 
155 	if (WriteOverflow(block))
156 		return -1;
157 
158 	return block->writeoffset - start;
159 }
160 
DM2_ReadMuzzleflash(block_t * block,int * entity,int * value)161 int DM2_ReadMuzzleflash(block_t *block, int *entity, int *value)
162 {
163 	SET(entity, (unsigned short)ReadShort(block));
164 	SET(value, ReadByte(block));
165 
166 	if (ReadOverflow(block))
167 		return -1;
168 
169 	// 3 bytes were read
170 	return 3;
171 }
172 
DM2_WriteMuzzleflash(block_t * block,int entity,int value)173 int DM2_WriteMuzzleflash(block_t *block, int entity, int value)
174 {
175 	WriteShort(block, (unsigned short)entity);
176 	WriteByte(block, (byte)value);
177 
178 	if (WriteOverflow(block))
179 		return -1;
180 
181 	// wrote 3 bytes
182 	return 3;
183 }
184 
DM2_ReadTempEntity(block_t * block,const dm2_t * dm2,temp_entity_t * p)185 int DM2_ReadTempEntity(block_t *block, const dm2_t *dm2, temp_entity_t *p)
186 {
187 	size_t			start;
188 	temp_entity_t	m;
189 
190 	start = block->readoffset;
191 	m.entity = 0;
192 	m.dest_entity = 0;
193 
194 	m.type = ReadByte(block);
195 	switch(m.type)
196 	{
197 	// case TE_PLASMATRAIL: 		// old meaning
198 	case TE_GREENBLOOD: 			// new meaning (3.15+)
199 		if (dm2->svd.version >= 32)
200 			goto impact_entity;
201 		else
202 			goto line_entity;
203 	// case TE_GREENBLOOD_old:		// old meaning
204 	case TE_BLUEHYPERBLASTER:		// new meaning (3.15+)
205 		if (dm2->svd.version >= 32)
206 			goto line_entity;
207 		else
208 			goto impact_entity;
209 		// point entity
210 	case TE_EXPLOSION1:
211 	case TE_EXPLOSION2:
212 	case TE_ROCKET_EXPLOSION:
213 	case TE_GRENADE_EXPLOSION:
214 	case TE_ROCKET_EXPLOSION_WATER:
215 	case TE_GRENADE_EXPLOSION_WATER:
216 	case TE_BFG_EXPLOSION:
217 	case TE_BFG_BIGEXPLOSION:
218 	case TE_BOSSTPORT:
219 	case TE_PLASMA_EXPLOSION:
220 	case TE_PLAIN_EXPLOSION:
221 	case TE_CHAINFIST_SMOKE:
222 	case TE_TRACKER_EXPLOSION:
223 	case TE_TELEPORT_EFFECT:
224 	case TE_DBALL_GOAL:
225 	case TE_NUKEBLAST:
226 	case TE_WIDOWSPLASH:
227 	case TE_EXPLOSION1_BIG:
228 	case TE_EXPLOSION1_NP:
229 		ReadPosition(block, m.origin);
230 		break;
231 		// impact entity
232 	case TE_GUNSHOT:
233 	case TE_BLOOD:
234 	case TE_BLASTER:
235 	case TE_SHOTGUN:
236 	case TE_SPARKS:
237 	case TE_SCREEN_SPARKS:
238 	case TE_SHIELD_SPARKS:
239 	case TE_BULLET_SPARKS:
240 	// case TE_GREENBLOOD_new:
241 	// case TE_GREENBLOOD_old:
242 	case TE_BLASTER2:
243 	case TE_MOREBLOOD:
244 	case TE_HEATBEAM_SPARKS:
245 	case TE_HEATBEAM_STEAM:
246 	case TE_ELECTRIC_SPARKS:
247 	case TE_FLECHETTE:
248 impact_entity:
249 		ReadPosition(block, m.origin);
250 		ReadDir(block, m.movedir);
251 		break;
252 	// line entity
253 	case TE_RAILTRAIL:
254 	case TE_BUBBLETRAIL:
255 	case TE_BFG_LASER:
256 	// case TE_PLASMATRAIL:
257 	// case TE_BLUEHYPERBLASTER:
258 	case TE_DEBUGTRAIL:
259 	case TE_BUBBLETRAIL2:
260 line_entity:
261 		ReadPosition(block, m.origin);
262 		ReadPosition(block, m.endpos);
263 		break;
264 	// special entity
265 	case TE_SPLASH:
266 	case TE_LASER_SPARKS:
267 	case TE_WELDING_SPARKS:
268 	case TE_TUNNEL_SPARKS:
269 		m.count = ReadByte(block);
270 		ReadPosition(block, m.origin);
271 		ReadDir(block, m.movedir);
272 		m.style = ReadByte(block);
273 		break;
274 	case TE_PARASITE_ATTACK:
275 	case TE_MEDIC_CABLE_ATTACK:
276 	case TE_HEATBEAM:
277 	case TE_MONSTER_HEATBEAM:
278 		m.entity = ReadShort(block);
279 		ReadPosition(block, m.origin);
280 		ReadPosition(block, m.endpos);
281 		break;
282 	case TE_GRAPPLE_CABLE:
283 		m.entity = ReadShort(block);
284 		ReadPosition(block, m.origin);
285 		ReadPosition(block, m.endpos);
286 		ReadPosition(block, m.pos1);
287 		break;
288 	case TE_FLAME:
289 		m.entity = ReadShort(block);
290 		m.count = ReadShort(block);
291 		ReadPosition(block, m.endpos);
292 		ReadPosition(block, m.origin);
293 		ReadPosition(block, m.pos1);
294 		ReadPosition(block, m.pos2);
295 		ReadPosition(block, m.pos3);
296 		ReadPosition(block, m.pos4);
297 		break;
298 	case TE_LIGHTNING:
299 		m.dest_entity = ReadShort(block);
300 		m.entity = ReadShort(block);
301 		ReadPosition(block, m.endpos);
302 		ReadPosition(block, m.origin);
303 		break;
304 	case TE_FLASHLIGHT:
305 		ReadPosition(block, m.origin);
306 		m.entity = ReadShort(block);
307 		break;
308 	case TE_FORCEWALL:
309 		ReadPosition(block, m.origin);
310 		ReadPosition(block, m.endpos);
311 		m.style = ReadShort(block);
312 		break;
313 	case TE_STEAM:
314 		m.nextid = ReadShort(block);
315 		m.count = ReadByte(block);
316 		ReadPosition(block, m.origin);
317 		ReadDir(block, m.movedir);
318 		m.style = ReadByte(block);
319 		m.plat2flags = ReadShort(block);
320 		if (m.nextid != -1)
321 			m.wait = ReadLong(block);
322 		break;
323 	default:
324 		return -1;
325 		break;
326 	}
327 
328 	if (ReadOverflow(block))
329 		return -1;
330 
331 	if (p)
332 		*p = m;
333 
334 	return block->readoffset - start;
335 }
336 
DM2_WriteTempEntity(block_t * block,const dm2_t * dm2,const temp_entity_t * p)337 int DM2_WriteTempEntity(block_t *block, const dm2_t *dm2, const temp_entity_t *p)
338 {
339 	size_t	start;
340 
341 	start = block->writeoffset;
342 
343 	WriteByte(block, p->type);
344 	switch(p->type)
345 	{
346 	// case TE_PLASMATRAIL: 		// old meaning
347 	case TE_GREENBLOOD: 			// new meaning (3.15+)
348 		if (dm2->svd.version >= 32)
349 			goto impact_entity;
350 		else
351 			goto line_entity;
352 	// case TE_GREENBLOOD_old:		// old meaning
353 	case TE_BLUEHYPERBLASTER:		// new meaning (3.15+)
354 		if (dm2->svd.version >= 32)
355 			goto line_entity;
356 		else
357 			goto impact_entity;
358 		// point entity
359 	case TE_EXPLOSION1:
360 	case TE_EXPLOSION2:
361 	case TE_ROCKET_EXPLOSION:
362 	case TE_GRENADE_EXPLOSION:
363 	case TE_ROCKET_EXPLOSION_WATER:
364 	case TE_GRENADE_EXPLOSION_WATER:
365 	case TE_BFG_EXPLOSION:
366 	case TE_BFG_BIGEXPLOSION:
367 	case TE_BOSSTPORT:
368 	case TE_PLASMA_EXPLOSION:
369 	case TE_PLAIN_EXPLOSION:
370 	case TE_CHAINFIST_SMOKE:
371 	case TE_TRACKER_EXPLOSION:
372 	case TE_TELEPORT_EFFECT:
373 	case TE_DBALL_GOAL:
374 	case TE_NUKEBLAST:
375 	case TE_WIDOWSPLASH:
376 	case TE_EXPLOSION1_BIG:
377 	case TE_EXPLOSION1_NP:
378 		WritePosition(block, p->origin);
379 		break;
380 		// impact entity
381 	case TE_GUNSHOT:
382 	case TE_BLOOD:
383 	case TE_BLASTER:
384 	case TE_SHOTGUN:
385 	case TE_SPARKS:
386 	case TE_SCREEN_SPARKS:
387 	case TE_SHIELD_SPARKS:
388 	case TE_BULLET_SPARKS:
389 	// case TE_GREENBLOOD_new:
390 	// case TE_GREENBLOOD_old:
391 	case TE_BLASTER2:
392 	case TE_MOREBLOOD:
393 	case TE_HEATBEAM_SPARKS:
394 	case TE_HEATBEAM_STEAM:
395 	case TE_ELECTRIC_SPARKS:
396 	case TE_FLECHETTE:
397 impact_entity:
398 		WritePosition(block, p->origin);
399 		WriteDir(block, p->movedir);
400 		break;
401 	// line entity
402 	case TE_RAILTRAIL:
403 	case TE_BUBBLETRAIL:
404 	case TE_BFG_LASER:
405 	// case TE_PLASMATRAIL:
406 	// case TE_BLUEHYPERBLASTER:
407 	case TE_DEBUGTRAIL:
408 	case TE_BUBBLETRAIL2:
409 line_entity:
410 		WritePosition(block, p->origin);
411 		WritePosition(block, p->endpos);
412 		break;
413 	// special entity
414 	case TE_SPLASH:
415 	case TE_LASER_SPARKS:
416 	case TE_WELDING_SPARKS:
417 	case TE_TUNNEL_SPARKS:
418 		WriteByte(block, (byte)p->count);
419 		WritePosition(block, p->origin);
420 		WriteDir(block, p->movedir);
421 		WriteByte(block, (byte)p->style);
422 		break;
423 	case TE_PARASITE_ATTACK:
424 	case TE_MEDIC_CABLE_ATTACK:
425 	case TE_HEATBEAM:
426 	case TE_MONSTER_HEATBEAM:
427 		WriteShort(block, p->entity);
428 		WritePosition(block, p->origin);
429 		WritePosition(block, p->endpos);
430 		break;
431 	case TE_GRAPPLE_CABLE:
432 		WriteShort(block, p->entity);
433 		WritePosition(block, p->origin);
434 		WritePosition(block, p->endpos);
435 		WritePosition(block, p->pos1);
436 		break;
437 	case TE_FLAME:
438 		WriteShort(block, p->entity);
439 		WriteShort(block, p->count);
440 		WritePosition(block, p->endpos);
441 		WritePosition(block, p->origin);
442 		WritePosition(block, p->pos1);
443 		WritePosition(block, p->pos2);
444 		WritePosition(block, p->pos3);
445 		WritePosition(block, p->pos4);
446 		break;
447 	case TE_LIGHTNING:
448 		WriteShort(block, p->dest_entity);
449 		WriteShort(block, p->entity);
450 		WritePosition(block, p->endpos);
451 		WritePosition(block, p->origin);
452 		break;
453 	case TE_FLASHLIGHT:
454 		WritePosition(block, p->origin);
455 		WriteShort(block, p->entity);
456 		break;
457 	case TE_FORCEWALL:
458 		WritePosition(block, p->origin);
459 		WritePosition(block, p->endpos);
460 		WriteShort(block, p->style);
461 		break;
462 	case TE_STEAM:
463 		WriteShort(block, p->nextid);
464 		WriteByte(block, (byte)p->count);
465 		WritePosition(block, p->origin);
466 		WriteDir(block, p->movedir);
467 		WriteByte(block, (byte)p->style);
468 		WriteShort(block, p->plat2flags);
469 		if (p->nextid != -1)
470 			WriteLong(block, p->wait);
471 		break;
472 	default:
473 		return -1;
474 		break;
475 	}
476 
477 	if (WriteOverflow(block))
478 		return -1;
479 
480 	return block->writeoffset - start;
481 }
482 
DM2_ReadInventory(block_t * block,short p[MAX_ITEMS])483 int DM2_ReadInventory(block_t *block, short p[MAX_ITEMS])
484 {
485 	int i;
486 
487 	if (p)
488 	{
489 		for (i = 0; i < MAX_ITEMS; i++)
490 			p[i] = ReadShort(block);
491 	}
492 	else
493 		BlockRead(block, NULL, MAX_ITEMS*2);
494 
495 	if (ReadOverflow(block))
496 		return -1;
497 
498 	return MAX_ITEMS*2;
499 }
500 
DM2_WriteInventory(block_t * block,const short p[MAX_ITEMS])501 int DM2_WriteInventory(block_t *block, const short p[MAX_ITEMS])
502 {
503 	int i;
504 
505 	for (i = 0; i < MAX_ITEMS; i++)
506 		WriteShort(block, p[i]);
507 
508 	if (WriteOverflow(block))
509 		return -1;
510 
511 	return MAX_ITEMS*2;
512 }
513 
DM2_ReadSound(block_t * block,int * soundindex,float * volume,float * attenuation,float * timeofs,int * entity,int * channel,vec3_t origin,qboolean * positioned)514 int DM2_ReadSound(block_t *block, int *soundindex, float *volume, float *attenuation, float *timeofs, int *entity, int *channel, vec3_t origin, qboolean *positioned)
515 {
516 	size_t	start;
517 	int 	mask, mix;
518 
519 	start = block->readoffset;
520 
521 	mask = ReadByte(block);
522 	SET(soundindex, ReadByte(block));
523 
524 	if (mask & SND_VOLUME)
525 		SET(volume, (float)ReadByte(block) / 255);
526 	else
527 		SET(volume, 1.0F);
528 
529 	if (mask & SND_ATTENUATION)
530 		SET(attenuation, (float)ReadByte(block) / 64);
531 	else
532 		SET(attenuation, 1.0F);
533 
534 	if (mask & SND_OFFSET)
535 		SET(timeofs, (float)ReadByte(block) * 0.001);
536 	else
537 		SET(timeofs, 0.0F);
538 
539 	if (mask & SND_ENT)
540 	{
541 		mix = ReadShort(block);
542 		SET(entity, mix >> 3);
543 		SET(channel, mix & 0x07);
544 	}
545 	else
546 	{
547 		SET(entity, 0);
548 		SET(channel, 0);
549 	}
550 
551 	if (mask & SND_POS)
552 	{
553 		if (origin)
554 			ReadPosition(block, origin);
555 		else
556 			BlockRead(block, NULL, 6);
557 
558 		SET(positioned, true);
559 	}
560 	else
561 		SET(positioned, false);
562 
563 	if (ReadOverflow(block))
564 		return -1;
565 
566 	return block->readoffset - start;
567 }
568 
DM2_WriteSound(block_t * block,int soundindex,float volume,float attenuation,float timeofs,int entity,int channel,vec3_t origin,qboolean positioned)569 int DM2_WriteSound(block_t *block, int soundindex, float volume, float attenuation, float timeofs, int entity, int channel, vec3_t origin, qboolean positioned)
570 {
571 	int 	mask;
572 	size_t	start;
573 
574 	start = block->writeoffset;
575 
576 	mask = 0;
577 	if (volume != 1.0F)
578 		mask |= SND_VOLUME;
579 	if (attenuation != 1.0F)
580 		mask |= SND_ATTENUATION;
581 	if (timeofs != 0.0F)
582 		mask |= SND_OFFSET;
583 	if (entity)
584 		mask |= SND_ENT;
585 	if (positioned)
586 		mask |= SND_POS;
587 
588 	WriteByte(block, (byte)mask);
589 	WriteByte(block, (byte)soundindex);
590 	if (mask & SND_VOLUME)
591 		WriteByte(block, (byte)(volume * 255));
592 	if (mask & SND_ATTENUATION)
593 		WriteByte(block, (byte)(attenuation * 64));
594 	if (mask & SND_OFFSET)
595 		WriteByte(block, (byte)(timeofs * 1000));
596 	if (mask & SND_ENT)
597 		WriteShort(block, (unsigned short)((entity << 3) | (channel & 0x07)));
598 	if (mask & SND_POS)
599 		WritePosition(block, origin);
600 
601 	if (WriteOverflow(block))
602 		return -1;
603 
604 	return block->writeoffset - start;
605 }
606 
DM2_ReadPrint(block_t * block,int * level,char * string,size_t len)607 int DM2_ReadPrint(block_t *block, int *level, char *string, size_t len)
608 {
609 	size_t	start;
610 
611 	start = block->readoffset;
612 
613 	SET(level, ReadByte(block));
614 	SETSTRN(string, ReadString(block), len);
615 
616 	if (ReadOverflow(block))
617 		return -1;
618 
619 	return block->readoffset - start;
620 }
621 
DM2_WritePrint(block_t * block,int level,const char * string)622 int DM2_WritePrint(block_t *block, int level, const char *string)
623 {
624 	size_t	start;
625 
626 	start = block->writeoffset;
627 
628 	WriteByte(block, (byte)level);
629 	WriteString(block, string);
630 
631 	if (WriteOverflow(block))
632 		return -1;
633 
634 	return block->writeoffset - start;
635 }
636 
DM2_ReadServerdata(block_t * block,serverdata_t * p)637 int DM2_ReadServerdata(block_t *block, serverdata_t *p)
638 {
639 	serverdata_t	m;
640 	size_t			start;
641 
642 	start = block->readoffset;
643 
644 	m.version = ReadLong(block);
645 	m.key = ReadLong(block);
646 	m.isdemo = ReadByte(block);
647 	strncpy(m.game, ReadString(block), sizeof(m.game)-1);
648 	m.game[sizeof(m.game)-1] = 0;
649 	m.player = ReadShort(block);
650 	strncpy(m.mapname, ReadString(block), sizeof(m.mapname)-1);
651 	m.mapname[sizeof(m.mapname)-1] = 0;
652 
653 	if (m.isdemo == RECORD_RELAY)
654 	{
655 		m.relayversion = m.version >> 16;
656 		m.version &= 0xffff;
657 	}
658 	else
659 		m.relayversion = 0;
660 
661 	if (ReadOverflow(block))
662 		return -1;
663 
664 	if (p)
665 		*p = m;
666 
667 	return block->readoffset - start;
668 }
669 
DM2_WriteServerdata(block_t * block,const serverdata_t * p)670 int DM2_WriteServerdata(block_t *block, const serverdata_t *p)
671 {
672 	size_t	start;
673 
674 	start = block->writeoffset;
675 
676 	if (p->isdemo == RECORD_RELAY)
677 		WriteLong(block, (p->relayversion << 16) | p->version);
678 	else
679 		WriteLong(block, p->version);
680 	WriteLong(block, p->key);
681 	WriteByte(block, p->isdemo);
682 	WriteString(block, p->game);
683 	WriteShort(block, p->player);
684 	WriteString(block, p->mapname);
685 
686 	if (WriteOverflow(block))
687 		return -1;
688 
689 	return block->writeoffset - start;
690 }
691 
DM2_ReadConfigstring(block_t * block,int * index,char * string)692 int DM2_ReadConfigstring(block_t *block, int *index, char *string)
693 {
694 	size_t			start;
695 
696 	start = block->readoffset;
697 
698 	SET(index, ReadShort(block));
699 	SETSTR(string, ReadString(block));
700 
701 	if (ReadOverflow(block))
702 		return -1;
703 
704 	return block->readoffset - start;
705 }
706 
DM2_WriteConfigstring(block_t * block,int index,const char * string)707 int DM2_WriteConfigstring(block_t *block, int index, const char *string)
708 {
709 	size_t	start;
710 
711 	start = block->writeoffset;
712 
713 	WriteShort(block, (unsigned short)index);
714 	WriteString(block, string);
715 
716 	if (WriteOverflow(block))
717 		return -1;
718 
719 	return block->writeoffset - start;
720 }
721 
DM2_ReadFrame(block_t * block,const serverdata_t * svd,int * seq1,int * seq2,int * area_count,byte * areas,int * connected_count,byte * connected)722 int DM2_ReadFrame(block_t *block, const serverdata_t *svd, int *seq1, int *seq2, int *area_count, byte *areas, int *connected_count, byte *connected)
723 {
724 	int 	len;
725 	size_t	start;
726 
727 	start = block->readoffset;
728 
729 	if (svd->isdemo != RECORD_SERVER)
730 	{
731 		SET(seq1, ReadLong(block));
732 		SET(seq2, ReadLong(block));
733 		if (svd->version != 26)
734 			ReadByte(block);	// ???
735 		len = ReadByte(block);
736 		SET(area_count, len);
737 		if (areas)
738 			BlockRead(block, areas, len);
739 		else
740 			BlockRead(block, NULL, len);
741 
742 		if (svd->isdemo == RECORD_RELAY)
743 		{
744 			len = ReadByte(block);
745 			SET(connected_count, len);
746 			if (connected)
747 				BlockRead(block, connected, len);
748 			else
749 				BlockRead(block, NULL, len);
750 		}
751 	}
752 	else
753 	{
754 		SET(seq1, ReadLong(block));
755 	}
756 
757 	if (ReadOverflow(block))
758 		return -1;
759 
760 	return block->readoffset - start;
761 }
762 
DM2_WriteFrame(block_t * block,const serverdata_t * svd,int seq1,int seq2,int area_count,const byte * areas,int connected_count,const byte * connected)763 int DM2_WriteFrame(block_t *block, const serverdata_t *svd, int seq1, int seq2, int area_count, const byte *areas, int connected_count, const byte *connected)
764 {
765 	size_t	start;
766 
767 	start = block->writeoffset;
768 
769 	if (svd->isdemo != RECORD_SERVER)
770 	{
771 		WriteLong(block, seq1);
772 		WriteLong(block, seq2);
773 		if (svd->version != 26)
774 			WriteByte(block, 0);	// ???
775 
776 		WriteByte(block, (byte)area_count);
777 		BlockWrite(block, areas, area_count);
778 
779 		if (svd->isdemo == RECORD_RELAY)
780 		{
781 			WriteByte(block, (byte)connected_count);
782 			BlockWrite(block, connected, connected_count);
783 		}
784 	}
785 	else
786 	{
787 		WriteLong(block, seq1);
788 	}
789 
790 	if (WriteOverflow(block))
791 		return -1;
792 
793 	return block->writeoffset - start;
794 }
795 
796 //
797 // ReadPS
798 // Reads a SVC_PLAYERINFO message from a block.
799 //
800 
DM2_ReadPS(block_t * block,player_state_t * ps)801 int DM2_ReadPS(block_t *block, player_state_t *ps)
802 {
803 	int 			mask, i;
804 	size_t			start;
805 
806 	start = block->readoffset;
807 
808 	mask = (unsigned short)ReadShort(block);
809 
810 	if (mask & PS_M_TYPE)
811 		ps->pmove.pm_type = ReadByte(block);
812 	if (mask & PS_M_ORIGIN)
813 		ReadShortPosition(block, ps->pmove.origin);
814 	if (mask & PS_M_VELOCITY)
815 		ReadShortPosition(block, ps->pmove.velocity);
816 	if (mask & PS_M_TIME)
817 		ps->pmove.pm_type = ReadByte(block);
818 	if (mask & PS_M_FLAGS)
819 		ps->pmove.pm_flags = ReadByte(block);
820 	if (mask & PS_M_GRAVITY)
821 		ps->pmove.gravity = ReadShort(block);
822 	if (mask & PS_M_DELTA_ANGLES)
823 		ReadShortPosition(block, ps->pmove.delta_angles);
824 
825 	if (mask & PS_VIEWOFFSET)
826 		ReadOffsetVec(block, ps->viewoffset);
827 	if (mask & PS_VIEWANGLES)
828 	{
829 		ps->viewangles[0] = ReadAngle16(block);
830 		ps->viewangles[1] = ReadAngle16(block);
831 		ps->viewangles[2] = ReadAngle16(block);
832 	}
833 	if (mask & PS_KICKANGLES)
834 		ReadOffsetVec(block, ps->kick_angles);
835 	if (mask & PS_WEAPONINDEX)
836 		ps->gunindex = ReadByte(block);
837 	if (mask & PS_WEAPONFRAME)
838 	{
839 		ps->gunframe = ReadByte(block);
840 		ReadOffsetVec(block, ps->gunoffset);
841 		ReadOffsetVec(block, ps->gunangles);
842 	}
843 	if (mask & PS_BLEND)
844 		ReadBlendVec(block, ps->blend);
845 	if (mask & PS_FOV)
846 		ps->fov = ReadByte(block);
847 	if (mask & PS_RDFLAGS)
848 		ps->rdflags = ReadByte(block);
849 
850 	mask = ReadLong(block);
851 	for (i = 0; i < MAX_STATS; i++)
852 	{
853 		if (mask & (1 << i))
854 			ps->stats[i] = ReadShort(block);
855 	}
856 
857 	if (ReadOverflow(block))
858 		return -1;
859 
860 	return block->readoffset - start;
861 }
862 
863 //
864 // WritePS
865 // Generates a SVC_PLAYERINFO message from two player states and
866 // writes it to a block.
867 //
868 
DM2_WritePS(block_t * block,const player_state_t * to,const player_state_t * from)869 int DM2_WritePS(block_t *block, const player_state_t *to, const player_state_t *from)
870 {
871 	unsigned short	mask;
872 	unsigned long	mask2;
873 	int 			i;
874 	size_t			start;
875 
876 	start = block->writeoffset;
877 
878 	// generate masks to save bandwidth
879 	mask = mask2 = 0;
880 	if (to->pmove.pm_type != from->pmove.pm_type)
881 		mask |= PS_M_TYPE;
882 	if (!VectorCompare(to->pmove.origin, from->pmove.origin))
883 		mask |= PS_M_ORIGIN;
884 	if (!VectorCompare(to->pmove.velocity, from->pmove.velocity))
885 		mask |= PS_M_VELOCITY;
886 	if (to->pmove.pm_time != from->pmove.pm_time)
887 		mask |= PS_M_TIME;
888 	if (to->pmove.pm_flags != from->pmove.pm_flags)
889 		mask |= PS_M_FLAGS;
890 	if (to->pmove.gravity != from->pmove.gravity)
891 		mask |= PS_M_GRAVITY;
892 	if (!VectorCompare(to->pmove.delta_angles, from->pmove.delta_angles))
893 		mask |= PS_M_DELTA_ANGLES;
894 
895 	if (!VectorCompare(to->viewoffset, from->viewoffset))
896 		mask |= PS_VIEWOFFSET;
897 	if (!VectorCompare(to->viewangles, from->viewangles))
898 		mask |= PS_VIEWANGLES;
899 	if (!VectorCompare(to->kick_angles, from->kick_angles))
900 		mask |= PS_KICKANGLES;
901 	if (to->gunindex != from->gunindex)
902 		mask |= PS_WEAPONINDEX;
903 	if (to->gunframe != from->gunframe ||
904 		!VectorCompare(to->gunoffset, from->gunoffset) ||
905 		!VectorCompare(to->gunangles, from->gunangles))
906 		mask |= PS_WEAPONFRAME;
907 	if (to->blend[0] != from->blend[0] ||
908 		to->blend[1] != from->blend[1] ||
909 		to->blend[2] != from->blend[2] ||
910 		to->blend[3] != from->blend[3])
911 		mask |= PS_BLEND;
912 	if (to->fov != from->fov)
913 		mask |= PS_FOV;
914 	if (to->rdflags != from->rdflags)
915 		mask |= PS_RDFLAGS;
916 
917 	for (i = 0; i < MAX_STATS; i++)
918 	{
919 		if (i == STAT_FLASHES)
920 		{	// stats are cleared every frame, so delta
921 			// from 0
922 			if (to->stats[i])
923 				mask2 |= (1 << i);
924 		}
925 		else
926 		{
927 			if (to->stats[i] != from->stats[i])
928 				mask2 |= (1 << i);
929 		}
930 	}
931 
932 	WriteShort(block, mask);
933 	if (mask & PS_M_TYPE)
934 		WriteByte(block, (byte)to->pmove.pm_type);
935 	if (mask & PS_M_ORIGIN)
936 		WriteShortPosition(block, to->pmove.origin);
937 	if (mask & PS_M_VELOCITY)
938 		WriteShortPosition(block, to->pmove.velocity);
939 	if (mask & PS_M_TIME)
940 		WriteByte(block, to->pmove.pm_time);
941 	if (mask & PS_M_FLAGS)
942 		WriteByte(block, to->pmove.pm_flags);
943 	if (mask & PS_M_GRAVITY)
944 		WriteShort(block, to->pmove.gravity);
945 	if (mask & PS_M_DELTA_ANGLES)
946 		WriteShortPosition(block, to->pmove.delta_angles);
947 
948 	if (mask & PS_VIEWOFFSET)
949 		WriteOffsetVec(block, to->viewoffset);
950 	if (mask & PS_VIEWANGLES)
951 	{
952 		WriteAngle16(block, to->viewangles[0]);
953 		WriteAngle16(block, to->viewangles[1]);
954 		WriteAngle16(block, to->viewangles[2]);
955 	}
956 	if (mask & PS_KICKANGLES)
957 		WriteOffsetVec(block, to->kick_angles);
958 	if (mask & PS_WEAPONINDEX)
959 		WriteByte(block, (byte)to->gunindex);
960 	if (mask & PS_WEAPONFRAME)
961 	{
962 		WriteByte(block, (byte)to->gunframe);
963 		WriteOffsetVec(block, to->gunoffset);
964 		WriteOffsetVec(block, to->gunangles);
965 	}
966 	if (mask & PS_BLEND)
967 		WriteBlendVec(block, to->blend);
968 	if (mask & PS_FOV)
969 		WriteByte(block, (byte)to->fov);
970 	if (mask & PS_RDFLAGS)
971 		WriteByte(block, (byte)to->rdflags);
972 
973 	WriteULong(block, mask2);
974 	for (i = 0; i < MAX_STATS; i++)
975 	{
976 		if (mask2 & (1 << i))
977 			WriteShort(block, to->stats[i]);
978 	}
979 
980 	if (WriteOverflow(block))
981 		return -1;
982 
983 	return block->writeoffset - start;
984 }
985 
986 //
987 // ReadEntityMask
988 // Reads in the mask and entity number of a SVC_SPAWNBASELINE or
989 // SVC_PACKETENTITIES message. This is separate from ReadEntity so
990 // the caller can choose which entity state to read to.
991 //
992 
DM2_ReadEntityMask(block_t * block,int * mask)993 int DM2_ReadEntityMask(block_t *block, int *mask)
994 {
995 	int entity;
996 
997 	*mask = ReadByte(block);
998 	if (*mask & U_MOREBITS1)
999 		*mask |= ReadByte(block) <<  8;
1000 	if (*mask & U_MOREBITS2)
1001 		*mask |= ReadByte(block) << 16;
1002 	if (*mask & U_MOREBITS3)
1003 		*mask |= ReadByte(block) << 24;
1004 
1005 	if (*mask & U_NUMBER16)
1006 		entity = (unsigned short)ReadShort(block);
1007 	else
1008 		entity = ReadByte(block);
1009 
1010 	return entity;
1011 }
1012 
1013 //
1014 // ReadEntity
1015 // Used by ReadPacketEntity or ReadBaselineEntity to read the changes to
1016 // one entity.
1017 //
1018 
DM2_ReadEntity(block_t * block,entity_state_t * es,int mask)1019 qboolean DM2_ReadEntity(block_t *block, entity_state_t *es, int mask)
1020 {
1021 	if (mask & U_MODEL)
1022 		es->modelindex = ReadByte(block);
1023 	if (mask & U_MODEL2)
1024 		es->modelindex2 = ReadByte(block);
1025 	if (mask & U_MODEL3)
1026 		es->modelindex3 = ReadByte(block);
1027 	if (mask & U_MODEL4)
1028 		es->modelindex4 = ReadByte(block);
1029 
1030 	if (mask & U_FRAME8)
1031 		es->frame = ReadByte(block);
1032 	if (mask & U_FRAME16)
1033 		es->frame = ReadShort(block);
1034 
1035 	if (mask & U_SKIN8)
1036 	{
1037 		if (mask & U_SKIN16)
1038 			es->skinnum = ReadLong(block);
1039 		else
1040 			es->skinnum = ReadByte(block);
1041 	}
1042 	else if (mask & U_SKIN16)
1043 		es->skinnum = (unsigned short)ReadShort(block);
1044 
1045 	if (mask & U_EFFECTS8)
1046 	{
1047 		if (mask & U_EFFECTS16)
1048 			es->effects = ReadLong(block);
1049 		else
1050 			es->effects = ReadByte(block);
1051 	}
1052 	else if (mask & U_EFFECTS16)
1053 		es->effects = (unsigned short)ReadShort(block);
1054 
1055 	if (mask & U_RENDERFX8)
1056 	{
1057 		if (mask & U_RENDERFX16)
1058 			es->renderfx = ReadLong(block);
1059 		else
1060 			es->renderfx = ReadByte(block);
1061 	}
1062 	else if (mask & U_RENDERFX16)
1063 		es->renderfx = (unsigned short)ReadShort(block);
1064 
1065 	if (mask & U_ORIGIN1)
1066 		es->origin[0] = ReadCoord(block);
1067 	if (mask & U_ORIGIN2)
1068 		es->origin[1] = ReadCoord(block);
1069 	if (mask & U_ORIGIN3)
1070 		es->origin[2] = ReadCoord(block);
1071 
1072 	if (mask & U_ANGLE1)
1073 		es->angles[0] = ReadAngle(block);
1074 	if (mask & U_ANGLE2)
1075 		es->angles[1] = ReadAngle(block);
1076 	if (mask & U_ANGLE3)
1077 		es->angles[2] = ReadAngle(block);
1078 
1079 	if (mask & U_OLDORIGIN)
1080 		ReadPosition(block, es->old_origin);
1081 	if (mask & U_SOUND)
1082 		es->sound = ReadByte(block);
1083 	if (mask & U_EVENT)
1084 		es->event = ReadByte(block);
1085 	if (mask & U_SOLID)
1086 		es->solid = ReadShort(block);
1087 
1088 	if (mask & U_REMOVE)
1089 		return false;
1090 
1091 	return true;
1092 }
1093 
1094 //
1095 // ReadPacketEntity
1096 // Reads one entity out of a SVC_PACKETENTITES message.
1097 //
1098 
DM2_ReadPacketEntity(block_t * block,state_t * state,const state_t * baselines)1099 int DM2_ReadPacketEntity(block_t *block, state_t *state, const state_t *baselines)
1100 {
1101 	int entity, mask;
1102 
1103 	entity = DM2_ReadEntityMask(block, &mask);
1104 	if (ReadOverflow(block))
1105 		return -1;
1106 
1107 	if (!entity && !mask)
1108 		return 0;
1109 
1110 	if (!ISBITSET(state->active, entity))
1111 		state->entities[entity] = baselines->entities[entity];
1112 
1113 	if (DM2_ReadEntity(block, &state->entities[entity], mask))
1114 		SETBIT(state->active, entity, true);
1115 	else
1116 		SETBIT(state->active, entity, false);
1117 
1118 	if (ReadOverflow(block))
1119 		return -1;
1120 
1121 	return entity;
1122 }
1123 
1124 //
1125 // ReadBaselineEntity
1126 // Reads a SVC_SPAWNBASELINE message.
1127 //
1128 
DM2_ReadBaselineEntity(block_t * block,state_t * baselines)1129 int DM2_ReadBaselineEntity(block_t *block, state_t *baselines)
1130 {
1131 	int entity, mask;
1132 
1133 	entity = DM2_ReadEntityMask(block, &mask);
1134 	DM2_ReadEntity(block, &baselines->entities[entity], mask);
1135 
1136 	if (ReadOverflow(block))
1137 		return -1;
1138 
1139 	return entity;
1140 }
1141 
1142 //
1143 // WriteEntity
1144 // Given a current entity and a delta entity, generates a bit mask
1145 // of the changes and writes them to a block.
1146 // With SVC_SPAWNBASELINE, use a zero-filled delta entity
1147 // With SVC_PACKETENTITIES, determine which delta entity to use (previous
1148 // frame or baseline)
1149 //
1150 
DM2_WriteEntity(block_t * block,const entity_state_t * to,const entity_state_t * from,qboolean is_active,qboolean was_active)1151 int DM2_WriteEntity(block_t *block, const entity_state_t *to, const entity_state_t *from, qboolean is_active, qboolean was_active)
1152 {
1153 	int 	mask;
1154 	size_t	start;
1155 
1156 	start = block->writeoffset;
1157 
1158 	mask = 0;
1159 	if (!is_active && was_active)
1160 	{	// entity is no longer active
1161 		mask |= U_REMOVE;
1162 	}
1163 	else
1164 	{	// generate delta bit mask
1165 		if (to->modelindex != from->modelindex)
1166 			mask |= U_MODEL;
1167 		if (to->modelindex2 != from->modelindex2)
1168 			mask |= U_MODEL2;
1169 		if (to->modelindex3 != from->modelindex3)
1170 			mask |= U_MODEL3;
1171 		if (to->modelindex4 != from->modelindex4)
1172 			mask |= U_MODEL4;
1173 		if (to->origin[0] != from->origin[0])
1174 			mask |= U_ORIGIN1;
1175 		if (to->origin[1] != from->origin[1])
1176 			mask |= U_ORIGIN2;
1177 		if (to->origin[2] != from->origin[2])
1178 			mask |= U_ORIGIN3;
1179 		if (to->angles[0] != from->angles[0])
1180 			mask |= U_ANGLE1;
1181 		if (to->angles[1] != from->angles[1])
1182 			mask |= U_ANGLE2;
1183 		if (to->angles[2] != from->angles[2])
1184 			mask |= U_ANGLE3;
1185 		if (to->frame != from->frame)
1186 		{
1187 			if ((unsigned)to->frame < 0x100)
1188 				mask |= U_FRAME8;
1189 			else
1190 				mask |= U_FRAME16;
1191 		}
1192 
1193 		// Use '< 0x8000' instead of '< 0x10000' because shorts are
1194 		// read as signed shorts. If bit 0x8000 is set and read
1195 		// as a short, it will be treated as negative when expanded
1196 		// to an int, which messes things up. "Fixing" this
1197 		// (writing it as a short and expecting the reader to typecast it
1198 		// to unsigned short before expanding to int)
1199 		// would break compatibility with quake2.exe
1200 		if (to->skinnum != from->skinnum)
1201 		{
1202 			if ((unsigned)to->skinnum < 0x100)
1203 				mask |= U_SKIN8;
1204 			else if ((unsigned)to->skinnum < 0x8000)
1205 				mask |= U_SKIN16;
1206 			else
1207 				mask |= U_SKIN16|U_SKIN8;
1208 		}
1209 		if (to->effects != from->effects)
1210 		{
1211 			if ((unsigned)to->effects < 0x100)
1212 				mask |= U_EFFECTS8;
1213 			else if ((unsigned)to->effects < 0x8000)
1214 				mask |= U_EFFECTS16;
1215 			else
1216 				mask |= U_EFFECTS16|U_EFFECTS8;
1217 		}
1218 		if (to->renderfx != from->renderfx)
1219 		{
1220 			if ((unsigned)to->renderfx < 0x100)
1221 				mask |= U_RENDERFX8;
1222 			else if ((unsigned)to->renderfx < 0x8000)
1223 				mask |= U_RENDERFX16;
1224 			else
1225 				mask |= U_RENDERFX16|U_RENDERFX8;
1226 		}
1227 		if (!VectorCompare(to->old_origin, from->origin))
1228 			mask |= U_OLDORIGIN;
1229 		if (to->sound != from->sound)
1230 			mask |= U_SOUND;
1231 		if (to->event)
1232 			mask |= U_EVENT;
1233 		if (to->solid != from->solid)
1234 			mask |= U_SOLID;
1235 	}
1236 
1237 	// check whether the entity needs to be sent
1238 	if (!mask && is_active && was_active)
1239 		return 0;
1240 	if (!is_active && !was_active)
1241 		return 0;
1242 
1243 	if (to->number > 0xFF)
1244 		mask |= U_NUMBER16;
1245 
1246 	if (mask & 0xFF000000)
1247 		mask |= U_MOREBITS1|U_MOREBITS2|U_MOREBITS3;
1248 	else if (mask & 0x00FF0000)
1249 		mask |= U_MOREBITS1|U_MOREBITS2;
1250 	else if (mask & 0x0000FF00)
1251 		mask |= U_MOREBITS1;
1252 
1253 	WriteByte(block, (byte)(mask & 0xFF));
1254 	if (mask & U_MOREBITS1)
1255 		WriteByte(block, (byte)((mask >>  8) & 0xFF));
1256 	if (mask & U_MOREBITS2)
1257 		WriteByte(block, (byte)((mask >> 16) & 0xFF));
1258 	if (mask & U_MOREBITS3)
1259 		WriteByte(block, (byte)((mask >> 24) & 0xFF));
1260 
1261 	if (mask & U_NUMBER16)
1262 		WriteShort(block, (unsigned short)to->number);
1263 	else
1264 		WriteByte(block, (byte)to->number);
1265 
1266 	if (mask & U_MODEL)
1267 		WriteByte(block, (byte)to->modelindex);
1268 	if (mask & U_MODEL2)
1269 		WriteByte(block, (byte)to->modelindex2);
1270 	if (mask & U_MODEL3)
1271 		WriteByte(block, (byte)to->modelindex3);
1272 	if (mask & U_MODEL4)
1273 		WriteByte(block, (byte)to->modelindex4);
1274 
1275 	if (mask & U_FRAME8)
1276 		WriteByte(block, (byte)to->frame);
1277 	if (mask & U_FRAME16)
1278 		WriteShort(block, (unsigned short)to->frame);
1279 
1280 	if (mask & U_SKIN8)
1281 	{
1282 		if (mask & U_SKIN16)
1283 			WriteLong(block, to->skinnum);
1284 		else
1285 			WriteByte(block, (byte)to->skinnum);
1286 	}
1287 	else if (mask & U_SKIN16)
1288 		WriteShort(block, (unsigned short)to->skinnum);
1289 
1290 	if (mask & U_EFFECTS8)
1291 	{
1292 		if (mask & U_EFFECTS16)
1293 			WriteLong(block, to->effects);
1294 		else
1295 			WriteByte(block, (byte)to->effects);
1296 	}
1297 	else if (mask & U_EFFECTS16)
1298 		WriteShort(block, (unsigned short)to->effects);
1299 
1300 	if (mask & U_RENDERFX8)
1301 	{
1302 		if (mask & U_RENDERFX16)
1303 			WriteLong(block, to->renderfx);
1304 		else
1305 			WriteByte(block, (byte)to->renderfx);
1306 	}
1307 	else if (mask & U_RENDERFX16)
1308 		WriteShort(block, (unsigned short)to->renderfx);
1309 
1310 	if (mask & U_ORIGIN1)
1311 		WriteCoord(block, to->origin[0]);
1312 	if (mask & U_ORIGIN2)
1313 		WriteCoord(block, to->origin[1]);
1314 	if (mask & U_ORIGIN3)
1315 		WriteCoord(block, to->origin[2]);
1316 
1317 	if (mask & U_ANGLE1)
1318 		WriteAngle(block, to->angles[0]);
1319 	if (mask & U_ANGLE2)
1320 		WriteAngle(block, to->angles[1]);
1321 	if (mask & U_ANGLE3)
1322 		WriteAngle(block, to->angles[2]);
1323 
1324 	if (mask & U_OLDORIGIN)
1325 		WritePosition(block, to->old_origin);
1326 	if (mask & U_SOUND)
1327 		WriteByte(block, (byte)to->sound);
1328 	if (mask & U_EVENT)
1329 		WriteByte(block, (byte)to->event);
1330 	if (mask & U_SOLID)
1331 		WriteShort(block, (unsigned short)to->solid);
1332 
1333 	if (WriteOverflow(block))
1334 		return -1;
1335 
1336 	return block->writeoffset - start;
1337 }
1338 
1339 //
1340 // WritePacketEntities
1341 // Generates a full SVC_PACKETENTITIES message via WriteEntity
1342 //
1343 
DM2_WritePacketEntities(block_t * block,const state_t * current,const state_t * delta,const state_t * baselines)1344 int DM2_WritePacketEntities(block_t *block, const state_t *current, const state_t *delta, const state_t *baselines)
1345 {
1346 	int 	i;
1347 	size_t	start;
1348 	const entity_state_t	*to, *from;
1349 
1350 	start = block->writeoffset;
1351 
1352 	for (i = 1; i < MAX_EDICTS; i++)
1353 	{
1354 		to = &current->entities[i];
1355 		from = &delta->entities[i];
1356 
1357 		if (ISBITSET(delta->active, i))
1358 			DM2_WriteEntity(block, to, from, ISBITSET(current->active, i), true);
1359 		else
1360 			DM2_WriteEntity(block, to, &baselines->entities[i], ISBITSET(current->active, i), false);
1361 	}
1362 
1363 	WriteShort(block, 0);	 // terminating packetentities message (mask=0, entity=0)
1364 
1365 	if (WriteOverflow(block))
1366 		return -1;
1367 
1368 	return block->writeoffset - start;
1369 }
1370 
1371 //
1372 // PRE-FRAME FUNCTIONS
1373 //
1374 
DM2_WriteConfigstrings(block_t * block,const char (* configstrings)[64],int start,size_t stopsize)1375 int DM2_WriteConfigstrings(block_t *block, const char (*configstrings)[64], int start, size_t stopsize)
1376 {
1377 	int i;
1378 
1379 	for (i = start; i < MAX_CONFIGSTRINGS; i++)
1380 	{
1381 		if (!configstrings[i][0])
1382 			continue;
1383 
1384 		if (i != 0 && strlen(configstrings[i-1]) >= 64)
1385 			continue;
1386 
1387 		if (block->writelen > stopsize)
1388 			break;
1389 
1390 		WriteByte(block, SVC_CONFIGSTRING);
1391 		DM2_WriteConfigstring(block, i, configstrings[i]);
1392 	}
1393 
1394 	return i;
1395 }
1396 
DM2_WriteBaselines(block_t * block,const state_t * baselines,int start,size_t stopsize)1397 int DM2_WriteBaselines(block_t *block, const state_t *baselines, int start, size_t stopsize)
1398 {
1399 	int 					i;
1400 	const entity_state_t	*es;
1401 	static entity_state_t	null_es = {0};
1402 
1403 	for (i = start, es = &baselines->entities[start]; i < MAX_EDICTS; i++, es++)
1404 	{
1405 		if (!es->origin[0] &&
1406 			!es->origin[1] &&
1407 			!es->origin[2] &&
1408 			!es->angles[0] &&
1409 			!es->angles[1] &&
1410 			!es->angles[2] &&
1411 			!es->old_origin[0] &&
1412 			!es->old_origin[1] &&
1413 			!es->old_origin[2] &&
1414 			!es->modelindex &&
1415 			!es->modelindex2 &&
1416 			!es->modelindex3 &&
1417 			!es->modelindex4 &&
1418 			!es->frame &&
1419 			!es->skinnum &&
1420 			!es->effects &&
1421 			!es->renderfx &&
1422 			!es->solid &&
1423 			!es->sound &&
1424 			!es->event)
1425 		{
1426 			continue;
1427 		}
1428 
1429 		if (block->writeoffset > stopsize)
1430 			break;
1431 
1432 		WriteByte(block, SVC_SPAWNBASELINE);
1433 		DM2_WriteEntity(block, es, &null_es, true, false);
1434 	}
1435 
1436 	return i;
1437 }
1438 
DM2_ReadPreFrame(serverdata_t * svd,relayinfo_t * relayinfo,char (* configstrings)[64],state_t * baselines,PFILE * fd)1439 int DM2_ReadPreFrame(serverdata_t *svd, relayinfo_t *relayinfo, char (*configstrings)[64], state_t *baselines, PFILE *fd)
1440 {
1441 	block_t 	in;
1442 	char		in_buffer[MAX_SVSLEN];
1443 	int 		numblocks, id;
1444 	qboolean	end;
1445 
1446 	BlockInit(&in, in_buffer, sizeof(in_buffer));
1447 	end = false;
1448 	numblocks = 0;
1449 
1450 	while (!end)
1451 	{
1452 		numblocks++;
1453 		if (DM2_ReadBlock(&in, fd) < 0)
1454 			return -1;
1455 
1456 		if (in.writeoffset == 0xffffffff)
1457 			return -1;
1458 
1459 		while (in.readoffset < in.writeoffset)
1460 		{
1461 			id = ReadByte(&in);
1462 
1463 			if (ReadOverflow(&in))
1464 				return -1;
1465 
1466 			switch(id)
1467 			{
1468 			case SVC_STUFFTEXT:
1469 				{
1470 					char		string[MAX_MSGLEN];
1471 					const char	*cur;
1472 
1473 					if (DM2_ReadStufftext(&in, string, sizeof(string)) < 0)
1474 						return -1;
1475 
1476 					cur = string;
1477 					while (cur)
1478 					{
1479 						cur = Cmd_TokenizeString(cur);
1480 						if (Cmd_Argc() == 0)
1481 							continue;
1482 
1483 						if (!strcmp(Cmd_Argv(0), "precache"))
1484 							end = true;
1485 					}
1486 				}
1487 				break;
1488 			case SVC_SERVERDATA:
1489 				{
1490 					if (DM2_ReadServerdata(&in, svd) < 0)
1491 						return -1;
1492 				}
1493 				break;
1494 			case SVC_CONFIGSTRING:
1495 				{
1496 					char	string[MAX_MSGLEN];
1497 					int 	index;
1498 
1499 					if (DM2_ReadConfigstring(&in, &index, string) < 0)
1500 						return -1;
1501 
1502 					strcpy(configstrings[index], string);
1503 				}
1504 				break;
1505 			case SVC_SPAWNBASELINE:
1506 				{
1507 					int 	entity;
1508 
1509 					entity = DM2_ReadBaselineEntity(&in, baselines);
1510 					if (entity < 0)
1511 						return -1;
1512 				}
1513 				break;
1514 			default:
1515 				return -1;
1516 			}
1517 		}
1518    }
1519 
1520 	return numblocks;
1521 }
1522 
1523 //
1524 // DM2_WritePreFrame
1525 // Writes the SVC_SERVERDATA, SVC_CONFIGSTRING, SVC_SPAWNBASELINE, and SVC_STUFFTEXT
1526 // that precedes all frame information
1527 //
DM2_WritePreFrame(const serverdata_t * svd,const relayinfo_t * relayinfo,const char (* configstrings)[64],const state_t * baselines,PFILE * fd)1528 int DM2_WritePreFrame(const serverdata_t *svd, const relayinfo_t *relayinfo, const char (*configstrings)[64], const state_t *baselines, PFILE *fd)
1529 {
1530 	block_t 		out;
1531 	char			out_buffer[MAX_SVSLEN];
1532 	int 			i, numblocks;
1533 
1534 	BlockInit(&out, out_buffer, sizeof(out_buffer));
1535 	numblocks = 0;
1536 
1537 	WriteByte(&out, SVC_SERVERDATA);
1538 	DM2_WriteServerdata(&out, svd);
1539 
1540 	i = 0;
1541 	for(;;)
1542 	{
1543 		i = DM2_WriteConfigstrings(&out, configstrings, i, 1024);
1544 		if (i == MAX_CONFIGSTRINGS)
1545 			break;
1546 
1547 		if (WriteOverflow(&out))
1548 			return -1;
1549 		DM2_WriteBlock(&out, fd);
1550 		BlockRewind(&out);
1551 		numblocks++;
1552 	}
1553 
1554 	i = 1;
1555 	for (;;)
1556 	{
1557 		i = DM2_WriteBaselines(&out, baselines, i, 1024);
1558 		if (i == MAX_EDICTS)
1559 			break;
1560 
1561 		if (WriteOverflow(&out))
1562 			return -1;
1563 		DM2_WriteBlock(&out, fd);
1564 		BlockRewind(&out);
1565 		numblocks++;
1566 	}
1567 
1568 	WriteByte(&out, SVC_STUFFTEXT);
1569 	DM2_WriteStufftext(&out, "precache\n");
1570 
1571 	if (WriteOverflow(&out))
1572 		return -1;
1573 
1574 	DM2_WriteBlock(&out, fd);
1575 	numblocks++;
1576 
1577 	return numblocks;
1578 }
1579