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 = ␣
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