summaryrefslogtreecommitdiff
path: root/src/qcommon/msg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qcommon/msg.cpp')
-rw-r--r--src/qcommon/msg.cpp2248
1 files changed, 2248 insertions, 0 deletions
diff --git a/src/qcommon/msg.cpp b/src/qcommon/msg.cpp
new file mode 100644
index 0000000..fc4a62a
--- /dev/null
+++ b/src/qcommon/msg.cpp
@@ -0,0 +1,2248 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+Copyright (C) 2000-2013 Darklegion Development
+Copyright (C) 2015-2019 GrangerHub
+
+This file is part of Tremulous.
+
+Tremulous is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+Tremulous is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Tremulous; if not, see <https://www.gnu.org/licenses/>
+
+===========================================================================
+*/
+
+#include "msg.h"
+
+#include "alternatePlayerstate.h"
+#include "cvar.h"
+#include "huffman.h"
+#include "q_shared.h"
+#include "qcommon.h"
+
+static huffman_t msgHuff;
+
+static bool msgInit = false;
+
+int pcount[256];
+
+/*
+==============================================================================
+
+ MESSAGE IO FUNCTIONS
+
+Handles uint8_t ordering and avoids alignment errors
+==============================================================================
+*/
+
+int oldsize = 0;
+
+void MSG_initHuffman(void);
+
+void MSG_Init(msg_t *buf, uint8_t *data, int length)
+{
+ if (!msgInit)
+ {
+ MSG_initHuffman();
+ }
+ ::memset(buf, 0, sizeof(*buf));
+ buf->data = data;
+ buf->maxsize = length;
+}
+
+void MSG_InitOOB(msg_t *buf, uint8_t *data, int length)
+{
+ if (!msgInit)
+ {
+ MSG_initHuffman();
+ }
+ ::memset(buf, 0, sizeof(*buf));
+ buf->data = data;
+ buf->maxsize = length;
+ buf->oob = true;
+}
+
+void MSG_Clear(msg_t *buf)
+{
+ buf->cursize = 0;
+ buf->overflowed = false;
+ buf->bit = 0; //<- in bits
+}
+
+void MSG_Bitstream(msg_t *buf) { buf->oob = false; }
+void MSG_BeginReading(msg_t *msg)
+{
+ msg->readcount = 0;
+ msg->bit = 0;
+ msg->oob = false;
+}
+
+void MSG_BeginReadingOOB(msg_t *msg)
+{
+ msg->readcount = 0;
+ msg->bit = 0;
+ msg->oob = true;
+}
+
+void MSG_Copy(msg_t *buf, uint8_t *data, int length, msg_t *src)
+{
+ if (length < src->cursize)
+ {
+ Com_Error(ERR_DROP, "MSG_Copy: can't copy into a smaller msg_t buffer");
+ }
+ ::memcpy(buf, src, sizeof(msg_t));
+ buf->data = data;
+ ::memcpy(buf->data, src->data, src->cursize);
+}
+
+/*
+=============================================================================
+
+bit functions
+
+=============================================================================
+*/
+
+int overflows;
+
+// negative bit values include signs
+void MSG_WriteBits(msg_t *msg, int value, int bits)
+{
+ int i;
+ //FILE* fp;
+
+ oldsize += bits;
+
+ if ( msg->overflowed )
+ {
+ return;
+ }
+
+ if (bits == 0 || bits < -31 || bits > 32)
+ {
+ Com_Error(ERR_DROP, "MSG_WriteBits: bad bits %i", bits);
+ }
+
+ // check for overflows
+ if (bits != 32)
+ {
+ if (bits > 0)
+ {
+ if (value > ((1 << bits) - 1) || value < 0)
+ {
+ overflows++;
+ }
+ }
+ else
+ {
+ int r;
+
+ r = 1 << (bits - 1);
+
+ if (value > r - 1 || value < -r)
+ {
+ overflows++;
+ }
+ }
+ }
+ if (bits < 0)
+ {
+ bits = -bits;
+ }
+ if (msg->oob)
+ {
+ if (msg->cursize + (bits >> 3) > msg->maxsize)
+ {
+ msg->overflowed = true;
+ return;
+ }
+ if (bits == 8)
+ {
+ msg->data[msg->cursize] = value;
+ msg->cursize += 1;
+ msg->bit += 8;
+ }
+ else if (bits == 16)
+ {
+ short temp = value;
+
+ CopyLittleShort(&msg->data[msg->cursize], &temp);
+ msg->cursize += 2;
+ msg->bit += 16;
+ }
+ else if (bits == 32)
+ {
+ CopyLittleLong(&msg->data[msg->cursize], &value);
+ msg->cursize += 4;
+ msg->bit += 32;
+ }
+ else
+ Com_Error(ERR_DROP, "can't write %d bits", bits);
+ }
+ else
+ {
+ value &= (0xffffffff >> (32 - bits));
+ if (bits & 7)
+ {
+ int nbits;
+ nbits = bits & 7;
+
+ if ( msg->bit + nbits > msg->maxsize << 3 )
+ {
+ msg->overflowed = true;
+ return;
+ }
+
+ for (i = 0; i < nbits; i++)
+ {
+ Huff_putBit((value & 1), msg->data, &msg->bit);
+ value = (value >> 1);
+ }
+ bits = bits - nbits;
+ }
+ if (bits)
+ {
+ for (i = 0; i < bits; i += 8)
+ {
+ Huff_offsetTransmit(&msgHuff.compressor, (value & 0xff), msg->data, &msg->bit, msg->maxsize << 3);
+ value = (value >> 8);
+
+ if (msg->bit > msg->maxsize << 3)
+ {
+ msg->overflowed = true;
+ return;
+ }
+ }
+ }
+ msg->cursize = (msg->bit >> 3) + 1;
+ }
+}
+
+int MSG_ReadBits(msg_t *msg, int bits)
+{
+ int value;
+ int get;
+ bool sgn;
+
+
+ if (msg->readcount > msg->cursize)
+ {
+ return 0;
+ }
+
+ value = 0;
+
+ if (bits < 0)
+ {
+ bits = -bits;
+ sgn = true;
+ }
+ else
+ {
+ sgn = false;
+ }
+
+ if (msg->oob)
+ {
+ if (msg->readcount + (bits >> 3) > msg->cursize)
+ {
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+
+ if (bits == 8)
+ {
+ value = msg->data[msg->readcount];
+ msg->readcount += 1;
+ msg->bit += 8;
+ }
+ else if (bits == 16)
+ {
+ short temp;
+
+ CopyLittleShort(&temp, &msg->data[msg->readcount]);
+ value = temp;
+ msg->readcount += 2;
+ msg->bit += 16;
+ }
+ else if (bits == 32)
+ {
+ CopyLittleLong(&value, &msg->data[msg->readcount]);
+ msg->readcount += 4;
+ msg->bit += 32;
+ }
+ else
+ Com_Error(ERR_DROP, "can't read %d bits", bits);
+ }
+ else
+ {
+ int nbits = 0;
+ if (bits & 7)
+ {
+ nbits = bits & 7;
+ if (msg->bit + nbits > msg->cursize << 3)
+ {
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+ for (int i = 0; i < nbits; i++)
+ {
+ value |= (Huff_getBit(msg->data, &msg->bit) << i);
+ }
+ bits = bits - nbits;
+ }
+ if (bits)
+ {
+ for (int i = 0; i < bits; i += 8)
+ {
+ Huff_offsetReceive(msgHuff.decompressor.tree, &get, msg->data, &msg->bit, msg->cursize << 3);
+ value |= (get << (i + nbits));
+
+ if (msg->bit > msg->cursize << 3)
+ {
+ msg->readcount = msg->cursize + 1;
+ return 0;
+ }
+ }
+ }
+ msg->readcount = (msg->bit >> 3) + 1;
+ }
+ if (sgn && bits > 0 && bits < 32)
+ {
+ if (value & (1 << (bits - 1)))
+ {
+ value |= -1 ^ ((1 << bits) - 1);
+ }
+ }
+
+ return value;
+}
+
+//================================================================================
+
+//
+// writing functions
+//
+
+void MSG_WriteChar(msg_t *sb, int c)
+{
+#ifdef PARANOID
+ if (c < -128 || c > 127) Com_Error(ERR_FATAL, "MSG_WriteChar: range error");
+#endif
+
+ MSG_WriteBits(sb, c, 8);
+}
+
+void MSG_WriteByte(msg_t *sb, int c)
+{
+#ifdef PARANOID
+ if (c < 0 || c > 255) Com_Error(ERR_FATAL, "MSG_WriteByte: range error");
+#endif
+
+ MSG_WriteBits(sb, c, 8);
+}
+
+void MSG_WriteData(msg_t *buf, const void *data, int length)
+{
+ int i;
+ for (i = 0; i < length; i++)
+ {
+ MSG_WriteByte(buf, ((uint8_t *)data)[i]);
+ }
+}
+
+void MSG_WriteShort(msg_t *sb, int c)
+{
+#ifdef PARANOID
+ if (c < ((short)0x8000) || c > (short)0x7fff) Com_Error(ERR_FATAL, "MSG_WriteShort: range error");
+#endif
+
+ MSG_WriteBits(sb, c, 16);
+}
+
+void MSG_WriteLong(msg_t *sb, int c) { MSG_WriteBits(sb, c, 32); }
+void MSG_WriteFloat(msg_t *sb, float f)
+{
+ floatint_t dat;
+ dat.f = f;
+ MSG_WriteBits(sb, dat.i, 32);
+}
+
+static void MSG_WriteString2(msg_t *sb, const char *s, int maxsize)
+{
+ int size = strlen(s) + 1;
+
+ if (size > maxsize)
+ {
+ Com_Printf("MSG_WriteString2: %i > %i\n", size, maxsize);
+ MSG_WriteData(sb, "", 1);
+ return;
+ }
+
+ MSG_WriteData(sb, s, size);
+}
+
+void MSG_WriteString(msg_t *sb, const char *s) { MSG_WriteString2(sb, s, MAX_STRING_CHARS); }
+void MSG_WriteBigString(msg_t *sb, const char *s) { MSG_WriteString2(sb, s, BIG_INFO_STRING); }
+void MSG_WriteAngle(msg_t *sb, float f) { MSG_WriteByte(sb, (int)(f * 256 / 360) & 255); }
+void MSG_WriteAngle16(msg_t *sb, float f) { MSG_WriteShort(sb, ANGLE2SHORT(f)); }
+//============================================================
+
+//
+// reading functions
+//
+
+// returns -1 if no more characters are available
+int MSG_ReadChar(msg_t *msg)
+{
+ int c;
+
+ c = (signed char)MSG_ReadBits(msg, 8);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+
+ return c;
+}
+
+int MSG_ReadByte(msg_t *msg)
+{
+ int c;
+
+ c = (unsigned char)MSG_ReadBits(msg, 8);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+ return c;
+}
+
+int MSG_LookaheadByte(msg_t *msg)
+{
+ const int bloc = Huff_getBloc();
+ const int readcount = msg->readcount;
+ const int bit = msg->bit;
+ int c = MSG_ReadByte(msg);
+ Huff_setBloc(bloc);
+ msg->readcount = readcount;
+ msg->bit = bit;
+ return c;
+}
+
+int MSG_ReadShort(msg_t *msg)
+{
+ int c;
+
+ c = (short)MSG_ReadBits(msg, 16);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+
+ return c;
+}
+
+int MSG_ReadLong(msg_t *msg)
+{
+ int c;
+
+ c = MSG_ReadBits(msg, 32);
+ if (msg->readcount > msg->cursize)
+ {
+ c = -1;
+ }
+
+ return c;
+}
+
+float MSG_ReadFloat(msg_t *msg)
+{
+ floatint_t dat;
+
+ dat.i = MSG_ReadBits(msg, 32);
+ if (msg->readcount > msg->cursize)
+ {
+ dat.f = -1;
+ }
+
+ return dat.f;
+}
+
+char *MSG_ReadString(msg_t *msg)
+{
+ static char string[MAX_STRING_CHARS];
+
+ size_t l = 0;
+ do
+ {
+ int c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
+ if (c == -1 || c == 0)
+ {
+ break;
+ }
+
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string) - 1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+char *MSG_ReadBigString(msg_t *msg)
+{
+ static char string[BIG_INFO_STRING];
+
+ size_t l = 0;
+ do
+ {
+ int c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
+ if (c == -1 || c == 0)
+ {
+ break;
+ }
+
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string) - 1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+char *MSG_ReadStringLine(msg_t *msg)
+{
+ static char string[MAX_STRING_CHARS];
+
+ size_t l = 0;
+ do
+ {
+ int c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
+ if (c == -1 || c == 0 || c == '\n')
+ {
+ break;
+ }
+
+ string[l] = c;
+ l++;
+ } while (l < sizeof(string) - 1);
+
+ string[l] = 0;
+
+ return string;
+}
+
+float MSG_ReadAngle16(msg_t *msg) { return SHORT2ANGLE(MSG_ReadShort(msg)); }
+void MSG_ReadData(msg_t *msg, void *data, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ ((uint8_t *)data)[i] = MSG_ReadByte(msg);
+ }
+}
+
+// a string hasher which gives the same hash value even if the
+// string is later modified via the legacy MSG read/write code
+int MSG_HashKey(int alternateProtocol, const char *string, int maxlen)
+{
+ int hash, i;
+
+ hash = 0;
+ for (i = 0; i < maxlen && string[i] != '\0'; i++)
+ {
+ if (string[i] & 0x80 || (alternateProtocol == 2 && string[i] == '%'))
+ hash += '.' * (119 + i);
+ else
+ hash += string[i] * (119 + i);
+ }
+ hash = (hash ^ (hash >> 10) ^ (hash >> 20));
+ return hash;
+}
+
+/*
+=============================================================================
+
+delta functions
+
+=============================================================================
+*/
+
+extern cvar_t *cl_shownet;
+
+#define LOG(x) \
+ if (cl_shownet && cl_shownet->integer == 4) \
+ { \
+ Com_Printf("%s ", x); \
+ };
+
+void MSG_WriteDelta(msg_t *msg, int oldV, int newV, int bits)
+{
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, newV, bits);
+}
+
+int MSG_ReadDelta(msg_t *msg, int oldV, int bits)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ return MSG_ReadBits(msg, bits);
+ }
+ return oldV;
+}
+
+void MSG_WriteDeltaFloat(msg_t *msg, float oldV, float newV)
+{
+ floatint_t fi;
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ fi.f = newV;
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, fi.i, 32);
+}
+
+float MSG_ReadDeltaFloat(msg_t *msg, float oldV)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ floatint_t fi;
+
+ fi.i = MSG_ReadBits(msg, 32);
+ return fi.f;
+ }
+ return oldV;
+}
+
+/*
+=============================================================================
+
+delta functions with keys
+
+=============================================================================
+*/
+
+unsigned int kbitmask[32] = {
+ 0x00000001, 0x00000003, 0x00000007, 0x0000000F, 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, 0x000001FF,
+ 0x000003FF, 0x000007FF, 0x00000FFF, 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, 0x0001FFFF, 0x0003FFFF,
+ 0x0007FFFF, 0x000FFFFF, 0x001FFFFf, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF,
+ 0x0FFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
+};
+
+void MSG_WriteDeltaKey(msg_t *msg, int key, int oldV, int newV, int bits)
+{
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, newV ^ key, bits);
+}
+
+int MSG_ReadDeltaKey(msg_t *msg, int key, int oldV, int bits)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ return MSG_ReadBits(msg, bits) ^ (key & kbitmask[bits - 1]);
+ }
+ return oldV;
+}
+
+void MSG_WriteDeltaKeyFloat(msg_t *msg, int key, float oldV, float newV)
+{
+ floatint_t fi;
+ if (oldV == newV)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ return;
+ }
+ fi.f = newV;
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, fi.i ^ key, 32);
+}
+
+float MSG_ReadDeltaKeyFloat(msg_t *msg, int key, float oldV)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ floatint_t fi;
+
+ fi.i = MSG_ReadBits(msg, 32) ^ key;
+ return fi.f;
+ }
+ return oldV;
+}
+
+/*
+============================================================================
+
+usercmd_t communication
+
+============================================================================
+*/
+
+/*
+=====================
+MSG_WriteDeltaUsercmdKey
+=====================
+*/
+void MSG_WriteDeltaUsercmdKey(msg_t *msg, int key, usercmd_t *from, usercmd_t *to)
+{
+ if (to->serverTime - from->serverTime < 256)
+ {
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, to->serverTime - from->serverTime, 8);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1);
+ MSG_WriteBits(msg, to->serverTime, 32);
+ }
+ if ( from->angles[0] == to->angles[0]
+ && from->angles[1] == to->angles[1]
+ && from->angles[2] == to->angles[2]
+ && from->forwardmove == to->forwardmove
+ && from->rightmove == to->rightmove
+ && from->upmove == to->upmove
+ && from->buttons == to->buttons
+ && from->weapon == to->weapon )
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ oldsize += 7;
+ return;
+ }
+ key ^= to->serverTime;
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteDeltaKey(msg, key, from->angles[0], to->angles[0], 16);
+ MSG_WriteDeltaKey(msg, key, from->angles[1], to->angles[1], 16);
+ MSG_WriteDeltaKey(msg, key, from->angles[2], to->angles[2], 16);
+ MSG_WriteDeltaKey(msg, key, from->forwardmove, to->forwardmove, 8);
+ MSG_WriteDeltaKey(msg, key, from->rightmove, to->rightmove, 8);
+ MSG_WriteDeltaKey(msg, key, from->upmove, to->upmove, 8);
+ MSG_WriteDeltaKey(msg, key, from->buttons, to->buttons, 16);
+ MSG_WriteDeltaKey(msg, key, from->weapon, to->weapon, 8);
+}
+
+/*
+=====================
+MSG_ReadDeltaUsercmdKey
+=====================
+*/
+void MSG_ReadDeltaUsercmdKey(msg_t *msg, int key, usercmd_t *from, usercmd_t *to)
+{
+ if (MSG_ReadBits(msg, 1))
+ {
+ to->serverTime = from->serverTime + MSG_ReadBits(msg, 8);
+ }
+ else
+ {
+ to->serverTime = MSG_ReadBits(msg, 32);
+ }
+ if (MSG_ReadBits(msg, 1))
+ {
+ key ^= to->serverTime;
+ to->angles[0] = MSG_ReadDeltaKey(msg, key, from->angles[0], 16);
+ to->angles[1] = MSG_ReadDeltaKey(msg, key, from->angles[1], 16);
+ to->angles[2] = MSG_ReadDeltaKey(msg, key, from->angles[2], 16);
+ to->forwardmove = MSG_ReadDeltaKey(msg, key, from->forwardmove, 8);
+ if (to->forwardmove == -128) to->forwardmove = -127;
+ to->rightmove = MSG_ReadDeltaKey(msg, key, from->rightmove, 8);
+ if (to->rightmove == -128) to->rightmove = -127;
+ to->upmove = MSG_ReadDeltaKey(msg, key, from->upmove, 8);
+ if (to->upmove == -128) to->upmove = -127;
+ to->buttons = MSG_ReadDeltaKey(msg, key, from->buttons, 16);
+ to->weapon = MSG_ReadDeltaKey(msg, key, from->weapon, 8);
+ }
+ else
+ {
+ to->angles[0] = from->angles[0];
+ to->angles[1] = from->angles[1];
+ to->angles[2] = from->angles[2];
+ to->forwardmove = from->forwardmove;
+ to->rightmove = from->rightmove;
+ to->upmove = from->upmove;
+ to->buttons = from->buttons;
+ to->weapon = from->weapon;
+ }
+}
+
+/*
+=============================================================================
+
+entityState_t communication
+
+=============================================================================
+*/
+
+/*
+=================
+MSG_ReportChangeVectors_f
+
+Prints out a table from the current statistics for copying to code
+=================
+*/
+void MSG_ReportChangeVectors_f(void)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ {
+ if (pcount[i])
+ {
+ Com_Printf("%d used %d\n", i, pcount[i]);
+ }
+ }
+}
+
+typedef struct {
+ const char *name;
+ size_t offset;
+ int bits; // 0 = float
+} netField_t;
+
+// using the stringizing operator to save typing...
+#define NETF(x) #x, (size_t) & ((entityState_t *) 0)->x
+
+netField_t entityStateFields[] = {
+ {NETF(pos.trTime), 32},
+ {NETF(pos.trBase[0]), 0},
+ {NETF(pos.trBase[1]), 0},
+ {NETF(pos.trDelta[0]), 0},
+ {NETF(pos.trDelta[1]), 0},
+ {NETF(pos.trBase[2]), 0},
+ {NETF(apos.trBase[1]), 0},
+ {NETF(pos.trDelta[2]), 0},
+ {NETF(apos.trBase[0]), 0},
+ {NETF(event), 10},
+ {NETF(angles2[1]), 0},
+ {NETF(eType), 8},
+ {NETF(torsoAnim), 8},
+ {NETF(weaponAnim), 8},
+ {NETF(eventParm), 8},
+ {NETF(legsAnim), 8},
+ {NETF(groundEntityNum), GENTITYNUM_BITS},
+ {NETF(pos.trType), 8},
+ {NETF(eFlags), 19},
+ {NETF(otherEntityNum), GENTITYNUM_BITS},
+ {NETF(weapon), 8},
+ {NETF(clientNum), 8},
+ {NETF(angles[1]), 0},
+ {NETF(pos.trDuration), 32},
+ {NETF(apos.trType), 8},
+ {NETF(origin[0]), 0},
+ {NETF(origin[1]), 0},
+ {NETF(origin[2]), 0},
+ {NETF(solid), 24},
+ {NETF(misc), MAX_MISC},
+ {NETF(modelindex), 8},
+ {NETF(otherEntityNum2), GENTITYNUM_BITS},
+ {NETF(loopSound), 8},
+ {NETF(generic1), 10},
+ {NETF(origin2[2]), 0},
+ {NETF(origin2[0]), 0},
+ {NETF(origin2[1]), 0},
+ {NETF(modelindex2), 8},
+ {NETF(angles[0]), 0},
+ {NETF(time), 32},
+ {NETF(apos.trTime), 32},
+ {NETF(apos.trDuration), 32},
+ {NETF(apos.trBase[2]), 0},
+ {NETF(apos.trDelta[0]), 0},
+ {NETF(apos.trDelta[1]), 0},
+ {NETF(apos.trDelta[2]), 0},
+ {NETF(time2), 32},
+ {NETF(angles[2]), 0},
+ {NETF(angles2[0]), 0},
+ {NETF(angles2[2]), 0},
+ {NETF(constantLight), 32},
+ {NETF(frame), 16}
+};
+
+// if (int)f == f and (int)f + ( 1<<(FLOAT_INT_BITS-1) ) < ( 1 << FLOAT_INT_BITS )
+// the float will be sent with FLOAT_INT_BITS, otherwise all 32 bits will be sent
+#define FLOAT_INT_BITS 13
+#define FLOAT_INT_BIAS (1 << (FLOAT_INT_BITS - 1))
+
+/*
+==================
+MSG_WriteDeltaEntity
+
+Writes part of a packetentities message, including the entity number.
+Can delta from either a baseline or a previous packet_entity
+If to is NULL, a remove entity update will be sent
+If force is not set, then nothing at all will be generated if the entity is
+identical, under the assumption that the in-order delta code will catch it.
+==================
+*/
+void MSG_WriteDeltaEntity(int alternateProtocol, msg_t *msg, struct entityState_s *from, struct entityState_s *to, bool force)
+{
+ int i, lc;
+ int numFields;
+ netField_t *field;
+ int trunc;
+ float fullFloat;
+ int *fromF, *toF;
+
+ numFields = ARRAY_LEN(entityStateFields);
+
+ // all fields should be 32 bits to avoid any compiler packing issues
+ // the "number" field is not part of the field list
+ // if this assert fails, someone added a field to the entityState_t
+ // struct without updating the message fields
+ assert(numFields + 1 == sizeof(*from) / 4);
+
+ // a NULL to is a delta remove message
+ if (to == NULL)
+ {
+ if (from == NULL)
+ {
+ return;
+ }
+ MSG_WriteBits(msg, from->number, GENTITYNUM_BITS);
+ MSG_WriteBits(msg, 1, 1);
+ return;
+ }
+
+ if (to->number < 0 || to->number >= MAX_GENTITIES)
+ {
+ Com_Error(ERR_FATAL, "MSG_WriteDeltaEntity: Bad entity number: %i", to->number);
+ }
+
+ lc = 0;
+ // build the change vector as bytes so it is endien independent
+ for (i = 0, field = entityStateFields; i < numFields; i++, field++)
+ {
+ if (alternateProtocol == 2 && i == 13)
+ {
+ continue;
+ }
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ if (*fromF != *toF)
+ {
+ lc = i + 1;
+ }
+ }
+
+ if (lc == 0)
+ {
+ // nothing at all changed
+ if (!force)
+ {
+ return; // nothing at all
+ }
+ // write two bits for no change
+ MSG_WriteBits(msg, to->number, GENTITYNUM_BITS);
+ MSG_WriteBits(msg, 0, 1); // not removed
+ MSG_WriteBits(msg, 0, 1); // no delta
+ return;
+ }
+
+ MSG_WriteBits(msg, to->number, GENTITYNUM_BITS);
+ MSG_WriteBits(msg, 0, 1); // not removed
+ MSG_WriteBits(msg, 1, 1); // we have a delta
+
+ if (alternateProtocol == 2 && lc - 1 > 13)
+ {
+ MSG_WriteByte(msg, lc - 1); // # of changes
+ }
+ else
+ {
+ MSG_WriteByte(msg, lc); // # of changes
+ }
+
+ oldsize += numFields;
+
+ for (i = 0, field = entityStateFields; i < lc; i++, field++)
+ {
+ if (alternateProtocol == 2 && i == 13)
+ {
+ continue;
+ }
+
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (*fromF == *toF)
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ continue;
+ }
+
+ MSG_WriteBits(msg, 1, 1); // changed
+
+ if (field->bits == 0)
+ {
+ // float
+ fullFloat = *(float *)toF;
+ trunc = (int)fullFloat;
+
+ if (fullFloat == 0.0f)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ oldsize += FLOAT_INT_BITS;
+ }
+ else
+ {
+ MSG_WriteBits(msg, 1, 1);
+ if (trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 && trunc + FLOAT_INT_BIAS < (1 << FLOAT_INT_BITS))
+ {
+ // send as small integer
+ MSG_WriteBits(msg, 0, 1);
+ MSG_WriteBits(msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS);
+ }
+ else
+ {
+ // send as full floating point value
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, *toF, 32);
+ }
+ }
+ }
+ else
+ {
+ if (*toF == 0)
+ {
+ MSG_WriteBits(msg, 0, 1);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 1, 1);
+ // integer
+ if (alternateProtocol == 2 && i == 33)
+ {
+ MSG_WriteBits(msg, *toF, 8);
+ }
+ else
+ {
+ MSG_WriteBits(msg, *toF, field->bits);
+ }
+ }
+ }
+ }
+}
+
+/*
+==================
+MSG_ReadDeltaEntity
+
+The entity number has already been read from the message, which
+is how the from state is identified.
+
+If the delta removes the entity, entityState_t->number will be set to MAX_GENTITIES-1
+
+Can go from either a baseline or a previous packet_entity
+==================
+*/
+void MSG_ReadDeltaEntity(int alternateProtocol, msg_t *msg, entityState_t *from, entityState_t *to, int number)
+{
+ int i, lc;
+ int numFields;
+ netField_t *field;
+ int *fromF, *toF;
+ int print;
+ int trunc;
+ int startBit, endBit;
+
+ if (number < 0 || number >= MAX_GENTITIES)
+ {
+ Com_Error(ERR_DROP, "Bad delta entity number: %i", number);
+ }
+
+ if (msg->bit == 0)
+ {
+ startBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ startBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+
+ // check for a remove
+ if (MSG_ReadBits(msg, 1) == 1)
+ {
+ ::memset(to, 0, sizeof(*to));
+ to->number = MAX_GENTITIES - 1;
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -1))
+ {
+ Com_Printf("%3i: #%-3i remove\n", msg->readcount, number);
+ }
+ return;
+ }
+
+ // check for no delta
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ *to = *from;
+ to->number = number;
+ return;
+ }
+
+ numFields = ARRAY_LEN(entityStateFields);
+ lc = MSG_ReadByte(msg);
+ if (alternateProtocol == 2 && lc - 1 >= 13)
+ {
+ ++lc;
+ }
+
+ if (lc > numFields || lc < 0)
+ {
+ Com_Error(ERR_DROP, "invalid entityState field count");
+ }
+
+ // shownet 2/3 will interleave with other printed info, -1 will
+ // just print the delta records`
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -1))
+ {
+ print = 1;
+ Com_Printf("%3i: #%-3i ", msg->readcount, to->number);
+ }
+ else
+ {
+ print = 0;
+ }
+
+ to->number = number;
+
+ for (i = 0, field = entityStateFields; i < lc; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ if (alternateProtocol == 2 && i == 13)
+ {
+ *toF = 0;
+ continue;
+ }
+
+ if (!MSG_ReadBits(msg, 1))
+ {
+ // no change
+ *toF = *fromF;
+ }
+ else
+ {
+ if (field->bits == 0)
+ {
+ // float
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ *(float *)toF = 0.0f;
+ }
+ else
+ {
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ // integral float
+ trunc = MSG_ReadBits(msg, FLOAT_INT_BITS);
+ // bias to allow equal parts positive and negative
+ trunc -= FLOAT_INT_BIAS;
+ *(float *)toF = trunc;
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, trunc);
+ }
+ }
+ else
+ {
+ // full floating point value
+ *toF = MSG_ReadBits(msg, 32);
+ if (print)
+ {
+ Com_Printf("%s:%f ", field->name, *(float *)toF);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ *toF = 0;
+ }
+ else
+ {
+ // integer
+ if (alternateProtocol == 2 && i == 33)
+ {
+ *toF = MSG_ReadBits(msg, 8);
+ }
+ else
+ {
+ *toF = MSG_ReadBits(msg, field->bits);
+ }
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, *toF);
+ }
+ }
+ }
+ // pcount[i]++;
+ }
+ }
+ for (i = lc, field = &entityStateFields[lc]; i < numFields; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ // no change
+ *toF = *fromF;
+ }
+
+ if (print)
+ {
+ if (msg->bit == 0)
+ {
+ endBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ endBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+ Com_Printf(" (%i bits)\n", endBit - startBit);
+ }
+}
+
+/*
+============================================================================
+
+plyer_state_t communication
+
+============================================================================
+*/
+
+// using the stringizing operator to save typing...
+#define PSF(x) #x, (size_t) & ((playerState_t *) 0)->x
+
+netField_t playerStateFields[] = {
+ {PSF(commandTime), 32},
+ {PSF(origin[0]), 0},
+ {PSF(origin[1]), 0},
+ {PSF(bobCycle), 8},
+ {PSF(velocity[0]), 0},
+ {PSF(velocity[1]), 0},
+ {PSF(viewangles[1]), 0},
+ {PSF(viewangles[0]), 0},
+ {PSF(weaponTime), -16},
+ {PSF(origin[2]), 0},
+ {PSF(velocity[2]), 0},
+ {PSF(legsTimer), 8},
+ {PSF(pm_time), -16},
+ {PSF(eventSequence), 16},
+ {PSF(torsoAnim), 8},
+ {PSF(weaponAnim), 8},
+ {PSF(movementDir), 4},
+ {PSF(events[0]), 8},
+ {PSF(legsAnim), 8},
+ {PSF(events[1]), 8},
+ {PSF(pm_flags), 24},
+ {PSF(groundEntityNum), GENTITYNUM_BITS},
+ {PSF(weaponstate), 4},
+ {PSF(eFlags), 16},
+ {PSF(externalEvent), 10},
+ {PSF(gravity), -16},
+ {PSF(speed), -16},
+ {PSF(delta_angles[1]), 16},
+ {PSF(externalEventParm), 8},
+ {PSF(viewheight), -8},
+ {PSF(damageEvent), 8},
+ {PSF(damageYaw), 8},
+ {PSF(damagePitch), 8},
+ {PSF(damageCount), 8},
+ {PSF(ammo), 12},
+ {PSF(clips), 4},
+ {PSF(generic1), 10},
+ {PSF(pm_type), 8},
+ {PSF(delta_angles[0]), 16},
+ {PSF(delta_angles[2]), 16},
+ {PSF(torsoTimer), 12},
+ {PSF(tauntTimer), 12},
+ {PSF(eventParms[0]), 8},
+ {PSF(eventParms[1]), 8},
+ {PSF(clientNum), 8},
+ {PSF(weapon), 5},
+ {PSF(viewangles[2]), 0},
+ {PSF(grapplePoint[0]), 0},
+ {PSF(grapplePoint[1]), 0},
+ {PSF(grapplePoint[2]), 0},
+ {PSF(otherEntityNum), GENTITYNUM_BITS},
+ {PSF(loopSound), 16}
+};
+
+#define APSF(x) #x, (size_t) & ((alternatePlayerState_t *) 0)->x
+
+netField_t alternatePlayerStateFields[] = {
+ {APSF(commandTime), 32},
+ {APSF(origin[0]), 0},
+ {APSF(origin[1]), 0},
+ {APSF(bobCycle), 8},
+ {APSF(velocity[0]), 0},
+ {APSF(velocity[1]), 0},
+ {APSF(viewangles[1]), 0},
+ {APSF(viewangles[0]), 0},
+ {APSF(weaponTime), -16},
+ {APSF(origin[2]), 0},
+ {APSF(velocity[2]), 0},
+ {APSF(legsTimer), 8},
+ {APSF(pm_time), -16},
+ {APSF(eventSequence), 16},
+ {APSF(torsoAnim), 8},
+ {APSF(movementDir), 4},
+ {APSF(events[0]), 8},
+ {APSF(legsAnim), 8},
+ {APSF(events[1]), 8},
+ {APSF(pm_flags), 16},
+ {APSF(groundEntityNum), GENTITYNUM_BITS},
+ {APSF(weaponstate), 4},
+ {APSF(eFlags), 16},
+ {APSF(externalEvent), 10},
+ {APSF(gravity), -16},
+ {APSF(speed), -16},
+ {APSF(delta_angles[1]), 16},
+ {APSF(externalEventParm), 8},
+ {APSF(viewheight), -8},
+ {APSF(damageEvent), 8},
+ {APSF(damageYaw), 8},
+ {APSF(damagePitch), 8},
+ {APSF(damageCount), 8},
+ {APSF(generic1), 8},
+ {APSF(pm_type), 8},
+ {APSF(delta_angles[0]), 16},
+ {APSF(delta_angles[2]), 16},
+ {APSF(torsoTimer), 12},
+ {APSF(eventParms[0]), 8},
+ {APSF(eventParms[1]), 8},
+ {APSF(clientNum), 8},
+ {APSF(weapon), 5},
+ {APSF(viewangles[2]), 0},
+ {APSF(grapplePoint[0]), 0},
+ {APSF(grapplePoint[1]), 0},
+ {APSF(grapplePoint[2]), 0},
+ {APSF(otherEntityNum), GENTITYNUM_BITS},
+ {APSF(loopSound), 16}
+};
+
+/*
+=============
+MSG_WriteDeltaPlayerstate
+
+=============
+*/
+void MSG_WriteDeltaPlayerstate(int alternateProtocol, msg_t *msg, struct playerState_s *from, struct playerState_s *to)
+{
+ int i;
+ playerState_t dummy;
+ int statsbits;
+ int persistantbits;
+ int altFromAmmo[3];
+ int altToAmmo[3];
+ int ammobits;
+ int miscbits;
+ int numFields;
+ netField_t *field;
+ int *fromF, *toF;
+ float fullFloat;
+ int trunc, lc;
+
+ if (!from)
+ {
+ from = &dummy;
+ ::memset(&dummy, 0, sizeof(dummy));
+ }
+
+ numFields = ARRAY_LEN(playerStateFields);
+
+ lc = 0;
+ for (i = 0, field = playerStateFields; i < numFields; i++, field++)
+ {
+ if (alternateProtocol == 2 && (i == 15 || i == 34 || i == 35 || i == 41))
+ {
+ continue;
+ }
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ if (*fromF != *toF)
+ {
+ lc = i + 1;
+ }
+ }
+
+ if (alternateProtocol == 2)
+ {
+ if (lc - 1 > 41)
+ {
+ MSG_WriteByte(msg, lc - 4); // # of changes
+ }
+ else if (lc - 1 > 35)
+ {
+ MSG_WriteByte(msg, lc - 3); // # of changes
+ }
+ else if (lc - 1 > 34)
+ {
+ MSG_WriteByte(msg, lc - 2); // # of changes
+ }
+ else if (lc - 1 > 15)
+ {
+ MSG_WriteByte(msg, lc - 1); // # of changes
+ }
+ else
+ {
+ MSG_WriteByte(msg, lc); // # of changes
+ }
+ }
+ else
+ {
+ MSG_WriteByte(msg, lc); // # of changes
+ }
+
+ oldsize += numFields - lc;
+
+ for (i = 0, field = playerStateFields; i < lc; i++, field++)
+ {
+ if (alternateProtocol == 2 && (i == 15 || i == 34 || i == 35 || i == 41))
+ {
+ continue;
+ }
+
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (*fromF == *toF)
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ continue;
+ }
+
+ MSG_WriteBits(msg, 1, 1); // changed
+ // pcount[i]++;
+
+ if (field->bits == 0)
+ {
+ // float
+ fullFloat = *(float *)toF;
+ trunc = (int)fullFloat;
+
+ if (trunc == fullFloat && trunc + FLOAT_INT_BIAS >= 0 && trunc + FLOAT_INT_BIAS < (1 << FLOAT_INT_BITS))
+ {
+ // send as small integer
+ MSG_WriteBits(msg, 0, 1);
+ MSG_WriteBits(msg, trunc + FLOAT_INT_BIAS, FLOAT_INT_BITS);
+ }
+ else
+ {
+ // send as full floating point value
+ MSG_WriteBits(msg, 1, 1);
+ MSG_WriteBits(msg, *toF, 32);
+ }
+ }
+ else
+ {
+ // integer
+ if (alternateProtocol == 2)
+ {
+ if (i == 20)
+ {
+ MSG_WriteBits(msg, *toF, 16);
+ }
+ else if (i == 36)
+ {
+ MSG_WriteBits(msg, *toF, 8);
+ }
+ else
+ {
+ MSG_WriteBits(msg, *toF, field->bits);
+ }
+ }
+ else
+ {
+ MSG_WriteBits(msg, *toF, field->bits);
+ }
+ }
+ }
+
+ //
+ // send the arrays
+ //
+ statsbits = 0;
+ for (i = 0; i < MAX_STATS; i++)
+ {
+ if (to->stats[i] != from->stats[i])
+ {
+ statsbits |= 1 << i;
+ }
+ }
+ persistantbits = 0;
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ {
+ if (to->persistant[i] != from->persistant[i])
+ {
+ persistantbits |= 1 << i;
+ }
+ }
+ if (alternateProtocol == 2)
+ {
+ altFromAmmo[0] = (from->weaponAnim & 0xFF) | ((from->pm_flags >> 8) & 0xFF00);
+ altFromAmmo[1] = (from->ammo & 0xFFF) | ((from->clips << 12) & 0xF000);
+ altFromAmmo[2] = (from->tauntTimer & 0xFFF) | ((from->generic1 << 4) & 0x3000);
+ altToAmmo[0] = (to->weaponAnim & 0xFF) | ((to->pm_flags >> 8) & 0xFF00);
+ altToAmmo[1] = (to->ammo & 0xFFF) | ((to->clips << 12) & 0xF000);
+ altToAmmo[2] = (to->tauntTimer & 0xFFF) | ((to->generic1 << 4) & 0x3000);
+ ammobits = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if (altToAmmo[i] != altFromAmmo[i])
+ {
+ ammobits |= 1 << i;
+ }
+ }
+ }
+ else
+ {
+ ammobits = 0;
+ }
+ miscbits = 0;
+ for (i = 0; i < MAX_MISC; i++)
+ {
+ if (to->misc[i] != from->misc[i])
+ {
+ miscbits |= 1 << i;
+ }
+ }
+
+ if (!statsbits && !persistantbits && !ammobits && !miscbits)
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ oldsize += 4;
+ return;
+ }
+ MSG_WriteBits(msg, 1, 1); // changed
+
+ if (statsbits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, statsbits, MAX_STATS);
+ for (i = 0; i < MAX_STATS; i++)
+ if (statsbits & (1 << i)) MSG_WriteShort(msg, to->stats[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+
+ if (persistantbits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, persistantbits, MAX_PERSISTANT);
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ if (persistantbits & (1 << i)) MSG_WriteShort(msg, to->persistant[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+
+ if (alternateProtocol == 2)
+ {
+ if (ammobits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, ammobits, 16);
+ for (i = 0; i < 3; i++)
+ if (ammobits & (1 << i)) MSG_WriteShort(msg, altToAmmo[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+ }
+
+ if (miscbits)
+ {
+ MSG_WriteBits(msg, 1, 1); // changed
+ MSG_WriteBits(msg, miscbits, MAX_MISC);
+ for (i = 0; i < MAX_MISC; i++)
+ if (miscbits & (1 << i)) MSG_WriteLong(msg, to->misc[i]);
+ }
+ else
+ {
+ MSG_WriteBits(msg, 0, 1); // no change
+ }
+}
+
+/*
+===================
+MSG_ReadDeltaPlayerstate
+===================
+*/
+void MSG_ReadDeltaPlayerstate(msg_t *msg, playerState_t *from, playerState_t *to)
+{
+ int i, lc;
+ int bits;
+ netField_t *field;
+ int numFields;
+ int startBit, endBit;
+ int print;
+ int *fromF, *toF;
+ int trunc;
+ playerState_t dummy;
+
+ if (!from)
+ {
+ from = &dummy;
+ ::memset(&dummy, 0, sizeof(dummy));
+ }
+ *to = *from;
+
+ if (msg->bit == 0)
+ {
+ startBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ startBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+
+ // shownet 2/3 will interleave with other printed info, -2 will
+ // just print the delta records
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -2))
+ {
+ print = 1;
+ Com_Printf("%3i: playerstate ", msg->readcount);
+ }
+ else
+ {
+ print = 0;
+ }
+
+ numFields = ARRAY_LEN(playerStateFields);
+ lc = MSG_ReadByte(msg);
+
+ if (lc > numFields || lc < 0)
+ {
+ Com_Error(ERR_DROP, "invalid playerState field count");
+ }
+
+ for (i = 0, field = playerStateFields; i < lc; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (!MSG_ReadBits(msg, 1))
+ {
+ // no change
+ *toF = *fromF;
+ }
+ else
+ {
+ if (field->bits == 0)
+ {
+ // float
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ // integral float
+ trunc = MSG_ReadBits(msg, FLOAT_INT_BITS);
+ // bias to allow equal parts positive and negative
+ trunc -= FLOAT_INT_BIAS;
+ *(float *)toF = trunc;
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, trunc);
+ }
+ }
+ else
+ {
+ // full floating point value
+ *toF = MSG_ReadBits(msg, 32);
+ if (print)
+ {
+ Com_Printf("%s:%f ", field->name, *(float *)toF);
+ }
+ }
+ }
+ else
+ {
+ // integer
+ *toF = MSG_ReadBits(msg, field->bits);
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, *toF);
+ }
+ }
+ }
+ }
+ for (i = lc, field = &playerStateFields[lc]; i < numFields; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ // no change
+ *toF = *fromF;
+ }
+
+ // read the arrays
+ if (MSG_ReadBits(msg, 1))
+ {
+ // parse stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_STATS");
+ bits = MSG_ReadBits(msg, MAX_STATS);
+ for (i = 0; i < MAX_STATS; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->stats[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse persistant stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_PERSISTANT");
+ bits = MSG_ReadBits(msg, MAX_PERSISTANT);
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->persistant[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse misc data
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_MISC");
+ bits = MSG_ReadBits(msg, MAX_MISC);
+ for (i = 0; i < MAX_MISC; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->misc[i] = MSG_ReadLong(msg);
+ }
+ }
+ }
+ }
+
+ if (print)
+ {
+ if (msg->bit == 0)
+ {
+ endBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ endBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+ Com_Printf(" (%i bits)\n", endBit - startBit);
+ }
+}
+
+void MSG_ReadDeltaAlternatePlayerstate(msg_t *msg, alternatePlayerState_t *from, alternatePlayerState_t *to)
+{
+ int i, lc;
+ int bits;
+ netField_t *field;
+ int numFields;
+ int startBit, endBit;
+ int print;
+ int *fromF, *toF;
+ int trunc;
+ alternatePlayerState_t dummy;
+
+ if (!from)
+ {
+ from = &dummy;
+ ::memset(&dummy, 0, sizeof(dummy));
+ }
+ *to = *from;
+
+ if (msg->bit == 0)
+ {
+ startBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ startBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+
+ // shownet 2/3 will interleave with other printed info, -2 will
+ // just print the delta records
+ if (cl_shownet && (cl_shownet->integer >= 2 || cl_shownet->integer == -2))
+ {
+ print = 1;
+ Com_Printf("%3i: playerstate ", msg->readcount);
+ }
+ else
+ {
+ print = 0;
+ }
+
+ numFields = ARRAY_LEN(alternatePlayerStateFields);
+ lc = MSG_ReadByte(msg);
+
+ if (lc > numFields || lc < 0)
+ {
+ Com_Error(ERR_DROP, "invalid playerState field count");
+ }
+
+ for (i = 0, field = alternatePlayerStateFields; i < lc; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+
+ if (!MSG_ReadBits(msg, 1))
+ {
+ // no change
+ *toF = *fromF;
+ }
+ else
+ {
+ if (field->bits == 0)
+ {
+ // float
+ if (MSG_ReadBits(msg, 1) == 0)
+ {
+ // integral float
+ trunc = MSG_ReadBits(msg, FLOAT_INT_BITS);
+ // bias to allow equal parts positive and negative
+ trunc -= FLOAT_INT_BIAS;
+ *(float *)toF = trunc;
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, trunc);
+ }
+ }
+ else
+ {
+ // full floating point value
+ *toF = MSG_ReadBits(msg, 32);
+ if (print)
+ {
+ Com_Printf("%s:%f ", field->name, *(float *)toF);
+ }
+ }
+ }
+ else
+ {
+ // integer
+ *toF = MSG_ReadBits(msg, field->bits);
+ if (print)
+ {
+ Com_Printf("%s:%i ", field->name, *toF);
+ }
+ }
+ }
+ }
+ for (i = lc, field = &alternatePlayerStateFields[lc]; i < numFields; i++, field++)
+ {
+ fromF = (int *)((uint8_t *)from + field->offset);
+ toF = (int *)((uint8_t *)to + field->offset);
+ // no change
+ *toF = *fromF;
+ }
+
+ // read the arrays
+ if (MSG_ReadBits(msg, 1))
+ {
+ // parse stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_STATS");
+ bits = MSG_ReadBits(msg, MAX_STATS);
+ for (i = 0; i < MAX_STATS; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->stats[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse persistant stats
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_PERSISTANT");
+ bits = MSG_ReadBits(msg, MAX_PERSISTANT);
+ for (i = 0; i < MAX_PERSISTANT; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->persistant[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse ammo
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_AMMO");
+ bits = MSG_ReadBits(msg, MAX_WEAPONS);
+ for (i = 0; i < MAX_WEAPONS; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->ammo[i] = MSG_ReadShort(msg);
+ }
+ }
+ }
+
+ // parse misc data
+ if (MSG_ReadBits(msg, 1))
+ {
+ LOG("PS_MISC");
+ bits = MSG_ReadBits(msg, MAX_MISC);
+ for (i = 0; i < MAX_MISC; i++)
+ {
+ if (bits & (1 << i))
+ {
+ to->misc[i] = MSG_ReadLong(msg);
+ }
+ }
+ }
+ }
+
+ if (print)
+ {
+ if (msg->bit == 0)
+ {
+ endBit = msg->readcount * 8 - GENTITYNUM_BITS;
+ }
+ else
+ {
+ endBit = (msg->readcount - 1) * 8 + msg->bit - GENTITYNUM_BITS;
+ }
+ Com_Printf(" (%i bits)\n", endBit - startBit);
+ }
+}
+
+int msg_hData[256] = {
+ 250315, // 0
+ 41193, // 1
+ 6292, // 2
+ 7106, // 3
+ 3730, // 4
+ 3750, // 5
+ 6110, // 6
+ 23283, // 7
+ 33317, // 8
+ 6950, // 9
+ 7838, // 10
+ 9714, // 11
+ 9257, // 12
+ 17259, // 13
+ 3949, // 14
+ 1778, // 15
+ 8288, // 16
+ 1604, // 17
+ 1590, // 18
+ 1663, // 19
+ 1100, // 20
+ 1213, // 21
+ 1238, // 22
+ 1134, // 23
+ 1749, // 24
+ 1059, // 25
+ 1246, // 26
+ 1149, // 27
+ 1273, // 28
+ 4486, // 29
+ 2805, // 30
+ 3472, // 31
+ 21819, // 32
+ 1159, // 33
+ 1670, // 34
+ 1066, // 35
+ 1043, // 36
+ 1012, // 37
+ 1053, // 38
+ 1070, // 39
+ 1726, // 40
+ 888, // 41
+ 1180, // 42
+ 850, // 43
+ 960, // 44
+ 780, // 45
+ 1752, // 46
+ 3296, // 47
+ 10630, // 48
+ 4514, // 49
+ 5881, // 50
+ 2685, // 51
+ 4650, // 52
+ 3837, // 53
+ 2093, // 54
+ 1867, // 55
+ 2584, // 56
+ 1949, // 57
+ 1972, // 58
+ 940, // 59
+ 1134, // 60
+ 1788, // 61
+ 1670, // 62
+ 1206, // 63
+ 5719, // 64
+ 6128, // 65
+ 7222, // 66
+ 6654, // 67
+ 3710, // 68
+ 3795, // 69
+ 1492, // 70
+ 1524, // 71
+ 2215, // 72
+ 1140, // 73
+ 1355, // 74
+ 971, // 75
+ 2180, // 76
+ 1248, // 77
+ 1328, // 78
+ 1195, // 79
+ 1770, // 80
+ 1078, // 81
+ 1264, // 82
+ 1266, // 83
+ 1168, // 84
+ 965, // 85
+ 1155, // 86
+ 1186, // 87
+ 1347, // 88
+ 1228, // 89
+ 1529, // 90
+ 1600, // 91
+ 2617, // 92
+ 2048, // 93
+ 2546, // 94
+ 3275, // 95
+ 2410, // 96
+ 3585, // 97
+ 2504, // 98
+ 2800, // 99
+ 2675, // 100
+ 6146, // 101
+ 3663, // 102
+ 2840, // 103
+ 14253, // 104
+ 3164, // 105
+ 2221, // 106
+ 1687, // 107
+ 3208, // 108
+ 2739, // 109
+ 3512, // 110
+ 4796, // 111
+ 4091, // 112
+ 3515, // 113
+ 5288, // 114
+ 4016, // 115
+ 7937, // 116
+ 6031, // 117
+ 5360, // 118
+ 3924, // 119
+ 4892, // 120
+ 3743, // 121
+ 4566, // 122
+ 4807, // 123
+ 5852, // 124
+ 6400, // 125
+ 6225, // 126
+ 8291, // 127
+ 23243, // 128
+ 7838, // 129
+ 7073, // 130
+ 8935, // 131
+ 5437, // 132
+ 4483, // 133
+ 3641, // 134
+ 5256, // 135
+ 5312, // 136
+ 5328, // 137
+ 5370, // 138
+ 3492, // 139
+ 2458, // 140
+ 1694, // 141
+ 1821, // 142
+ 2121, // 143
+ 1916, // 144
+ 1149, // 145
+ 1516, // 146
+ 1367, // 147
+ 1236, // 148
+ 1029, // 149
+ 1258, // 150
+ 1104, // 151
+ 1245, // 152
+ 1006, // 153
+ 1149, // 154
+ 1025, // 155
+ 1241, // 156
+ 952, // 157
+ 1287, // 158
+ 997, // 159
+ 1713, // 160
+ 1009, // 161
+ 1187, // 162
+ 879, // 163
+ 1099, // 164
+ 929, // 165
+ 1078, // 166
+ 951, // 167
+ 1656, // 168
+ 930, // 169
+ 1153, // 170
+ 1030, // 171
+ 1262, // 172
+ 1062, // 173
+ 1214, // 174
+ 1060, // 175
+ 1621, // 176
+ 930, // 177
+ 1106, // 178
+ 912, // 179
+ 1034, // 180
+ 892, // 181
+ 1158, // 182
+ 990, // 183
+ 1175, // 184
+ 850, // 185
+ 1121, // 186
+ 903, // 187
+ 1087, // 188
+ 920, // 189
+ 1144, // 190
+ 1056, // 191
+ 3462, // 192
+ 2240, // 193
+ 4397, // 194
+ 12136, // 195
+ 7758, // 196
+ 1345, // 197
+ 1307, // 198
+ 3278, // 199
+ 1950, // 200
+ 886, // 201
+ 1023, // 202
+ 1112, // 203
+ 1077, // 204
+ 1042, // 205
+ 1061, // 206
+ 1071, // 207
+ 1484, // 208
+ 1001, // 209
+ 1096, // 210
+ 915, // 211
+ 1052, // 212
+ 995, // 213
+ 1070, // 214
+ 876, // 215
+ 1111, // 216
+ 851, // 217
+ 1059, // 218
+ 805, // 219
+ 1112, // 220
+ 923, // 221
+ 1103, // 222
+ 817, // 223
+ 1899, // 224
+ 1872, // 225
+ 976, // 226
+ 841, // 227
+ 1127, // 228
+ 956, // 229
+ 1159, // 230
+ 950, // 231
+ 7791, // 232
+ 954, // 233
+ 1289, // 234
+ 933, // 235
+ 1127, // 236
+ 3207, // 237
+ 1020, // 238
+ 927, // 239
+ 1355, // 240
+ 768, // 241
+ 1040, // 242
+ 745, // 243
+ 952, // 244
+ 805, // 245
+ 1073, // 246
+ 740, // 247
+ 1013, // 248
+ 805, // 249
+ 1008, // 250
+ 796, // 251
+ 996, // 252
+ 1057, // 253
+ 11457, // 254
+ 13504, // 255
+};
+
+void MSG_initHuffman(void)
+{
+ int i, j;
+
+ msgInit = true;
+ Huff_Init(&msgHuff);
+ for (i = 0; i < 256; i++)
+ {
+ for (j = 0; j < msg_hData[i]; j++)
+ {
+ Huff_addRef(&msgHuff.compressor, (uint8_t)i); // Do update
+ Huff_addRef(&msgHuff.decompressor, (uint8_t)i); // Do update
+ }
+ }
+}
+
+/*
+void MSG_NUinitHuffman() {
+ uint8_t *data;
+ int size, i, ch;
+ int array[256];
+
+ msgInit = true;
+
+ Huff_Init(&msgHuff);
+ // load it in
+ size = FS_ReadFile( "netchan/netchan.bin", (void **)&data );
+
+ for(i=0;i<256;i++) {
+ array[i] = 0;
+ }
+ for(i=0;i<size;i++) {
+ ch = data[i];
+ Huff_addRef(&msgHuff.compressor, ch); // Do update
+ Huff_addRef(&msgHuff.decompressor, ch); // Do update
+ array[ch]++;
+ }
+ Com_Printf("msg_hData {\n");
+ for(i=0;i<256;i++) {
+ if (array[i] == 0) {
+ Huff_addRef(&msgHuff.compressor, i); // Do update
+ Huff_addRef(&msgHuff.decompressor, i); // Do update
+ }
+ Com_Printf("%d, // %d\n", array[i], i);
+ }
+ Com_Printf("};\n");
+ FS_FreeFile( data );
+ Cbuf_AddText( "condump dump.txt\n" );
+}
+*/
+
+//===========================================================================