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/common/net_encode.c

1723 lines
42 KiB
C
Raw Normal View History

2010-06-23 22:00:00 +02:00
//=======================================================================
// Copyright XashXT Group 2010 <20>
// net_encode.c - encode network messages
//=======================================================================
#include "common.h"
2010-10-07 22:00:00 +02:00
#include "netchan.h"
2010-06-23 22:00:00 +02:00
#include "mathlib.h"
2010-08-04 22:00:00 +02:00
#include "net_encode.h"
2010-08-07 22:00:00 +02:00
#include "event_api.h"
2010-10-07 22:00:00 +02:00
#include "usercmd.h"
#include "pm_movevars.h"
#include "entity_state.h"
2010-08-05 22:00:00 +02:00
#include "weaponinfo.h"
2010-10-26 22:00:00 +02:00
#include "event_args.h"
2010-10-10 22:00:00 +02:00
#include "protocol.h"
2010-08-04 22:00:00 +02:00
#define DELTA_PATH "delta.lst"
2010-10-26 22:00:00 +02:00
static qboolean delta_init = false;
2010-08-04 22:00:00 +02:00
// list of all the struct names
static const delta_field_t cmd_fields[] =
{
{ UCMD_DEF(lerp_msec) },
{ UCMD_DEF(msec) },
{ UCMD_DEF(viewangles[0]) },
{ UCMD_DEF(viewangles[1]) },
{ UCMD_DEF(viewangles[2]) },
{ UCMD_DEF(forwardmove) },
{ UCMD_DEF(sidemove) },
{ UCMD_DEF(upmove) },
{ UCMD_DEF(lightlevel) },
{ UCMD_DEF(buttons) },
{ UCMD_DEF(impulse) },
{ UCMD_DEF(weaponselect) },
{ UCMD_DEF(impact_index) },
{ UCMD_DEF(impact_position[0])},
{ UCMD_DEF(impact_position[1])},
{ UCMD_DEF(impact_position[2])},
{ NULL },
};
2010-08-05 22:00:00 +02:00
static const delta_field_t pm_fields[] =
{
{ PHYS_DEF( gravity ) },
{ PHYS_DEF( stopspeed ) },
{ PHYS_DEF( maxspeed ) },
{ PHYS_DEF( spectatormaxspeed ) },
{ PHYS_DEF( accelerate ) },
{ PHYS_DEF( airaccelerate ) },
{ PHYS_DEF( wateraccelerate ) },
{ PHYS_DEF( friction ) },
{ PHYS_DEF( edgefriction ) },
{ PHYS_DEF( waterfriction ) },
{ PHYS_DEF( bounce ) },
{ PHYS_DEF( stepsize ) },
{ PHYS_DEF( maxvelocity ) },
2010-08-15 22:00:00 +02:00
{ PHYS_DEF( zmax ) },
{ PHYS_DEF( waveHeight ) },
2010-08-05 22:00:00 +02:00
{ PHYS_DEF( footsteps ) },
2010-08-15 22:00:00 +02:00
{ PHYS_DEF( skyName ) },
2010-08-05 22:00:00 +02:00
{ PHYS_DEF( rollangle ) },
{ PHYS_DEF( rollspeed ) },
2010-08-15 22:00:00 +02:00
{ PHYS_DEF( skycolor_r ) },
{ PHYS_DEF( skycolor_g ) },
{ PHYS_DEF( skycolor_b ) },
{ PHYS_DEF( skyvec_x ) },
{ PHYS_DEF( skyvec_y ) },
{ PHYS_DEF( skyvec_z ) },
2011-02-15 22:00:00 +01:00
{ PHYS_DEF( studio_scale ) },
2010-08-05 22:00:00 +02:00
{ NULL },
};
2010-08-04 22:00:00 +02:00
static const delta_field_t ev_fields[] =
{
{ EVNT_DEF( flags ) },
{ EVNT_DEF( entindex ) },
{ EVNT_DEF( origin[0] ) },
{ EVNT_DEF( origin[1] ) },
{ EVNT_DEF( origin[2] ) },
{ EVNT_DEF( angles[0] ) },
{ EVNT_DEF( angles[1] ) },
{ EVNT_DEF( angles[2] ) },
{ EVNT_DEF( velocity[0] ) },
{ EVNT_DEF( velocity[1] ) },
{ EVNT_DEF( velocity[2] ) },
{ EVNT_DEF( ducking ) },
{ EVNT_DEF( fparam1 ) },
{ EVNT_DEF( fparam2 ) },
{ EVNT_DEF( iparam1 ) },
{ EVNT_DEF( iparam2 ) },
{ EVNT_DEF( bparam1 ) },
{ EVNT_DEF( bparam2 ) },
{ NULL },
};
2010-08-05 22:00:00 +02:00
static const delta_field_t wd_fields[] =
{
{ WPDT_DEF( m_iId ) },
{ WPDT_DEF( m_iClip ) },
{ WPDT_DEF( m_flNextPrimaryAttack ) },
{ WPDT_DEF( m_flNextSecondaryAttack ) },
{ WPDT_DEF( m_flTimeWeaponIdle ) },
{ WPDT_DEF( m_fInReload ) },
{ WPDT_DEF( m_fInSpecialReload ) },
{ WPDT_DEF( m_flNextReload ) },
{ WPDT_DEF( m_flPumpTime ) },
{ WPDT_DEF( m_fReloadTime ) },
{ WPDT_DEF( m_fAimedDamage ) },
{ WPDT_DEF( m_fNextAimBonus ) },
{ WPDT_DEF( m_fInZoom ) },
{ WPDT_DEF( m_iWeaponState ) },
{ WPDT_DEF( iuser1 ) },
{ WPDT_DEF( iuser2 ) },
{ WPDT_DEF( iuser3 ) },
{ WPDT_DEF( iuser4 ) },
{ WPDT_DEF( fuser1 ) },
{ WPDT_DEF( fuser2 ) },
{ WPDT_DEF( fuser3 ) },
{ WPDT_DEF( fuser4 ) },
{ NULL },
};
2010-08-04 22:00:00 +02:00
static const delta_field_t cd_fields[] =
{
{ CLDT_DEF( origin[0] ) },
{ CLDT_DEF( origin[1] ) },
{ CLDT_DEF( origin[2] ) },
{ CLDT_DEF( velocity[0] ) },
{ CLDT_DEF( velocity[1] ) },
{ CLDT_DEF( velocity[2] ) },
{ CLDT_DEF( viewmodel ) },
{ CLDT_DEF( punchangle[0] ) },
{ CLDT_DEF( punchangle[1] ) },
{ CLDT_DEF( punchangle[2] ) },
{ CLDT_DEF( flags ) },
{ CLDT_DEF( waterlevel ) },
{ CLDT_DEF( watertype ) },
{ CLDT_DEF( view_ofs[0] ) },
{ CLDT_DEF( view_ofs[1] ) },
{ CLDT_DEF( view_ofs[2] ) },
{ CLDT_DEF( health ) },
{ CLDT_DEF( bInDuck ) },
{ CLDT_DEF( weapons ) },
{ CLDT_DEF( flTimeStepSound ) },
{ CLDT_DEF( flDuckTime ) },
{ CLDT_DEF( flSwimTime ) },
{ CLDT_DEF( waterjumptime ) },
{ CLDT_DEF( maxspeed ) },
{ CLDT_DEF( fov ) },
{ CLDT_DEF( weaponanim ) },
{ CLDT_DEF( m_iId ) },
{ CLDT_DEF( ammo_shells ) },
{ CLDT_DEF( ammo_nails ) },
{ CLDT_DEF( ammo_cells ) },
{ CLDT_DEF( ammo_rockets ) },
{ CLDT_DEF( m_flNextAttack ) },
{ CLDT_DEF( tfstate ) },
{ CLDT_DEF( pushmsec ) },
{ CLDT_DEF( deadflag ) },
{ CLDT_DEF( physinfo ) },
{ CLDT_DEF( iuser1 ) },
{ CLDT_DEF( iuser2 ) },
{ CLDT_DEF( iuser3 ) },
{ CLDT_DEF( iuser4 ) },
{ CLDT_DEF( fuser1 ) },
{ CLDT_DEF( fuser2 ) },
{ CLDT_DEF( fuser3 ) },
{ CLDT_DEF( fuser4 ) },
{ CLDT_DEF( vuser1[0] ) },
{ CLDT_DEF( vuser1[1] ) },
{ CLDT_DEF( vuser1[2] ) },
{ CLDT_DEF( vuser2[0] ) },
{ CLDT_DEF( vuser2[1] ) },
{ CLDT_DEF( vuser2[2] ) },
{ CLDT_DEF( vuser3[0] ) },
{ CLDT_DEF( vuser3[1] ) },
{ CLDT_DEF( vuser3[2] ) },
{ CLDT_DEF( vuser4[0] ) },
{ CLDT_DEF( vuser4[1] ) },
{ CLDT_DEF( vuser4[2] ) },
{ NULL },
};
static const delta_field_t ent_fields[] =
{
2010-08-15 22:00:00 +02:00
{ ENTS_DEF( entityType ) },
2010-08-04 22:00:00 +02:00
{ ENTS_DEF( origin[0] ) },
{ ENTS_DEF( origin[1] ) },
{ ENTS_DEF( origin[2] ) },
{ ENTS_DEF( angles[0] ) },
{ ENTS_DEF( angles[1] ) },
{ ENTS_DEF( angles[2] ) },
{ ENTS_DEF( modelindex ) },
{ ENTS_DEF( sequence ) },
{ ENTS_DEF( frame ) },
{ ENTS_DEF( colormap ) },
{ ENTS_DEF( skin ) },
{ ENTS_DEF( solid ) },
{ ENTS_DEF( effects ) },
{ ENTS_DEF( scale ) },
{ ENTS_DEF( eflags ) },
{ ENTS_DEF( rendermode ) },
{ ENTS_DEF( renderamt ) },
{ ENTS_DEF( rendercolor.r ) },
{ ENTS_DEF( rendercolor.g ) },
{ ENTS_DEF( rendercolor.b ) },
{ ENTS_DEF( renderfx ) },
{ ENTS_DEF( movetype ) },
{ ENTS_DEF( animtime ) },
{ ENTS_DEF( framerate ) },
{ ENTS_DEF( body ) },
{ ENTS_DEF( controller[0] ) },
{ ENTS_DEF( controller[1] ) },
{ ENTS_DEF( controller[2] ) },
{ ENTS_DEF( controller[3] ) },
{ ENTS_DEF( blending[0] ) },
{ ENTS_DEF( blending[1] ) },
{ ENTS_DEF( blending[2] ) },
{ ENTS_DEF( blending[3] ) },
{ ENTS_DEF( velocity[0] ) },
{ ENTS_DEF( velocity[1] ) },
{ ENTS_DEF( velocity[2] ) },
{ ENTS_DEF( mins[0] ) },
{ ENTS_DEF( mins[1] ) },
{ ENTS_DEF( mins[2] ) },
{ ENTS_DEF( maxs[0] ) },
{ ENTS_DEF( maxs[1] ) },
{ ENTS_DEF( maxs[2] ) },
{ ENTS_DEF( aiment ) },
{ ENTS_DEF( owner ) },
{ ENTS_DEF( friction ) },
{ ENTS_DEF( gravity ) },
{ ENTS_DEF( team ) },
{ ENTS_DEF( playerclass ) },
{ ENTS_DEF( health ) },
{ ENTS_DEF( spectator ) },
{ ENTS_DEF( weaponmodel ) },
{ ENTS_DEF( gaitsequence ) },
{ ENTS_DEF( basevelocity[0] ) },
{ ENTS_DEF( basevelocity[1] ) },
{ ENTS_DEF( basevelocity[2] ) },
{ ENTS_DEF( usehull ) },
{ ENTS_DEF( oldbuttons ) }, // probably never transmitted
{ ENTS_DEF( onground ) },
{ ENTS_DEF( iStepLeft ) },
{ ENTS_DEF( flFallVelocity ) },
{ ENTS_DEF( fov ) },
{ ENTS_DEF( weaponanim ) },
{ ENTS_DEF( startpos[0] ) },
{ ENTS_DEF( startpos[1] ) },
{ ENTS_DEF( startpos[2] ) },
{ ENTS_DEF( endpos[0] ) },
{ ENTS_DEF( endpos[1] ) },
{ ENTS_DEF( endpos[2] ) },
{ ENTS_DEF( impacttime ) },
{ ENTS_DEF( starttime ) },
{ ENTS_DEF( iuser1 ) },
{ ENTS_DEF( iuser2 ) },
{ ENTS_DEF( iuser3 ) },
{ ENTS_DEF( iuser4 ) },
{ ENTS_DEF( fuser1 ) },
{ ENTS_DEF( fuser2 ) },
{ ENTS_DEF( fuser3 ) },
{ ENTS_DEF( fuser4 ) },
{ ENTS_DEF( vuser1[0] ) },
{ ENTS_DEF( vuser1[1] ) },
{ ENTS_DEF( vuser1[2] ) },
{ ENTS_DEF( vuser2[0] ) },
{ ENTS_DEF( vuser2[1] ) },
{ ENTS_DEF( vuser2[2] ) },
{ ENTS_DEF( vuser3[0] ) },
{ ENTS_DEF( vuser3[1] ) },
{ ENTS_DEF( vuser3[2] ) },
{ ENTS_DEF( vuser4[0] ) },
{ ENTS_DEF( vuser4[1] ) },
{ ENTS_DEF( vuser4[2] ) },
{ NULL },
};
static delta_info_t dt_info[] =
{
{ "event_t", ev_fields, NUM_FIELDS( ev_fields ) },
2010-08-05 22:00:00 +02:00
{ "movevars_t", pm_fields, NUM_FIELDS( pm_fields ) },
2010-08-04 22:00:00 +02:00
{ "usercmd_t", cmd_fields, NUM_FIELDS( cmd_fields ) },
{ "clientdata_t", cd_fields, NUM_FIELDS( cd_fields ) },
2010-08-05 22:00:00 +02:00
{ "weapon_data_t", wd_fields, NUM_FIELDS( wd_fields ) },
2010-08-04 22:00:00 +02:00
{ "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
{ "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
{ "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
{ NULL },
};
delta_info_t *Delta_FindStruct( const char *name )
{
int i;
if( !name || !name[0] )
return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
{
if( !com.stricmp( dt_info[i].pName, name ))
return &dt_info[i];
}
MsgDev( D_WARN, "Struct %s not found in delta_info\n", name );
// found nothing
return NULL;
}
2010-08-05 22:00:00 +02:00
int Delta_NumTables( void )
{
return NUM_FIELDS( dt_info );
}
delta_info_t *Delta_FindStructByIndex( int index )
{
if( index < 0 || index >= NUM_FIELDS( dt_info ))
return NULL;
return &dt_info[index];
}
delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
{
int i;
if( !encoderName || !encoderName[0] )
return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
{
if( !com.stricmp( dt_info[i].funcName, encoderName ))
return &dt_info[i];
}
// found nothing
return NULL;
}
delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
{
int i;
if( !pFields ) return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
{
if( dt_info[i].pFields == pFields )
return &dt_info[i];
}
// found nothing
return NULL;
}
void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *to )
{
int i;
ASSERT( dt != NULL );
// set all fields is active by default
for( i = 0; i < dt->numFields; i++ )
dt->pFields[i].bInactive = false;
if( dt->userCallback )
{
dt->userCallback( dt->pFields, from, to );
}
}
2010-08-04 22:00:00 +02:00
delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
{
if( !fieldName || !*fieldName )
return NULL;
for( ; pInfo->name; pInfo++ )
{
if( !com.strcmp( pInfo->name, fieldName ))
return (delta_field_t *)pInfo;
}
return NULL;
}
2010-08-05 22:00:00 +02:00
int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
{
int i;
if( !fieldName || !*fieldName )
return -1;
for( i = 0; pInfo->name; i++, pInfo++ )
{
if( !com.strcmp( pInfo->name, fieldName ))
return i;
}
return -1;
}
2010-10-26 22:00:00 +02:00
qboolean Delta_AddField( const char *pStructName, const char *pName, int flags, int bits, float mul, float post_mul )
2010-08-04 22:00:00 +02:00
{
delta_info_t *dt;
delta_field_t *pFieldInfo;
delta_t *pField;
int i;
// get the delta struct
dt = Delta_FindStruct( pStructName );
ASSERT( dt != NULL );
// check for coexisting field
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
{
if( !com.strcmp( pField->name, pName ))
{
2010-12-27 22:00:00 +01:00
MsgDev( D_NOTE, "Delta_Add: %s->%s already existing\n", pStructName, pName );
2010-08-04 22:00:00 +02:00
return false; // field already exist
}
}
// find field description
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName );
if( !pFieldInfo )
{
MsgDev( D_ERROR, "Delta_Add: couldn't find description for %s->%s\n", pStructName, pName );
return false;
}
if( dt->numFields + 1 > dt->maxFields )
{
MsgDev( D_WARN, "Delta_Add: can't add %s->%s encoder list is full\n", pStructName, pName );
return false; // too many fields specified (duplicated ?)
}
// allocate a new one
dt->pFields = Z_Realloc( dt->pFields, (dt->numFields + 1) * sizeof( delta_t ));
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ );
// copy info to new field
pField->name = pFieldInfo->name;
pField->offset = pFieldInfo->offset;
2010-08-05 22:00:00 +02:00
pField->size = pFieldInfo->size;
2010-08-04 22:00:00 +02:00
pField->flags = flags;
pField->bits = bits;
2010-08-05 22:00:00 +02:00
pField->multiplier = mul;
pField->post_multiplier = post_mul;
2010-08-04 22:00:00 +02:00
dt->numFields++;
return true;
}
2010-08-06 22:00:00 +02:00
void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t *pField )
2010-08-05 22:00:00 +02:00
{
int nameIndex;
delta_info_t *dt;
ASSERT( pField );
if( !pField->name || !*pField->name )
return; // not initialized ?
dt = Delta_FindStructByIndex( tableIndex );
ASSERT( dt && dt->bInitialized );
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );
BF_WriteByte( msg, svc_deltatable );
BF_WriteUBitLong( msg, tableIndex, 4 ); // assume we support 16 network tables
BF_WriteUBitLong( msg, nameIndex, 8 ); // 255 fields by struct should be enough
BF_WriteUBitLong( msg, pField->flags, 8 ); // flags is full, expand to 10 bits ?
BF_WriteUBitLong( msg, pField->bits - 1, 5 ); // max received value is 32 (32 bit)
// multipliers is null-compressed
if( pField->multiplier != 1.0f )
{
BF_WriteOneBit( msg, 1 );
BF_WriteFloat( msg, pField->multiplier );
}
else BF_WriteOneBit( msg, 0 );
if( pField->post_multiplier != 1.0f )
{
BF_WriteOneBit( msg, 1 );
BF_WriteFloat( msg, pField->post_multiplier );
}
else BF_WriteOneBit( msg, 0 );
}
2010-08-06 22:00:00 +02:00
void Delta_ParseTableField( sizebuf_t *msg )
2010-08-05 22:00:00 +02:00
{
int tableIndex, nameIndex;
float mul = 1.0f, post_mul = 1.0f;
int flags, bits;
const char *pName;
delta_info_t *dt;
tableIndex = BF_ReadUBitLong( msg, 4 );
dt = Delta_FindStructByIndex( tableIndex );
ASSERT( dt != NULL );
nameIndex = BF_ReadUBitLong( msg, 8 ); // read field name index
ASSERT( nameIndex >= 0 && nameIndex < dt->maxFields );
pName = dt->pInfo[nameIndex].name;
flags = BF_ReadUBitLong( msg, 8 );
bits = BF_ReadUBitLong( msg, 5 ) + 1;
// read the multipliers
if( BF_ReadOneBit( msg ))
mul = BF_ReadFloat( msg );
if( BF_ReadOneBit( msg ))
post_mul = BF_ReadFloat( msg );
// delta encoders it's already initialized on this machine
if( delta_init ) return;
// add field to table
Delta_AddField( dt->pName, pName, flags, bits, mul, post_mul );
}
2011-03-01 22:00:00 +01:00
qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
string token;
2010-08-04 22:00:00 +02:00
delta_field_t *pFieldInfo;
2011-03-01 22:00:00 +01:00
char *oldpos;
2010-08-04 22:00:00 +02:00
2011-03-01 22:00:00 +01:00
*delta_script = COM_ParseFile( *delta_script, token );
if( com.strcmp( token, "(" ))
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ParseField: expected '(', found '%s' instead\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
// read the variable name
2011-03-01 22:00:00 +01:00
if(( *delta_script = COM_ParseFile( *delta_script, token )) == NULL )
2010-08-04 22:00:00 +02:00
{
MsgDev( D_ERROR, "Delta_ParseField: missing field name\n" );
return false;
}
2011-03-01 22:00:00 +01:00
pFieldInfo = Delta_FindFieldInfo( pInfo, token );
2010-08-04 22:00:00 +02:00
if( !pFieldInfo )
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ParseField: unable to find field %s\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
2011-03-01 22:00:00 +01:00
*delta_script = COM_ParseFile( *delta_script, token );
if( com.strcmp( token, "," ))
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ParseField: expected ',', found '%s' instead\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
// copy base info to new field
pField->name = pFieldInfo->name;
pField->offset = pFieldInfo->offset;
2010-08-05 22:00:00 +02:00
pField->size = pFieldInfo->size;
2010-08-04 22:00:00 +02:00
pField->flags = 0;
// read delta-flags
2011-03-01 22:00:00 +01:00
while(( *delta_script = COM_ParseFile( *delta_script, token )) != NULL )
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
if( !com.strcmp( token, "," ))
2010-08-04 22:00:00 +02:00
break; // end of flags argument
2011-03-01 22:00:00 +01:00
if( !com.strcmp( token, "|" ))
2010-08-04 22:00:00 +02:00
continue;
2011-03-01 22:00:00 +01:00
if( !com.strcmp( token, "DT_BYTE" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_BYTE;
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DT_SHORT" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_SHORT;
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DT_FLOAT" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_FLOAT;
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DT_INTEGER" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_INTEGER;
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DT_ANGLE" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_ANGLE;
2011-03-01 22:00:00 +01:00
else if( !com.strncmp( token, "DT_TIMEWINDOW", 13 ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_TIMEWINDOW;
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DT_STRING" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_STRING;
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DT_SIGNED" ))
2010-08-04 22:00:00 +02:00
pField->flags |= DT_SIGNED;
}
2011-03-01 22:00:00 +01:00
if( com.strcmp( token, "," ))
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ParseField: expected ',', found '%s' instead\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
// read delta-bits
2011-03-01 22:00:00 +01:00
if(( *delta_script = COM_ParseFile( *delta_script, token )) == NULL )
2010-08-04 22:00:00 +02:00
{
MsgDev( D_ERROR, "Delta_ReadField: %s field bits argument is missing\n", pField->name );
return false;
}
2011-03-01 22:00:00 +01:00
pField->bits = com.atoi( token );
*delta_script = COM_ParseFile( *delta_script, token );
if( com.strcmp( token, "," ))
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ReadField: expected ',', found '%s' instead\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
// read delta-multiplier
2011-03-01 22:00:00 +01:00
if(( *delta_script = COM_ParseFile( *delta_script, token )) == NULL )
2010-08-04 22:00:00 +02:00
{
MsgDev( D_ERROR, "Delta_ReadField: %s missing 'multiplier' argument\n", pField->name );
return false;
}
2011-03-01 22:00:00 +01:00
pField->multiplier = com.atof( token );
2010-08-04 22:00:00 +02:00
if( bPost )
{
2011-03-01 22:00:00 +01:00
*delta_script = COM_ParseFile( *delta_script, token );
if( com.strcmp( token, "," ))
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ReadField: expected ',', found '%s' instead\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
// read delta-postmultiplier
2011-03-01 22:00:00 +01:00
if(( *delta_script = COM_ParseFile( *delta_script, token )) == NULL )
2010-08-04 22:00:00 +02:00
{
MsgDev( D_ERROR, "Delta_ReadField: %s missing 'post_multiply' argument\n", pField->name );
return false;
}
2011-03-01 22:00:00 +01:00
pField->post_multiplier = com.atof( token );
2010-08-04 22:00:00 +02:00
}
else
{
// to avoid division by zero
pField->post_multiplier = 1.0f;
}
// closing brace...
2011-03-01 22:00:00 +01:00
*delta_script = COM_ParseFile( *delta_script, token );
if( com.strcmp( token, ")" ))
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
MsgDev( D_ERROR, "Delta_ParseField: expected ')', found '%s' instead\n", token );
2010-08-04 22:00:00 +02:00
return false;
}
// ... and trying to parse optional ',' post-symbol
2011-03-01 22:00:00 +01:00
oldpos = *delta_script;
*delta_script = COM_ParseFile( *delta_script, token );
if( token[0] != ',' ) *delta_script = oldpos; // not a ','
2010-08-04 22:00:00 +02:00
return true;
}
2011-03-01 22:00:00 +01:00
void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char *encodeDll, const char *encodeFunc )
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
string token;
2010-08-04 22:00:00 +02:00
delta_t *pField;
const delta_field_t *pInfo;
// allocate the delta-structures
if( !dt->pFields ) dt->pFields = (delta_t *)Z_Malloc( dt->maxFields * sizeof( delta_t ));
pField = dt->pFields;
pInfo = dt->pInfo;
dt->numFields = 0;
// assume we have handled '{'
2011-03-01 22:00:00 +01:00
while(( *delta_script = COM_ParseFile( *delta_script, token )) != NULL )
2010-08-04 22:00:00 +02:00
{
ASSERT( dt->numFields <= dt->maxFields );
2011-03-01 22:00:00 +01:00
if( !com.strcmp( token, "DEFINE_DELTA" ))
2010-08-04 22:00:00 +02:00
{
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], false ))
dt->numFields++;
}
2011-03-01 22:00:00 +01:00
else if( !com.strcmp( token, "DEFINE_DELTA_POST" ))
2010-08-04 22:00:00 +02:00
{
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], true ))
dt->numFields++;
}
2011-03-01 22:00:00 +01:00
else if( token[0] == '}' )
2010-08-04 22:00:00 +02:00
{
// end of the section
break;
}
}
// copy function name
com.strncpy( dt->funcName, encodeFunc, sizeof( dt->funcName ));
if( !com.stricmp( encodeDll, "none" ))
dt->customEncode = CUSTOM_NONE;
else if( !com.stricmp( encodeDll, "gamedll" ))
2010-10-17 22:00:00 +02:00
dt->customEncode = CUSTOM_SERVER_ENCODE;
2010-08-04 22:00:00 +02:00
else if( !com.stricmp( encodeDll, "clientdll" ))
dt->customEncode = CUSTOM_CLIENT_ENCODE;
// adjust to fit memory size
if( dt->numFields < dt->maxFields )
{
dt->pFields = Z_Realloc( dt->pFields, dt->numFields * sizeof( delta_t ));
}
dt->bInitialized = true; // table is ok
}
void Delta_InitFields( void )
{
2011-03-01 22:00:00 +01:00
char *afile, *pfile;
string encodeDll, encodeFunc, token;
2010-08-04 22:00:00 +02:00
delta_info_t *dt;
2011-03-01 22:00:00 +01:00
afile = FS_LoadFile( DELTA_PATH, NULL );
if( !afile )
2010-08-15 22:00:00 +02:00
{
static string errormsg;
com.snprintf( errormsg, sizeof( errormsg ), "DELTA_Load: couldn't load file %s\n", DELTA_PATH );
SV_SysError( errormsg );
com.error( errormsg );
}
2010-08-04 22:00:00 +02:00
2011-03-01 22:00:00 +01:00
pfile = afile;
while(( pfile = COM_ParseFile( pfile, token )) != NULL )
2010-08-04 22:00:00 +02:00
{
2011-03-01 22:00:00 +01:00
dt = Delta_FindStruct( token );
if( dt == NULL )
{
Sys_Break( "delta.lst: unknown struct %s\n", token );
}
2010-08-04 22:00:00 +02:00
2011-03-01 22:00:00 +01:00
pfile = COM_ParseFile( pfile, encodeDll );
2010-08-04 22:00:00 +02:00
if( !com.stricmp( encodeDll, "none" ))
com.strcpy( encodeFunc, "null" );
2011-03-01 22:00:00 +01:00
else pfile = COM_ParseFile( pfile, encodeFunc );
2010-08-04 22:00:00 +02:00
// jump to '{'
2011-03-01 22:00:00 +01:00
pfile = COM_ParseFile( pfile, token );
if( token[0] != '{' )
{
Sys_Break( "delta.lst: missing '{' in section %s\n", dt->pName );
}
Delta_ParseTable( &pfile, dt, encodeDll, encodeFunc );
2010-08-04 22:00:00 +02:00
}
2011-03-01 22:00:00 +01:00
Mem_Free( afile );
2010-08-04 22:00:00 +02:00
// adding some requrid fields fields that use may forget or don't know how to specified
2010-08-05 22:00:00 +02:00
Delta_AddField( "event_t", "flags", DT_INTEGER, 8, 1.0f, 1.0f );
2010-12-27 22:00:00 +01:00
Delta_AddField( "event_t", "velocity[0]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f );
Delta_AddField( "event_t", "velocity[1]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f );
Delta_AddField( "event_t", "velocity[2]", DT_SIGNED | DT_FLOAT, 16, 8.0f, 1.0f );
2010-08-04 22:00:00 +02:00
}
void Delta_Init( void )
{
2010-08-06 22:00:00 +02:00
delta_info_t *dt;
2010-08-07 22:00:00 +02:00
// shutdown it first
if( delta_init ) Delta_Shutdown ();
2010-08-06 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
Delta_InitFields (); // initialize fields
2010-08-06 22:00:00 +02:00
delta_init = true;
dt = Delta_FindStruct( "movevars_t" );
ASSERT( dt != NULL );
if( dt->bInitialized ) return; // specified by user
// create movevars_t delta
Delta_AddField( "movevars_t", "gravity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "stopspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "maxspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "spectatormaxspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "accelerate", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "airaccelerate", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "wateraccelerate", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "friction", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "edgefriction", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "waterfriction", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "bounce", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
Delta_AddField( "movevars_t", "stepsize", DT_FLOAT|DT_SIGNED, 16, 16.0f, 1.0f );
Delta_AddField( "movevars_t", "maxvelocity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
2010-08-15 22:00:00 +02:00
Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f ); // no fractional part
2010-11-15 22:00:00 +01:00
Delta_AddField( "movevars_t", "waveHeight", DT_FLOAT|DT_SIGNED, 16, 16.0f, 8.0f );
2010-08-15 22:00:00 +02:00
Delta_AddField( "movevars_t", "skyName", DT_STRING, 1, 1.0f, 1.0f );
2010-08-06 22:00:00 +02:00
Delta_AddField( "movevars_t", "footsteps", DT_INTEGER, 1, 1.0f, 1.0f );
Delta_AddField( "movevars_t", "rollangle", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
Delta_AddField( "movevars_t", "rollspeed", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f );
2010-08-15 22:00:00 +02:00
Delta_AddField( "movevars_t", "skycolor_r", DT_FLOAT|DT_SIGNED, 9, 1.0f, 1.0f ); // 0 - 264
Delta_AddField( "movevars_t", "skycolor_g", DT_FLOAT|DT_SIGNED, 9, 1.0f, 1.0f );
Delta_AddField( "movevars_t", "skycolor_b", DT_FLOAT|DT_SIGNED, 9, 1.0f, 1.0f );
Delta_AddField( "movevars_t", "skyvec_x", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); // 0 - 1
Delta_AddField( "movevars_t", "skyvec_y", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
Delta_AddField( "movevars_t", "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
2011-02-15 22:00:00 +01:00
Delta_AddField( "movevars_t", "studio_scale", DT_INTEGER, 1, 1.0f, 1.0f );
2010-08-06 22:00:00 +02:00
// now done
dt->bInitialized = true;
2010-08-04 22:00:00 +02:00
}
2010-08-07 22:00:00 +02:00
void Delta_InitClient( void )
{
int i, numActive = 0;
// already initalized
if( delta_init ) return;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
{
if( dt_info[i].numFields > 0 )
{
dt_info[i].bInitialized = true;
numActive++;
}
}
if( numActive ) delta_init = true;
}
2010-08-04 22:00:00 +02:00
void Delta_Shutdown( void )
{
2010-08-05 22:00:00 +02:00
int i;
2010-08-06 22:00:00 +02:00
if( !delta_init ) return;
2010-08-05 22:00:00 +02:00
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
{
2010-08-06 22:00:00 +02:00
dt_info[i].numFields = 0;
dt_info[i].customEncode = CUSTOM_NONE;
dt_info[i].userCallback = NULL;
dt_info[i].funcName[0] = '\0';
2010-08-05 22:00:00 +02:00
if( dt_info[i].pFields )
{
Z_Free( dt_info[i].pFields );
dt_info[i].pFields = NULL;
}
2010-08-06 22:00:00 +02:00
dt_info[i].bInitialized = false;
2010-08-05 22:00:00 +02:00
}
2010-08-06 22:00:00 +02:00
delta_init = false;
2010-08-04 22:00:00 +02:00
}
/*
=====================
Delta_CompareField
compare fields by offsets
assume from and to is valid
=====================
*/
2010-10-26 22:00:00 +02:00
qboolean Delta_CompareField( delta_t *pField, void *from, void *to )
2010-08-04 22:00:00 +02:00
{
int fromF, toF;
ASSERT( pField );
ASSERT( from );
ASSERT( to );
2010-08-05 22:00:00 +02:00
if( pField->bInactive )
return true;
2010-08-04 22:00:00 +02:00
fromF = toF = 0;
if( pField->flags & DT_BYTE )
{
if( pField->flags & DT_SIGNED )
{
fromF = *(signed char *)((byte *)from + pField->offset );
toF = *(signed char *)((byte *)to + pField->offset );
}
else
{
fromF = *(byte *)((byte *)from + pField->offset );
toF = *(byte *)((byte *)to + pField->offset );
}
}
else if( pField->flags & DT_SHORT )
{
if( pField->flags & DT_SIGNED )
{
fromF = *(short *)((byte *)from + pField->offset );
toF = *(short *)((byte *)to + pField->offset );
}
else
{
fromF = *(word *)((byte *)from + pField->offset );
toF = *(word *)((byte *)to + pField->offset );
}
}
else if( pField->flags & DT_INTEGER )
{
if( pField->flags & DT_SIGNED )
{
fromF = *(int *)((byte *)from + pField->offset );
toF = *(int *)((byte *)to + pField->offset );
}
else
{
fromF = *(uint *)((byte *)from + pField->offset );
toF = *(uint *)((byte *)to + pField->offset );
}
}
else if( pField->flags & ( DT_FLOAT|DT_ANGLE|DT_TIMEWINDOW ))
{
// don't convert floats to integers
fromF = *((int *)((byte *)from + pField->offset ));
toF = *((int *)((byte *)to + pField->offset ));
}
else if( pField->flags & DT_STRING )
{
// compare strings
char *s1 = (char *)((byte *)from + pField->offset );
char *s2 = (char *)((byte *)to + pField->offset );
// 0 is equal, otherwise not equal
toF = com.strcmp( s1, s2 );
}
return ( fromF == toF ) ? true : false;
}
/*
=====================
Delta_WriteField
write fields by offsets
assume from and to is valid
=====================
*/
2010-10-26 22:00:00 +02:00
qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase )
2010-08-04 22:00:00 +02:00
{
2010-10-26 22:00:00 +02:00
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
2010-08-05 22:00:00 +02:00
float flValue, flAngle, flTime;
uint iValue;
const char *pStr;
2010-08-04 22:00:00 +02:00
if( Delta_CompareField( pField, from, to ))
{
BF_WriteOneBit( msg, 0 ); // unchanged
return false;
}
BF_WriteOneBit( msg, 1 ); // changed
if( pField->flags & DT_BYTE )
{
iValue = *(byte *)((byte *)to + pField->offset );
iValue *= pField->multiplier;
BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
}
else if( pField->flags & DT_SHORT )
{
iValue = *(word *)((byte *)to + pField->offset );
iValue *= pField->multiplier;
BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
}
else if( pField->flags & DT_INTEGER )
{
iValue = *(uint *)((byte *)to + pField->offset );
iValue *= pField->multiplier;
BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
}
else if( pField->flags & DT_FLOAT )
{
flValue = *(float *)((byte *)to + pField->offset );
iValue = (int)(flValue * pField->multiplier);
BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
}
else if( pField->flags & DT_ANGLE )
{
flAngle = *(float *)((byte *)to + pField->offset );
// NOTE: never applies multipliers to angle because
// result may be wrong on client-side
BF_WriteBitAngle( msg, flAngle, pField->bits );
}
else if( pField->flags & DT_TIMEWINDOW )
{
flValue = *(float *)((byte *)to + pField->offset );
flTime = ( timebase - flValue );
iValue = (uint)( flTime * 1000 );
BF_WriteBitLong( msg, iValue, pField->bits, bSigned );
}
2010-08-05 22:00:00 +02:00
else if( pField->flags & DT_STRING )
{
pStr = (char *)((byte *)to + pField->offset );
BF_WriteString( msg, pStr );
}
2010-08-04 22:00:00 +02:00
return true;
}
/*
=====================
Delta_ReadField
read fields by offsets
assume from and to is valid
=====================
*/
2010-10-26 22:00:00 +02:00
qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, float timebase )
2010-08-04 22:00:00 +02:00
{
2010-10-26 22:00:00 +02:00
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
2010-08-05 22:00:00 +02:00
float flValue, flAngle, flTime;
2010-10-26 22:00:00 +02:00
qboolean bChanged;
2010-08-05 22:00:00 +02:00
uint iValue;
const char *pStr;
char *pOut;
2010-08-04 22:00:00 +02:00
bChanged = BF_ReadOneBit( msg );
ASSERT( pField->multiplier != 0.0f );
if( pField->flags & DT_BYTE )
{
if( bChanged )
{
iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
iValue /= pField->multiplier;
}
else
{
iValue = *(byte *)((byte *)from + pField->offset );
}
*(byte *)((byte *)to + pField->offset ) = iValue;
}
else if( pField->flags & DT_SHORT )
{
if( bChanged )
{
iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
iValue /= pField->multiplier;
}
else
{
iValue = *(word *)((byte *)from + pField->offset );
}
*(word *)((byte *)to + pField->offset ) = iValue;
}
else if( pField->flags & DT_INTEGER )
{
if( bChanged )
{
iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
iValue /= pField->multiplier;
}
else
{
iValue = *(uint *)((byte *)from + pField->offset );
}
*(uint *)((byte *)to + pField->offset ) = iValue;
}
else if( pField->flags & DT_FLOAT )
{
if( bChanged )
{
iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
flValue = (int)iValue * ( 1.0f / pField->multiplier );
2010-08-05 22:00:00 +02:00
flValue = flValue * pField->post_multiplier;
2010-08-04 22:00:00 +02:00
}
else
{
flValue = *(float *)((byte *)from + pField->offset );
}
*(float *)((byte *)to + pField->offset ) = flValue;
}
else if( pField->flags & DT_ANGLE )
{
if( bChanged )
{
flAngle = BF_ReadBitAngle( msg, pField->bits );
}
else
{
flAngle = *(float *)((byte *)from + pField->offset );
}
*(float *)((byte *)to + pField->offset ) = flAngle;
}
else if( pField->flags & DT_TIMEWINDOW )
{
if( bChanged )
{
iValue = BF_ReadBitLong( msg, pField->bits, bSigned );
flValue = (float)((int)(iValue * 0.001f ));
flTime = timebase + flValue;
}
else
{
flTime = *(float *)((byte *)from + pField->offset );
}
*(float *)((byte *)to + pField->offset ) = flTime;
}
2010-08-05 22:00:00 +02:00
else if( pField->flags & DT_STRING )
{
if( bChanged )
{
pStr = BF_ReadString( msg );
}
else
{
pStr = (char *)((byte *)from + pField->offset );
}
2010-08-04 22:00:00 +02:00
2010-08-05 22:00:00 +02:00
pOut = (char *)((byte *)to + pField->offset );
com.strncpy( pOut, pStr, pField->size );
}
2010-08-04 22:00:00 +02:00
return bChanged;
}
/*
=============================================================================
usercmd_t communication
=============================================================================
*/
/*
=====================
MSG_WriteDeltaUsercmd
=====================
*/
2010-08-06 22:00:00 +02:00
void MSG_WriteDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
2010-08-04 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "usercmd_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
2010-08-05 22:00:00 +02:00
// activate fields and call custom encode func
Delta_CustomEncode( dt, from, to );
2010-08-04 22:00:00 +02:00
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
Delta_WriteField( msg, pField, from, to, 0.0f );
}
}
/*
=====================
MSG_ReadDeltaUsercmd
=====================
*/
2010-08-06 22:00:00 +02:00
void MSG_ReadDeltaUsercmd( sizebuf_t *msg, usercmd_t *from, usercmd_t *to )
2010-08-04 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "usercmd_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
*to = *from;
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
Delta_ReadField( msg, pField, from, to, 0.0f );
}
}
/*
============================================================================
event_args_t communication
============================================================================
*/
/*
=====================
MSG_WriteDeltaEvent
=====================
*/
2010-08-06 22:00:00 +02:00
void MSG_WriteDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
2010-08-04 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "event_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
2010-08-05 22:00:00 +02:00
// activate fields and call custom encode func
Delta_CustomEncode( dt, from, to );
2010-08-04 22:00:00 +02:00
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
Delta_WriteField( msg, pField, from, to, 0.0f );
}
}
/*
=====================
MSG_ReadDeltaEvent
=====================
*/
2010-08-06 22:00:00 +02:00
void MSG_ReadDeltaEvent( sizebuf_t *msg, event_args_t *from, event_args_t *to )
2010-08-04 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "event_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
*to = *from;
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
Delta_ReadField( msg, pField, from, to, 0.0f );
}
}
/*
=============================================================================
2010-08-06 22:00:00 +02:00
movevars_t communication
=============================================================================
*/
2010-10-26 22:00:00 +02:00
qboolean MSG_WriteDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to )
2010-08-06 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i, startBit;
int numChanges = 0;
dt = Delta_FindStruct( "movevars_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
startBit = msg->iCurBit;
// activate fields and call custom encode func
Delta_CustomEncode( dt, from, to );
2010-08-16 22:00:00 +02:00
BF_WriteByte( msg, svc_deltamovevars );
2010-08-06 22:00:00 +02:00
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
if( Delta_WriteField( msg, pField, from, to, 0.0f ))
numChanges++;
}
// if we have no changes - kill the message
if( !numChanges )
{
BF_SeekToBit( msg, startBit );
return false;
}
return true;
}
void MSG_ReadDeltaMovevars( sizebuf_t *msg, movevars_t *from, movevars_t *to )
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "movevars_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
*to = *from;
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
Delta_ReadField( msg, pField, from, to, 0.0f );
}
}
/*
=============================================================================
2010-08-04 22:00:00 +02:00
clientdata_t communication
=============================================================================
*/
/*
==================
MSG_WriteClientData
Writes current client data only for local client
Other clients can grab the client state from entity_state_t
==================
*/
2010-10-09 22:00:00 +02:00
void MSG_WriteClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, float timebase )
2010-08-04 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "clientdata_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
2010-08-05 22:00:00 +02:00
// activate fields and call custom encode func
Delta_CustomEncode( dt, from, to );
2010-08-04 22:00:00 +02:00
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
2010-10-09 22:00:00 +02:00
Delta_WriteField( msg, pField, from, to, timebase );
2010-08-04 22:00:00 +02:00
}
}
/*
==================
MSG_ReadClientData
Read the clientdata
==================
*/
2010-10-09 22:00:00 +02:00
void MSG_ReadClientData( sizebuf_t *msg, clientdata_t *from, clientdata_t *to, float timebase )
2010-08-04 22:00:00 +02:00
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "clientdata_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
*to = *from;
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
2010-10-09 22:00:00 +02:00
Delta_ReadField( msg, pField, from, to, timebase );
2010-08-04 22:00:00 +02:00
}
}
/*
=============================================================================
2010-10-14 22:00:00 +02:00
weapon_data_t communication
=============================================================================
*/
/*
==================
MSG_WriteWeaponData
Writes current client data only for local client
Other clients can grab the client state from entity_state_t
==================
*/
void MSG_WriteWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, float timebase, int index )
{
delta_t *pField;
delta_info_t *dt;
int i, startBit;
int numChanges = 0;
dt = Delta_FindStruct( "weapon_data_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
// activate fields and call custom encode func
Delta_CustomEncode( dt, from, to );
startBit = msg->iCurBit;
BF_WriteOneBit( msg, 1 );
BF_WriteUBitLong( msg, index, MAX_WEAPON_BITS );
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
if( Delta_WriteField( msg, pField, from, to, timebase ))
numChanges++;
}
// if we have no changes - kill the message
if( !numChanges ) BF_SeekToBit( msg, startBit );
}
/*
==================
MSG_ReadWeaponData
Read the clientdata
==================
*/
void MSG_ReadWeaponData( sizebuf_t *msg, weapon_data_t *from, weapon_data_t *to, float timebase )
{
delta_t *pField;
delta_info_t *dt;
int i;
dt = Delta_FindStruct( "weapon_data_t" );
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
*to = *from;
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
Delta_ReadField( msg, pField, from, to, timebase );
}
}
/*
=============================================================================
2010-08-04 22:00:00 +02:00
entity_state_t communication
=============================================================================
*/
/*
==================
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.
==================
*/
2010-10-26 22:00:00 +02:00
void MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean player, float timebase )
2010-08-04 22:00:00 +02:00
{
2010-10-20 22:00:00 +02:00
delta_info_t *dt = NULL;
2010-08-04 22:00:00 +02:00
delta_t *pField;
int i, startBit;
int numChanges = 0;
if( to == NULL )
{
2010-08-25 22:00:00 +02:00
int fRemoveType;
2010-08-04 22:00:00 +02:00
if( from == NULL ) return;
// a NULL to is a delta remove message
BF_WriteWord( msg, from->number );
2010-08-25 22:00:00 +02:00
// fRemoveType:
// 0 - keep alive, has delta-update
// 1 - remove from delta message (but keep states)
// 2 - completely remove from server
if( force ) fRemoveType = 2;
else fRemoveType = 1;
BF_WriteUBitLong( msg, fRemoveType, 2 );
2010-08-04 22:00:00 +02:00
return;
}
startBit = msg->iCurBit;
if( to->number < 0 || to->number >= GI->max_edicts )
Host_Error( "MSG_WriteDeltaEntity: Bad entity number: %i\n", to->number );
BF_WriteWord( msg, to->number );
2010-08-25 22:00:00 +02:00
BF_WriteUBitLong( msg, 0, 2 ); // alive
2010-08-04 22:00:00 +02:00
2010-08-15 22:00:00 +02:00
if( to->entityType != from->entityType )
2010-08-04 22:00:00 +02:00
{
BF_WriteOneBit( msg, 1 );
2010-10-20 22:00:00 +02:00
BF_WriteUBitLong( msg, to->entityType, 2 );
2010-08-04 22:00:00 +02:00
}
else BF_WriteOneBit( msg, 0 );
2010-10-20 22:00:00 +02:00
if( to->entityType == ENTITY_NORMAL )
{
if( player )
{
dt = Delta_FindStruct( "entity_state_player_t" );
}
else
{
dt = Delta_FindStruct( "entity_state_t" );
}
}
else if( to->entityType == ENTITY_BEAM )
2010-08-04 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
dt = Delta_FindStruct( "custom_entity_state_t" );
2010-08-04 22:00:00 +02:00
}
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
2010-08-05 22:00:00 +02:00
// activate fields and call custom encode func
Delta_CustomEncode( dt, from, to );
2010-08-04 22:00:00 +02:00
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
2010-10-09 22:00:00 +02:00
if( Delta_WriteField( msg, pField, from, to, timebase ))
2010-08-04 22:00:00 +02:00
numChanges++;
}
// if we have no changes - kill the message
if( !numChanges && !force ) BF_SeekToBit( msg, startBit );
}
/*
==================
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, entity_state_t->number will be set to MAX_EDICTS
Can go from either a baseline or a previous packet_entity
==================
*/
2010-10-26 22:00:00 +02:00
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, qboolean player, float timebase )
2010-08-04 22:00:00 +02:00
{
2010-10-20 22:00:00 +02:00
delta_info_t *dt = NULL;
2010-08-04 22:00:00 +02:00
delta_t *pField;
2010-08-25 22:00:00 +02:00
int i, fRemoveType;
2010-08-04 22:00:00 +02:00
if( number < 0 || number >= GI->max_edicts )
Host_Error( "MSG_ReadDeltaEntity: bad delta entity number: %i\n", number );
*to = *from;
to->number = number;
2010-08-25 22:00:00 +02:00
fRemoveType = BF_ReadUBitLong( msg, 2 );
2010-08-04 22:00:00 +02:00
2010-08-25 22:00:00 +02:00
if( fRemoveType )
2010-08-04 22:00:00 +02:00
{
// check for a remove
2010-08-25 22:00:00 +02:00
Mem_Set( to, 0, sizeof( *to ));
if( fRemoveType & 1 )
{
// removed from delta-message
return false;
}
if( fRemoveType & 2 )
{
// entity was removed from server
to->number = -1;
return false;
}
Host_Error( "MSG_ReadDeltaEntity: unknown update type %i\n", fRemoveType );
2010-08-04 22:00:00 +02:00
}
if( BF_ReadOneBit( msg ))
2010-10-20 22:00:00 +02:00
to->entityType = BF_ReadUBitLong( msg, 2 );
2010-08-04 22:00:00 +02:00
2010-10-20 22:00:00 +02:00
if( to->entityType == ENTITY_NORMAL )
{
if( player )
{
dt = Delta_FindStruct( "entity_state_player_t" );
}
else
{
dt = Delta_FindStruct( "entity_state_t" );
}
}
else if( to->entityType == ENTITY_BEAM )
2010-08-04 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
dt = Delta_FindStruct( "custom_entity_state_t" );
2010-08-04 22:00:00 +02:00
}
ASSERT( dt && dt->bInitialized );
pField = dt->pFields;
ASSERT( pField );
// process fields
for( i = 0; i < dt->numFields; i++, pField++ )
{
2010-10-09 22:00:00 +02:00
Delta_ReadField( msg, pField, from, to, timebase );
2010-08-04 22:00:00 +02:00
}
2010-08-25 22:00:00 +02:00
// message parsed
return true;
2010-08-04 22:00:00 +02:00
}
2010-06-23 22:00:00 +02:00
2010-08-06 22:00:00 +02:00
void Delta_AddEncoder( char *name, pfnDeltaEncode encodeFunc )
2010-06-23 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
delta_info_t *dt;
dt = Delta_FindStructByEncoder( name );
if( !dt || !dt->bInitialized )
{
MsgDev( D_ERROR, "Delta_AddEncoder: couldn't find delta with specified custom encode %s\n", name );
return;
}
if( dt->customEncode == CUSTOM_NONE )
{
MsgDev( D_ERROR, "Delta_AddEncoder: %s not supposed for custom encoding\n", dt->pName );
return;
}
// register new encode func
dt->userCallback = encodeFunc;
2010-06-23 22:00:00 +02:00
}
2010-08-06 22:00:00 +02:00
int Delta_FindField( delta_t *pFields, const char *fieldname )
2010-06-23 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
delta_info_t *dt;
delta_t *pField;
int i;
dt = Delta_FindStructByDelta( pFields );
if( dt == NULL || !fieldname || !fieldname[0] )
return -1;
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
{
if( !com.strcmp( pField->name, fieldname ))
return i;
}
return -1;
2010-06-23 22:00:00 +02:00
}
2010-08-06 22:00:00 +02:00
void Delta_SetField( delta_t *pFields, const char *fieldname )
2010-06-23 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
delta_info_t *dt;
delta_t *pField;
int i;
dt = Delta_FindStructByDelta( pFields );
if( dt == NULL || !fieldname || !fieldname[0] )
return;
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
{
if( !com.strcmp( pField->name, fieldname ))
{
pField->bInactive = false;
return;
}
}
2010-06-23 22:00:00 +02:00
}
2010-08-06 22:00:00 +02:00
void Delta_UnsetField( delta_t *pFields, const char *fieldname )
2010-06-23 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
delta_info_t *dt;
delta_t *pField;
int i;
dt = Delta_FindStructByDelta( pFields );
if( dt == NULL || !fieldname || !fieldname[0] )
return;
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
{
if( !com.strcmp( pField->name, fieldname ))
{
pField->bInactive = true;
return;
}
}
2010-06-23 22:00:00 +02:00
}
2010-08-06 22:00:00 +02:00
void Delta_SetFieldByIndex( delta_t *pFields, int fieldNumber )
2010-06-23 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
delta_info_t *dt;
dt = Delta_FindStructByDelta( pFields );
if( dt == NULL || fieldNumber < 0 || fieldNumber >= dt->numFields )
return;
dt->pFields[fieldNumber].bInactive = false;
2010-06-23 22:00:00 +02:00
}
2010-08-06 22:00:00 +02:00
void Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
2010-06-23 22:00:00 +02:00
{
2010-08-05 22:00:00 +02:00
delta_info_t *dt;
dt = Delta_FindStructByDelta( pFields );
if( dt == NULL || fieldNumber < 0 || fieldNumber >= dt->numFields )
return;
dt->pFields[fieldNumber].bInactive = true;
2010-06-23 22:00:00 +02:00
}