1 /*
2 ** d_protocol.cpp
3 ** Basic network packet creation routines and simple IFF parsing
4 **
5 **---------------------------------------------------------------------------
6 ** Copyright 1998-2006 Randy Heit
7 ** All rights reserved.
8 **
9 ** Redistribution and use in source and binary forms, with or without
10 ** modification, are permitted provided that the following conditions
11 ** are met:
12 **
13 ** 1. Redistributions of source code must retain the above copyright
14 **    notice, this list of conditions and the following disclaimer.
15 ** 2. Redistributions in binary form must reproduce the above copyright
16 **    notice, this list of conditions and the following disclaimer in the
17 **    documentation and/or other materials provided with the distribution.
18 ** 3. The name of the author may not be used to endorse or promote products
19 **    derived from this software without specific prior written permission.
20 **
21 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 **---------------------------------------------------------------------------
32 **
33 */
34 
35 #include "i_system.h"
36 #include "d_ticcmd.h"
37 #include "d_net.h"
38 #include "doomdef.h"
39 #include "doomstat.h"
40 #include "cmdlib.h"
41 #include "farchive.h"
42 
43 
ReadString(BYTE ** stream)44 char *ReadString (BYTE **stream)
45 {
46 	char *string = *((char **)stream);
47 
48 	*stream += strlen (string) + 1;
49 	return copystring (string);
50 }
51 
ReadStringConst(BYTE ** stream)52 const char *ReadStringConst(BYTE **stream)
53 {
54 	const char *string = *((const char **)stream);
55 	*stream += strlen (string) + 1;
56 	return string;
57 }
58 
ReadByte(BYTE ** stream)59 int ReadByte (BYTE **stream)
60 {
61 	BYTE v = **stream;
62 	*stream += 1;
63 	return v;
64 }
65 
ReadWord(BYTE ** stream)66 int ReadWord (BYTE **stream)
67 {
68 	short v = (((*stream)[0]) << 8) | (((*stream)[1]));
69 	*stream += 2;
70 	return v;
71 }
72 
ReadLong(BYTE ** stream)73 int ReadLong (BYTE **stream)
74 {
75 	int v = (((*stream)[0]) << 24) | (((*stream)[1]) << 16) | (((*stream)[2]) << 8) | (((*stream)[3]));
76 	*stream += 4;
77 	return v;
78 }
79 
ReadFloat(BYTE ** stream)80 float ReadFloat (BYTE **stream)
81 {
82 	union
83 	{
84 		int i;
85 		float f;
86 	} fakeint;
87 	fakeint.i = ReadLong (stream);
88 	return fakeint.f;
89 }
90 
WriteString(const char * string,BYTE ** stream)91 void WriteString (const char *string, BYTE **stream)
92 {
93 	char *p = *((char **)stream);
94 
95 	while (*string) {
96 		*p++ = *string++;
97 	}
98 
99 	*p++ = 0;
100 	*stream = (BYTE *)p;
101 }
102 
103 
WriteByte(BYTE v,BYTE ** stream)104 void WriteByte (BYTE v, BYTE **stream)
105 {
106 	**stream = v;
107 	*stream += 1;
108 }
109 
WriteWord(short v,BYTE ** stream)110 void WriteWord (short v, BYTE **stream)
111 {
112 	(*stream)[0] = v >> 8;
113 	(*stream)[1] = v & 255;
114 	*stream += 2;
115 }
116 
WriteLong(int v,BYTE ** stream)117 void WriteLong (int v, BYTE **stream)
118 {
119 	(*stream)[0] = v >> 24;
120 	(*stream)[1] = (v >> 16) & 255;
121 	(*stream)[2] = (v >> 8) & 255;
122 	(*stream)[3] = v & 255;
123 	*stream += 4;
124 }
125 
WriteFloat(float v,BYTE ** stream)126 void WriteFloat (float v, BYTE **stream)
127 {
128 	union
129 	{
130 		int i;
131 		float f;
132 	} fakeint;
133 	fakeint.f = v;
134 	WriteLong (fakeint.i, stream);
135 }
136 
137 // Returns the number of bytes read
UnpackUserCmd(usercmd_t * ucmd,const usercmd_t * basis,BYTE ** stream)138 int UnpackUserCmd (usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream)
139 {
140 	BYTE *start = *stream;
141 	BYTE flags;
142 
143 	if (basis != NULL)
144 	{
145 		if (basis != ucmd)
146 		{
147 			memcpy (ucmd, basis, sizeof(usercmd_t));
148 		}
149 	}
150 	else
151 	{
152 		memset (ucmd, 0, sizeof(usercmd_t));
153 	}
154 
155 	flags = ReadByte (stream);
156 
157 	if (flags)
158 	{
159 		// We can support up to 29 buttons, using from 0 to 4 bytes to store them.
160 		if (flags & UCMDF_BUTTONS)
161 		{
162 			DWORD buttons = ucmd->buttons;
163 			BYTE in = ReadByte(stream);
164 
165 			buttons = (buttons & ~0x7F) | (in & 0x7F);
166 			if (in & 0x80)
167 			{
168 				in = ReadByte(stream);
169 				buttons = (buttons & ~(0x7F << 7)) | ((in & 0x7F) << 7);
170 				if (in & 0x80)
171 				{
172 					in = ReadByte(stream);
173 					buttons = (buttons & ~(0x7F << 14)) | ((in & 0x7F) << 14);
174 					if (in & 0x80)
175 					{
176 						in = ReadByte(stream);
177 						buttons = (buttons & ~(0xFF << 21)) | (in << 21);
178 					}
179 				}
180 			}
181 			ucmd->buttons = buttons;
182 		}
183 		if (flags & UCMDF_PITCH)
184 			ucmd->pitch = ReadWord (stream);
185 		if (flags & UCMDF_YAW)
186 			ucmd->yaw = ReadWord (stream);
187 		if (flags & UCMDF_FORWARDMOVE)
188 			ucmd->forwardmove = ReadWord (stream);
189 		if (flags & UCMDF_SIDEMOVE)
190 			ucmd->sidemove = ReadWord (stream);
191 		if (flags & UCMDF_UPMOVE)
192 			ucmd->upmove = ReadWord (stream);
193 		if (flags & UCMDF_ROLL)
194 			ucmd->roll = ReadWord (stream);
195 	}
196 
197 	return int(*stream - start);
198 }
199 
200 // Returns the number of bytes written
PackUserCmd(const usercmd_t * ucmd,const usercmd_t * basis,BYTE ** stream)201 int PackUserCmd (const usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream)
202 {
203 	BYTE flags = 0;
204 	BYTE *temp = *stream;
205 	BYTE *start = *stream;
206 	usercmd_t blank;
207 	DWORD buttons_changed;
208 
209 	if (basis == NULL)
210 	{
211 		memset (&blank, 0, sizeof(blank));
212 		basis = &blank;
213 	}
214 
215 	WriteByte (0, stream);			// Make room for the packing bits
216 
217 	buttons_changed = ucmd->buttons ^ basis->buttons;
218 	if (buttons_changed != 0)
219 	{
220 		BYTE bytes[4] = {  BYTE(ucmd->buttons        & 0x7F),
221 						  BYTE((ucmd->buttons >> 7)  & 0x7F),
222 						  BYTE((ucmd->buttons >> 14) & 0x7F),
223 						  BYTE((ucmd->buttons >> 21) & 0xFF) };
224 
225 		flags |= UCMDF_BUTTONS;
226 
227 		if (buttons_changed & 0xFFFFFF80)
228 		{
229 			bytes[0] |= 0x80;
230 			if (buttons_changed & 0xFFFFC000)
231 			{
232 				bytes[1] |= 0x80;
233 				if (buttons_changed & 0xFFE00000)
234 				{
235 					bytes[2] |= 0x80;
236 				}
237 			}
238 		}
239 		WriteByte (bytes[0], stream);
240 		if (bytes[0] & 0x80)
241 		{
242 			WriteByte (bytes[1], stream);
243 			if (bytes[1] & 0x80)
244 			{
245 				WriteByte (bytes[2], stream);
246 				if (bytes[2] & 0x80)
247 				{
248 					WriteByte (bytes[3], stream);
249 				}
250 			}
251 		}
252 	}
253 	if (ucmd->pitch != basis->pitch)
254 	{
255 		flags |= UCMDF_PITCH;
256 		WriteWord (ucmd->pitch, stream);
257 	}
258 	if (ucmd->yaw != basis->yaw)
259 	{
260 		flags |= UCMDF_YAW;
261 		WriteWord (ucmd->yaw, stream);
262 	}
263 	if (ucmd->forwardmove != basis->forwardmove)
264 	{
265 		flags |= UCMDF_FORWARDMOVE;
266 		WriteWord (ucmd->forwardmove, stream);
267 	}
268 	if (ucmd->sidemove != basis->sidemove)
269 	{
270 		flags |= UCMDF_SIDEMOVE;
271 		WriteWord (ucmd->sidemove, stream);
272 	}
273 	if (ucmd->upmove != basis->upmove)
274 	{
275 		flags |= UCMDF_UPMOVE;
276 		WriteWord (ucmd->upmove, stream);
277 	}
278 	if (ucmd->roll != basis->roll)
279 	{
280 		flags |= UCMDF_ROLL;
281 		WriteWord (ucmd->roll, stream);
282 	}
283 
284 	// Write the packing bits
285 	WriteByte (flags, &temp);
286 
287 	return int(*stream - start);
288 }
289 
operator <<(FArchive & arc,ticcmd_t & cmd)290 FArchive &operator<< (FArchive &arc, ticcmd_t &cmd)
291 {
292 	return arc << cmd.consistancy << cmd.ucmd;
293 }
294 
operator <<(FArchive & arc,usercmd_t & cmd)295 FArchive &operator<< (FArchive &arc, usercmd_t &cmd)
296 {
297 	BYTE bytes[256];
298 	BYTE *stream = bytes;
299 	if (arc.IsStoring ())
300 	{
301 		BYTE len = PackUserCmd (&cmd, NULL, &stream);
302 		arc << len;
303 		arc.Write (bytes, len);
304 	}
305 	else
306 	{
307 		BYTE len;
308 		arc << len;
309 		arc.Read (bytes, len);
310 		UnpackUserCmd (&cmd, NULL, &stream);
311 	}
312 	return arc;
313 }
314 
WriteUserCmdMessage(usercmd_t * ucmd,const usercmd_t * basis,BYTE ** stream)315 int WriteUserCmdMessage (usercmd_t *ucmd, const usercmd_t *basis, BYTE **stream)
316 {
317 	if (basis == NULL)
318 	{
319 		if (ucmd->buttons != 0 ||
320 			ucmd->pitch != 0 ||
321 			ucmd->yaw != 0 ||
322 			ucmd->forwardmove != 0 ||
323 			ucmd->sidemove != 0 ||
324 			ucmd->upmove != 0 ||
325 			ucmd->roll != 0)
326 		{
327 			WriteByte (DEM_USERCMD, stream);
328 			return PackUserCmd (ucmd, basis, stream) + 1;
329 		}
330 	}
331 	else
332 	if (ucmd->buttons != basis->buttons ||
333 		ucmd->pitch != basis->pitch ||
334 		ucmd->yaw != basis->yaw ||
335 		ucmd->forwardmove != basis->forwardmove ||
336 		ucmd->sidemove != basis->sidemove ||
337 		ucmd->upmove != basis->upmove ||
338 		ucmd->roll != basis->roll)
339 	{
340 		WriteByte (DEM_USERCMD, stream);
341 		return PackUserCmd (ucmd, basis, stream) + 1;
342 	}
343 
344 	WriteByte (DEM_EMPTYUSERCMD, stream);
345 	return 1;
346 }
347 
348 
SkipTicCmd(BYTE ** stream,int count)349 int SkipTicCmd (BYTE **stream, int count)
350 {
351 	int i, skip;
352 	BYTE *flow = *stream;
353 
354 	for (i = count; i > 0; i--)
355 	{
356 		bool moreticdata = true;
357 
358 		flow += 2;		// Skip consistancy marker
359 		while (moreticdata)
360 		{
361 			BYTE type = *flow++;
362 
363 			if (type == DEM_USERCMD)
364 			{
365 				moreticdata = false;
366 				skip = 1;
367 				if (*flow & UCMDF_PITCH)		skip += 2;
368 				if (*flow & UCMDF_YAW)			skip += 2;
369 				if (*flow & UCMDF_FORWARDMOVE)	skip += 2;
370 				if (*flow & UCMDF_SIDEMOVE)		skip += 2;
371 				if (*flow & UCMDF_UPMOVE)		skip += 2;
372 				if (*flow & UCMDF_ROLL)			skip += 2;
373 				if (*flow & UCMDF_BUTTONS)
374 				{
375 					if (*++flow & 0x80)
376 					{
377 						if (*++flow & 0x80)
378 						{
379 							if (*++flow & 0x80)
380 							{
381 								++flow;
382 							}
383 						}
384 					}
385 				}
386 				flow += skip;
387 			}
388 			else if (type == DEM_EMPTYUSERCMD)
389 			{
390 				moreticdata = false;
391 			}
392 			else
393 			{
394 				Net_SkipCommand (type, &flow);
395 			}
396 		}
397 	}
398 
399 	skip = int(flow - *stream);
400 	*stream = flow;
401 
402 	return skip;
403 }
404 
405 #include <assert.h>
406 extern short consistancy[MAXPLAYERS][BACKUPTICS];
ReadTicCmd(BYTE ** stream,int player,int tic)407 void ReadTicCmd (BYTE **stream, int player, int tic)
408 {
409 	int type;
410 	BYTE *start;
411 	ticcmd_t *tcmd;
412 
413 	int ticmod = tic % BACKUPTICS;
414 
415 	tcmd = &netcmds[player][ticmod];
416 	tcmd->consistancy = ReadWord (stream);
417 
418 	start = *stream;
419 
420 	while ((type = ReadByte (stream)) != DEM_USERCMD && type != DEM_EMPTYUSERCMD)
421 		Net_SkipCommand (type, stream);
422 
423 	NetSpecs[player][ticmod].SetData (start, int(*stream - start - 1));
424 
425 	if (type == DEM_USERCMD)
426 	{
427 		UnpackUserCmd (&tcmd->ucmd,
428 			tic ? &netcmds[player][(tic-1)%BACKUPTICS].ucmd : NULL, stream);
429 	}
430 	else
431 	{
432 		if (tic)
433 		{
434 			memcpy (&tcmd->ucmd, &netcmds[player][(tic-1)%BACKUPTICS].ucmd, sizeof(tcmd->ucmd));
435 		}
436 		else
437 		{
438 			memset (&tcmd->ucmd, 0, sizeof(tcmd->ucmd));
439 		}
440 	}
441 
442 	if (player==consoleplayer&&tic>BACKUPTICS)
443 		assert(consistancy[player][ticmod] == tcmd->consistancy);
444 }
445 
RunNetSpecs(int player,int buf)446 void RunNetSpecs (int player, int buf)
447 {
448 	BYTE *stream;
449 	int len;
450 
451 	if (gametic % ticdup == 0)
452 	{
453 		stream = NetSpecs[player][buf].GetData (&len);
454 		if (stream)
455 		{
456 			BYTE *end = stream + len;
457 			while (stream < end)
458 			{
459 				int type = ReadByte (&stream);
460 				Net_DoCommand (type, &stream, player);
461 			}
462 			if (!demorecording)
463 				NetSpecs[player][buf].SetData (NULL, 0);
464 		}
465 	}
466 }
467 
468 BYTE *lenspot;
469 
470 // Write the header of an IFF chunk and leave space
471 // for the length field.
StartChunk(int id,BYTE ** stream)472 void StartChunk (int id, BYTE **stream)
473 {
474 	WriteLong (id, stream);
475 	lenspot = *stream;
476 	*stream += 4;
477 }
478 
479 // Write the length field for the chunk and insert
480 // pad byte if the chunk is odd-sized.
FinishChunk(BYTE ** stream)481 void FinishChunk (BYTE **stream)
482 {
483 	int len;
484 
485 	if (!lenspot)
486 		return;
487 
488 	len = int(*stream - lenspot - 4);
489 	WriteLong (len, &lenspot);
490 	if (len & 1)
491 		WriteByte (0, stream);
492 
493 	lenspot = NULL;
494 }
495 
496 // Skip past an unknown chunk. *stream should be
497 // pointing to the chunk's length field.
SkipChunk(BYTE ** stream)498 void SkipChunk (BYTE **stream)
499 {
500 	int len;
501 
502 	len = ReadLong (stream);
503 	*stream += len + (len & 1);
504 }
505