engine: common: add GoldSrc delta support
This commit is contained in:
parent
d128997d40
commit
ba7c789ec9
2 changed files with 206 additions and 37 deletions
|
@ -37,6 +37,7 @@ GNU General Public License for more details.
|
|||
#define DT_TIMEWINDOW_BIG BIT( 6 ) // and re-encoded on the client relative to the client's clock
|
||||
#define DT_STRING BIT( 7 ) // A null terminated string, sent as 8 byte chars
|
||||
#define DT_SIGNED BIT( 8 ) // sign modificator
|
||||
#define DT_SIGNED_GS BIT( 31 ) // GoldSrc-specific sign modificator
|
||||
|
||||
#define NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
|
||||
|
||||
|
@ -47,6 +48,7 @@ GNU General Public License for more details.
|
|||
#define PHYS_DEF( x ) #x, offsetof( movevars_t, x ), sizeof( ((movevars_t *)0)->x )
|
||||
#define CLDT_DEF( x ) #x, offsetof( clientdata_t, x ), sizeof( ((clientdata_t *)0)->x )
|
||||
#define WPDT_DEF( x ) #x, offsetof( weapon_data_t, x ), sizeof( ((weapon_data_t *)0)->x )
|
||||
#define DESC_DEF( x ) #x, offsetof( goldsrc_delta_t, x ), sizeof( ((goldsrc_delta_t *)0)->x )
|
||||
|
||||
static qboolean delta_init = false;
|
||||
|
||||
|
@ -315,6 +317,18 @@ static const delta_field_t ent_fields[] =
|
|||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t meta_fields[] =
|
||||
{
|
||||
{ DESC_DEF( fieldType ), },
|
||||
{ DESC_DEF( fieldName ), },
|
||||
{ DESC_DEF( fieldOffset ), },
|
||||
{ DESC_DEF( fieldSize ), },
|
||||
{ DESC_DEF( significant_bits ), },
|
||||
{ DESC_DEF( premultiply ), },
|
||||
{ DESC_DEF( postmultiply ), },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
typedef struct delta_test_struct_t
|
||||
{
|
||||
|
@ -352,22 +366,6 @@ static const delta_field_t test_fields[] =
|
|||
};
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
DT_EVENT_T = 0,
|
||||
DT_MOVEVARS_T,
|
||||
DT_USERCMD_T,
|
||||
DT_CLIENTDATA_T,
|
||||
DT_WEAPONDATA_T,
|
||||
DT_ENTITY_STATE_T,
|
||||
DT_ENTITY_STATE_PLAYER_T,
|
||||
DT_CUSTOM_ENTITY_STATE_T,
|
||||
#if XASH_ENGINE_TESTS
|
||||
DT_DELTA_TEST_STRUCT_T,
|
||||
#endif
|
||||
DT_STRUCT_COUNT
|
||||
};
|
||||
|
||||
static delta_info_t dt_info[] =
|
||||
{
|
||||
[DT_EVENT_T] = { "event_t", ev_fields, NUM_FIELDS( ev_fields ) },
|
||||
|
@ -375,9 +373,10 @@ static delta_info_t dt_info[] =
|
|||
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, NUM_FIELDS( cmd_fields ) },
|
||||
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, NUM_FIELDS( cd_fields ) },
|
||||
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, NUM_FIELDS( wd_fields ) },
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_GOLDSRC_DELTA_T] = { "goldsrc_delta_t", meta_fields, NUM_FIELDS( meta_fields ) },
|
||||
#if XASH_ENGINE_TESTS
|
||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
||||
#endif
|
||||
|
@ -493,7 +492,7 @@ static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags,
|
|||
int i;
|
||||
|
||||
// check for coexisting field
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields && pField; i++, pField++ )
|
||||
{
|
||||
if( !Q_strcmp( pField->name, pName ))
|
||||
{
|
||||
|
@ -621,6 +620,64 @@ void Delta_ParseTableField( sizebuf_t *msg )
|
|||
Delta_AddField( dt, pName, flags, bits, mul, post_mul );
|
||||
}
|
||||
|
||||
void Delta_InitMeta( void )
|
||||
{
|
||||
delta_info_t *dt = Delta_FindStructByIndex( DT_GOLDSRC_DELTA_T );
|
||||
|
||||
if( dt->bInitialized )
|
||||
return;
|
||||
|
||||
Delta_AddField( dt, "fieldType", DT_INTEGER, 32, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "fieldName", DT_STRING, 1, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "fieldOffset", DT_INTEGER, 16, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "fieldSize", DT_INTEGER, 8, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "significant_bits", DT_INTEGER, 8, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "premultiply", DT_FLOAT, 32, 4000.0f, 1.0f );
|
||||
Delta_AddField( dt, "postmultiply", DT_FLOAT, 32, 4000.0f, 1.0f );
|
||||
dt->numFields = dt->maxFields;
|
||||
dt->bInitialized = true;
|
||||
}
|
||||
|
||||
void Delta_ParseTableField_GS( sizebuf_t *msg )
|
||||
{
|
||||
const char *s = MSG_ReadString( msg );
|
||||
delta_info_t *dt = Delta_FindStruct( s );
|
||||
goldsrc_delta_t null = { 0 };
|
||||
int i, num_fields;
|
||||
|
||||
|
||||
// delta encoders it's already initialized on this machine (local game)
|
||||
if( delta_init )
|
||||
{
|
||||
Delta_Shutdown();
|
||||
Delta_InitMeta();
|
||||
}
|
||||
|
||||
if( !dt )
|
||||
Host_Error( "%s: not initialized", __func__ );
|
||||
|
||||
num_fields = MSG_ReadShort( msg );
|
||||
if( num_fields > dt->maxFields )
|
||||
Host_Error( "%s: numFields > maxFields", __func__ );
|
||||
|
||||
MSG_StartBitWriting( msg );
|
||||
|
||||
for( i = 0; i < num_fields; i++ )
|
||||
{
|
||||
goldsrc_delta_t to;
|
||||
|
||||
Delta_ReadGSFields( msg, DT_GOLDSRC_DELTA_T, &null, &to, 0.0f );
|
||||
|
||||
// patch our DT_SIGNED flag
|
||||
if( FBitSet( to.fieldType, DT_SIGNED_GS ))
|
||||
SetBits( to.fieldType, DT_SIGNED );
|
||||
|
||||
Delta_AddField( dt, to.fieldName, to.fieldType, to.significant_bits, to.premultiply, to.postmultiply );
|
||||
}
|
||||
|
||||
MSG_EndBitWriting( msg );
|
||||
}
|
||||
|
||||
static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
|
||||
{
|
||||
string token;
|
||||
|
@ -1166,7 +1223,7 @@ write fields by offsets
|
|||
assume from and to is valid
|
||||
=====================
|
||||
*/
|
||||
static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, const void *from, const void *to, double timebase )
|
||||
static void Delta_WriteField_( sizebuf_t *msg, delta_t *pField, const void *from, const void *to, double timebase )
|
||||
{
|
||||
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
||||
float flValue, flAngle;
|
||||
|
@ -1174,14 +1231,6 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, const void *f
|
|||
int dt;
|
||||
const char *pStr;
|
||||
|
||||
if( Delta_CompareField( pField, from, to ))
|
||||
{
|
||||
MSG_WriteOneBit( msg, 0 ); // unchanged
|
||||
return false;
|
||||
}
|
||||
|
||||
MSG_WriteOneBit( msg, 1 ); // changed
|
||||
|
||||
if( pField->flags & DT_BYTE )
|
||||
{
|
||||
if( signbit )
|
||||
|
@ -1255,6 +1304,21 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, const void *f
|
|||
pStr = (char *)((byte *)to + pField->offset );
|
||||
MSG_WriteString( msg, pStr );
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, const void *from, const void *to, double timebase )
|
||||
{
|
||||
if( Delta_CompareField( pField, from, to ))
|
||||
{
|
||||
MSG_WriteOneBit( msg, 0 ); // unchanged
|
||||
return false;
|
||||
}
|
||||
|
||||
MSG_WriteOneBit( msg, 1 ); // changed
|
||||
|
||||
Delta_WriteField_( msg, pField, from, to, timebase );
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1313,7 +1377,7 @@ read fields by offsets
|
|||
assume 'from' and 'to' is valid
|
||||
=====================
|
||||
*/
|
||||
static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, const void *from, void *to, double timebase )
|
||||
static void Delta_ReadField_( sizebuf_t *msg, delta_t *pField, void *to, double timebase )
|
||||
{
|
||||
qboolean bSigned = ( pField->flags & DT_SIGNED ) ? true : false;
|
||||
float flValue, flAngle, flTime;
|
||||
|
@ -1321,12 +1385,6 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, const void *fr
|
|||
const char *pStr;
|
||||
char *pOut;
|
||||
|
||||
if( !MSG_ReadOneBit( msg ) )
|
||||
{
|
||||
Delta_CopyField( pField, from, to, timebase );
|
||||
return false;
|
||||
}
|
||||
|
||||
Assert( pField->multiplier != 0.0f );
|
||||
|
||||
if( pField->flags & DT_BYTE )
|
||||
|
@ -1410,9 +1468,80 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, const void *fr
|
|||
pOut = (char *)((byte *)to + pField->offset );
|
||||
Q_strncpy( pOut, pStr, pField->size );
|
||||
}
|
||||
}
|
||||
|
||||
static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, const void *from, void *to, double timebase )
|
||||
{
|
||||
if( !MSG_ReadOneBit( msg ))
|
||||
{
|
||||
Delta_CopyField( pField, from, to, timebase );
|
||||
return false;
|
||||
}
|
||||
|
||||
Delta_ReadField_( msg, pField, to, timebase );
|
||||
return true;
|
||||
}
|
||||
|
||||
void Delta_ReadGSFields( sizebuf_t *msg, int index, const void *from, void *to, double timebase )
|
||||
{
|
||||
delta_info_t *dt = Delta_FindStructByIndex( index );
|
||||
uint8_t bits[8] = { 0 };
|
||||
delta_t *pField;
|
||||
byte c;
|
||||
int i;
|
||||
|
||||
c = MSG_ReadUBitLong( msg, 3 );
|
||||
|
||||
for( i = 0; i < c; i++ )
|
||||
bits[i] = MSG_ReadByte( msg );
|
||||
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
{
|
||||
int b = i >> 3;
|
||||
int n = 1 << ( i & 7 );
|
||||
|
||||
if( FBitSet( bits[b], n ))
|
||||
Delta_ReadField_( msg, pField, to, timebase );
|
||||
else Delta_CopyField( pField, from, to, timebase );
|
||||
}
|
||||
}
|
||||
|
||||
void Delta_WriteGSFields( sizebuf_t *msg, int index, const void *from, const void *to, double timebase )
|
||||
{
|
||||
delta_info_t *dt = Delta_FindStructByIndex( index );
|
||||
delta_t *pField;
|
||||
uint8_t bits[8] = { 0 };
|
||||
uint c = 0;
|
||||
int i;
|
||||
|
||||
Delta_CustomEncode( dt, from, to );
|
||||
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
{
|
||||
if( !Delta_CompareField( pField, from, to ))
|
||||
{
|
||||
int b = i >> 3;
|
||||
int n = 1 << ( i & 7 );
|
||||
|
||||
SetBits( bits[b], n );
|
||||
c = b + 1;
|
||||
}
|
||||
}
|
||||
|
||||
MSG_WriteUBitLong( msg, c, 3 );
|
||||
for( i = 0; i < c; i++ )
|
||||
MSG_WriteByte( msg, bits[i] );
|
||||
|
||||
for( i = 0, pField = dt->pFields; i < dt->numFields; i++, pField++ )
|
||||
{
|
||||
int b = i >> 3;
|
||||
int n = 1 << ( i & 7 );
|
||||
|
||||
if( FBitSet( bits[b], n ))
|
||||
Delta_WriteField_( msg, pField, from, to, timebase );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
|
@ -1882,7 +2011,10 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, const entity_state_t *from, entity
|
|||
int baseline_offset = 0;
|
||||
|
||||
if( number < 0 || number >= clgame.maxEntities )
|
||||
Host_Error( "%s: bad delta entity number: %i\n", __func__, number );
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: bad delta entity number: %i\n", __func__, number );
|
||||
return false;
|
||||
}
|
||||
|
||||
fRemoveType = MSG_ReadUBitLong( msg, 2 );
|
||||
|
||||
|
@ -1904,7 +2036,8 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, const entity_state_t *from, entity
|
|||
return false;
|
||||
}
|
||||
|
||||
Host_Error( "%s: unknown update type %i\n", __func__, fRemoveType );
|
||||
Con_Printf( S_ERROR "%s: unknown update type %i\n", __func__, fRemoveType );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !cls.legacymode )
|
||||
|
@ -1952,7 +2085,11 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, const entity_state_t *from, entity
|
|||
dt = Delta_FindStructByIndex( DT_ENTITY_STATE_T );
|
||||
}
|
||||
|
||||
Assert( dt && dt->bInitialized );
|
||||
if( !dt || !dt->bInitialized )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s: broken delta\n", __func__ );
|
||||
return true;
|
||||
}
|
||||
|
||||
pField = dt->pFields;
|
||||
Assert( pField != NULL );
|
||||
|
|
|
@ -33,6 +33,23 @@ enum
|
|||
DELTA_STATIC,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DT_EVENT_T = 0,
|
||||
DT_MOVEVARS_T,
|
||||
DT_USERCMD_T,
|
||||
DT_CLIENTDATA_T,
|
||||
DT_WEAPONDATA_T,
|
||||
DT_ENTITY_STATE_T,
|
||||
DT_ENTITY_STATE_PLAYER_T,
|
||||
DT_CUSTOM_ENTITY_STATE_T,
|
||||
DT_GOLDSRC_DELTA_T,
|
||||
#if XASH_ENGINE_TESTS
|
||||
DT_DELTA_TEST_STRUCT_T,
|
||||
#endif
|
||||
DT_STRUCT_COUNT
|
||||
};
|
||||
|
||||
// struct info (filled by engine)
|
||||
typedef struct
|
||||
{
|
||||
|
@ -54,6 +71,17 @@ struct delta_s
|
|||
qboolean bInactive; // unsetted by user request
|
||||
};
|
||||
|
||||
typedef struct goldsrc_delta_s
|
||||
{
|
||||
int fieldType;
|
||||
char fieldName[32];
|
||||
int fieldOffset;
|
||||
short fieldSize;
|
||||
int significant_bits;
|
||||
float premultiply;
|
||||
float postmultiply;
|
||||
} goldsrc_delta_t;
|
||||
|
||||
typedef void (*pfnDeltaEncode)( struct delta_s *pFields, const byte *from, const byte *to );
|
||||
|
||||
typedef struct
|
||||
|
@ -76,6 +104,7 @@ typedef struct
|
|||
//
|
||||
void Delta_Init( void );
|
||||
void Delta_InitClient( void );
|
||||
void Delta_InitMeta( void );
|
||||
void Delta_Shutdown( void );
|
||||
void Delta_AddEncoder( char *name, pfnDeltaEncode encodeFunc );
|
||||
int Delta_FindField( delta_t *pFields, const char *fieldname );
|
||||
|
@ -87,6 +116,7 @@ void Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber );
|
|||
// send table over network
|
||||
void Delta_WriteDescriptionToClient( sizebuf_t *msg );
|
||||
void Delta_ParseTableField( sizebuf_t *msg );
|
||||
void Delta_ParseTableField_GS( sizebuf_t *msg );
|
||||
|
||||
|
||||
// encode routines
|
||||
|
@ -109,5 +139,7 @@ void MSG_ReadWeaponData( sizebuf_t *msg, const struct weapon_data_s *from, struc
|
|||
void MSG_WriteDeltaEntity( const struct entity_state_s *from, const struct entity_state_s *to, sizebuf_t *msg, qboolean force, int type, double timebase, int ofs );
|
||||
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, const struct entity_state_s *from, struct entity_state_s *to, int num, int type, double timebase );
|
||||
int Delta_TestBaseline( const struct entity_state_s *from, const struct entity_state_s *to, qboolean player, double timebase );
|
||||
void Delta_ReadGSFields( sizebuf_t *msg, int index, const void *from, void *to, double timebase );
|
||||
void Delta_WriteGSFields( sizebuf_t *msg, int index, const void *from, const void *to, double timebase );
|
||||
|
||||
#endif//NET_ENCODE_H
|
||||
|
|
Loading…
Add table
Reference in a new issue