📄 msg.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code 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 2 of the License,
or (at your option) any later version.
Quake III Arena source code 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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "../game/q_shared.h"
#include "qcommon.h"
static huffman_t msgHuff;
static qboolean msgInit = qfalse;
int pcount[256];
/*
==============================================================================
MESSAGE IO FUNCTIONS
Handles byte ordering and avoids alignment errors
==============================================================================
*/
int oldsize = 0;
void MSG_initHuffman();
void MSG_Init( msg_t *buf, byte *data, int length ) {
if (!msgInit) {
MSG_initHuffman();
}
Com_Memset (buf, 0, sizeof(*buf));
buf->data = data;
buf->maxsize = length;
}
void MSG_InitOOB( msg_t *buf, byte *data, int length ) {
if (!msgInit) {
MSG_initHuffman();
}
Com_Memset (buf, 0, sizeof(*buf));
buf->data = data;
buf->maxsize = length;
buf->oob = qtrue;
}
void MSG_Clear( msg_t *buf ) {
buf->cursize = 0;
buf->overflowed = qfalse;
buf->bit = 0; //<- in bits
}
void MSG_Bitstream( msg_t *buf ) {
buf->oob = qfalse;
}
void MSG_BeginReading( msg_t *msg ) {
msg->readcount = 0;
msg->bit = 0;
msg->oob = qfalse;
}
void MSG_BeginReadingOOB( msg_t *msg ) {
msg->readcount = 0;
msg->bit = 0;
msg->oob = qtrue;
}
void MSG_Copy(msg_t *buf, byte *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");
}
Com_Memcpy(buf, src, sizeof(msg_t));
buf->data = data;
Com_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;
// this isn't an exact overflow check, but close enough
if ( msg->maxsize - msg->cursize < 4 ) {
msg->overflowed = qtrue;
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 (bits==8) {
msg->data[msg->cursize] = value;
msg->cursize += 1;
msg->bit += 8;
} else if (bits==16) {
unsigned short *sp = (unsigned short *)&msg->data[msg->cursize];
*sp = LittleShort(value);
msg->cursize += 2;
msg->bit += 16;
} else if (bits==32) {
unsigned int *ip = (unsigned int *)&msg->data[msg->cursize];
*ip = LittleLong(value);
msg->cursize += 4;
msg->bit += 8;
} else {
Com_Error(ERR_DROP, "can't read %d bits\n", bits);
}
} else {
// fp = fopen("c:\\netchan.bin", "a");
value &= (0xffffffff>>(32-bits));
if (bits&7) {
int nbits;
nbits = bits&7;
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) {
// fwrite(bp, 1, 1, fp);
Huff_offsetTransmit (&msgHuff.compressor, (value&0xff), msg->data, &msg->bit);
value = (value>>8);
}
}
msg->cursize = (msg->bit>>3)+1;
// fclose(fp);
}
}
int MSG_ReadBits( msg_t *msg, int bits ) {
int value;
int get;
qboolean sgn;
int i, nbits;
// FILE* fp;
value = 0;
if ( bits < 0 ) {
bits = -bits;
sgn = qtrue;
} else {
sgn = qfalse;
}
if (msg->oob) {
if (bits==8) {
value = msg->data[msg->readcount];
msg->readcount += 1;
msg->bit += 8;
} else if (bits==16) {
unsigned short *sp = (unsigned short *)&msg->data[msg->readcount];
value = LittleShort(*sp);
msg->readcount += 2;
msg->bit += 16;
} else if (bits==32) {
unsigned int *ip = (unsigned int *)&msg->data[msg->readcount];
value = LittleLong(*ip);
msg->readcount += 4;
msg->bit += 32;
} else {
Com_Error(ERR_DROP, "can't read %d bits\n", bits);
}
} else {
nbits = 0;
if (bits&7) {
nbits = bits&7;
for(i=0;i<nbits;i++) {
value |= (Huff_getBit(msg->data, &msg->bit)<<i);
}
bits = bits - nbits;
}
if (bits) {
// fp = fopen("c:\\netchan.bin", "a");
for(i=0;i<bits;i+=8) {
Huff_offsetReceive (msgHuff.decompressor.tree, &get, msg->data, &msg->bit);
// fwrite(&get, 1, 1, fp);
value |= (get<<(i+nbits));
}
// fclose(fp);
}
msg->readcount = (msg->bit>>3)+1;
}
if ( sgn ) {
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, ((byte *)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 ) {
union {
float f;
int l;
} dat;
dat.f = f;
MSG_WriteBits( sb, dat.l, 32 );
}
void MSG_WriteString( msg_t *sb, const char *s ) {
if ( !s ) {
MSG_WriteData (sb, "", 1);
} else {
int l,i;
char string[MAX_STRING_CHARS];
l = strlen( s );
if ( l >= MAX_STRING_CHARS ) {
Com_Printf( "MSG_WriteString: MAX_STRING_CHARS" );
MSG_WriteData (sb, "", 1);
return;
}
Q_strncpyz( string, s, sizeof( string ) );
// get rid of 0xff chars, because old clients don't like them
for ( i = 0 ; i < l ; i++ ) {
if ( ((byte *)string)[i] > 127 ) {
string[i] = '.';
}
}
MSG_WriteData (sb, string, l+1);
}
}
void MSG_WriteBigString( msg_t *sb, const char *s ) {
if ( !s ) {
MSG_WriteData (sb, "", 1);
} else {
int l,i;
char string[BIG_INFO_STRING];
l = strlen( s );
if ( l >= BIG_INFO_STRING ) {
Com_Printf( "MSG_WriteString: BIG_INFO_STRING" );
MSG_WriteData (sb, "", 1);
return;
}
Q_strncpyz( string, s, sizeof( string ) );
// get rid of 0xff chars, because old clients don't like them
for ( i = 0 ; i < l ; i++ ) {
if ( ((byte *)string)[i] > 127 ) {
string[i] = '.';
}
}
MSG_WriteData (sb, string, l+1);
}
}
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_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 ) {
union {
byte b[4];
float f;
int l;
} dat;
dat.l = 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];
int l,c;
l = 0;
do {
c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
if ( c == -1 || c == 0 ) {
break;
}
// translate all fmt spec to avoid crash bugs
if ( c == '%' ) {
c = '.';
}
// don't allow higher ascii values
if ( c > 127 ) {
c = '.';
}
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];
int l,c;
l = 0;
do {
c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
if ( c == -1 || c == 0 ) {
break;
}
// translate all fmt spec to avoid crash bugs
if ( c == '%' ) {
c = '.';
}
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];
int l,c;
l = 0;
do {
c = MSG_ReadByte(msg); // use ReadByte so -1 is out of bounds
if (c == -1 || c == 0 || c == '\n') {
break;
}
// translate all fmt spec to avoid crash bugs
if ( c == '%' ) {
c = '.';
}
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++) {
((byte *)data)[i] = MSG_ReadByte (msg);
}
}
/*
=============================================================================
delta functions
=============================================================================
*/
extern cvar_t *cl_shownet;
#define LOG(x) if( 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 ) {
if ( oldV == newV ) {
MSG_WriteBits( msg, 0, 1 );
return;
}
MSG_WriteBits( msg, 1, 1 );
MSG_WriteBits( msg, *(int *)&newV, 32 );
}
float MSG_ReadDeltaFloat( msg_t *msg, float oldV ) {
if ( MSG_ReadBits( msg, 1 ) ) {
float newV;
*(int *)&newV = MSG_ReadBits( msg, 32 );
return newV;
}
return oldV;
}
/*
=============================================================================
delta functions with keys
=============================================================================
*/
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -