You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1383 lines
34 KiB
1383 lines
34 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
|
||
|
#include "quakedef.h"
|
||
|
#include "dt.h"
|
||
|
#include "dt_encode.h"
|
||
|
#include "coordsize.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
extern void DataTable_Warning( const char *pInMessage, ... );
|
||
|
extern bool ShouldWatchThisProp( const SendTable *pTable, int objectID, const char *pPropName );
|
||
|
|
||
|
// The engine implements this.
|
||
|
extern const char* GetObjectClassName( int objectID );
|
||
|
|
||
|
void EncodeFloat( const SendProp *pProp, float fVal, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
// Check for special flags like SPROP_COORD, SPROP_NOSCALE, and SPROP_NORMAL.
|
||
|
int flags = pProp->GetFlags();
|
||
|
if ( flags & SPROP_COORD )
|
||
|
{
|
||
|
pOut->WriteBitCoord( fVal );
|
||
|
}
|
||
|
else if ( flags & ( SPROP_COORD_MP | SPROP_COORD_MP_LOWPRECISION | SPROP_COORD_MP_INTEGRAL ) )
|
||
|
{
|
||
|
COMPILE_TIME_ASSERT( SPROP_COORD_MP_INTEGRAL == (1<<15) );
|
||
|
COMPILE_TIME_ASSERT( SPROP_COORD_MP_LOWPRECISION == (1<<14) );
|
||
|
pOut->WriteBitCoordMP( fVal, ((flags >> 15) & 1), ((flags >> 14) & 1) );
|
||
|
}
|
||
|
else if ( flags & SPROP_NORMAL )
|
||
|
{
|
||
|
pOut->WriteBitNormal( fVal );
|
||
|
}
|
||
|
else // standard clamped-range float
|
||
|
{
|
||
|
unsigned long ulVal;
|
||
|
int nBits = pProp->m_nBits;
|
||
|
if ( flags & SPROP_NOSCALE )
|
||
|
{
|
||
|
union { float f; uint32 u; } convert = { fVal };
|
||
|
ulVal = convert.u;
|
||
|
nBits = 32;
|
||
|
}
|
||
|
else if( fVal < pProp->m_fLowValue )
|
||
|
{
|
||
|
// clamp < 0
|
||
|
ulVal = 0;
|
||
|
|
||
|
if(!(flags & SPROP_ROUNDUP))
|
||
|
{
|
||
|
DataTable_Warning("(class %s): Out-of-range value (%f / %f) in SendPropFloat '%s', clamping.\n",
|
||
|
GetObjectClassName( objectID ), fVal, pProp->m_fLowValue, pProp->m_pVarName );
|
||
|
}
|
||
|
}
|
||
|
else if( fVal > pProp->m_fHighValue )
|
||
|
{
|
||
|
// clamp > 1
|
||
|
ulVal = ((1 << pProp->m_nBits) - 1);
|
||
|
|
||
|
if(!(flags & SPROP_ROUNDDOWN))
|
||
|
{
|
||
|
DataTable_Warning("%s: Out-of-range value (%f/%f) in SendPropFloat '%s', clamping.\n",
|
||
|
GetObjectClassName( objectID ), fVal, pProp->m_fHighValue, pProp->m_pVarName );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float fRangeVal = (fVal - pProp->m_fLowValue) * pProp->m_fHighLowMul;
|
||
|
if ( pProp->m_nBits <= 22 )
|
||
|
{
|
||
|
// this is the case we always expect to hit
|
||
|
ulVal = FastFloatToSmallInt( fRangeVal );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// retain old logic just in case anyone relies on its behavior
|
||
|
ulVal = RoundFloatToUnsignedLong( fRangeVal );
|
||
|
}
|
||
|
}
|
||
|
pOut->WriteUBitLong(ulVal, nBits);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static float DecodeFloat(SendProp const *pProp, bf_read *pIn)
|
||
|
{
|
||
|
int flags = pProp->GetFlags();
|
||
|
if ( flags & SPROP_COORD )
|
||
|
{
|
||
|
return pIn->ReadBitCoord();
|
||
|
}
|
||
|
else if ( flags & ( SPROP_COORD_MP | SPROP_COORD_MP_LOWPRECISION | SPROP_COORD_MP_INTEGRAL ) )
|
||
|
{
|
||
|
return pIn->ReadBitCoordMP( (flags >> 15) & 1, (flags >> 14) & 1 );
|
||
|
}
|
||
|
else if ( flags & SPROP_NOSCALE )
|
||
|
{
|
||
|
return pIn->ReadBitFloat();
|
||
|
}
|
||
|
else if ( flags & SPROP_NORMAL )
|
||
|
{
|
||
|
return pIn->ReadBitNormal();
|
||
|
}
|
||
|
else // standard clamped-range float
|
||
|
{
|
||
|
unsigned long dwInterp = pIn->ReadUBitLong(pProp->m_nBits);
|
||
|
float fVal = (float)dwInterp / ((1 << pProp->m_nBits) - 1);
|
||
|
fVal = pProp->m_fLowValue + (pProp->m_fHighValue - pProp->m_fLowValue) * fVal;
|
||
|
return fVal;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void DecodeVector(SendProp const *pProp, bf_read *pIn, float *v)
|
||
|
{
|
||
|
v[0] = DecodeFloat(pProp, pIn);
|
||
|
v[1] = DecodeFloat(pProp, pIn);
|
||
|
|
||
|
// Don't read in the third component for normals
|
||
|
if ((pProp->GetFlags() & SPROP_NORMAL) == 0)
|
||
|
{
|
||
|
v[2] = DecodeFloat(pProp, pIn);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int signbit = pIn->ReadOneBit();
|
||
|
|
||
|
float v0v0v1v1 = v[0] * v[0] +
|
||
|
v[1] * v[1];
|
||
|
if (v0v0v1v1 < 1.0f)
|
||
|
v[2] = sqrtf( 1.0f - v0v0v1v1 );
|
||
|
else
|
||
|
v[2] = 0.0f;
|
||
|
|
||
|
if (signbit)
|
||
|
v[2] *= -1.0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void DecodeQuaternion(SendProp const *pProp, bf_read *pIn, float *v)
|
||
|
{
|
||
|
v[0] = DecodeFloat(pProp, pIn);
|
||
|
v[1] = DecodeFloat(pProp, pIn);
|
||
|
v[2] = DecodeFloat(pProp, pIn);
|
||
|
v[3] = DecodeFloat(pProp, pIn);
|
||
|
}
|
||
|
|
||
|
int DecodeBits( DecodeInfo *pInfo, unsigned char *pOut )
|
||
|
{
|
||
|
bf_read temp;
|
||
|
|
||
|
// Read the property in (note: we don't return the bits from here because Decode returns
|
||
|
// the decoded bits.. we're interested in getting the encoded bits).
|
||
|
temp = *pInfo->m_pIn;
|
||
|
pInfo->m_pRecvProp = NULL;
|
||
|
pInfo->m_pData = NULL;
|
||
|
g_PropTypeFns[pInfo->m_pProp->m_Type].Decode( pInfo );
|
||
|
|
||
|
// Return the encoded bits.
|
||
|
int nBits = pInfo->m_pIn->GetNumBitsRead() - temp.GetNumBitsRead();
|
||
|
temp.ReadBits(pOut, nBits);
|
||
|
return nBits;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Most of the prop types can use this generic FastCopy version. Arrays are a bit of a pain.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
inline void Generic_FastCopy(
|
||
|
const SendProp *pSendProp,
|
||
|
const RecvProp *pRecvProp,
|
||
|
const unsigned char *pSendData,
|
||
|
unsigned char *pRecvData,
|
||
|
int objectID )
|
||
|
{
|
||
|
// Get the data out of the ent.
|
||
|
CRecvProxyData recvProxyData;
|
||
|
|
||
|
pSendProp->GetProxyFn()(
|
||
|
pSendProp,
|
||
|
pSendData,
|
||
|
pSendData + pSendProp->GetOffset(),
|
||
|
&recvProxyData.m_Value,
|
||
|
0,
|
||
|
objectID
|
||
|
);
|
||
|
|
||
|
// Fill in the data for the recv proxy.
|
||
|
recvProxyData.m_pRecvProp = pRecvProp;
|
||
|
recvProxyData.m_iElement = 0;
|
||
|
recvProxyData.m_ObjectID = objectID;
|
||
|
pRecvProp->GetProxyFn()( &recvProxyData, pRecvData, pRecvData + pRecvProp->GetOffset() );
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// DecodeInfo implementation.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void DecodeInfo::CopyVars( const DecodeInfo *pOther )
|
||
|
{
|
||
|
m_pStruct = pOther->m_pStruct;
|
||
|
m_pData = pOther->m_pData;
|
||
|
|
||
|
m_pRecvProp = pOther->m_pRecvProp;
|
||
|
m_pProp = pOther->m_pProp;
|
||
|
m_pIn = pOther->m_pIn;
|
||
|
m_ObjectID = pOther->m_ObjectID;
|
||
|
m_iElement = pOther->m_iElement;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Int property type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void Int_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
int nValue = pVar->m_Int;
|
||
|
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
pOut->WriteVarInt32( nValue );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pOut->WriteSignedVarInt32( nValue );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If signed, preserve lower bits and then re-extend sign if nValue < 0;
|
||
|
// if unsigned, preserve all 32 bits no matter what. Bonus: branchless.
|
||
|
int nPreserveBits = ( 0x7FFFFFFF >> ( 32 - pProp->m_nBits ) );
|
||
|
nPreserveBits |= ( pProp->GetFlags() & SPROP_UNSIGNED ) ? 0xFFFFFFFF : 0;
|
||
|
int nSignExtension = ( nValue >> 31 ) & ~nPreserveBits;
|
||
|
|
||
|
nValue &= nPreserveBits;
|
||
|
nValue |= nSignExtension;
|
||
|
|
||
|
#ifdef DBGFLAG_ASSERT
|
||
|
// Assert that either the property is unsigned and in valid range,
|
||
|
// or signed with a consistent sign extension in the high bits
|
||
|
if ( pProp->m_nBits < 32 )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
AssertMsg3( nValue == pVar->m_Int, "Unsigned prop %s needs more bits? Expected %i == %i", pProp->GetName(), nValue, pVar->m_Int );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AssertMsg3( nValue == pVar->m_Int, "Signed prop %s needs more bits? Expected %i == %i", pProp->GetName(), nValue, pVar->m_Int );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This should never trigger, but I'm leaving it in for old-time's sake.
|
||
|
Assert( nValue == pVar->m_Int );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
pOut->WriteUBitLong( nValue, pProp->m_nBits, false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Int_Decode( DecodeInfo *pInfo )
|
||
|
{
|
||
|
const SendProp *pProp = pInfo->m_pProp;
|
||
|
int flags = pProp->GetFlags();
|
||
|
|
||
|
if ( flags & SPROP_VARINT )
|
||
|
{
|
||
|
if ( flags & SPROP_UNSIGNED )
|
||
|
{
|
||
|
pInfo->m_Value.m_Int = (long)pInfo->m_pIn->ReadVarInt32();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pInfo->m_Value.m_Int = pInfo->m_pIn->ReadSignedVarInt32();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int bits = pProp->m_nBits;
|
||
|
pInfo->m_Value.m_Int = pInfo->m_pIn->ReadUBitLong(bits);
|
||
|
|
||
|
if( bits != 32 && (flags & SPROP_UNSIGNED) == 0 )
|
||
|
{
|
||
|
unsigned long highbit = 1ul << (pProp->m_nBits - 1);
|
||
|
if ( pInfo->m_Value.m_Int & highbit )
|
||
|
{
|
||
|
pInfo->m_Value.m_Int -= highbit; // strip high bit...
|
||
|
pInfo->m_Value.m_Int -= highbit; // ... then put it back with sign extension
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int Int_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
return p1->ReadVarInt32() != p2->ReadVarInt32();
|
||
|
}
|
||
|
return p1->ReadSignedVarInt32() != p2->ReadSignedVarInt32();
|
||
|
}
|
||
|
|
||
|
return p1->CompareBits(p2, pProp->m_nBits);
|
||
|
}
|
||
|
|
||
|
const char* Int_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_Int";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Int_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
return (pVar->m_Int == 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Int_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_Int = 0;
|
||
|
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool Int_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
return pIn->ReadVarInt32() == 0;
|
||
|
}
|
||
|
return pIn->ReadSignedVarInt32() == 0;
|
||
|
}
|
||
|
return pIn->ReadUBitLong( pProp->m_nBits ) == 0;
|
||
|
}
|
||
|
|
||
|
void Int_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
pIn->ReadVarInt32();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIn->ReadSignedVarInt32();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIn->SeekRelative( pProp->m_nBits );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Float type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void Float_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
EncodeFloat( pProp, pVar->m_Float, pOut, objectID );
|
||
|
}
|
||
|
|
||
|
|
||
|
void Float_Decode( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_Float = DecodeFloat(pInfo->m_pProp, pInfo->m_pIn);
|
||
|
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
|
||
|
int Float_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
int flags = pProp->GetFlags();
|
||
|
if ( flags & SPROP_COORD )
|
||
|
{
|
||
|
return p1->ReadBitCoordBits() != p2->ReadBitCoordBits();
|
||
|
}
|
||
|
else if ( flags & ( SPROP_COORD_MP | SPROP_COORD_MP_LOWPRECISION | SPROP_COORD_MP_INTEGRAL ) )
|
||
|
{
|
||
|
return p1->ReadBitCoordMPBits( (flags >> 15) & 1, (flags >> 14) & 1 )
|
||
|
!= p2->ReadBitCoordMPBits( (flags >> 15) & 1, (flags >> 14) & 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int bits;
|
||
|
if ( flags & SPROP_NOSCALE )
|
||
|
bits = 32;
|
||
|
else if ( flags & SPROP_NORMAL )
|
||
|
bits = NORMAL_FRACTIONAL_BITS+1;
|
||
|
else
|
||
|
bits = pProp->m_nBits;
|
||
|
return p1->ReadUBitLong( bits ) != p2->ReadUBitLong( bits );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* Float_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_Float";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Float_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
return (pVar->m_Float == 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Float_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_Float = 0;
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
bool Float_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
return DecodeFloat( pProp, pIn ) == 0.0f;
|
||
|
}
|
||
|
|
||
|
void Float_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
// Check for special flags..
|
||
|
if(pProp->GetFlags() & SPROP_COORD)
|
||
|
{
|
||
|
// Read the required integer and fraction flags
|
||
|
unsigned int val = pIn->ReadUBitLong(2);
|
||
|
// this reads two bits, the first bit (bit0 in this word) indicates integer part
|
||
|
// the second bit (bit1 in this word) indicates the fractional part
|
||
|
|
||
|
// If we got either parse them, otherwise it's a zero.
|
||
|
if ( val )
|
||
|
{
|
||
|
// sign bit
|
||
|
int seekDist = 1;
|
||
|
|
||
|
// If there's an integer, read it in
|
||
|
if ( val & 1 )
|
||
|
seekDist += COORD_INTEGER_BITS;
|
||
|
|
||
|
if ( val & 2 )
|
||
|
seekDist += COORD_FRACTIONAL_BITS;
|
||
|
|
||
|
pIn->SeekRelative( seekDist );
|
||
|
}
|
||
|
}
|
||
|
else if ( pProp->GetFlags() & SPROP_COORD_MP )
|
||
|
{
|
||
|
pIn->ReadBitCoordMP( false, false );
|
||
|
}
|
||
|
else if ( pProp->GetFlags() & SPROP_COORD_MP_LOWPRECISION )
|
||
|
{
|
||
|
pIn->ReadBitCoordMP( false, true );
|
||
|
}
|
||
|
else if ( pProp->GetFlags() & SPROP_COORD_MP_INTEGRAL )
|
||
|
{
|
||
|
pIn->ReadBitCoordMP( true, false );
|
||
|
}
|
||
|
else if(pProp->GetFlags() & SPROP_NOSCALE)
|
||
|
{
|
||
|
pIn->SeekRelative( 32 );
|
||
|
}
|
||
|
else if(pProp->GetFlags() & SPROP_NORMAL)
|
||
|
{
|
||
|
pIn->SeekRelative( NORMAL_FRACTIONAL_BITS + 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIn->SeekRelative( pProp->m_nBits );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Vector type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void Vector_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
EncodeFloat(pProp, pVar->m_Vector[0], pOut, objectID);
|
||
|
EncodeFloat(pProp, pVar->m_Vector[1], pOut, objectID);
|
||
|
// Don't write out the third component for normals
|
||
|
if ((pProp->GetFlags() & SPROP_NORMAL) == 0)
|
||
|
{
|
||
|
EncodeFloat(pProp, pVar->m_Vector[2], pOut, objectID);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Write a sign bit for z instead!
|
||
|
int signbit = (pVar->m_Vector[2] <= -NORMAL_RESOLUTION);
|
||
|
pOut->WriteOneBit( signbit );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Vector_Decode(DecodeInfo *pInfo)
|
||
|
{
|
||
|
DecodeVector( pInfo->m_pProp, pInfo->m_pIn, pInfo->m_Value.m_Vector );
|
||
|
|
||
|
if( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
|
||
|
int Vector_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
int c1 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
int c2 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
int c3;
|
||
|
|
||
|
if ( pProp->GetFlags() & SPROP_NORMAL )
|
||
|
{
|
||
|
c3 = p1->ReadOneBit() != p2->ReadOneBit();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
c3 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
}
|
||
|
|
||
|
return c1 | c2 | c3;
|
||
|
}
|
||
|
|
||
|
const char* Vector_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_Vector";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Vector_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
return ( pVar->m_Vector[0] == 0 ) && ( pVar->m_Vector[1] == 0 ) && ( pVar->m_Vector[2] == 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
void Vector_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_Vector[0] = 0;
|
||
|
pInfo->m_Value.m_Vector[1] = 0;
|
||
|
pInfo->m_Value.m_Vector[2] = 0;
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
bool Vector_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
float v[3];
|
||
|
|
||
|
DecodeVector( pProp, pIn, v );
|
||
|
|
||
|
return ( v[0] == 0 ) && ( v[1] == 0 ) && ( v[2] == 0 );
|
||
|
}
|
||
|
|
||
|
void Vector_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
|
||
|
// Don't read in the third component for normals
|
||
|
if ( pProp->GetFlags() & SPROP_NORMAL )
|
||
|
{
|
||
|
pIn->SeekRelative( 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// VectorXY type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void VectorXY_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
EncodeFloat(pProp, pVar->m_Vector[0], pOut, objectID);
|
||
|
EncodeFloat(pProp, pVar->m_Vector[1], pOut, objectID);
|
||
|
}
|
||
|
|
||
|
|
||
|
void VectorXY_Decode(DecodeInfo *pInfo)
|
||
|
{
|
||
|
pInfo->m_Value.m_Vector[0] = DecodeFloat(pInfo->m_pProp, pInfo->m_pIn);
|
||
|
pInfo->m_Value.m_Vector[1] = DecodeFloat(pInfo->m_pProp, pInfo->m_pIn);
|
||
|
|
||
|
if( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
|
||
|
int VectorXY_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
int c1 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
int c2 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
|
||
|
return c1 | c2;
|
||
|
}
|
||
|
|
||
|
const char* VectorXY_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_VectorXY";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool VectorXY_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
return ( pVar->m_Vector[0] == 0 ) && ( pVar->m_Vector[1] == 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
void VectorXY_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_Vector[0] = 0;
|
||
|
pInfo->m_Value.m_Vector[1] = 0;
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
bool VectorXY_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
float v[2];
|
||
|
|
||
|
v[0] = DecodeFloat(pProp, pIn);
|
||
|
v[1] = DecodeFloat(pProp, pIn);
|
||
|
|
||
|
return ( v[0] == 0 ) && ( v[1] == 0 );
|
||
|
}
|
||
|
|
||
|
void VectorXY_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
}
|
||
|
|
||
|
#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!!
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Quaternion type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void Quaternion_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
EncodeFloat(pProp, pVar->m_Vector[0], pOut, objectID);
|
||
|
EncodeFloat(pProp, pVar->m_Vector[1], pOut, objectID);
|
||
|
EncodeFloat(pProp, pVar->m_Vector[2], pOut, objectID);
|
||
|
EncodeFloat(pProp, pVar->m_Vector[3], pOut, objectID);
|
||
|
}
|
||
|
|
||
|
|
||
|
void Quaternion_Decode(DecodeInfo *pInfo)
|
||
|
{
|
||
|
DecodeQuaternion( pInfo->m_pProp, pInfo->m_pIn, pInfo->m_Value.m_Vector );
|
||
|
|
||
|
if( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int Quaternion_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
int c1 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
int c2 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
int c3 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
int c4 = Float_CompareDeltas( pProp, p1, p2 );
|
||
|
return c1 | c2 | c3 | c4;
|
||
|
}
|
||
|
|
||
|
const char* Quaternion_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_Quaternion";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Quaternion_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
return ( pVar->m_Vector[0] == 0 ) && ( pVar->m_Vector[1] == 0 ) && ( pVar->m_Vector[2] == 0 ) && ( pVar->m_Vector[3] == 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
void Quaternion_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_Vector[0] = 0;
|
||
|
pInfo->m_Value.m_Vector[1] = 0;
|
||
|
pInfo->m_Value.m_Vector[2] = 0;
|
||
|
pInfo->m_Value.m_Vector[3] = 0;
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool Quaternion_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
float v[4];
|
||
|
|
||
|
DecodeQuaternion( pProp, pIn, v );
|
||
|
|
||
|
return ( v[0] == 0 ) && ( v[1] == 0 ) && ( v[2] == 0 ) && ( v[3] == 0 );
|
||
|
}
|
||
|
|
||
|
void Quaternion_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
Float_SkipProp(pProp, pIn);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// String type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void String_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
// First count the string length, then do one WriteBits call.
|
||
|
int len;
|
||
|
for ( len=0; len < DT_MAX_STRING_BUFFERSIZE-1; len++ )
|
||
|
{
|
||
|
if( pVar->m_pString[len] == 0 )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Optionally write the length here so deltas can be compared faster.
|
||
|
pOut->WriteUBitLong( len, DT_MAX_STRING_BITS );
|
||
|
pOut->WriteBits( pVar->m_pString, len * 8 );
|
||
|
}
|
||
|
|
||
|
|
||
|
void String_Decode(DecodeInfo *pInfo)
|
||
|
{
|
||
|
// Read it in.
|
||
|
int len = pInfo->m_pIn->ReadUBitLong( DT_MAX_STRING_BITS );
|
||
|
|
||
|
char *tempStr = pInfo->m_TempStr;
|
||
|
|
||
|
if ( len >= DT_MAX_STRING_BUFFERSIZE )
|
||
|
{
|
||
|
Warning( "String_Decode( %s ) invalid length (%d)\n", pInfo->m_pRecvProp->GetName(), len );
|
||
|
len = DT_MAX_STRING_BUFFERSIZE - 1;
|
||
|
}
|
||
|
|
||
|
pInfo->m_pIn->ReadBits( tempStr, len*8 );
|
||
|
tempStr[len] = 0;
|
||
|
|
||
|
pInfo->m_Value.m_pString = tempStr;
|
||
|
|
||
|
// Give it to the RecvProxy.
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
|
||
|
// Compare the bits in pBuf1 and pBuf2 and return 1 if they are different.
|
||
|
// This must always seek both buffers to wherever they start at + nBits.
|
||
|
static inline int AreBitsDifferent( bf_read *pBuf1, bf_read *pBuf2, int nBits )
|
||
|
{
|
||
|
int nDWords = nBits >> 5;
|
||
|
|
||
|
int diff = 0;
|
||
|
for ( int iDWord=0; iDWord < nDWords; iDWord++ )
|
||
|
{
|
||
|
diff |= (pBuf1->ReadUBitLong(32) != pBuf2->ReadUBitLong(32));
|
||
|
}
|
||
|
|
||
|
int nRemainingBits = nBits - (nDWords<<5);
|
||
|
if (nRemainingBits > 0)
|
||
|
diff |= pBuf1->ReadUBitLong( nRemainingBits ) != pBuf2->ReadUBitLong( nRemainingBits );
|
||
|
|
||
|
return diff;
|
||
|
}
|
||
|
|
||
|
|
||
|
int String_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
int len1 = p1->ReadUBitLong( DT_MAX_STRING_BITS );
|
||
|
int len2 = p2->ReadUBitLong( DT_MAX_STRING_BITS );
|
||
|
|
||
|
if ( len1 == len2 )
|
||
|
{
|
||
|
// check if both strings are empty
|
||
|
if (len1 == 0)
|
||
|
return false;
|
||
|
|
||
|
// Ok, they're short and fast.
|
||
|
return AreBitsDifferent( p1, p2, len1*8 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p1->SeekRelative( len1 * 8 );
|
||
|
p2->SeekRelative( len2 * 8 );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* String_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_String";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool String_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
return ( pVar->m_pString[0] == 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
void String_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
pInfo->m_Value.m_pString = pInfo->m_TempStr;
|
||
|
pInfo->m_TempStr[0] = 0;
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
|
||
|
bool String_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
// Read it in.
|
||
|
int len = pIn->ReadUBitLong( DT_MAX_STRING_BITS );
|
||
|
|
||
|
pIn->SeekRelative( len*8 );
|
||
|
|
||
|
return len == 0;
|
||
|
}
|
||
|
|
||
|
void String_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
int len = pIn->ReadUBitLong( DT_MAX_STRING_BITS );
|
||
|
pIn->SeekRelative( len*8 );
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Array abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
int Array_GetLength( const unsigned char *pStruct, const SendProp *pProp, int objectID )
|
||
|
{
|
||
|
// Get the array length from the proxy.
|
||
|
ArrayLengthSendProxyFn proxy = pProp->GetArrayLengthProxy();
|
||
|
|
||
|
if ( proxy )
|
||
|
{
|
||
|
int nElements = proxy( pStruct, objectID );
|
||
|
|
||
|
// Make sure it's not too big.
|
||
|
if ( nElements > pProp->GetNumElements() )
|
||
|
{
|
||
|
Assert( false );
|
||
|
nElements = pProp->GetNumElements();
|
||
|
}
|
||
|
|
||
|
return nElements;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return pProp->GetNumElements();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Array_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
SendProp *pArrayProp = pProp->GetArrayProp();
|
||
|
AssertMsg( pArrayProp, "Array_Encode: missing m_pArrayProp for SendProp '%s'.", pProp->m_pVarName );
|
||
|
|
||
|
int nElements = Array_GetLength( pStruct, pProp, objectID );
|
||
|
|
||
|
// Write the number of elements.
|
||
|
pOut->WriteUBitLong( nElements, pProp->GetNumArrayLengthBits() );
|
||
|
|
||
|
unsigned char *pCurStructOffset = (unsigned char*)pStruct + pArrayProp->GetOffset();
|
||
|
for ( int iElement=0; iElement < nElements; iElement++ )
|
||
|
{
|
||
|
DVariant var;
|
||
|
|
||
|
// Call the proxy to get the value, then encode.
|
||
|
pArrayProp->GetProxyFn()( pArrayProp, pStruct, pCurStructOffset, &var, iElement, objectID );
|
||
|
g_PropTypeFns[pArrayProp->GetType()].Encode( pStruct, &var, pArrayProp, pOut, objectID );
|
||
|
|
||
|
pCurStructOffset += pProp->GetElementStride();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Array_Decode( DecodeInfo *pInfo )
|
||
|
{
|
||
|
SendProp *pArrayProp = pInfo->m_pProp->GetArrayProp();
|
||
|
AssertMsg( pArrayProp, ("Array_Decode: missing m_pArrayProp for a property.") );
|
||
|
|
||
|
// Setup a DecodeInfo that is used to decode each of the child properties.
|
||
|
DecodeInfo subDecodeInfo;
|
||
|
subDecodeInfo.CopyVars( pInfo );
|
||
|
subDecodeInfo.m_pProp = pArrayProp;
|
||
|
|
||
|
int elementStride = 0;
|
||
|
ArrayLengthRecvProxyFn lengthProxy = 0;
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
RecvProp *pArrayRecvProp = pInfo->m_pRecvProp->GetArrayProp();
|
||
|
subDecodeInfo.m_pRecvProp = pArrayRecvProp;
|
||
|
|
||
|
// Note we get the OFFSET from the array element property and the STRIDE from the array itself.
|
||
|
subDecodeInfo.m_pData = (char*)pInfo->m_pData + pArrayRecvProp->GetOffset();
|
||
|
elementStride = pInfo->m_pRecvProp->GetElementStride();
|
||
|
Assert( elementStride != -1 ); // (Make sure it was set..)
|
||
|
|
||
|
lengthProxy = pInfo->m_pRecvProp->GetArrayLengthProxy();
|
||
|
}
|
||
|
|
||
|
int nElements = pInfo->m_pIn->ReadUBitLong( pInfo->m_pProp->GetNumArrayLengthBits() );
|
||
|
|
||
|
if ( lengthProxy )
|
||
|
lengthProxy( pInfo->m_pStruct, pInfo->m_ObjectID, nElements );
|
||
|
|
||
|
for ( subDecodeInfo.m_iElement=0; subDecodeInfo.m_iElement < nElements; subDecodeInfo.m_iElement++ )
|
||
|
{
|
||
|
g_PropTypeFns[pArrayProp->GetType()].Decode( &subDecodeInfo );
|
||
|
subDecodeInfo.m_pData = (char*)subDecodeInfo.m_pData + elementStride;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
int Array_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
SendProp *pArrayProp = pProp->GetArrayProp();
|
||
|
AssertMsg( pArrayProp, "Array_CompareDeltas: missing m_pArrayProp for SendProp '%s'.", pProp->m_pVarName );
|
||
|
|
||
|
int nLengthBits = pProp->GetNumArrayLengthBits();
|
||
|
int length1 = p1->ReadUBitLong( nLengthBits );
|
||
|
int length2 = p2->ReadUBitLong( nLengthBits );
|
||
|
|
||
|
int bDifferent = length1 != length2;
|
||
|
|
||
|
// Compare deltas on the props that are the same.
|
||
|
int nSame = min( length1, length2 );
|
||
|
for ( int iElement=0; iElement < nSame; iElement++ )
|
||
|
{
|
||
|
bDifferent |= g_PropTypeFns[pArrayProp->GetType()].CompareDeltas( pArrayProp, p1, p2 );
|
||
|
}
|
||
|
|
||
|
// Now just eat up the remaining properties in whichever buffer was larger.
|
||
|
if ( length1 != length2 )
|
||
|
{
|
||
|
bf_read *buffer = (length1 > length2) ? p1 : p2;
|
||
|
|
||
|
int nExtra = max( length1, length2 ) - nSame;
|
||
|
for ( int iEatUp=0; iEatUp < nExtra; iEatUp++ )
|
||
|
{
|
||
|
SkipPropData( buffer, pArrayProp );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bDifferent;
|
||
|
}
|
||
|
|
||
|
|
||
|
void Array_FastCopy(
|
||
|
const SendProp *pSendProp,
|
||
|
const RecvProp *pRecvProp,
|
||
|
const unsigned char *pSendData,
|
||
|
unsigned char *pRecvData,
|
||
|
int objectID )
|
||
|
{
|
||
|
const RecvProp *pArrayRecvProp = pRecvProp->GetArrayProp();
|
||
|
const SendProp *pArraySendProp = pSendProp->GetArrayProp();
|
||
|
|
||
|
CRecvProxyData recvProxyData;
|
||
|
recvProxyData.m_pRecvProp = pArrayRecvProp;
|
||
|
recvProxyData.m_ObjectID = objectID;
|
||
|
|
||
|
// Find out the array length and call the RecvProp's array-length proxy.
|
||
|
int nElements = Array_GetLength( pSendData, pSendProp, objectID );
|
||
|
ArrayLengthRecvProxyFn lengthProxy = pRecvProp->GetArrayLengthProxy();
|
||
|
if ( lengthProxy )
|
||
|
lengthProxy( pRecvData, objectID, nElements );
|
||
|
|
||
|
const unsigned char *pCurSendPos = pSendData + pArraySendProp->GetOffset();
|
||
|
unsigned char *pCurRecvPos = pRecvData + pArrayRecvProp->GetOffset();
|
||
|
for ( recvProxyData.m_iElement=0; recvProxyData.m_iElement < nElements; recvProxyData.m_iElement++ )
|
||
|
{
|
||
|
// Get this array element out of the sender's data.
|
||
|
pArraySendProp->GetProxyFn()( pArraySendProp, pSendData, pCurSendPos, &recvProxyData.m_Value, recvProxyData.m_iElement, objectID );
|
||
|
pCurSendPos += pSendProp->GetElementStride();
|
||
|
|
||
|
// Write it into the receiver.
|
||
|
pArrayRecvProp->GetProxyFn()( &recvProxyData, pRecvData, pCurRecvPos );
|
||
|
pCurRecvPos += pRecvProp->GetElementStride();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* Array_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_Array";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Array_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
int nElements = Array_GetLength( pStruct, pProp, -1 );
|
||
|
return ( nElements == 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
void Array_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
ArrayLengthRecvProxyFn lengthProxy = pInfo->m_pRecvProp->GetArrayLengthProxy();
|
||
|
if ( lengthProxy )
|
||
|
lengthProxy( pInfo->m_pStruct, pInfo->m_ObjectID, 0 );
|
||
|
}
|
||
|
|
||
|
bool Array_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
SendProp *pArrayProp = pProp->GetArrayProp();
|
||
|
AssertMsg( pArrayProp, ("Array_IsEncodedZero: missing m_pArrayProp for a property.") );
|
||
|
|
||
|
int nElements = pIn->ReadUBitLong( pProp->GetNumArrayLengthBits() );
|
||
|
|
||
|
for ( int i=0; i < nElements; i++ )
|
||
|
{
|
||
|
// skip over data
|
||
|
g_PropTypeFns[pArrayProp->GetType()].IsEncodedZero( pArrayProp, pIn );
|
||
|
}
|
||
|
|
||
|
return nElements == 0;;
|
||
|
}
|
||
|
|
||
|
void Array_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
SendProp *pArrayProp = pProp->GetArrayProp();
|
||
|
AssertMsg( pArrayProp, ("Array_SkipProp: missing m_pArrayProp for a property.") );
|
||
|
|
||
|
int nElements = pIn->ReadUBitLong( pProp->GetNumArrayLengthBits() );
|
||
|
|
||
|
for ( int i=0; i < nElements; i++ )
|
||
|
{
|
||
|
// skip over data
|
||
|
g_PropTypeFns[pArrayProp->GetType()].SkipProp( pArrayProp, pIn );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Datatable type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
const char* DataTable_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_DataTable";
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
// Int 64 property type abstraction.
|
||
|
// ---------------------------------------------------------------------------------------- //
|
||
|
|
||
|
void Int64_Encode( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp, bf_write *pOut, int objectID )
|
||
|
{
|
||
|
#ifdef SUPPORTS_INT64
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
pOut->WriteVarInt64( pVar->m_Int64 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pOut->WriteSignedVarInt32( pVar->m_Int64 );
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bool bNeg = pVar->m_Int64 < 0;
|
||
|
int64 iCopy = bNeg ? -pVar->m_Int64 : pVar->m_Int64;
|
||
|
uint32 *pInt = (uint32*)&iCopy;
|
||
|
uint32 lowInt = *pInt++;
|
||
|
uint32 highInt = *pInt;
|
||
|
if( pProp->IsSigned() )
|
||
|
{
|
||
|
pOut->WriteOneBit( bNeg );
|
||
|
pOut->WriteUBitLong( (unsigned int)lowInt, 32 );
|
||
|
pOut->WriteUBitLong( (unsigned int)highInt, pProp->m_nBits - 32 - 1 ); // For the sign bit
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pOut->WriteUBitLong( (unsigned int)lowInt, 32 );
|
||
|
pOut->WriteUBitLong( (unsigned int)highInt, pProp->m_nBits - 32 );
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Int64_Decode( DecodeInfo *pInfo )
|
||
|
{
|
||
|
#ifdef SUPPORTS_INT64
|
||
|
if ( pInfo->m_pProp->GetFlags() & SPROP_VARINT )
|
||
|
{
|
||
|
if ( pInfo->m_pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
pInfo->m_Value.m_Int64 = (int64)pInfo->m_pIn->ReadVarInt64();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pInfo->m_Value.m_Int64 = pInfo->m_pIn->ReadSignedVarInt64();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32 highInt = 0;
|
||
|
uint32 lowInt = 0;
|
||
|
bool bNeg = false;
|
||
|
if(pInfo->m_pProp->IsSigned())
|
||
|
{
|
||
|
bNeg = pInfo->m_pIn->ReadOneBit() != 0;
|
||
|
lowInt = pInfo->m_pIn->ReadUBitLong( 32 );
|
||
|
highInt = pInfo->m_pIn->ReadUBitLong( pInfo->m_pProp->m_nBits - 32 - 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lowInt = pInfo->m_pIn->ReadUBitLong( 32 );
|
||
|
highInt = pInfo->m_pIn->ReadUBitLong( pInfo->m_pProp->m_nBits - 32 );
|
||
|
}
|
||
|
|
||
|
uint32 *pInt = (uint32*)&pInfo->m_Value.m_Int64;
|
||
|
*pInt++ = lowInt;
|
||
|
*pInt = highInt;
|
||
|
|
||
|
if ( bNeg )
|
||
|
{
|
||
|
pInfo->m_Value.m_Int64 = -pInfo->m_Value.m_Int64;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
int Int64_CompareDeltas( const SendProp *pProp, bf_read *p1, bf_read *p2 )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
return p1->ReadVarInt64() != p2->ReadVarInt64();
|
||
|
}
|
||
|
return p1->ReadSignedVarInt64() != p2->ReadSignedVarInt64();
|
||
|
}
|
||
|
|
||
|
uint32 highInt1 = p1->ReadUBitLong( pProp->m_nBits - 32 );
|
||
|
uint32 lowInt1 = p1->ReadUBitLong( 32 );
|
||
|
uint32 highInt2 = p2->ReadUBitLong( pProp->m_nBits - 32 );
|
||
|
uint32 lowInt2 = p2->ReadUBitLong( 32 );
|
||
|
return highInt1 != highInt2 || lowInt1 != lowInt2;
|
||
|
}
|
||
|
|
||
|
const char* Int64_GetTypeNameString()
|
||
|
{
|
||
|
return "DPT_Int64";
|
||
|
}
|
||
|
|
||
|
|
||
|
bool Int64_IsZero( const unsigned char *pStruct, DVariant *pVar, const SendProp *pProp )
|
||
|
{
|
||
|
#ifdef SUPPORTS_INT64
|
||
|
return (pVar->m_Int64 == 0);
|
||
|
#else
|
||
|
return false;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void Int64_DecodeZero( DecodeInfo *pInfo )
|
||
|
{
|
||
|
#ifdef SUPPORTS_INT64
|
||
|
pInfo->m_Value.m_Int64 = 0;
|
||
|
|
||
|
if ( pInfo->m_pRecvProp )
|
||
|
{
|
||
|
pInfo->m_pRecvProp->GetProxyFn()( pInfo, pInfo->m_pStruct, pInfo->m_pData );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
bool Int64_IsEncodedZero( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
return pIn->ReadVarInt64() == 0;
|
||
|
}
|
||
|
return pIn->ReadSignedVarInt64() == 0;
|
||
|
}
|
||
|
|
||
|
uint32 highInt1 = pIn->ReadUBitLong( pProp->m_nBits - 32 );
|
||
|
uint32 lowInt1 = pIn->ReadUBitLong( 32 );
|
||
|
return (highInt1 == 0 && lowInt1 == 0);
|
||
|
}
|
||
|
|
||
|
void Int64_SkipProp( const SendProp *pProp, bf_read *pIn )
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_VARINT)
|
||
|
{
|
||
|
if ( pProp->GetFlags() & SPROP_UNSIGNED )
|
||
|
{
|
||
|
pIn->ReadVarInt64();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIn->ReadSignedVarInt64();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pIn->SeekRelative( pProp->m_nBits );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
PropTypeFns g_PropTypeFns[DPT_NUMSendPropTypes] =
|
||
|
{
|
||
|
// DPT_Int
|
||
|
{
|
||
|
Int_Encode,
|
||
|
Int_Decode,
|
||
|
Int_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
Int_GetTypeNameString,
|
||
|
Int_IsZero,
|
||
|
Int_DecodeZero,
|
||
|
Int_IsEncodedZero,
|
||
|
Int_SkipProp,
|
||
|
},
|
||
|
|
||
|
// DPT_Float
|
||
|
{
|
||
|
Float_Encode,
|
||
|
Float_Decode,
|
||
|
Float_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
Float_GetTypeNameString,
|
||
|
Float_IsZero,
|
||
|
Float_DecodeZero,
|
||
|
Float_IsEncodedZero,
|
||
|
Float_SkipProp,
|
||
|
},
|
||
|
|
||
|
// DPT_Vector
|
||
|
{
|
||
|
Vector_Encode,
|
||
|
Vector_Decode,
|
||
|
Vector_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
Vector_GetTypeNameString,
|
||
|
Vector_IsZero,
|
||
|
Vector_DecodeZero,
|
||
|
Vector_IsEncodedZero,
|
||
|
Vector_SkipProp,
|
||
|
},
|
||
|
|
||
|
// DPT_VectorXY
|
||
|
{
|
||
|
VectorXY_Encode,
|
||
|
VectorXY_Decode,
|
||
|
VectorXY_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
VectorXY_GetTypeNameString,
|
||
|
VectorXY_IsZero,
|
||
|
VectorXY_DecodeZero,
|
||
|
VectorXY_IsEncodedZero,
|
||
|
VectorXY_SkipProp,
|
||
|
},
|
||
|
|
||
|
// DPT_String
|
||
|
{
|
||
|
String_Encode,
|
||
|
String_Decode,
|
||
|
String_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
String_GetTypeNameString,
|
||
|
String_IsZero,
|
||
|
String_DecodeZero,
|
||
|
String_IsEncodedZero,
|
||
|
String_SkipProp,
|
||
|
},
|
||
|
|
||
|
// DPT_Array
|
||
|
{
|
||
|
Array_Encode,
|
||
|
Array_Decode,
|
||
|
Array_CompareDeltas,
|
||
|
Array_FastCopy,
|
||
|
Array_GetTypeNameString,
|
||
|
Array_IsZero,
|
||
|
Array_DecodeZero,
|
||
|
Array_IsEncodedZero,
|
||
|
Array_SkipProp,
|
||
|
},
|
||
|
|
||
|
// DPT_DataTable
|
||
|
{
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
DataTable_GetTypeNameString,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
},
|
||
|
#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!!
|
||
|
|
||
|
// DPT_Quaternion
|
||
|
{
|
||
|
Quaternion_Encode,
|
||
|
Quaternion_Decode,
|
||
|
Quaternion_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
Quaternion_GetTypeNameString,
|
||
|
Quaternion_IsZero,
|
||
|
Quaternion_DecodeZero,
|
||
|
Quaternion_IsEncodedZero,
|
||
|
Quaternion_SkipProp,
|
||
|
},
|
||
|
#endif
|
||
|
|
||
|
#ifdef SUPPORTS_INT64
|
||
|
// DPT_Int64
|
||
|
{
|
||
|
Int64_Encode,
|
||
|
Int64_Decode,
|
||
|
Int64_CompareDeltas,
|
||
|
Generic_FastCopy,
|
||
|
Int64_GetTypeNameString,
|
||
|
Int64_IsZero,
|
||
|
Int64_DecodeZero,
|
||
|
Int64_IsEncodedZero,
|
||
|
Int64_SkipProp,
|
||
|
},
|
||
|
#endif
|
||
|
|
||
|
};
|