diff options
Diffstat (limited to 'src/q_msg.c')
-rw-r--r-- | src/q_msg.c | 2806 |
1 files changed, 2806 insertions, 0 deletions
diff --git a/src/q_msg.c b/src/q_msg.c new file mode 100644 index 0000000..5887a88 --- /dev/null +++ b/src/q_msg.c @@ -0,0 +1,2806 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program 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. + +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "com_local.h" +#include "protocol.h" +#include "q_msg.h" + +sizebuf_t msg_write; +byte msg_write_buffer[MAX_MSGLEN]; + +sizebuf_t msg_read; +byte msg_read_buffer[MAX_MSGLEN]; + +/* +============================================================================== + + MESSAGE IO FUNCTIONS + +Handles byte ordering and avoids alignment errors +============================================================================== +*/ + +const entity_state_t nullEntityState; +const player_state_t nullPlayerState; +const usercmd_t nullUserCmd; + + +/* +============= +MSG_Init +============= +*/ +void MSG_Init( void ) { + // initialize default buffers + // don't allow them to overflow + SZ_TagInit( &msg_read, msg_read_buffer, MAX_MSGLEN, SZ_MSG_READ ); + SZ_TagInit( &msg_write, msg_write_buffer, MAX_MSGLEN, SZ_MSG_WRITE ); +} + + +// +// writing functions +// + +/* +============= +MSG_BeginWriting +============= +*/ +void MSG_BeginWriting( void ) { + msg_write.cursize = 0; + msg_write.bitpos = 0; + msg_write.overflowed = qfalse; +} + +/* +============= +MSG_WriteChar +============= +*/ +void MSG_WriteChar( int c ) { + byte *buf; + +#ifdef PARANOID + if( c < -128 || c > 127 ) + Com_Error( ERR_FATAL, "MSG_WriteChar: range error" ); +#endif + + buf = SZ_GetSpace( &msg_write, 1 ); + buf[0] = c; +} + +/* +============= +MSG_WriteByte +============= +*/ +void MSG_WriteByte( int c ) { + byte *buf; + +#ifdef PARANOID + if( c < 0 || c > 255 ) + Com_Error( ERR_FATAL, "MSG_WriteByte: range error" ); +#endif + + buf = SZ_GetSpace( &msg_write, 1 ); + buf[0] = c; +} + +/* +============= +MSG_WriteShort +============= +*/ +void MSG_WriteShort( int c ) { + byte *buf; + +#ifdef PARANOID + if (c < ((short)0x8000) || c > (short)0x7fff) + Com_Error (ERR_FATAL, "MSG_WriteShort: range error"); +#endif + + buf = SZ_GetSpace( &msg_write, 2 ); + buf[0] = c & 0xff; + buf[1] = c >> 8; +} + +/* +============= +MSG_WriteLong +============= +*/ +void MSG_WriteLong( int c ) { + byte *buf; + + buf = SZ_GetSpace( &msg_write, 4 ); + buf[0] = c & 0xff; + buf[1] = ( c >> 8 ) & 0xff; + buf[2] = ( c >> 16 ) & 0xff; + buf[3] = c >> 24; +} + +/* +============= +MSG_WriteString +============= +*/ +void MSG_WriteString( const char *string ) { + size_t length; + + if( !string ) { + MSG_WriteByte( 0 ); + return; + } + + length = strlen( string ); + if( length >= MAX_NET_STRING ) { + Com_WPrintf( "%s: overflow: %"PRIz" chars", __func__, length ); + MSG_WriteByte( 0 ); + return; + } + + MSG_WriteData( string, length + 1 ); +} + +/* +============= +MSG_WriteCoord +============= +*/ + +#define COORD2SHORT(x) ((int)((x)*8.0f)) +#define SHORT2COORD(x) ((x)*(1.0f/8)) + +static inline void MSG_WriteCoord( float f ) { + MSG_WriteShort( COORD2SHORT(f) ); +} + +/* +============= +MSG_WritePos +============= +*/ +void MSG_WritePos( const vec3_t pos ) { + MSG_WriteCoord( pos[0] ); + MSG_WriteCoord( pos[1] ); + MSG_WriteCoord( pos[2] ); +} + +/* +============= +MSG_WriteAngle +============= +*/ + +#define ANGLE2BYTE(x) ((int)((x)*256.0f/360)&255) +#define BYTE2ANGLE(x) ((x)*(360.0f/256)) + +void MSG_WriteAngle( float f ) { + MSG_WriteByte( ANGLE2BYTE( f ) ); +} + +/* +============= +MSG_WriteAngle16 +============= +*/ +static inline void MSG_WriteAngle16( float f ) { + MSG_WriteShort( ANGLE2SHORT( f ) ); +} + +#if USE_CLIENT + +/* +============= +MSG_WriteDeltaUsercmd +============= +*/ +int MSG_WriteDeltaUsercmd( const usercmd_t *from, const usercmd_t *cmd, int version ) { + int bits, buttons = cmd->buttons & BUTTON_MASK; + + if( !from ) { + from = &nullUserCmd; + } + +// +// send the movement message +// + bits = 0; + 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 ( bits ); + + if( version >= PROTOCOL_VERSION_R1Q2_UCMD ) { + if( bits & CM_BUTTONS ) { + if( ( bits & CM_FORWARD ) && !( cmd->forwardmove % 5 ) ) { + buttons |= BUTTON_FORWARD; + } + if( ( bits & CM_SIDE ) && !( cmd->sidemove % 5 ) ) { + buttons |= BUTTON_SIDE; + } + if( ( bits & CM_UP ) && !( cmd->upmove % 5 ) ) { + buttons |= BUTTON_UP; + } + MSG_WriteByte( buttons ); + } + } + + if( bits & CM_ANGLE1 ) + MSG_WriteShort( cmd->angles[0] ); + if( bits & CM_ANGLE2 ) + MSG_WriteShort( cmd->angles[1] ); + if( bits & CM_ANGLE3 ) + MSG_WriteShort( cmd->angles[2] ); + + if( bits & CM_FORWARD ) { + if( buttons & BUTTON_FORWARD ) { + MSG_WriteChar( cmd->forwardmove / 5 ); + } else { + MSG_WriteShort( cmd->forwardmove ); + } + } + if( bits & CM_SIDE ) { + if( buttons & BUTTON_SIDE ) { + MSG_WriteChar( cmd->sidemove / 5 ); + } else { + MSG_WriteShort( cmd->sidemove ); + } + } + if( bits & CM_UP ) { + if( buttons & BUTTON_UP ) { + MSG_WriteChar( cmd->upmove / 5 ); + } else { + MSG_WriteShort( cmd->upmove ); + } + } + + if( version < PROTOCOL_VERSION_R1Q2_UCMD ) { + if( bits & CM_BUTTONS ) + MSG_WriteByte( cmd->buttons ); + } + if( bits & CM_IMPULSE ) + MSG_WriteByte( cmd->impulse ); + + MSG_WriteByte( cmd->msec ); + + return bits; +} + +/* +============= +MSG_WriteBits +============= +*/ +void MSG_WriteBits( int value, int bits ) { + int i; + size_t bitpos; + + if( bits == 0 || bits < -31 || bits > 32 ) { + Com_Error( ERR_FATAL, "MSG_WriteBits: bad bits: %d", bits ); + } + + if( msg_write.maxsize - msg_write.cursize < 4 ) { + Com_Error( ERR_FATAL, "MSG_WriteBits: overflow" ); + } + + if( bits < 0 ) { + bits = -bits; + } + + bitpos = msg_write.bitpos; + if( ( bitpos & 7 ) == 0 ) { + // optimized case + switch( bits ) { + case 8: + MSG_WriteByte( value ); + return; + case 16: + MSG_WriteShort( value ); + return; + case 32: + MSG_WriteLong( value ); + return; + default: + break; + } + } + for( i = 0; i < bits; i++, bitpos++ ) { + if( ( bitpos & 7 ) == 0 ) { + msg_write.data[ bitpos >> 3 ] = 0; + } + msg_write.data[ bitpos >> 3 ] |= ( value & 1 ) << ( bitpos & 7 ); + value >>= 1; + } + msg_write.bitpos = bitpos; + msg_write.cursize = ( bitpos + 7 ) >> 3; +} + +/* +============= +MSG_WriteDeltaUsercmd_Enhanced +============= +*/ +int MSG_WriteDeltaUsercmd_Enhanced( const usercmd_t *from, + const usercmd_t *cmd, + int version ) +{ + int bits, delta, count; + + if( !from ) { + from = &nullUserCmd; + } + +// +// send the movement message +// + bits = 0; + 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->msec != from->msec ) + bits |= CM_IMPULSE; + + if( !bits ) { + MSG_WriteBits( 0, 1 ); + return 0; + } + + MSG_WriteBits( 1, 1 ); + MSG_WriteBits( bits, 8 ); + + if( bits & CM_ANGLE1 ) { + delta = cmd->angles[0] - from->angles[0]; + if( delta >= -128 && delta <= 127 ) { + MSG_WriteBits( 1, 1 ); + MSG_WriteBits( delta, -8 ); + } else { + MSG_WriteBits( 0, 1 ); + MSG_WriteBits( cmd->angles[0], -16 ); + } + } + if( bits & CM_ANGLE2 ) { + delta = cmd->angles[1] - from->angles[1]; + if( delta >= -128 && delta <= 127 ) { + MSG_WriteBits( 1, 1 ); + MSG_WriteBits( delta, -8 ); + } else { + MSG_WriteBits( 0, 1 ); + MSG_WriteBits( cmd->angles[1], -16 ); + } + } + if( bits & CM_ANGLE3 ) { + MSG_WriteBits( cmd->angles[2], -16 ); + } + + if( version >= PROTOCOL_VERSION_Q2PRO_UCMD ) { + count = -10; + } else { + count = -16; + } + + if( bits & CM_FORWARD ) { + MSG_WriteBits( cmd->forwardmove, count ); + } + if( bits & CM_SIDE ) { + MSG_WriteBits( cmd->sidemove, count ); + } + if( bits & CM_UP ) { + MSG_WriteBits( cmd->upmove, count ); + } + + if( bits & CM_BUTTONS ) { + int buttons = ( cmd->buttons & 3 ) | ( cmd->buttons >> 5 ); + MSG_WriteBits( buttons, 3 ); + } + if( bits & CM_IMPULSE ) { + MSG_WriteBits( cmd->msec, 8 ); + } + + return bits; +} + +#endif // USE_CLIENT + +void MSG_WriteDir( const vec3_t dir ) { + int best; + + best = DirToByte( dir ); + MSG_WriteByte( best ); +} + +// values transmitted over network are discrete, so +// we use special macros to check for delta conditions +#define delta_angle(a,b) (ANGLE2BYTE(b)!=ANGLE2BYTE(a)) +#define delta_angle16(a,b) (ANGLE2SHORT(b)!=ANGLE2SHORT(a)) +#define delta_angle16_v(a,b) \ + (delta_angle16(a[0],b[0])|| \ + delta_angle16(a[1],b[1])|| \ + delta_angle16(a[2],b[2])) +#define delta_coord(a,b) (COORD2SHORT(b)!=COORD2SHORT(a)) +#define delta_pos_v(a,b) \ + (delta_coord(a[0],b[0])|| \ + delta_coord(a[1],b[1])|| \ + delta_coord(a[2],b[2])) +#define delta_ofs(a,b) ((int)((b)*4)!=(int)((a)*4)) +#define delta_ofs_v(a,b) \ + (delta_ofs(a[0],b[0])|| \ + delta_ofs(a[1],b[1])|| \ + delta_ofs(a[2],b[2])) +#define delta_blend(a,b) ((int)((b)*255)!=(int)((a)*255)) +#define delta_blend_v(a,b) \ + (delta_blend(a[0],b[0])|| \ + delta_blend(a[1],b[1])|| \ + delta_blend(a[2],b[2])|| \ + delta_blend(a[3],b[3])) +#define delta_fov(a,b) ((int)(b)!=(int)(a)) + +/* +================== +MSG_WriteDeltaEntity + +Writes part of a packetentities message. +Can delta from either a baseline or a previous packet_entity +================== +*/ +void MSG_WriteDeltaEntity( const entity_state_t *from, + const entity_state_t *to, + msgEsFlags_t flags ) +{ + unsigned bits, mask; + + if( !to ) { + if( !from ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + if( from->number < 1 || from->number >= MAX_EDICTS ) { + Com_Error( ERR_DROP, "%s: bad number: %d", __func__, from->number ); + } + bits = U_REMOVE; + if( from->number >= 256 ) { + bits |= U_NUMBER16 | U_MOREBITS1; + } + + MSG_WriteByte( bits & 255 ); + if( bits & 0x0000ff00 ) + MSG_WriteByte( ( bits >> 8 ) & 255 ); + + if( bits & U_NUMBER16 ) + MSG_WriteShort( from->number ); + else + MSG_WriteByte( from->number ); + + return; // remove entity + } + + if( to->number < 1 || to->number >= MAX_EDICTS ) { + Com_Error( ERR_DROP, "%s: bad number: %d", __func__, to->number ); + } + + if( !from ) { + from = &nullEntityState; + } + +// send an update + bits = 0; + + if( !( flags & MSG_ES_FIRSTPERSON ) ) { + if( delta_coord( to->origin[0], from->origin[0] ) ) + bits |= U_ORIGIN1; + if( delta_coord( to->origin[1], from->origin[1] ) ) + bits |= U_ORIGIN2; + if( delta_coord( to->origin[2], from->origin[2] ) ) + bits |= U_ORIGIN3; + + if( delta_angle( to->angles[0], from->angles[0] ) ) + bits |= U_ANGLE1; + if( delta_angle( to->angles[1], from->angles[1] ) ) + bits |= U_ANGLE2; + if( delta_angle( to->angles[2], from->angles[2] ) ) + bits |= U_ANGLE3; + + if( flags & MSG_ES_NEWENTITY ) { + if( delta_pos_v( to->old_origin, from->old_origin ) ) { + bits |= U_OLDORIGIN; + } + } + } + + if( flags & MSG_ES_UMASK ) { + mask = 0xffff0000; + } else { + mask = 0xffff8000; // don't confuse old clients + } + + if( to->skinnum != from->skinnum ) { + if( to->skinnum & mask ) { + bits |= U_SKIN8|U_SKIN16; + } else if( to->skinnum & 0x0000ff00 ) { + bits |= U_SKIN16; + } else { + bits |= U_SKIN8; + } + } + + if( to->frame != from->frame ) { + if( to->frame < 256 ) + bits |= U_FRAME8; + else + bits |= U_FRAME16; + } + + if( to->effects != from->effects ) { + if( to->effects & mask ) { + bits |= U_EFFECTS8|U_EFFECTS16; + } else if( to->effects & 0x0000ff00 ) { + bits |= U_EFFECTS16; + } else { + bits |= U_EFFECTS8; + } + } + + if( to->renderfx != from->renderfx ) { + if( to->renderfx & mask ) { + bits |= U_RENDERFX8|U_RENDERFX16; + } else if( to->renderfx & 0x0000ff00 ) { + bits |= U_RENDERFX16; + } else { + bits |= U_RENDERFX8; + } + } + + if( to->solid != from->solid ) + bits |= U_SOLID; + + // event is not delta compressed, just 0 compressed + if( to->event ) + bits |= U_EVENT; + + if( to->modelindex != from->modelindex ) + bits |= U_MODEL; + if( to->modelindex2 != from->modelindex2 ) + bits |= U_MODEL2; + if( to->modelindex3 != from->modelindex3 ) + bits |= U_MODEL3; + if( to->modelindex4 != from->modelindex4 ) + bits |= U_MODEL4; + + if( to->sound != from->sound ) + bits |= U_SOUND; + + if( ( to->renderfx & RF_BEAM ) ) + bits |= U_OLDORIGIN; + + // + // write the message + // + if( !bits && !( flags & MSG_ES_FORCE ) ) + return; // nothing to send! + + if( flags & MSG_ES_REMOVE ) { + bits |= U_REMOVE; // used for MVD stream only + } + + //---------- + + if (to->number >= 256) + bits |= U_NUMBER16; // number8 is implicit otherwise + + 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 (bits&255 ); + + if (bits & 0xff000000) { + MSG_WriteByte ((bits>>8)&255 ); + MSG_WriteByte ((bits>>16)&255 ); + MSG_WriteByte ((bits>>24)&255 ); + } else if (bits & 0x00ff0000) { + MSG_WriteByte ((bits>>8)&255 ); + MSG_WriteByte ((bits>>16)&255 ); + } else if (bits & 0x0000ff00) { + MSG_WriteByte ((bits>>8)&255 ); + } + + //---------- + + if (bits & U_NUMBER16) + MSG_WriteShort (to->number); + else + MSG_WriteByte (to->number); + + if (bits & U_MODEL) + MSG_WriteByte (to->modelindex); + if (bits & U_MODEL2) + MSG_WriteByte (to->modelindex2); + if (bits & U_MODEL3) + MSG_WriteByte (to->modelindex3); + if (bits & U_MODEL4) + MSG_WriteByte (to->modelindex4); + + if (bits & U_FRAME8) + MSG_WriteByte (to->frame); + else if (bits & U_FRAME16) + MSG_WriteShort (to->frame); + + if ((bits & (U_SKIN8|U_SKIN16)) == (U_SKIN8|U_SKIN16) ) //used for laser colors + MSG_WriteLong (to->skinnum); + else if (bits & U_SKIN8) + MSG_WriteByte (to->skinnum); + else if (bits & U_SKIN16) + MSG_WriteShort (to->skinnum); + + if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) ) + MSG_WriteLong (to->effects); + else if (bits & U_EFFECTS8) + MSG_WriteByte (to->effects); + else if (bits & U_EFFECTS16) + MSG_WriteShort (to->effects); + + if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) ) + MSG_WriteLong (to->renderfx); + else if (bits & U_RENDERFX8) + MSG_WriteByte (to->renderfx); + else if (bits & U_RENDERFX16) + MSG_WriteShort (to->renderfx); + + if (bits & U_ORIGIN1) + MSG_WriteCoord (to->origin[0]); + if (bits & U_ORIGIN2) + MSG_WriteCoord (to->origin[1]); + if (bits & U_ORIGIN3) + MSG_WriteCoord (to->origin[2]); + + if (bits & U_ANGLE1) + MSG_WriteAngle(to->angles[0]); + if (bits & U_ANGLE2) + MSG_WriteAngle(to->angles[1]); + if (bits & U_ANGLE3) + MSG_WriteAngle(to->angles[2]); + + if (bits & U_OLDORIGIN) + MSG_WritePos (to->old_origin); + + if (bits & U_SOUND) + MSG_WriteByte (to->sound); + if (bits & U_EVENT) + MSG_WriteByte (to->event); + if (bits & U_SOLID) { + if( flags & MSG_ES_LONGSOLID ) { + MSG_WriteLong (to->solid); + } else { + MSG_WriteShort (to->solid); + } + } +} + +/* +================== +MSG_WriteDeltaPlayerstate_Default +================== +*/ +void MSG_WriteDeltaPlayerstate_Default( const player_state_t *from, const player_state_t *to ) { + int i; + int pflags; + int statbits; + + if( !to ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + + if( !from ) { + from = &nullPlayerState; + } + + // + // determine what needs to be sent + // + pflags = 0; + + if( to->pmove.pm_type != from->pmove.pm_type ) + pflags |= PS_M_TYPE; + + if( to->pmove.origin[0] != from->pmove.origin[0] || + to->pmove.origin[1] != from->pmove.origin[1] || + to->pmove.origin[2] != from->pmove.origin[2] ) + { + pflags |= PS_M_ORIGIN; + } + + if( to->pmove.velocity[0] != from->pmove.velocity[0] || + to->pmove.velocity[1] != from->pmove.velocity[1] || + to->pmove.velocity[2] != from->pmove.velocity[2] ) + { + pflags |= PS_M_VELOCITY; + } + + if( to->pmove.pm_time != from->pmove.pm_time ) + pflags |= PS_M_TIME; + + if( to->pmove.pm_flags != from->pmove.pm_flags ) + pflags |= PS_M_FLAGS; + + if( to->pmove.gravity != from->pmove.gravity ) + pflags |= PS_M_GRAVITY; + + if( to->pmove.delta_angles[0] != from->pmove.delta_angles[0] || + to->pmove.delta_angles[1] != from->pmove.delta_angles[1] || + to->pmove.delta_angles[2] != from->pmove.delta_angles[2] ) + { + pflags |= PS_M_DELTA_ANGLES; + } + + if( delta_ofs_v( to->viewoffset, from->viewoffset ) ) { + pflags |= PS_VIEWOFFSET; + } + + if( delta_angle16_v( to->viewangles, from->viewangles ) ) { + pflags |= PS_VIEWANGLES; + } + + if( delta_ofs_v( to->kick_angles, from->kick_angles ) ) { + pflags |= PS_KICKANGLES; + } + + if( delta_blend_v( to->blend, from->blend ) ) { + pflags |= PS_BLEND; + } + + if( delta_fov( to->fov, from->fov ) ) + pflags |= PS_FOV; + + if( to->rdflags != from->rdflags ) + pflags |= PS_RDFLAGS; + + if( to->gunframe != from->gunframe || + delta_ofs_v( to->gunoffset, from->gunoffset ) || + delta_ofs_v( to->gunangles, from->gunangles ) ) + { + pflags |= PS_WEAPONFRAME; + } + + if( to->gunindex != from->gunindex ) + pflags |= PS_WEAPONINDEX; + + + // + // write it + // + MSG_WriteShort( pflags ); + + // + // write the pmove_state_t + // + if( pflags & PS_M_TYPE ) + MSG_WriteByte( to->pmove.pm_type ); + + if( pflags & PS_M_ORIGIN ) { + MSG_WriteShort( to->pmove.origin[0] ); + MSG_WriteShort( to->pmove.origin[1] ); + MSG_WriteShort( to->pmove.origin[2] ); + } + + if( pflags & PS_M_VELOCITY ) { + MSG_WriteShort( to->pmove.velocity[0] ); + MSG_WriteShort( to->pmove.velocity[1] ); + MSG_WriteShort( to->pmove.velocity[2] ); + } + + if( pflags & PS_M_TIME ) + MSG_WriteByte( to->pmove.pm_time ); + + if( pflags & PS_M_FLAGS ) + MSG_WriteByte( to->pmove.pm_flags ); + + if( pflags & PS_M_GRAVITY ) + MSG_WriteShort( to->pmove.gravity ); + + if( pflags & PS_M_DELTA_ANGLES ) { + MSG_WriteShort( to->pmove.delta_angles[0] ); + MSG_WriteShort( to->pmove.delta_angles[1] ); + MSG_WriteShort( to->pmove.delta_angles[2] ); + } + + // + // write the rest of the player_state_t + // + if( pflags & PS_VIEWOFFSET ) { + MSG_WriteChar( to->viewoffset[0] * 4 ); + MSG_WriteChar( to->viewoffset[1] * 4 ); + MSG_WriteChar( to->viewoffset[2] * 4 ); + } + + if( pflags & PS_VIEWANGLES ) { + MSG_WriteAngle16( to->viewangles[0] ); + MSG_WriteAngle16( to->viewangles[1] ); + MSG_WriteAngle16( to->viewangles[2] ); + } + + if( pflags & PS_KICKANGLES ) { + MSG_WriteChar( to->kick_angles[0] * 4 ); + MSG_WriteChar( to->kick_angles[1] * 4 ); + MSG_WriteChar( to->kick_angles[2] * 4 ); + } + + if( pflags & PS_WEAPONINDEX ) { + MSG_WriteByte( to->gunindex ); + } + + if( pflags & PS_WEAPONFRAME ) { + MSG_WriteByte( to->gunframe ); + MSG_WriteChar( to->gunoffset[0] * 4 ); + MSG_WriteChar( to->gunoffset[1] * 4 ); + MSG_WriteChar( to->gunoffset[2] * 4 ); + MSG_WriteChar( to->gunangles[0] * 4 ); + MSG_WriteChar( to->gunangles[1] * 4 ); + MSG_WriteChar( to->gunangles[2] * 4 ); + } + + if( pflags & PS_BLEND ) { + MSG_WriteByte( to->blend[0] * 255 ); + MSG_WriteByte( to->blend[1] * 255 ); + MSG_WriteByte( to->blend[2] * 255 ); + MSG_WriteByte( to->blend[3] * 255 ); + } + + if( pflags & PS_FOV ) + MSG_WriteByte( to->fov ); + + if( pflags & PS_RDFLAGS ) + MSG_WriteByte( to->rdflags ); + + // send stats + statbits = 0; + for( i = 0; i < MAX_STATS; i++ ) + if( to->stats[i] != from->stats[i] ) + statbits |= 1 << i; + + MSG_WriteLong( statbits ); + for( i = 0; i < MAX_STATS; i++ ) + if( statbits & ( 1 << i ) ) + MSG_WriteShort( to->stats[i] ); +} + +/* +================== +MSG_WriteDeltaPlayerstate_Enhanced +================== +*/ +int MSG_WriteDeltaPlayerstate_Enhanced( const player_state_t *from, + player_state_t *to, + msgPsFlags_t flags ) +{ + int i; + int pflags, extraflags; + int statbits; + + if( !to ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + + if( !from ) { + from = &nullPlayerState; + } + + // + // determine what needs to be sent + // + pflags = 0; + extraflags = 0; + + if( to->pmove.pm_type != from->pmove.pm_type ) + pflags |= PS_M_TYPE; + + if( to->pmove.origin[0] != from->pmove.origin[0] || + to->pmove.origin[1] != from->pmove.origin[1] ) + { + pflags |= PS_M_ORIGIN; + } + + if( to->pmove.origin[2] != from->pmove.origin[2] ) { + extraflags |= EPS_M_ORIGIN2; + } + + if( !( flags & MSG_PS_IGNORE_PREDICTION ) ) { + if( to->pmove.velocity[0] != from->pmove.velocity[0] || + to->pmove.velocity[1] != from->pmove.velocity[1] ) + { + pflags |= PS_M_VELOCITY; + } + + if( to->pmove.velocity[2] != from->pmove.velocity[2] ) { + extraflags |= EPS_M_VELOCITY2; + } + + if( to->pmove.pm_time != from->pmove.pm_time ) + pflags |= PS_M_TIME; + + if( to->pmove.pm_flags != from->pmove.pm_flags ) + pflags |= PS_M_FLAGS; + + if( to->pmove.gravity != from->pmove.gravity ) + pflags |= PS_M_GRAVITY; + } else { + // save previous state + VectorCopy( from->pmove.velocity, to->pmove.velocity ); + to->pmove.pm_time = from->pmove.pm_time; + to->pmove.pm_flags = from->pmove.pm_flags; + to->pmove.gravity = from->pmove.gravity; + } + + if( !( flags & MSG_PS_IGNORE_DELTAANGLES ) ) { + if( to->pmove.delta_angles[0] != from->pmove.delta_angles[0] || + to->pmove.delta_angles[1] != from->pmove.delta_angles[1] || + to->pmove.delta_angles[2] != from->pmove.delta_angles[2] ) + { + pflags |= PS_M_DELTA_ANGLES; + } + } else { + // save previous state + VectorCopy( from->pmove.delta_angles, to->pmove.delta_angles ); + } + + if( delta_ofs_v( from->viewoffset, to->viewoffset ) ) { + pflags |= PS_VIEWOFFSET; + } + + if( !( flags & MSG_PS_IGNORE_VIEWANGLES ) ) { + if( delta_angle16( from->viewangles[0], to->viewangles[0] ) || + delta_angle16( from->viewangles[1], to->viewangles[1] ) ) + { + pflags |= PS_VIEWANGLES; + } + + if( delta_angle16( from->viewangles[2], to->viewangles[2] ) ) { + extraflags |= EPS_VIEWANGLE2; + } + } else { + // save previous state + to->viewangles[0] = from->viewangles[0]; + to->viewangles[1] = from->viewangles[1]; + to->viewangles[2] = from->viewangles[2]; + } + + if( delta_ofs_v( from->kick_angles, to->kick_angles ) ) { + pflags |= PS_KICKANGLES; + } + + if( !( flags & MSG_PS_IGNORE_BLEND ) ) { + if( delta_blend_v( from->blend, to->blend ) ) { + pflags |= PS_BLEND; + } + } else { + // save previous state + to->blend[0] = from->blend[0]; + to->blend[1] = from->blend[1]; + to->blend[2] = from->blend[2]; + to->blend[3] = from->blend[3]; + } + + if( delta_fov( from->fov, to->fov ) ) + pflags |= PS_FOV; + + if( to->rdflags != from->rdflags ) + pflags |= PS_RDFLAGS; + + if( !( flags & MSG_PS_IGNORE_GUNINDEX ) ) { + if( to->gunindex != from->gunindex ) + pflags |= PS_WEAPONINDEX; + } else { + // save previous state + to->gunindex = from->gunindex; + } + + if( !( flags & MSG_PS_IGNORE_GUNFRAMES ) ) { + if( to->gunframe != from->gunframe ) + pflags |= PS_WEAPONFRAME; + + if( delta_ofs_v( from->gunoffset, to->gunoffset ) ) { + extraflags |= EPS_GUNOFFSET; + } + + if( delta_ofs_v( from->gunangles, to->gunangles ) ) { + extraflags |= EPS_GUNANGLES; + } + } else { + // save previous state + to->gunframe = from->gunframe; + + to->gunoffset[0] = from->gunoffset[0]; + to->gunoffset[1] = from->gunoffset[1]; + to->gunoffset[2] = from->gunoffset[2]; + + to->gunangles[0] = from->gunangles[0]; + to->gunangles[1] = from->gunangles[1]; + to->gunangles[2] = from->gunangles[2]; + } + + statbits = 0; + for( i = 0; i < MAX_STATS; i++ ) { + if( to->stats[i] != from->stats[i] ) { + statbits |= 1 << i; + } + } + + if( statbits ) { + extraflags |= EPS_STATS; + } + + // + // write it + // + MSG_WriteShort( pflags ); + + // + // write the pmove_state_t + // + if( pflags & PS_M_TYPE ) + MSG_WriteByte( to->pmove.pm_type ); + + if( pflags & PS_M_ORIGIN ) { + MSG_WriteShort( to->pmove.origin[0] ); + MSG_WriteShort( to->pmove.origin[1] ); + } + + if( extraflags & EPS_M_ORIGIN2 ) { + MSG_WriteShort( to->pmove.origin[2] ); + } + + if( pflags & PS_M_VELOCITY ) { + MSG_WriteShort( to->pmove.velocity[0] ); + MSG_WriteShort( to->pmove.velocity[1] ); + } + + if( extraflags & EPS_M_VELOCITY2 ) { + MSG_WriteShort( to->pmove.velocity[2] ); + } + + if( pflags & PS_M_TIME ) { + MSG_WriteByte( to->pmove.pm_time ); + } + + if( pflags & PS_M_FLAGS ) { + MSG_WriteByte( to->pmove.pm_flags ); + } + + if( pflags & PS_M_GRAVITY ) { + MSG_WriteShort( to->pmove.gravity ); + } + + if( pflags & PS_M_DELTA_ANGLES ) { + MSG_WriteShort( to->pmove.delta_angles[0] ); + MSG_WriteShort( to->pmove.delta_angles[1] ); + MSG_WriteShort( to->pmove.delta_angles[2] ); + } + + // + // write the rest of the player_state_t + // + if( pflags & PS_VIEWOFFSET ) { + MSG_WriteChar( to->viewoffset[0] * 4 ); + MSG_WriteChar( to->viewoffset[1] * 4 ); + MSG_WriteChar( to->viewoffset[2] * 4 ); + } + + if( pflags & PS_VIEWANGLES ) { + MSG_WriteAngle16( to->viewangles[0] ); + MSG_WriteAngle16( to->viewangles[1] ); + + } + + if( extraflags & EPS_VIEWANGLE2 ) { + MSG_WriteAngle16( to->viewangles[2] ); + } + + if( pflags & PS_KICKANGLES ) { + MSG_WriteChar( to->kick_angles[0] * 4 ); + MSG_WriteChar( to->kick_angles[1] * 4 ); + MSG_WriteChar( to->kick_angles[2] * 4 ); + } + + if( pflags & PS_WEAPONINDEX ) { + MSG_WriteByte( to->gunindex ); + } + + if( pflags & PS_WEAPONFRAME ) { + MSG_WriteByte( to->gunframe ); + } + + if( extraflags & EPS_GUNOFFSET ) { + MSG_WriteChar( to->gunoffset[0] * 4 ); + MSG_WriteChar( to->gunoffset[1] * 4 ); + MSG_WriteChar( to->gunoffset[2] * 4 ); + } + + if( extraflags & EPS_GUNANGLES ) { + MSG_WriteChar( to->gunangles[0] * 4 ); + MSG_WriteChar( to->gunangles[1] * 4 ); + MSG_WriteChar( to->gunangles[2] * 4 ); + } + + if( pflags & PS_BLEND ) { + MSG_WriteByte( to->blend[0] * 255 ); + MSG_WriteByte( to->blend[1] * 255 ); + MSG_WriteByte( to->blend[2] * 255 ); + MSG_WriteByte( to->blend[3] * 255 ); + } + + if( pflags & PS_FOV ) + MSG_WriteByte( to->fov ); + + if( pflags & PS_RDFLAGS ) + MSG_WriteByte( to->rdflags ); + + // send stats + if( extraflags & EPS_STATS ) { + MSG_WriteLong( statbits ); + for( i = 0; i < MAX_STATS; i++ ) { + if( statbits & ( 1 << i ) ) { + MSG_WriteShort( to->stats[i] ); + } + } + } + + return extraflags; +} + +#if USE_MVD_SERVER || USE_MVD_CLIENT + +/* +================== +MSG_WriteDeltaPlayerstate_Packet + +Throw away most of the pmove_state_t fields as they are used only +for client prediction, and not needed in MVDs. +================== +*/ +void MSG_WriteDeltaPlayerstate_Packet( const player_state_t *from, + const player_state_t *to, + int number, + msgPsFlags_t flags ) +{ + int i; + int pflags; + int statbits; + + if( number < 0 || number >= MAX_CLIENTS ) { + Com_Error( ERR_DROP, "%s: bad number: %d", __func__, number ); + } + + if( !to ) { + MSG_WriteByte( number ); + MSG_WriteShort( PPS_REMOVE ); + return; + } + + if( !from ) { + from = &nullPlayerState; + } + + // + // determine what needs to be sent + // + pflags = 0; + + if( to->pmove.pm_type != from->pmove.pm_type ) + pflags |= PPS_M_TYPE; + + if( to->pmove.origin[0] != from->pmove.origin[0] || + to->pmove.origin[1] != from->pmove.origin[1] ) + { + pflags |= PPS_M_ORIGIN; + } + + if( to->pmove.origin[2] != from->pmove.origin[2] ) { + pflags |= PPS_M_ORIGIN2; + } + + if( delta_ofs_v( from->viewoffset, to->viewoffset ) ) { + pflags |= PPS_VIEWOFFSET; + } + + if( delta_angle16( from->viewangles[0], to->viewangles[0] ) || + delta_angle16( from->viewangles[1], to->viewangles[1] ) ) + { + pflags |= PPS_VIEWANGLES; + } + + if( delta_angle16( from->viewangles[2], to->viewangles[2] ) ) { + pflags |= PPS_VIEWANGLE2; + } + + if( delta_ofs_v( from->kick_angles, to->kick_angles ) ) { + pflags |= PPS_KICKANGLES; + } + + if( !( flags & MSG_PS_IGNORE_BLEND ) ) { + if( delta_blend_v( from->blend, to->blend ) ) { + pflags |= PPS_BLEND; + } + } + + if( delta_fov( from->fov, to->fov ) ) + pflags |= PPS_FOV; + + if( to->rdflags != from->rdflags ) + pflags |= PPS_RDFLAGS; + + if( !( flags & MSG_PS_IGNORE_GUNINDEX ) ) { + if( to->gunindex != from->gunindex ) + pflags |= PPS_WEAPONINDEX; + } + + if( !( flags & MSG_PS_IGNORE_GUNFRAMES ) ) { + if( to->gunframe != from->gunframe ) + pflags |= PPS_WEAPONFRAME; + + if( delta_ofs_v( from->gunoffset, to->gunoffset ) ) { + pflags |= PPS_GUNOFFSET; + } + + if( delta_ofs_v( from->gunangles, to->gunangles ) ) { + pflags |= PPS_GUNANGLES; + } + } + + statbits = 0; + for( i = 0; i < MAX_STATS; i++ ) { + if( to->stats[i] != from->stats[i] ) { + statbits |= 1 << i; + pflags |= PPS_STATS; + } + } + + if( !pflags && !( flags & MSG_PS_FORCE ) ) { + return; + } + + if( flags & MSG_PS_REMOVE ) { + pflags |= PPS_REMOVE; // used for MVD stream only + } + + // + // write it + // + MSG_WriteByte( number ); + MSG_WriteShort( pflags ); + + // + // write some part of the pmove_state_t + // + if( pflags & PPS_M_TYPE ) + MSG_WriteByte( to->pmove.pm_type ); + + if( pflags & PPS_M_ORIGIN ) { + MSG_WriteShort( to->pmove.origin[0] ); + MSG_WriteShort( to->pmove.origin[1] ); + } + + if( pflags & PPS_M_ORIGIN2 ) { + MSG_WriteShort( to->pmove.origin[2] ); + } + + // + // write the rest of the player_state_t + // + if( pflags & PPS_VIEWOFFSET ) { + MSG_WriteChar( to->viewoffset[0] * 4 ); + MSG_WriteChar( to->viewoffset[1] * 4 ); + MSG_WriteChar( to->viewoffset[2] * 4 ); + } + + if( pflags & PPS_VIEWANGLES ) { + MSG_WriteAngle16( to->viewangles[0] ); + MSG_WriteAngle16( to->viewangles[1] ); + } + + if( pflags & PPS_VIEWANGLE2 ) { + MSG_WriteAngle16( to->viewangles[2] ); + } + + if( pflags & PPS_KICKANGLES ) { + MSG_WriteChar( to->kick_angles[0] * 4 ); + MSG_WriteChar( to->kick_angles[1] * 4 ); + MSG_WriteChar( to->kick_angles[2] * 4 ); + } + + if( pflags & PPS_WEAPONINDEX ) { + MSG_WriteByte( to->gunindex ); + } + + if( pflags & PPS_WEAPONFRAME ) { + MSG_WriteByte( to->gunframe ); + } + + if( pflags & PPS_GUNOFFSET ) { + MSG_WriteChar( to->gunoffset[0] * 4 ); + MSG_WriteChar( to->gunoffset[1] * 4 ); + MSG_WriteChar( to->gunoffset[2] * 4 ); + } + + if( pflags & PPS_GUNANGLES ) { + MSG_WriteChar( to->gunangles[0] * 4 ); + MSG_WriteChar( to->gunangles[1] * 4 ); + MSG_WriteChar( to->gunangles[2] * 4 ); + } + + if( pflags & PPS_BLEND ) { + MSG_WriteByte( to->blend[0] * 255 ); + MSG_WriteByte( to->blend[1] * 255 ); + MSG_WriteByte( to->blend[2] * 255 ); + MSG_WriteByte( to->blend[3] * 255 ); + } + + if( pflags & PPS_FOV ) + MSG_WriteByte( to->fov ); + + if( pflags & PPS_RDFLAGS ) + MSG_WriteByte( to->rdflags ); + + // send stats + if( pflags & PPS_STATS ) { + MSG_WriteLong( statbits ); + for( i = 0; i < MAX_STATS; i++ ) { + if( statbits & ( 1 << i ) ) { + MSG_WriteShort( to->stats[i] ); + } + } + } +} + +#endif // USE_MVD_SERVER || USE_MVD_CLIENT + +/* +============= +MSG_FlushTo +============= +*/ +void MSG_FlushTo( sizebuf_t *dest ) { + memcpy( SZ_GetSpace( dest, msg_write.cursize ), msg_write.data, msg_write.cursize ); + SZ_Clear( &msg_write ); +} + +#if 0 +// NOTE: does not NUL-terminate the string +void MSG_Printf( const char *fmt, ... ) { + char buffer[MAX_STRING_CHARS]; + va_list argptr; + size_t len; + + va_start( argptr, fmt ); + len = Q_vsnprintf( buffer, sizeof( buffer ), fmt, argptr ); + va_end( argptr ); + + if( len >= sizeof( buffer ) ) { + Com_WPrintf( "%s: overflow\n", __func__ ); + return; + } + + MSG_WriteData( buffer, len ); +} +#endif + +//============================================================ + +// +// reading functions +// + +void MSG_BeginReading( void ) { + msg_read.readcount = 0; + msg_read.bitpos = 0; +} + +byte *MSG_ReadData( size_t len ) { + byte *buf = msg_read.data + msg_read.readcount; + + msg_read.readcount += len; + msg_read.bitpos = msg_read.readcount << 3; + + if( msg_read.readcount > msg_read.cursize ) { + if( !msg_read.allowunderflow ) { + Com_Error( ERR_DROP, "%s: read past end of message", __func__ ); + } + return NULL; + } + + return buf; +} + +// returns -1 if no more characters are available +int MSG_ReadChar( void ) { + byte *buf = MSG_ReadData( 1 ); + int c; + + if (!buf) { + c = -1; + } else { + c = (signed char)buf[0]; + } + + return c; +} + +int MSG_ReadByte( void ) { + byte *buf = MSG_ReadData( 1 ); + int c; + + if (!buf) { + c = -1; + } else { + c = (unsigned char)buf[0]; + } + + return c; +} + +int MSG_ReadShort( void ) { + byte *buf = MSG_ReadData( 2 ); + int c; + + if (!buf) { + c = -1; + } else { + c = (signed short)LittleShortMem(buf); + } + + return c; +} + +int MSG_ReadWord( void ) { + byte *buf = MSG_ReadData( 2 ); + int c; + + if (!buf) { + c = -1; + } else { + c = (unsigned short)LittleShortMem(buf); + } + + return c; +} + +int MSG_ReadLong( void ) { + byte *buf = MSG_ReadData( 4 ); + int c; + + if (!buf) { + c = -1; + } else { + c = LittleLongMem(buf); + } + + return c; +} + +size_t MSG_ReadString( char *dest, size_t size ) { + int c; + size_t len = 0; + + while( 1 ) { + c = MSG_ReadByte(); + if( c == -1 || c == 0 ) { + break; + } + if( len + 1 < size ) { + *dest++ = c; + } + len++; + } + if( size ) { + *dest = 0; + } + + return len; +} + +size_t MSG_ReadStringLine( char *dest, size_t size ) { + int c; + size_t len = 0; + + while( 1 ) { + c = MSG_ReadByte(); + if( c == -1 || c == 0 || c == '\n' ) { + break; + } + if( len + 1 < size ) { + *dest++ = c; + } + len++; + } + if( size ) { + *dest = 0; + } + + return len; +} + +static inline float MSG_ReadCoord (void) { + return SHORT2COORD(MSG_ReadShort()); +} + +#if !USE_CLIENT +static inline +#endif +void MSG_ReadPos( vec3_t pos ) { + pos[0] = MSG_ReadCoord(); + pos[1] = MSG_ReadCoord(); + pos[2] = MSG_ReadCoord(); +} + +static inline float MSG_ReadAngle (void) { + return BYTE2ANGLE(MSG_ReadChar()); +} + +static inline float MSG_ReadAngle16 (void) { + return SHORT2ANGLE(MSG_ReadShort()); +} + +#if USE_CLIENT +void MSG_ReadDir( vec3_t dir ) { + int b; + + b = MSG_ReadByte(); + if( b < 0 || b >= NUMVERTEXNORMALS ) + Com_Error( ERR_DROP, "MSG_ReadDir: out of range" ); + VectorCopy( bytedirs[b], dir ); +} +#endif + +void MSG_ReadDeltaUsercmd( const usercmd_t *from, usercmd_t *to ) { + int bits; + + if( from ) { + memcpy( to, from, sizeof( *to ) ); + } else { + memset( to, 0, sizeof( *to ) ); + } + + bits = MSG_ReadByte(); + +// read current angles + if( bits & CM_ANGLE1 ) + to->angles[0] = MSG_ReadShort(); + if( bits & CM_ANGLE2 ) + to->angles[1] = MSG_ReadShort(); + if( bits & CM_ANGLE3 ) + to->angles[2] = MSG_ReadShort(); + +// read movement + if( bits & CM_FORWARD ) + to->forwardmove = MSG_ReadShort(); + if( bits & CM_SIDE ) + to->sidemove = MSG_ReadShort(); + if( bits & CM_UP ) + to->upmove = MSG_ReadShort(); + +// read buttons + if( bits & CM_BUTTONS ) + to->buttons = MSG_ReadByte(); + + if( bits & CM_IMPULSE ) + to->impulse = MSG_ReadByte(); + +// read time to run command + to->msec = MSG_ReadByte(); + +// read the light level + to->lightlevel = MSG_ReadByte(); +} + +void MSG_ReadDeltaUsercmd_Hacked( const usercmd_t *from, usercmd_t *to ) { + int bits, buttons = 0; + + if( from ) { + memcpy( to, from, sizeof( *to ) ); + } else { + memset( to, 0, sizeof( *to ) ); + } + + bits = MSG_ReadByte(); + +// read buttons + if( bits & CM_BUTTONS ) { + buttons = MSG_ReadByte(); + to->buttons = buttons & BUTTON_MASK; + } + +// read current angles + if( bits & CM_ANGLE1 ) { + if( buttons & BUTTON_ANGLE1 ) { + to->angles[0] = MSG_ReadChar() * 64; + } else { + to->angles[0] = MSG_ReadShort(); + } + } + if( bits & CM_ANGLE2 ) { + if( buttons & BUTTON_ANGLE2 ) { + to->angles[1] = MSG_ReadChar() * 256; + } else { + to->angles[1] = MSG_ReadShort(); + } + } + if( bits & CM_ANGLE3 ) + to->angles[2] = MSG_ReadShort(); + +// read movement + if( bits & CM_FORWARD ) { + if( buttons & BUTTON_FORWARD ) { + to->forwardmove = MSG_ReadChar() * 5; + } else { + to->forwardmove = MSG_ReadShort(); + } + } + if( bits & CM_SIDE ) { + if( buttons & BUTTON_SIDE ) { + to->sidemove = MSG_ReadChar() * 5; + } else { + to->sidemove = MSG_ReadShort(); + } + } + if( bits & CM_UP ) { + if( buttons & BUTTON_UP ) { + to->upmove = MSG_ReadChar() * 5; + } else { + to->upmove = MSG_ReadShort(); + } + } + + if( bits & CM_IMPULSE ) + to->impulse = MSG_ReadByte(); + +// read time to run command + to->msec = MSG_ReadByte(); + +// read the light level + to->lightlevel = MSG_ReadByte(); +} + +int MSG_ReadBits( int bits ) { + int i, get; + size_t bitpos; + qboolean sgn; + int value; + + if( bits == 0 || bits < -31 || bits > 32 ) { + Com_Error( ERR_FATAL, "MSG_ReadBits: bad bits: %d", bits ); + } + + bitpos = msg_read.bitpos; + if( ( bitpos & 7 ) == 0 ) { + // optimized case + switch( bits ) { + case -8: + value = MSG_ReadChar(); + return value; + case 8: + value = MSG_ReadByte(); + return value; + case -16: + value = MSG_ReadShort(); + return value; + case 32: + value = MSG_ReadLong(); + return value; + default: + break; + } + } + + sgn = qfalse; + if( bits < 0 ) { + bits = -bits; + sgn = qtrue; + } + + value = 0; + for( i = 0; i < bits; i++, bitpos++ ) { + get = ( msg_read.data[ bitpos >> 3 ] >> ( bitpos & 7 ) ) & 1; + value |= get << i; + } + msg_read.bitpos = bitpos; + msg_read.readcount = ( bitpos + 7 ) >> 3; + + if( sgn ) { + if( value & ( 1 << ( bits - 1 ) ) ) { + value |= -1 ^ ( ( 1 << bits ) - 1 ); + } + } + + return value; +} + +void MSG_ReadDeltaUsercmd_Enhanced( const usercmd_t *from, + usercmd_t *to, + int version ) +{ + int bits, count; + + if( from ) { + memcpy( to, from, sizeof( *to ) ); + } else { + memset( to, 0, sizeof( *to ) ); + } + + if( !MSG_ReadBits( 1 ) ) { + return; + } + + bits = MSG_ReadBits( 8 ); + +// read current angles + if( bits & CM_ANGLE1 ) { + if( MSG_ReadBits( 1 ) ) { + to->angles[0] += MSG_ReadBits( -8 ); + } else { + to->angles[0] = MSG_ReadBits( -16 ); + } + } + if( bits & CM_ANGLE2 ) { + if( MSG_ReadBits( 1 ) ) { + to->angles[1] += MSG_ReadBits( -8 ); + } else { + to->angles[1] = MSG_ReadBits( -16 ); + } + } + if( bits & CM_ANGLE3 ) { + to->angles[2] = MSG_ReadBits( -16 ); + } + +// read movement + if( version >= PROTOCOL_VERSION_Q2PRO_UCMD ) { + count = -10; + } else { + count = -16; + } + + if( bits & CM_FORWARD ) { + to->forwardmove = MSG_ReadBits( count ); + } + if( bits & CM_SIDE ) { + to->sidemove = MSG_ReadBits( count ); + } + if( bits & CM_UP ) { + to->upmove = MSG_ReadBits( count ); + } + +// read buttons + if( bits & CM_BUTTONS ) { + int buttons = MSG_ReadBits( 3 ); + to->buttons = ( buttons & 3 ) | ( ( buttons & 4 ) << 5 ); + } + +// read time to run command + if( bits & CM_IMPULSE ) { + to->msec = MSG_ReadBits( 8 ); + } +} + +#if USE_CLIENT || USE_MVD_CLIENT + +/* +================= +MSG_ParseEntityBits + +Returns the entity number and the header bits +================= +*/ +int MSG_ParseEntityBits( int *bits ) { + int b, total; + int number; + + total = MSG_ReadByte(); + if( total & U_MOREBITS1 ) { + b = MSG_ReadByte(); + total |= b<<8; + } + if( total & U_MOREBITS2 ) { + b = MSG_ReadByte(); + total |= b<<16; + } + if( total & U_MOREBITS3 ) { + b = MSG_ReadByte(); + total |= b<<24; + } + + if( total & U_NUMBER16 ) + number = MSG_ReadShort(); + else + number = MSG_ReadByte(); + + *bits = total; + + return number; +} + +/* +================== +MSG_ParseDeltaEntity + +Can go from either a baseline or a previous packet_entity +================== +*/ +void MSG_ParseDeltaEntity( const entity_state_t *from, + entity_state_t *to, + int number, + int bits, + msgEsFlags_t flags ) +{ + if( !to ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + + if( number < 1 || number >= MAX_EDICTS ) { + Com_Error( ERR_DROP, "%s: bad entity number: %d", __func__, number ); + } + + // set everything to the state we are delta'ing from + if( from ) { + if( to != from ) { + memcpy( to, from, sizeof( *to ) ); + } + VectorCopy( from->origin, to->old_origin ); + } else { + memset( to, 0, sizeof( *to ) ); + from = &nullEntityState; + } + + to->number = number; + to->event = 0; + + if( !bits ) { + return; + } + + if( bits & U_MODEL ) { + to->modelindex = MSG_ReadByte(); + } + if( bits & U_MODEL2 ) { + to->modelindex2 = MSG_ReadByte(); + } + if( bits & U_MODEL3 ) { + to->modelindex3 = MSG_ReadByte(); + } + if( bits & U_MODEL4 ) { + to->modelindex4 = MSG_ReadByte(); + } + + if( bits & U_FRAME8 ) + to->frame = MSG_ReadByte(); + if( bits & U_FRAME16 ) + to->frame = MSG_ReadShort(); + + if( (bits & (U_SKIN8|U_SKIN16)) == (U_SKIN8|U_SKIN16) ) //used for laser colors + to->skinnum = MSG_ReadLong(); + else if( bits & U_SKIN8 ) + to->skinnum = MSG_ReadByte(); + else if( bits & U_SKIN16 ) + to->skinnum = MSG_ReadWord(); + + if( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) ) + to->effects = MSG_ReadLong(); + else if( bits & U_EFFECTS8 ) + to->effects = MSG_ReadByte(); + else if( bits & U_EFFECTS16 ) + to->effects = MSG_ReadWord(); + + if( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) ) + to->renderfx = MSG_ReadLong(); + else if( bits & U_RENDERFX8 ) + to->renderfx = MSG_ReadByte(); + else if( bits & U_RENDERFX16 ) + to->renderfx = MSG_ReadWord(); + + if( bits & U_ORIGIN1 ) { + to->origin[0] = MSG_ReadCoord(); + } + if( bits & U_ORIGIN2 ) { + to->origin[1] = MSG_ReadCoord(); + } + if( bits & U_ORIGIN3 ) { + to->origin[2] = MSG_ReadCoord(); + } + + if( bits & U_ANGLE1 ) { + to->angles[0] = MSG_ReadAngle(); + } + if( bits & U_ANGLE2 ) { + to->angles[1] = MSG_ReadAngle(); + } + if( bits & U_ANGLE3 ) { + to->angles[2] = MSG_ReadAngle(); + } + + if( bits & U_OLDORIGIN ) { + MSG_ReadPos( to->old_origin ); + } + + if( bits & U_SOUND ) { + to->sound = MSG_ReadByte(); + } + + if( bits & U_EVENT ) { + to->event = MSG_ReadByte(); + } + + if( bits & U_SOLID ) { + if( flags & MSG_ES_LONGSOLID ) { + to->solid = MSG_ReadLong(); + } else { + to->solid = MSG_ReadWord(); + } + } +} + +#endif // USE_CLIENT || USE_MVD_CLIENT + +#if USE_CLIENT + +/* +=================== +MSG_ParseDeltaPlayerstate_Default +=================== +*/ +void MSG_ParseDeltaPlayerstate_Default( const player_state_t *from, + player_state_t *to, + int flags ) +{ + int i; + int statbits; + + if( !to ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + + // clear to old value before delta parsing + if( from ) { + memcpy( to, from, sizeof( *to ) ); + } else { + memset( to, 0, sizeof( *to ) ); + } + + // + // parse the pmove_state_t + // + if( flags & PS_M_TYPE ) + to->pmove.pm_type = MSG_ReadByte(); + + if( flags & PS_M_ORIGIN ) { + to->pmove.origin[0] = MSG_ReadShort(); + to->pmove.origin[1] = MSG_ReadShort(); + to->pmove.origin[2] = MSG_ReadShort(); + } + + if( flags & PS_M_VELOCITY ) { + to->pmove.velocity[0] = MSG_ReadShort(); + to->pmove.velocity[1] = MSG_ReadShort(); + to->pmove.velocity[2] = MSG_ReadShort(); + } + + if( flags & PS_M_TIME ) + to->pmove.pm_time = MSG_ReadByte(); + + if( flags & PS_M_FLAGS ) + to->pmove.pm_flags = MSG_ReadByte(); + + if( flags & PS_M_GRAVITY ) + to->pmove.gravity = MSG_ReadShort(); + + if( flags & PS_M_DELTA_ANGLES ) { + to->pmove.delta_angles[0] = MSG_ReadShort(); + to->pmove.delta_angles[1] = MSG_ReadShort(); + to->pmove.delta_angles[2] = MSG_ReadShort(); + } + + // + // parse the rest of the player_state_t + // + if( flags & PS_VIEWOFFSET ) { + to->viewoffset[0] = MSG_ReadChar() * 0.25f; + to->viewoffset[1] = MSG_ReadChar() * 0.25f; + to->viewoffset[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PS_VIEWANGLES ) { + to->viewangles[0] = MSG_ReadAngle16(); + to->viewangles[1] = MSG_ReadAngle16(); + to->viewangles[2] = MSG_ReadAngle16(); + } + + if( flags & PS_KICKANGLES ) { + to->kick_angles[0] = MSG_ReadChar() * 0.25f; + to->kick_angles[1] = MSG_ReadChar() * 0.25f; + to->kick_angles[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PS_WEAPONINDEX ) { + to->gunindex = MSG_ReadByte(); + } + + if( flags & PS_WEAPONFRAME ) { + to->gunframe = MSG_ReadByte(); + to->gunoffset[0] = MSG_ReadChar() * 0.25f; + to->gunoffset[1] = MSG_ReadChar() * 0.25f; + to->gunoffset[2] = MSG_ReadChar() * 0.25f; + to->gunangles[0] = MSG_ReadChar() * 0.25f; + to->gunangles[1] = MSG_ReadChar() * 0.25f; + to->gunangles[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PS_BLEND ) { + to->blend[0] = MSG_ReadByte() / 255.0f; + to->blend[1] = MSG_ReadByte() / 255.0f; + to->blend[2] = MSG_ReadByte() / 255.0f; + to->blend[3] = MSG_ReadByte() / 255.0f; + } + + if( flags & PS_FOV ) + to->fov = MSG_ReadByte(); + + if( flags & PS_RDFLAGS ) + to->rdflags = MSG_ReadByte(); + + // parse stats + statbits = MSG_ReadLong(); + for( i = 0; i < MAX_STATS; i++ ) + if( statbits & ( 1 << i ) ) + to->stats[i] = MSG_ReadShort(); +} + + +/* +=================== +MSG_ParseDeltaPlayerstate_Default +=================== +*/ +void MSG_ParseDeltaPlayerstate_Enhanced( const player_state_t *from, + player_state_t *to, + int flags, + int extraflags ) +{ + int i; + int statbits; + + if( !to ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + + // clear to old value before delta parsing + if( from ) { + memcpy( to, from, sizeof( *to ) ); + } else { + memset( to, 0, sizeof( *to ) ); + } + + // + // parse the pmove_state_t + // + if( flags & PS_M_TYPE ) + to->pmove.pm_type = MSG_ReadByte(); + + if( flags & PS_M_ORIGIN ) { + to->pmove.origin[0] = MSG_ReadShort(); + to->pmove.origin[1] = MSG_ReadShort(); + } + + if( extraflags & EPS_M_ORIGIN2 ) { + to->pmove.origin[2] = MSG_ReadShort(); + } + + if( flags & PS_M_VELOCITY ) { + to->pmove.velocity[0] = MSG_ReadShort(); + to->pmove.velocity[1] = MSG_ReadShort(); + } + + if( extraflags & EPS_M_VELOCITY2 ) { + to->pmove.velocity[2] = MSG_ReadShort(); + } + + if( flags & PS_M_TIME ) + to->pmove.pm_time = MSG_ReadByte(); + + if( flags & PS_M_FLAGS ) + to->pmove.pm_flags = MSG_ReadByte(); + + if( flags & PS_M_GRAVITY ) + to->pmove.gravity = MSG_ReadShort(); + + if( flags & PS_M_DELTA_ANGLES ) { + to->pmove.delta_angles[0] = MSG_ReadShort(); + to->pmove.delta_angles[1] = MSG_ReadShort(); + to->pmove.delta_angles[2] = MSG_ReadShort(); + } + + // + // parse the rest of the player_state_t + // + if( flags & PS_VIEWOFFSET ) { + to->viewoffset[0] = MSG_ReadChar() * 0.25f; + to->viewoffset[1] = MSG_ReadChar() * 0.25f; + to->viewoffset[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PS_VIEWANGLES ) { + to->viewangles[0] = MSG_ReadAngle16(); + to->viewangles[1] = MSG_ReadAngle16(); + } + + if( extraflags & EPS_VIEWANGLE2 ) { + to->viewangles[2] = MSG_ReadAngle16(); + } + + if( flags & PS_KICKANGLES ) { + to->kick_angles[0] = MSG_ReadChar() * 0.25f; + to->kick_angles[1] = MSG_ReadChar() * 0.25f; + to->kick_angles[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PS_WEAPONINDEX ) { + to->gunindex = MSG_ReadByte(); + } + + if( flags & PS_WEAPONFRAME ) { + to->gunframe = MSG_ReadByte(); + } + + if( extraflags & EPS_GUNOFFSET ) { + to->gunoffset[0] = MSG_ReadChar() * 0.25f; + to->gunoffset[1] = MSG_ReadChar() * 0.25f; + to->gunoffset[2] = MSG_ReadChar() * 0.25f; + } + + if( extraflags & EPS_GUNANGLES ) { + to->gunangles[0] = MSG_ReadChar() * 0.25f; + to->gunangles[1] = MSG_ReadChar() * 0.25f; + to->gunangles[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PS_BLEND ) { + to->blend[0] = MSG_ReadByte() / 255.0f; + to->blend[1] = MSG_ReadByte() / 255.0f; + to->blend[2] = MSG_ReadByte() / 255.0f; + to->blend[3] = MSG_ReadByte() / 255.0f; + } + + if( flags & PS_FOV ) + to->fov = MSG_ReadByte(); + + if( flags & PS_RDFLAGS ) + to->rdflags = MSG_ReadByte(); + + // parse stats + if( extraflags & EPS_STATS ) { + statbits = MSG_ReadLong(); + for( i = 0; i < MAX_STATS; i++ ) { + if( statbits & ( 1 << i ) ) { + to->stats[i] = MSG_ReadShort(); + } + } + } + +} + +#endif // USE_CLIENT + +#if USE_MVD_CLIENT + +/* +=================== +MSG_ParseDeltaPlayerstate_Packet +=================== +*/ +void MSG_ParseDeltaPlayerstate_Packet( const player_state_t *from, + player_state_t *to, + int flags ) +{ + int i; + int statbits; + + if( !to ) { + Com_Error( ERR_DROP, "%s: NULL", __func__ ); + } + + // clear to old value before delta parsing + if( from ) { + memcpy( to, from, sizeof( *to ) ); + } else { + memset( to, 0, sizeof( *to ) ); + } + + // + // parse the pmove_state_t + // + if( flags & PPS_M_TYPE ) + to->pmove.pm_type = MSG_ReadByte(); + + if( flags & PPS_M_ORIGIN ) { + to->pmove.origin[0] = MSG_ReadShort(); + to->pmove.origin[1] = MSG_ReadShort(); + } + + if( flags & PPS_M_ORIGIN2 ) { + to->pmove.origin[2] = MSG_ReadShort(); + } + + // + // parse the rest of the player_state_t + // + if( flags & PPS_VIEWOFFSET ) { + to->viewoffset[0] = MSG_ReadChar() * 0.25f; + to->viewoffset[1] = MSG_ReadChar() * 0.25f; + to->viewoffset[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PPS_VIEWANGLES ) { + to->viewangles[0] = MSG_ReadAngle16(); + to->viewangles[1] = MSG_ReadAngle16(); + } + + if( flags & PPS_VIEWANGLE2 ) { + to->viewangles[2] = MSG_ReadAngle16(); + } + + if( flags & PPS_KICKANGLES ) { + to->kick_angles[0] = MSG_ReadChar() * 0.25f; + to->kick_angles[1] = MSG_ReadChar() * 0.25f; + to->kick_angles[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PPS_WEAPONINDEX ) { + to->gunindex = MSG_ReadByte(); + } + + if( flags & PPS_WEAPONFRAME ) { + to->gunframe = MSG_ReadByte(); + } + + if( flags & PPS_GUNOFFSET ) { + to->gunoffset[0] = MSG_ReadChar() * 0.25f; + to->gunoffset[1] = MSG_ReadChar() * 0.25f; + to->gunoffset[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PPS_GUNANGLES ) { + to->gunangles[0] = MSG_ReadChar() * 0.25f; + to->gunangles[1] = MSG_ReadChar() * 0.25f; + to->gunangles[2] = MSG_ReadChar() * 0.25f; + } + + if( flags & PPS_BLEND ) { + to->blend[0] = MSG_ReadByte() / 255.0f; + to->blend[1] = MSG_ReadByte() / 255.0f; + to->blend[2] = MSG_ReadByte() / 255.0f; + to->blend[3] = MSG_ReadByte() / 255.0f; + } + + if( flags & PPS_FOV ) + to->fov = MSG_ReadByte(); + + if( flags & PPS_RDFLAGS ) + to->rdflags = MSG_ReadByte(); + + // parse stats + if( flags & PPS_STATS ) { + statbits = MSG_ReadLong(); + for( i = 0; i < MAX_STATS; i++ ) { + if( statbits & ( 1 << i ) ) { + to->stats[i] = MSG_ReadShort(); + } + } + } +} + +#endif // USE_MVD_CLIENT + +#ifdef _DEBUG + +#define SHOWBITS( data ) \ + do { Com_Printf( "%s ", data ); } while( 0 ) + +#if USE_CLIENT + +void MSG_ShowDeltaPlayerstateBits_Default( int flags ) { + if( flags & PS_M_TYPE ) { + SHOWBITS( "pmove.pm_type" ); + } + + if( flags & PS_M_ORIGIN ) { + SHOWBITS( "pmove.origin" ); + } + + if( flags & PS_M_VELOCITY ) { + SHOWBITS( "pmove.velocity" ); + } + + if( flags & PS_M_TIME ) { + SHOWBITS( "pmove.pm_time" ); + } + + if( flags & PS_M_FLAGS ) { + SHOWBITS( "pmove.pm_flags" ); + } + + if( flags & PS_M_GRAVITY ) { + SHOWBITS( "pmove.gravity" ); + } + + if( flags & PS_M_DELTA_ANGLES ) { + SHOWBITS( "pmove.delta_angles" ); + } + + if( flags & PS_VIEWOFFSET ) { + SHOWBITS( "viewoffset" ); + } + + if( flags & PS_VIEWANGLES ) { + SHOWBITS( "viewangles" ); + } + + if( flags & PS_KICKANGLES ) { + SHOWBITS( "kick_angles" ); + } + + if( flags & PS_WEAPONINDEX ) { + SHOWBITS( "gunindex" ); + } + + if( flags & PS_WEAPONFRAME ) { + SHOWBITS( "gunframe" ); + } + + if( flags & PS_BLEND ) { + SHOWBITS( "blend" ); + } + + if( flags & PS_FOV ) { + SHOWBITS( "fov" ); + } + + if( flags & PS_RDFLAGS ) { + SHOWBITS( "rdflags" ); + } +} + +void MSG_ShowDeltaPlayerstateBits_Enhanced( int flags ) { + int extraflags; + + extraflags = flags >> PS_BITS; + flags &= PS_MASK; + + if( flags & PS_M_TYPE ) { + SHOWBITS( "pmove.pm_type" ); + } + + if( flags & PS_M_ORIGIN ) { + SHOWBITS( "pmove.origin[0,1]" ); + } + + if( extraflags & EPS_M_ORIGIN2 ) { + SHOWBITS( "pmove.origin[2]" ); + } + + if( flags & PS_M_VELOCITY ) { + SHOWBITS( "pmove.velocity[0,1]" ); + } + + if( extraflags & EPS_M_VELOCITY2 ) { + SHOWBITS( "pmove.velocity[2]" ); + } + + if( flags & PS_M_TIME ) { + SHOWBITS( "pmove.pm_time" ); + } + + if( flags & PS_M_FLAGS ) { + SHOWBITS( "pmove.pm_flags" ); + } + + if( flags & PS_M_GRAVITY ) { + SHOWBITS( "pmove.gravity" ); + } + + if( flags & PS_M_DELTA_ANGLES ) { + SHOWBITS( "pmove.delta_angles" ); + } + + if( flags & PS_VIEWOFFSET ) { + SHOWBITS( "viewoffset" ); + } + + if( flags & PS_VIEWANGLES ) { + SHOWBITS( "viewangles[0,1]" ); + } + + if( extraflags & EPS_VIEWANGLE2 ) { + SHOWBITS( "viewangles[2]" ); + } + + if( flags & PS_KICKANGLES ) { + SHOWBITS( "kick_angles" ); + } + + if( flags & PS_WEAPONINDEX ) { + SHOWBITS( "gunindex" ); + } + + if( flags & PS_WEAPONFRAME ) { + SHOWBITS( "gunframe" ); + } + + if( extraflags & EPS_GUNOFFSET ) { + SHOWBITS( "gunoffset" ); + } + + if( extraflags & EPS_GUNANGLES ) { + SHOWBITS( "gunangles" ); + } + + if( flags & PS_BLEND ) { + SHOWBITS( "blend" ); + } + + if( flags & PS_FOV ) { + SHOWBITS( "fov" ); + } + + if( flags & PS_RDFLAGS ) { + SHOWBITS( "rdflags" ); + } + + if( extraflags & EPS_STATS ) { + SHOWBITS( "stats" ); + } +} + + +void MSG_ShowDeltaUsercmdBits_Enhanced( int bits ) { + if( !bits ) { + SHOWBITS( "<none>" ); + return; + } + if( bits & CM_ANGLE1 ) + SHOWBITS( "angle1" ); + if( bits & CM_ANGLE2 ) + SHOWBITS( "angle2" ); + if( bits & CM_ANGLE3 ) + SHOWBITS( "angle3" ); + + if( bits & CM_FORWARD ) + SHOWBITS( "forward" ); + if( bits & CM_SIDE ) + SHOWBITS( "side" ); + if( bits & CM_UP ) + SHOWBITS( "up" ); + + if( bits & CM_BUTTONS ) + SHOWBITS( "buttons" ); + if( bits & CM_IMPULSE ) + SHOWBITS( "msec" ); +} + +#endif // USE_CLIENT + +#if USE_CLIENT || USE_MVD_CLIENT + +void MSG_ShowDeltaEntityBits( int bits ) { + if( bits & U_MODEL ) { + SHOWBITS( "modelindex" ); + } + if( bits & U_MODEL2 ) { + SHOWBITS( "modelindex2" ); + } + if( bits & U_MODEL3 ) { + SHOWBITS( "modelindex3" ); + } + if( bits & U_MODEL4 ) { + SHOWBITS( "modelindex4" ); + } + + if( bits & U_FRAME8 ) + SHOWBITS( "frame8" ); + if( bits & U_FRAME16 ) + SHOWBITS( "frame16" ); + + if( ( bits & ( U_SKIN8 | U_SKIN16 ) ) == ( U_SKIN8 | U_SKIN16 ) ) + SHOWBITS( "skinnum32" ); + else if( bits & U_SKIN8 ) + SHOWBITS( "skinnum8" ); + else if( bits & U_SKIN16 ) + SHOWBITS( "skinnum16" ); + + if( ( bits & ( U_EFFECTS8 | U_EFFECTS16 ) ) == ( U_EFFECTS8 | U_EFFECTS16 ) ) + SHOWBITS( "effects32" ); + else if( bits & U_EFFECTS8 ) + SHOWBITS( "effects8" ); + else if( bits & U_EFFECTS16 ) + SHOWBITS( "effects16" ); + + if( ( bits & ( U_RENDERFX8 | U_RENDERFX16 ) ) == ( U_RENDERFX8 | U_RENDERFX16 ) ) + SHOWBITS( "renderfx32" ); + else if( bits & U_RENDERFX8 ) + SHOWBITS( "renderfx8" ); + else if( bits & U_RENDERFX16 ) + SHOWBITS( "renderfx16" ); + + if( bits & U_ORIGIN1 ) { + SHOWBITS( "origin[0]" ); + } + if( bits & U_ORIGIN2 ) { + SHOWBITS( "origin[1]" ); + } + if( bits & U_ORIGIN3 ) { + SHOWBITS( "origin[2]" ); + } + + if( bits & U_ANGLE1 ) { + SHOWBITS( "angles[0]" ); + } + if( bits & U_ANGLE2 ) { + SHOWBITS( "angles[2]" ); + } + if( bits & U_ANGLE3 ) { + SHOWBITS( "angles[3]" ); + } + + if( bits & U_OLDORIGIN ) { + SHOWBITS( "old_origin" ); + } + + if( bits & U_SOUND ) { + SHOWBITS( "sound" ); + } + + if( bits & U_EVENT ) { + SHOWBITS( "event" ); + } + + if( bits & U_SOLID ) { + SHOWBITS( "solid" ); + } +} + +void MSG_ShowDeltaPlayerstateBits_Packet( int flags ) { + if( flags & PPS_M_TYPE ) { + SHOWBITS( "pmove.pm_type" ); + } + + if( flags & PPS_M_ORIGIN ) { + SHOWBITS( "pmove.origin[0,1]" ); + } + + if( flags & PPS_M_ORIGIN2 ) { + SHOWBITS( "pmove.origin[2]" ); + } + + if( flags & PPS_VIEWOFFSET ) { + SHOWBITS( "viewoffset" ); + } + + if( flags & PPS_VIEWANGLES ) { + SHOWBITS( "viewangles[0,1]" ); + } + + if( flags & PPS_VIEWANGLE2 ) { + SHOWBITS( "viewangles[2]" ); + } + + if( flags & PPS_KICKANGLES ) { + SHOWBITS( "kick_angles" ); + } + + if( flags & PPS_WEAPONINDEX ) { + SHOWBITS( "gunindex" ); + } + + if( flags & PPS_WEAPONFRAME ) { + SHOWBITS( "gunframe" ); + } + + if( flags & PPS_GUNOFFSET ) { + SHOWBITS( "gunoffset" ); + } + + if( flags & PPS_GUNANGLES ) { + SHOWBITS( "gunangles" ); + } + + if( flags & PPS_BLEND ) { + SHOWBITS( "blend" ); + } + + if( flags & PPS_FOV ) { + SHOWBITS( "fov" ); + } + + if( flags & PPS_RDFLAGS ) { + SHOWBITS( "rdflags" ); + } + + if( flags & PPS_STATS ) { + SHOWBITS( "stats" ); + } +} + +const char *MSG_ServerCommandString( int cmd ) { + switch( cmd ) { + case -1: return "END OF MESSAGE"; + default: return "UNKNOWN COMMAND"; +#define S(x) \ + case svc_##x: return "svc_" #x; + S(bad) + S(muzzleflash) + S(muzzleflash2) + S(temp_entity) + S(layout) + S(inventory) + S(nop) + S(disconnect) + S(reconnect) + S(sound) + S(print) + S(stufftext) + S(serverdata) + S(configstring) + S(spawnbaseline) + S(centerprint) + S(download) + S(playerinfo) + S(packetentities) + S(deltapacketentities) + S(frame) + S(zpacket) + S(zdownload) + S(gamestate) + } +} + +#endif // USE_CLIENT || USE_MVD_CLIENT + +#endif // _DEBUG + +//=========================================================================== + +void SZ_TagInit( sizebuf_t *buf, void *data, size_t length, uint32_t tag ) { + memset( buf, 0, sizeof( *buf ) ); + buf->data = data; + buf->maxsize = length; + buf->tag = tag; +} + +void SZ_Init( sizebuf_t *buf, void *data, size_t length ) { + memset( buf, 0, sizeof( *buf ) ); + buf->data = data; + buf->maxsize = length; + buf->allowoverflow = qtrue; + buf->allowunderflow = qtrue; +} + +void SZ_Clear( sizebuf_t *buf ) { + buf->cursize = 0; + buf->readcount = 0; + buf->bitpos = 0; + buf->overflowed = qfalse; +} + +void *SZ_GetSpace( sizebuf_t *buf, size_t length ) { + void *data; + + if( buf->cursize + length > buf->maxsize ) { + if( !buf->allowoverflow ) { + Com_Error( ERR_FATAL, + "%s: %#x: overflow without allowoverflow set", + __func__, buf->tag ); + } + if( length > buf->maxsize ) { + Com_Error( ERR_FATAL, + "%s: %#x: %"PRIz" is > full buffer size %"PRIz"", + __func__, buf->tag, length, buf->maxsize ); + } + + //Com_DPrintf( "%s: %#x: overflow\n", __func__, buf->tag ); + SZ_Clear( buf ); + buf->overflowed = qtrue; + } + + data = buf->data + buf->cursize; + buf->cursize += length; + buf->bitpos = buf->cursize << 3; + + return data; +} + +void SZ_WriteByte( sizebuf_t *sb, int c ) { + byte *buf; + + buf = SZ_GetSpace( sb, 1 ); + buf[0] = c; +} + +void SZ_WriteShort( sizebuf_t *sb, int c ) { + byte *buf; + + buf = SZ_GetSpace( sb, 2 ); + buf[0] = c & 0xff; + buf[1] = c >> 8; +} + +void SZ_WriteLong( sizebuf_t *sb, int c ) { + byte *buf; + + buf = SZ_GetSpace( sb, 4 ); + buf[0] = c & 0xff; + buf[1] = ( c >> 8 ) & 0xff; + buf[2] = ( c >> 16 ) & 0xff; + buf[3] = c >> 24; +} + +#if USE_MVD_SERVER + +void SZ_WriteString( sizebuf_t *sb, const char *string ) { + size_t length; + + if( !string ) { + SZ_WriteByte( sb, 0 ); + return; + } + + length = strlen( string ); + if( length >= MAX_NET_STRING ) { + Com_WPrintf( "%s: overflow: %"PRIz" chars", __func__, length ); + SZ_WriteByte( sb, 0 ); + return; + } + + SZ_Write( sb, string, length + 1 ); +} + +#endif + + |