This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/net_msg.c

603 lines
18 KiB
C

//=======================================================================
// Copyright XashXT Group 2007 ©
// net_msg.c - network messages
//=======================================================================
#include "engine.h"
#include "mathlib.h"
/*
==============================================================================
MESSAGE IO FUNCTIONS
Handles byte ordering and avoids alignment errors
==============================================================================
*/
/*
=======================
writing functions
=======================
*/
void _MSG_WriteChar (sizebuf_t *sb, int c, const char *filename, int fileline)
{
byte *buf;
if (c < -128 || c > 127)
MsgWarn("MSG_WriteChar: range error %d (called at %s:%i)\n", c, filename, fileline);
buf = _SZ_GetSpace (sb, 1, filename, fileline );
buf[0] = c;
}
void _MSG_WriteByte (sizebuf_t *sb, int c, const char *filename, int fileline)
{
byte *buf;
if (c < 0 || c > 255)
MsgWarn("MSG_WriteByte: range error %d (called at %s:%i)\n", c, filename, fileline);
buf = _SZ_GetSpace (sb, 1, filename, fileline);
buf[0] = c;
}
void _MSG_WriteShort (sizebuf_t *sb, int c, const char *filename, int fileline)
{
byte *buf;
if (c < -32767 || c > 32767)
MsgWarn("MSG_WriteShort: range error %d (called at %s:%i)\n", c, filename, fileline);
buf = _SZ_GetSpace (sb, 2, filename, fileline);
buf[0] = c&0xff;
buf[1] = c>>8;
}
void _MSG_WriteWord (sizebuf_t *sb, int c, const char *filename, int fileline)
{
byte *buf;
if (c < 0 || c > 65535)
MsgWarn("MSG_WriteWord: range error %d (called at %s:%i)\n", c, filename, fileline);
buf = _SZ_GetSpace (sb, 2, filename, fileline);
buf[0] = c&0xff;
buf[1] = c>>8;
}
void _MSG_WriteLong (sizebuf_t *sb, int c, const char *filename, int fileline)
{
byte *buf;
buf = _SZ_GetSpace (sb, 4, filename, fileline);
buf[0] = (c>>0 ) & 0xff;
buf[1] = (c>>8 ) & 0xff;
buf[2] = (c>>16) & 0xff;
buf[3] = (c>>24);
}
void _MSG_WriteFloat (sizebuf_t *sb, float f, const char *filename, int fileline)
{
union
{
float f;
int l;
} dat;
dat.f = f;
dat.l = LittleLong (dat.l);
_SZ_Write (sb, &dat.l, 4, filename, fileline);
}
void _MSG_WriteString (sizebuf_t *sb, const char *s, const char *filename, int fileline)
{
if (!s || !*s) _MSG_WriteChar (sb, 0, filename, fileline );
else _SZ_Write (sb, s, strlen(s)+1, filename, fileline);
}
void _MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s, const char *filename, int fileline)
{
if (s && *s) _SZ_Write (sb, (byte *)s, (int)strlen(s), filename, fileline);
}
void _MSG_WriteCoord16(sizebuf_t *sb, float f, const char *filename, int fileline)
{
_MSG_WriteShort(sb, (int)(f * SV_COORD_FRAC), filename, fileline );
}
void _MSG_WriteAngle16 (sizebuf_t *sb, float f, const char *filename, int fileline)
{
_MSG_WriteWord(sb, ANGLE2SHORT(f), filename, fileline );
}
void _MSG_WriteCoord32(sizebuf_t *sb, float f, const char *filename, int fileline)
{
_MSG_WriteFloat(sb, f, filename, fileline );
}
void _MSG_WriteAngle32(sizebuf_t *sb, float f, const char *filename, int fileline)
{
_MSG_WriteFloat(sb, f, filename, fileline );
}
void _MSG_WritePos16(sizebuf_t *sb, vec3_t pos, const char *filename, int fileline)
{
_MSG_WriteCoord16(sb, pos[0], filename, fileline );
_MSG_WriteCoord16(sb, pos[1], filename, fileline );
_MSG_WriteCoord16(sb, pos[2], filename, fileline );
}
void _MSG_WritePos32(sizebuf_t *sb, vec3_t pos, const char *filename, int fileline)
{
_MSG_WriteCoord32(sb, pos[0], filename, fileline );
_MSG_WriteCoord32(sb, pos[1], filename, fileline );
_MSG_WriteCoord32(sb, pos[2], filename, fileline );
}
void _MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd, const char *filename, int fileline)
{
int bits = 0;
// send the movement message
if (cmd->angles[0] != from->angles[0]) bits |= CM_ANGLE1;
if (cmd->angles[1] != from->angles[1]) bits |= CM_ANGLE2;
if (cmd->angles[2] != from->angles[2]) bits |= CM_ANGLE3;
if (cmd->forwardmove != from->forwardmove) bits |= CM_FORWARD;
if (cmd->sidemove != from->sidemove) bits |= CM_SIDE;
if (cmd->upmove != from->upmove) bits |= CM_UP;
if (cmd->buttons != from->buttons) bits |= CM_BUTTONS;
if (cmd->impulse != from->impulse) bits |= CM_IMPULSE;
_MSG_WriteByte (buf, bits, filename, fileline );
if (bits & CM_ANGLE1) _MSG_WriteShort (buf, cmd->angles[0], filename, fileline );
if (bits & CM_ANGLE2) _MSG_WriteShort (buf, cmd->angles[1], filename, fileline );
if (bits & CM_ANGLE3) _MSG_WriteShort (buf, cmd->angles[2], filename, fileline );
if (bits & CM_FORWARD) _MSG_WriteShort (buf, cmd->forwardmove, filename, fileline );
if (bits & CM_SIDE) _MSG_WriteShort (buf, cmd->sidemove, filename, fileline );
if (bits & CM_UP) _MSG_WriteShort (buf, cmd->upmove, filename, fileline );
if (bits & CM_BUTTONS) _MSG_WriteByte (buf, cmd->buttons, filename, fileline );
if (bits & CM_IMPULSE) _MSG_WriteByte (buf, cmd->impulse, filename, fileline );
_MSG_WriteByte (buf, cmd->msec, filename, fileline );
_MSG_WriteByte (buf, cmd->lightlevel, filename, fileline );
}
/*
==================
MSG_WriteDeltaEntity
Writes part of a packetentities message.
Can delta from either a baseline or a previous packet_entity
==================
*/
void _MSG_WriteDeltaEntity (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, bool force, bool newentity, const char *filename, int fileline)
{
int bits = 0;
if (!to->number) Host_Error("Unset entity number\n");
if (to->number >= MAX_EDICTS) Host_Error("Entity number >= MAX_EDICTS\n");
// send an update
if (to->number >= 256) bits |= U_NUMBER16; // number8 is implicit otherwise
if (to->origin[0] != from->origin[0]) bits |= U_ORIGIN1;
if (to->origin[1] != from->origin[1]) bits |= U_ORIGIN2;
if (to->origin[2] != from->origin[2]) bits |= U_ORIGIN3;
if ( to->angles[0] != from->angles[0] ) bits |= U_ANGLE1;
if ( to->angles[1] != from->angles[1] ) bits |= U_ANGLE2;
if ( to->angles[2] != from->angles[2] ) bits |= U_ANGLE3;
if ( to->skin != from->skin )
{
if (to->skin < 256) bits |= U_SKIN8;
else bits |= U_SKIN16;
}
if ( to->frame != from->frame )
{
if (to->frame < 256) bits |= U_FRAME8;
else bits |= U_FRAME16;
}
if ( to->effects != from->effects )
{
if (to->effects < 256) bits |= U_EFFECTS8;
else if (to->effects < 32768) bits |= U_EFFECTS16;
else bits |= U_EFFECTS8 | U_EFFECTS16;
}
if ( to->renderfx != from->renderfx )
{
if (to->renderfx < 256) bits |= U_RENDERFX8;
else if (to->renderfx < 32768) bits |= U_RENDERFX16;
else bits |= U_RENDERFX8 | U_RENDERFX16;
}
if ( to->solid != from->solid ) bits |= U_SOLID;
if ( to->event ) bits |= U_EVENT; // event is not delta compressed, just 0 compressed
if ( to->modelindex != from->modelindex ) bits |= U_MODEL;
if ( to->weaponmodel != from->weaponmodel ) bits |= U_WEAPONMODEL;
if ( to->body != from->body ) bits |= U_BODY;
if ( to->sequence != from->sequence ) bits |= U_SEQUENCE;
if ( to->soundindex != from->soundindex ) bits |= U_SOUNDIDX;
if (newentity || (to->renderfx & RF_BEAM)) bits |= U_OLDORIGIN;
if( to->alpha != from->alpha ) bits |= U_ALPHA;
// write the message
if (!bits && !force) return; // nothing to send!
if (bits & 0xff000000) bits |= U_MOREBITS3 | U_MOREBITS2 | U_MOREBITS1;
else if (bits & 0x00ff0000) bits |= U_MOREBITS2 | U_MOREBITS1;
else if (bits & 0x0000ff00) bits |= U_MOREBITS1;
_MSG_WriteByte (msg, bits & 255, filename, fileline );
if (bits & 0xff000000)
{
_MSG_WriteByte (msg, (bits >> 8 ) & 255, filename, fileline );
_MSG_WriteByte (msg, (bits >> 16) & 255, filename, fileline );
_MSG_WriteByte (msg, (bits >> 24) & 255, filename, fileline );
}
else if (bits & 0x00ff0000)
{
_MSG_WriteByte (msg, (bits >> 8 ) & 255, filename, fileline );
_MSG_WriteByte (msg, (bits >> 16) & 255, filename, fileline );
}
else if (bits & 0x0000ff00)
{
_MSG_WriteByte (msg, (bits >> 8 ) & 255, filename, fileline );
}
//----------
if (bits & U_NUMBER16) _MSG_WriteShort (msg, to->number, filename, fileline );
else _MSG_WriteByte (msg, to->number, filename, fileline);
if (bits & U_MODEL) _MSG_WriteShort (msg, to->modelindex, filename, fileline);
if (bits & U_WEAPONMODEL) _MSG_WriteShort (msg, to->weaponmodel, filename, fileline);
if (bits & U_FRAME8) _MSG_WriteByte (msg, to->frame, filename, fileline);
if (bits & U_FRAME16) _MSG_WriteShort (msg, to->frame, filename, fileline);
if (bits & U_SKIN8 ) _MSG_WriteByte (msg, to->skin, filename, fileline);
if (bits & U_SKIN16) _MSG_WriteShort (msg, to->skin, filename, fileline);
if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16))
_MSG_WriteLong (msg, to->effects, filename, fileline);
else if (bits & U_EFFECTS8) _MSG_WriteByte (msg, to->effects, filename, fileline);
else if (bits & U_EFFECTS16) _MSG_WriteShort (msg, to->effects, filename, fileline);
if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16))
_MSG_WriteLong (msg, to->renderfx, filename, fileline);
else if (bits & U_RENDERFX8) _MSG_WriteByte (msg, to->renderfx, filename, fileline);
else if (bits & U_RENDERFX16) _MSG_WriteShort (msg, to->renderfx, filename, fileline);
if (bits & U_ORIGIN1) _MSG_WriteCoord32(msg, to->origin[0], filename, fileline);
if (bits & U_ORIGIN2) _MSG_WriteCoord32(msg, to->origin[1], filename, fileline);
if (bits & U_ORIGIN3) _MSG_WriteCoord32(msg, to->origin[2], filename, fileline);
if (bits & U_ANGLE1) _MSG_WriteAngle32(msg, to->angles[0], filename, fileline);
if (bits & U_ANGLE2) _MSG_WriteAngle32(msg, to->angles[1], filename, fileline);
if (bits & U_ANGLE3) _MSG_WriteAngle32(msg, to->angles[2], filename, fileline);
if (bits & U_OLDORIGIN) _MSG_WritePos32(msg, to->old_origin, filename, fileline);
if (bits & U_SEQUENCE) _MSG_WriteByte (msg, to->sequence, filename, fileline);
if (bits & U_SOLID) _MSG_WriteShort (msg, to->solid, filename, fileline);
if (bits & U_ALPHA) _MSG_WriteFloat (msg, to->alpha, filename, fileline);
if (bits & U_EVENT) _MSG_WriteByte (msg, to->event, filename, fileline);
if (bits & U_SOUNDIDX) _MSG_WriteByte (msg, to->soundindex, filename, fileline);
if (bits & U_BODY) _MSG_WriteByte (msg, to->body, filename, fileline);
}
/*
=======================
reading functions
=======================
*/
void MSG_BeginReading (sizebuf_t *msg)
{
msg->readcount = 0;
msg->errorcount = 0;
}
void MSG_EndReading (sizebuf_t *msg)
{
if(!msg->errorcount) return;
MsgWarn("MSG_EndReading: received with errors\n");
}
// returns -1 if no more characters are available
int MSG_ReadChar (sizebuf_t *msg_read)
{
int c;
if (msg_read->readcount + 1 > msg_read->cursize)
{
c = -1;
msg_read->errorcount++;
}
else c = (signed char)msg_read->data[msg_read->readcount];
msg_read->readcount++;
return c;
}
int MSG_ReadByte (sizebuf_t *msg_read)
{
int c;
if (msg_read->readcount + 1 > msg_read->cursize)
{
c = -1;
msg_read->errorcount++;
}
else c = (byte)msg_read->data[msg_read->readcount];
msg_read->readcount++;
return c;
}
int MSG_ReadShort (sizebuf_t *msg_read)
{
int c;
if (msg_read->readcount + 2 > msg_read->cursize)
{
c = -1;
msg_read->errorcount++;
}
else c = (short)BuffLittleShort(msg_read->data + msg_read->readcount);
msg_read->readcount += 2;
return c;
}
int MSG_ReadLong (sizebuf_t *msg_read)
{
int c;
if (msg_read->readcount + 4 > msg_read->cursize)
{
c = -1;
msg_read->errorcount++;
}
else c = BuffLittleLong(msg_read->data + msg_read->readcount);
msg_read->readcount += 4;
return c;
}
float MSG_ReadFloat (sizebuf_t *msg_read)
{
union
{
byte b[4];
float f;
int l;
} dat;
if (msg_read->readcount + 4 > msg_read->cursize)
{
dat.f = -1;
msg_read->errorcount++;
}
else
{
dat.b[0] = msg_read->data[msg_read->readcount+0];
dat.b[1] = msg_read->data[msg_read->readcount+1];
dat.b[2] = msg_read->data[msg_read->readcount+2];
dat.b[3] = msg_read->data[msg_read->readcount+3];
}
msg_read->readcount += 4;
dat.l = LittleLong (dat.l);
return dat.f;
}
char *MSG_ReadString (sizebuf_t *msg_read)
{
static char string[2048];
int l = 0, c;
do
{
c = MSG_ReadChar (msg_read);
if (c == -1 || c == 0) break;
string[l] = c;
l++;
} while (l < sizeof(string) - 1);
string[l] = 0; //write terminator
return string;
}
char *MSG_ReadStringLine (sizebuf_t *msg_read)
{
static char string[2048];
int l = 0, c;
do
{
c = MSG_ReadChar (msg_read);
if (c == -1 || c == 0 || c == '\n') break;
string[l] = c;
l++;
} while (l < sizeof(string)-1);
string[l] = 0; // write terminator
return string;
}
float MSG_ReadCoord16(sizebuf_t *msg_read)
{
return MSG_ReadShort(msg_read) * CL_COORD_FRAC;
}
float MSG_ReadCoord32(sizebuf_t *msg_read)
{
return MSG_ReadFloat(msg_read);
}
void MSG_ReadPos32(sizebuf_t *msg_read, vec3_t pos)
{
pos[0] = MSG_ReadFloat(msg_read);
pos[1] = MSG_ReadFloat(msg_read);
pos[2] = MSG_ReadFloat(msg_read);
}
void MSG_ReadPos16(sizebuf_t *msg_read, vec3_t pos)
{
pos[0] = MSG_ReadCoord16(msg_read);
pos[1] = MSG_ReadCoord16(msg_read);
pos[2] = MSG_ReadCoord16(msg_read);
}
float MSG_ReadAngle16(sizebuf_t *msg_read)
{
return SHORT2ANGLE(MSG_ReadShort(msg_read));
}
float MSG_ReadAngle32(sizebuf_t *msg_read)
{
return MSG_ReadFloat(msg_read);
}
void MSG_ReadDeltaUsercmd (sizebuf_t *msg_read, usercmd_t *from, usercmd_t *move)
{
int bits = MSG_ReadByte (msg_read);
Mem_Copy (move, from, sizeof(*move));
// read current angles
if (bits & CM_ANGLE1) move->angles[0] = MSG_ReadShort (msg_read);
if (bits & CM_ANGLE2) move->angles[1] = MSG_ReadShort (msg_read);
if (bits & CM_ANGLE3) move->angles[2] = MSG_ReadShort (msg_read);
// read movement
if (bits & CM_FORWARD) move->forwardmove = MSG_ReadShort (msg_read);
if (bits & CM_SIDE) move->sidemove = MSG_ReadShort (msg_read);
if (bits & CM_UP) move->upmove = MSG_ReadShort (msg_read);
// read buttons
if (bits & CM_BUTTONS) move->buttons = MSG_ReadByte (msg_read);
if (bits & CM_IMPULSE) move->impulse = MSG_ReadByte (msg_read);
move->msec = MSG_ReadByte (msg_read); // read time to run command
move->lightlevel = MSG_ReadByte (msg_read); // read the light level
}
void MSG_ReadDeltaEntity(entity_state_t *from, entity_state_t *to, int number, int bits)
{
// set everything to the state we are delta'ing from
*to = *from;
VectorCopy (from->origin, to->old_origin);
to->number = number;
if (bits & U_MODEL) to->modelindex = MSG_ReadShort (&net_message);
if (bits & U_WEAPONMODEL) to->weaponmodel = MSG_ReadShort (&net_message);
if (bits & U_FRAME8 ) to->frame = MSG_ReadByte (&net_message);
if (bits & U_FRAME16) to->frame = MSG_ReadShort (&net_message);
if (bits & U_SKIN8 ) to->skin = MSG_ReadByte(&net_message);
if (bits & U_SKIN16) to->skin = MSG_ReadShort(&net_message);
if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
to->effects = MSG_ReadLong(&net_message);
else if (bits & U_EFFECTS8 ) to->effects = MSG_ReadByte(&net_message);
else if (bits & U_EFFECTS16) to->effects = MSG_ReadShort(&net_message);
if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
to->renderfx = MSG_ReadLong(&net_message);
else if (bits & U_RENDERFX8 ) to->renderfx = MSG_ReadByte(&net_message);
else if (bits & U_RENDERFX16) to->renderfx = MSG_ReadShort(&net_message);
if (bits & U_ORIGIN1) to->origin[0] = MSG_ReadCoord32(&net_message);
if (bits & U_ORIGIN2) to->origin[1] = MSG_ReadCoord32(&net_message);
if (bits & U_ORIGIN3) to->origin[2] = MSG_ReadCoord32(&net_message);
if (bits & U_ANGLE1) to->angles[0] = MSG_ReadAngle32(&net_message);
if (bits & U_ANGLE2) to->angles[1] = MSG_ReadAngle32(&net_message);
if (bits & U_ANGLE3) to->angles[2] = MSG_ReadAngle32(&net_message);
if (bits & U_OLDORIGIN) MSG_ReadPos32(&net_message, to->old_origin);
if (bits & U_SEQUENCE) to->sequence = MSG_ReadByte(&net_message);
if (bits & U_SOLID) to->solid = MSG_ReadShort(&net_message);
if (bits & U_ALPHA) to->alpha = MSG_ReadFloat(&net_message);
if (bits & U_EVENT) to->event = MSG_ReadByte (&net_message);
if (bits & U_SOUNDIDX) to->soundindex = MSG_ReadByte (&net_message);
else to->event = 0;
if (bits & U_BODY) to->body = MSG_ReadByte (&net_message);
}
void MSG_ReadData (sizebuf_t *msg_read, void *data, int len)
{
int i;
for (i = 0; i < len; i++)
{
((byte *)data)[i] = MSG_ReadByte (msg_read);
}
}
/*
=======================
SZ BUFFER
=======================
*/
void SZ_Init (sizebuf_t *buf, byte *data, int length)
{
memset (buf, 0, sizeof(*buf));
buf->data = data;
buf->maxsize = length;
}
void SZ_Clear (sizebuf_t *buf)
{
buf->cursize = 0;
buf->overflowed = false;
}
void *_SZ_GetSpace (sizebuf_t *buf, int length, const char *filename, int fileline )
{
void *data;
if (buf->cursize + length > buf->maxsize)
{
if (length > buf->maxsize)
Host_Error("SZ_GetSpace: length[%i] > buffer maxsize [%i]\n", length, buf->maxsize );
MsgWarn("SZ_GetSpace: overflow [cursize %d maxsize %d], called at %s:%i\n", buf->cursize + length, buf->maxsize, filename, fileline );
SZ_Clear (buf);
buf->overflowed = true;
}
data = buf->data + buf->cursize;
buf->cursize += length;
return data;
}
void _SZ_Write (sizebuf_t *buf, const void *data, int length, const char *filename, int fileline)
{
Mem_Copy(_SZ_GetSpace(buf, length, filename, fileline), (void *)data, length);
}
void SZ_Print (sizebuf_t *buf, char *data)
{
int len;
len = strlen(data) + 1;
if (buf->cursize)
{
if (buf->data[buf->cursize - 1]) Mem_Copy ((byte *)SZ_GetSpace(buf, len),data,len); //no trailing 0
else Mem_Copy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
}
else Mem_Copy ((byte *)SZ_GetSpace(buf, len),data,len);
}