/*
===========================================================================
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
===========================================================================
*/
#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