1 /**
2 * @file
3 */
4
5 /*
6 Copyright (C) 1997-2001 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 */
24
25 #include "common.h"
26
27 const vec3_t bytedirs[] = {
28 #include "../shared/vertex_normals.h"
29 };
30
31 static const float POSSCALE = 32.0f;
32
NET_WriteChar(dbuffer * buf,char c)33 void NET_WriteChar (dbuffer* buf, char c)
34 {
35 buf->add(&c, 1);
36 Com_DPrintf(DEBUG_EVENTSYS, "char event data: %s (%i)\n", Com_ByteToBinary(c), c);
37 }
38
NET_WriteByte(dbuffer * buf,byte c)39 void NET_WriteByte (dbuffer* buf, byte c)
40 {
41 buf->add((const char*)&c, 1);
42 Com_DPrintf(DEBUG_EVENTSYS, "byte event data: %s (%i)\n", Com_ByteToBinary(c), c);
43 }
44
NET_WriteShort(dbuffer * buf,int c)45 void NET_WriteShort (dbuffer* buf, int c)
46 {
47 const unsigned short v = LittleShort(c);
48 buf->add((const char*)&v, 2);
49 Com_DPrintf(DEBUG_EVENTSYS, "short event data: %i\n", c);
50 }
51
NET_WriteLong(dbuffer * buf,int c)52 void NET_WriteLong (dbuffer* buf, int c)
53 {
54 const int v = LittleLong(c);
55 buf->add((const char*)&v, 4);
56 Com_DPrintf(DEBUG_EVENTSYS, "long event data: %i\n", c);
57 }
58
NET_WriteString(dbuffer * buf,const char * str)59 void NET_WriteString (dbuffer* buf, const char* str)
60 {
61 if (!str)
62 buf->add("", 1);
63 else
64 buf->add(str, strlen(str) + 1);
65 Com_DPrintf(DEBUG_EVENTSYS, "string event data: %s\n", str);
66 }
67
68 /**
69 * @brief Skip the zero string terminal character. If you need it, use @c NET_WriteString.
70 */
NET_WriteRawString(dbuffer * buf,const char * str)71 void NET_WriteRawString (dbuffer* buf, const char* str)
72 {
73 if (!str)
74 return;
75 buf->add(str, strlen(str));
76 Com_DPrintf(DEBUG_EVENTSYS, "string raw event data: %s\n", str);
77 }
78
NET_WriteCoord(dbuffer * buf,float f)79 void NET_WriteCoord (dbuffer* buf, float f)
80 {
81 NET_WriteLong(buf, (int) (f * 32));
82 }
83
84 /**
85 * @sa NET_Read2Pos
86 */
NET_Write2Pos(dbuffer * buf,const vec2_t pos)87 void NET_Write2Pos (dbuffer* buf, const vec2_t pos)
88 {
89 NET_WriteLong(buf, (long) (pos[0] * POSSCALE));
90 NET_WriteLong(buf, (long) (pos[1] * POSSCALE));
91 }
92
93 /**
94 * @sa NET_ReadPos
95 */
NET_WritePos(dbuffer * buf,const vec3_t pos)96 void NET_WritePos (dbuffer* buf, const vec3_t pos)
97 {
98 NET_WriteLong(buf, (long) (pos[0] * POSSCALE));
99 NET_WriteLong(buf, (long) (pos[1] * POSSCALE));
100 NET_WriteLong(buf, (long) (pos[2] * POSSCALE));
101 }
102
NET_WriteGPos(dbuffer * buf,const pos3_t pos)103 void NET_WriteGPos (dbuffer* buf, const pos3_t pos)
104 {
105 NET_WriteByte(buf, pos[0]);
106 NET_WriteByte(buf, pos[1]);
107 NET_WriteByte(buf, pos[2]);
108 }
109
NET_WriteAngle(dbuffer * buf,float f)110 void NET_WriteAngle (dbuffer* buf, float f)
111 {
112 NET_WriteByte(buf, (int) (f * 256 / 360) & 255);
113 }
114
NET_WriteAngle16(dbuffer * buf,float f)115 void NET_WriteAngle16 (dbuffer* buf, float f)
116 {
117 NET_WriteShort(buf, ANGLE2SHORT(f));
118 }
119
120 /**
121 * @note EV_ACTOR_SHOOT is using WriteDir for writing the normal, but ReadByte
122 * for reading it - keep that in mind when you change something here
123 */
NET_WriteDir(dbuffer * buf,const vec3_t dir)124 void NET_WriteDir (dbuffer* buf, const vec3_t dir)
125 {
126 if (!dir) {
127 NET_WriteByte(buf, 0);
128 return;
129 }
130
131 float bestd = 0.0f;
132 int best = 0;
133 const size_t bytedirsLength = lengthof(bytedirs);
134 for (int i = 0; i < bytedirsLength; i++) {
135 const float d = DotProduct(dir, bytedirs[i]);
136 if (d > bestd) {
137 bestd = d;
138 best = i;
139 }
140 }
141 NET_WriteByte(buf, best);
142 }
143
144 /**
145 * @brief Writes to buffer according to format; version without syntactic sugar
146 * for variable arguments, to call it from other functions with variable arguments
147 * @note short and char are promoted to int when passed to variadic functions!
148 */
NET_vWriteFormat(dbuffer * buf,const char * format,va_list ap)149 void NET_vWriteFormat (dbuffer* buf, const char* format, va_list ap)
150 {
151 while (*format) {
152 const char typeID = *format++;
153
154 switch (typeID) {
155 case 'c':
156 NET_WriteChar(buf, va_arg(ap, int));
157 break;
158 case 'b':
159 NET_WriteByte(buf, va_arg(ap, int));
160 break;
161 case 's':
162 NET_WriteShort(buf, va_arg(ap, int));
163 break;
164 case 'l':
165 NET_WriteLong(buf, va_arg(ap, int));
166 break;
167 case 'p':
168 NET_WritePos(buf, va_arg(ap, float*));
169 break;
170 case 'g':
171 NET_WriteGPos(buf, va_arg(ap, byte*));
172 break;
173 case 'd':
174 NET_WriteDir(buf, va_arg(ap, float*));
175 break;
176 case 'a':
177 /* NOTE: float is promoted to double through ... */
178 NET_WriteAngle(buf, va_arg(ap, double));
179 break;
180 case '!':
181 break;
182 case '&':
183 NET_WriteString(buf, va_arg(ap, char*));
184 break;
185 case '*': {
186 const int n = va_arg(ap, int);
187 const byte* p = va_arg(ap, byte*);
188 NET_WriteShort(buf, n);
189 for (int i = 0; i < n; i++)
190 NET_WriteByte(buf, *p++);
191 break;
192 }
193 default:
194 Com_Error(ERR_DROP, "WriteFormat: Unknown type!");
195 }
196 }
197 /* Too many arguments for the given format; too few cause crash above */
198 #ifdef PARANOID
199 if (!ap)
200 Com_Error(ERR_DROP, "WriteFormat: Too many arguments!");
201 #endif
202 }
203
204 /**
205 * @brief The user-friendly version of NET_WriteFormat that writes variable arguments to buffer according to format
206 */
NET_WriteFormat(dbuffer * buf,const char * format,...)207 void NET_WriteFormat (dbuffer* buf, const char* format, ...)
208 {
209 va_list ap;
210 va_start(ap, format);
211 NET_vWriteFormat(buf, format, ap);
212 va_end(ap);
213 }
214
215
216 /* reading functions */
217
218 /**
219 * returns -1 if no more characters are available
220 */
NET_ReadChar(dbuffer * buf)221 int NET_ReadChar (dbuffer* buf)
222 {
223 char c;
224 if (buf->extract(&c, 1) == 0)
225 return -1;
226 return c;
227 }
228
229 /**
230 * @brief Reads a byte from the netchannel
231 * @note Beware that you don't put this into a byte or short - this will overflow
232 * use an int value to store the return value when you read this via the net format strings!!!
233 */
NET_ReadByte(dbuffer * buf)234 int NET_ReadByte (dbuffer* buf)
235 {
236 unsigned char c;
237 if (buf->extract((char*)&c, 1) == 0)
238 return -1;
239 return c;
240 }
241
NET_ReadShort(dbuffer * buf)242 int NET_ReadShort (dbuffer* buf)
243 {
244 unsigned short v;
245 if (buf->extract((char*)&v, 2) < 2)
246 return -1;
247
248 return LittleShort(v);
249 }
250
NET_PeekByte(const dbuffer * buf)251 int NET_PeekByte (const dbuffer* buf)
252 {
253 unsigned char c;
254 if (buf->get((char*)&c, 1) == 0)
255 return -1;
256 return c;
257 }
258
259 /**
260 * @brief Peeks into a buffer without changing it to get a short int.
261 * @param buf The buffer, returned unchanged, no need to be copied before.
262 * @return The short at the beginning of the buffer, -1 if it couldn't be read.
263 */
NET_PeekShort(const dbuffer * buf)264 int NET_PeekShort (const dbuffer* buf)
265 {
266 uint16_t v;
267 if (buf->get((char*)&v, 2) < 2)
268 return -1;
269
270 return LittleShort(v);
271 }
272
NET_PeekLong(const dbuffer * buf)273 int NET_PeekLong (const dbuffer* buf)
274 {
275 uint32_t v;
276 if (buf->get((char*)&v, 4) < 4)
277 return -1;
278
279 return LittleLong(v);
280 }
281
NET_ReadLong(dbuffer * buf)282 int NET_ReadLong (dbuffer* buf)
283 {
284 unsigned int v;
285 if (buf->extract((char*)&v, 4) < 4)
286 return -1;
287
288 return LittleLong(v);
289 }
290
291 /**
292 * @note Don't use this function in a way like
293 * <code> char* s = NET_ReadString(sb);
294 * char* t = NET_ReadString(sb);</code>
295 * The second reading uses the same data buffer for the string - so
296 * s is no longer the first - but the second string
297 * @sa NET_ReadStringLine
298 * @param[in,out] buf The input buffer to read the string data from
299 * @param[out] string The output buffer to read the string into
300 * @param[in] length The size of the output buffer
301 */
NET_ReadString(dbuffer * buf,char * string,size_t length)302 int NET_ReadString (dbuffer* buf, char* string, size_t length)
303 {
304 unsigned int l = 0;
305
306 for (;;) {
307 int c = NET_ReadByte(buf);
308 if (c == -1 || c == 0)
309 break;
310 if (string && l < length - 1) {
311 /* translate all format specs to avoid crash bugs */
312 if (c == '%')
313 c = '.';
314 string[l] = c;
315 }
316 l++;
317 }
318
319 if (string)
320 string[l] = '\0';
321
322 return l;
323 }
324
325 /**
326 * @sa NET_ReadString
327 */
NET_ReadStringLine(dbuffer * buf,char * string,size_t length)328 int NET_ReadStringLine (dbuffer* buf, char* string, size_t length)
329 {
330 unsigned int l;
331
332 l = 0;
333 do {
334 int c = NET_ReadByte(buf);
335 if (c == -1 || c == 0 || c == '\n')
336 break;
337 /* translate all format specs to avoid crash bugs */
338 if (c == '%')
339 c = '.';
340 string[l] = c;
341 l++;
342 } while (l < length - 1);
343
344 string[l] = 0;
345
346 return l;
347 }
348
NET_ReadCoord(dbuffer * buf)349 float NET_ReadCoord (dbuffer* buf)
350 {
351 return (float) NET_ReadLong(buf) * (1.0 / 32);
352 }
353
354 /**
355 * @sa NET_Write2Pos
356 */
NET_Read2Pos(dbuffer * buf,vec2_t pos)357 void NET_Read2Pos (dbuffer* buf, vec2_t pos)
358 {
359 pos[0] = NET_ReadLong(buf) / POSSCALE;
360 pos[1] = NET_ReadLong(buf) / POSSCALE;
361 }
362
363 /**
364 * @sa NET_WritePos
365 */
NET_ReadPos(dbuffer * buf,vec3_t pos)366 void NET_ReadPos (dbuffer* buf, vec3_t pos)
367 {
368 pos[0] = NET_ReadLong(buf) / POSSCALE;
369 pos[1] = NET_ReadLong(buf) / POSSCALE;
370 pos[2] = NET_ReadLong(buf) / POSSCALE;
371 }
372
373 /**
374 * @sa NET_WriteGPos
375 * @sa NET_ReadByte
376 * @note pos3_t are byte values
377 */
NET_ReadGPos(dbuffer * buf,pos3_t pos)378 void NET_ReadGPos (dbuffer* buf, pos3_t pos)
379 {
380 pos[0] = NET_ReadByte(buf);
381 pos[1] = NET_ReadByte(buf);
382 pos[2] = NET_ReadByte(buf);
383 }
384
NET_ReadAngle(dbuffer * buf)385 float NET_ReadAngle (dbuffer* buf)
386 {
387 return (float) NET_ReadChar(buf) * (360.0 / 256);
388 }
389
NET_ReadAngle16(dbuffer * buf)390 float NET_ReadAngle16 (dbuffer* buf)
391 {
392 const short s = NET_ReadShort(buf);
393 return (float) SHORT2ANGLE(s);
394 }
395
NET_ReadData(dbuffer * buf,void * data,int len)396 void NET_ReadData (dbuffer* buf, void* data, int len)
397 {
398 int i;
399
400 for (i = 0; i < len; i++)
401 ((byte*) data)[i] = NET_ReadByte(buf);
402 }
403
NET_ReadDir(dbuffer * buf,vec3_t dir)404 void NET_ReadDir (dbuffer* buf, vec3_t dir)
405 {
406 const int b = NET_ReadByte(buf);
407 if (b >= lengthof(bytedirs))
408 Com_Error(ERR_DROP, "NET_ReadDir: out of range");
409 VectorCopy(bytedirs[b], dir);
410 }
411
412 /**
413 * @brief Reads from a buffer according to format; version without syntactic sugar for variable arguments, to call it from other functions with variable arguments
414 * @sa SV_ReadFormat
415 * @param[in] buf The buffer we read the data from
416 * @param[in] format The format string may not be nullptr
417 */
NET_vReadFormat(dbuffer * buf,const char * format,va_list ap)418 void NET_vReadFormat (dbuffer* buf, const char* format, va_list ap)
419 {
420 while (*format) {
421 const char typeID = *format++;
422
423 switch (typeID) {
424 case 'c':
425 *va_arg(ap, int*) = NET_ReadChar(buf);
426 break;
427 case 'b':
428 *va_arg(ap, int*) = NET_ReadByte(buf);
429 break;
430 case 's':
431 *va_arg(ap, int*) = NET_ReadShort(buf);
432 break;
433 case 'l':
434 *va_arg(ap, int*) = NET_ReadLong(buf);
435 break;
436 case 'p':
437 NET_ReadPos(buf, *va_arg(ap, vec3_t*));
438 break;
439 case 'g':
440 NET_ReadGPos(buf, *va_arg(ap, pos3_t*));
441 break;
442 case 'd':
443 NET_ReadDir(buf, *va_arg(ap, vec3_t*));
444 break;
445 case 'a':
446 *va_arg(ap, float*) = NET_ReadAngle(buf);
447 break;
448 case '!':
449 format++;
450 break;
451 case '&': {
452 char* str = va_arg(ap, char*);
453 const size_t length = va_arg(ap, size_t);
454 NET_ReadString(buf, str, length);
455 break;
456 }
457 case '*':
458 {
459 int i;
460 byte* p;
461 const int n = NET_ReadShort(buf);
462
463 *va_arg(ap, int*) = n;
464 p = va_arg(ap, byte*);
465
466 for (i = 0; i < n; i++)
467 *p++ = NET_ReadByte(buf);
468 }
469 break;
470 default:
471 Com_Error(ERR_DROP, "ReadFormat: Unknown type!");
472 }
473 }
474 /* Too many arguments for the given format; too few cause crash above */
475 #ifdef PARANOID
476 if (!ap)
477 Com_Error(ERR_DROP, "ReadFormat: Too many arguments!");
478 #endif
479 }
480
NET_SkipFormat(dbuffer * buf,const char * format)481 void NET_SkipFormat (dbuffer* buf, const char* format)
482 {
483 while (*format) {
484 const char typeID = *format++;
485
486 switch (typeID) {
487 case 'c':
488 NET_ReadChar(buf);
489 break;
490 case 'b':
491 NET_ReadByte(buf);
492 break;
493 case 's':
494 NET_ReadShort(buf);
495 break;
496 case 'l':
497 NET_ReadLong(buf);
498 break;
499 case 'p': {
500 vec3_t v;
501 NET_ReadPos(buf, v);
502 break;
503 }
504 case 'g': {
505 pos3_t p;
506 NET_ReadGPos(buf, p);
507 break;
508 }
509 case 'd': {
510 vec3_t v;
511 NET_ReadDir(buf, v);
512 break;
513 }
514 case 'a':
515 NET_ReadAngle(buf);
516 break;
517 case '!':
518 format++;
519 break;
520 case '&':
521 NET_ReadString(buf, nullptr, 0);
522 break;
523 case '*': {
524 const int n = NET_ReadShort(buf);
525 for (int i = 0; i < n; i++)
526 NET_ReadByte(buf);
527 break;
528 }
529 default:
530 Com_Error(ERR_DROP, "ReadFormat: Unknown type!");
531 }
532 }
533 }
534
535 /**
536 * @brief The user-friendly version of NET_ReadFormat that reads variable arguments from a buffer according to format
537 */
NET_ReadFormat(dbuffer * buf,const char * format,...)538 void NET_ReadFormat (dbuffer* buf, const char* format, ...)
539 {
540 va_list ap;
541
542 va_start(ap, format);
543 NET_vReadFormat(buf, format, ap);
544 va_end(ap);
545 }
546
547 /**
548 * @brief Out of band print
549 * @sa clc_oob
550 * @sa CL_ReadPackets
551 * @sa SV_ConnectionlessPacket
552 */
NET_OOB_Printf(struct net_stream * s,const char * format,...)553 void NET_OOB_Printf (struct net_stream *s, const char* format, ...)
554 {
555 va_list argptr;
556 char string[256];
557 const char cmd = (const char)clc_oob;
558
559 va_start(argptr, format);
560 Q_vsnprintf(string, sizeof(string), format, argptr);
561 va_end(argptr);
562
563 const int len = LittleLong(strlen(string) + 1);
564 NET_StreamEnqueue(s, (const char*)&len, 4);
565 NET_StreamEnqueue(s, &cmd, 1);
566 NET_StreamEnqueue(s, string, strlen(string));
567 }
568
569 /**
570 * @brief Enqueue the buffer in the net stream for ONE client
571 * @note Frees the msg buffer
572 * @sa NET_WriteConstMsg
573 */
NET_WriteMsg(struct net_stream * s,dbuffer & buf)574 void NET_WriteMsg (struct net_stream *s, dbuffer &buf)
575 {
576 char tmp[256];
577 int len = LittleLong(buf.length());
578 NET_StreamEnqueue(s, (char*)&len, 4);
579
580 while (buf.length()) {
581 len = buf.extract(tmp, sizeof(tmp));
582 NET_StreamEnqueue(s, tmp, len);
583 }
584 }
585
586 /**
587 * @brief Enqueue the buffer in the net stream for MULTIPLE clients
588 * @note Same as NET_WriteMsg but doesn't free the buffer, use this if you send
589 * the same buffer to more than one connected clients
590 * @note Make sure that you free the msg buffer after you called this
591 * @sa NET_WriteMsg
592 */
NET_WriteConstMsg(struct net_stream * s,const dbuffer & buf)593 void NET_WriteConstMsg (struct net_stream *s, const dbuffer &buf)
594 {
595 char tmp[256];
596 const int len = LittleLong(buf.length());
597 int pos = 0;
598 NET_StreamEnqueue(s, (const char*)&len, 4);
599
600 while (pos < buf.length()) {
601 const int x = buf.getAt(pos, tmp, sizeof(tmp));
602 assert(x > 0);
603 NET_StreamEnqueue(s, tmp, x);
604 pos += x;
605 }
606 }
607
NET_VPrintf(dbuffer * buf,const char * format,va_list ap,char * str,size_t length)608 void NET_VPrintf (dbuffer* buf, const char* format, va_list ap, char* str, size_t length)
609 {
610 const int len = Q_vsnprintf(str, length, format, ap);
611 buf->add(str, len);
612 }
613