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.
522 lines
13 KiB
522 lines
13 KiB
5 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
|
||
|
#ifndef DATATABLE_H
|
||
|
#define DATATABLE_H
|
||
|
#ifdef _WIN32
|
||
|
#pragma once
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#include "dt_common.h"
|
||
|
#include "dt_recv_eng.h"
|
||
|
#include "dt_send_eng.h"
|
||
|
#include "utlvector.h"
|
||
|
#include "dt_encode.h"
|
||
|
#include "utlmap.h"
|
||
|
#include "tier1/bitbuf.h"
|
||
|
|
||
|
|
||
|
class SendTable;
|
||
|
class RecvTable;
|
||
|
class CDTISendTable;
|
||
|
|
||
|
|
||
|
|
||
|
#define MAX_EXCLUDE_PROPS 512
|
||
|
|
||
|
|
||
|
// Bit counts used to encode the information about a property.
|
||
|
#define PROPINFOBITS_NUMPROPS 10
|
||
|
#define PROPINFOBITS_TYPE 5
|
||
|
#define PROPINFOBITS_FLAGS SPROP_NUMFLAGBITS_NETWORKED
|
||
|
#define PROPINFOBITS_STRINGBUFFERLEN 10
|
||
|
#define PROPINFOBITS_NUMBITS 7
|
||
|
#define PROPINFOBITS_RIGHTSHIFT 6
|
||
|
#define PROPINFOBITS_NUMELEMENTS 10 // For arrays.
|
||
|
|
||
|
|
||
|
|
||
|
class ExcludeProp
|
||
|
{
|
||
|
public:
|
||
|
char const *m_pTableName;
|
||
|
char const *m_pPropName;
|
||
|
};
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------------------------ //
|
||
|
// CDeltaBitsReader.
|
||
|
// ------------------------------------------------------------------------------------ //
|
||
|
|
||
|
|
||
|
class CDeltaBitsReader
|
||
|
{
|
||
|
public:
|
||
|
CDeltaBitsReader( bf_read *pBuf );
|
||
|
~CDeltaBitsReader();
|
||
|
|
||
|
// Write the next property index. Returns the number of bits used.
|
||
|
unsigned int ReadNextPropIndex();
|
||
|
unsigned int ReadNextPropIndex_Continued();
|
||
|
void SkipPropData( const SendProp *pProp );
|
||
|
int ComparePropData( CDeltaBitsReader* pOut, const SendProp *pProp );
|
||
|
void CopyPropData( bf_write* pOut, const SendProp *pProp );
|
||
|
|
||
|
// If you know you're done but you're not at the end (you haven't called until
|
||
|
// ReadNextPropIndex returns -1), call this so it won't assert in its destructor.
|
||
|
void ForceFinished();
|
||
|
|
||
|
private:
|
||
|
bf_read *m_pBuf;
|
||
|
int m_iLastProp;
|
||
|
};
|
||
|
|
||
|
|
||
|
FORCEINLINE CDeltaBitsReader::CDeltaBitsReader( bf_read *pBuf )
|
||
|
{
|
||
|
m_pBuf = pBuf;
|
||
|
m_iLastProp = -1;
|
||
|
}
|
||
|
|
||
|
FORCEINLINE CDeltaBitsReader::~CDeltaBitsReader()
|
||
|
{
|
||
|
// Make sure they read to the end unless they specifically said they don't care.
|
||
|
Assert( !m_pBuf );
|
||
|
}
|
||
|
|
||
|
FORCEINLINE void CDeltaBitsReader::ForceFinished()
|
||
|
{
|
||
|
#ifdef DBGFLAG_ASSERT
|
||
|
m_pBuf = NULL;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
FORCEINLINE unsigned int CDeltaBitsReader::ReadNextPropIndex()
|
||
|
{
|
||
|
Assert( m_pBuf );
|
||
|
// Expanded and optimized version of
|
||
|
// if ( m_pBuf->ReadOneBit() )
|
||
|
// {
|
||
|
// m_iLastProp += 1 + m_pBuf->ReadUBitVar();
|
||
|
// return m_iLastProp;
|
||
|
// }
|
||
|
// return ~0u;
|
||
|
if ( m_pBuf->GetNumBitsLeft() >= 7 )
|
||
|
{
|
||
|
uint bits = m_pBuf->ReadUBitLong( 7 );
|
||
|
if ( bits & 1 )
|
||
|
{
|
||
|
uint delta = bits >> 3;
|
||
|
if ( bits & 6 )
|
||
|
{
|
||
|
delta = m_pBuf->ReadUBitVarInternal( (bits & 6) >> 1 );
|
||
|
}
|
||
|
m_iLastProp = m_iLastProp + 1 + delta;
|
||
|
Assert( m_iLastProp < MAX_DATATABLE_PROPS );
|
||
|
return m_iLastProp;
|
||
|
}
|
||
|
m_pBuf->m_iCurBit -= 6; // Unread six bits we shouldn't have looked at
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Not enough bits for a property index.
|
||
|
if ( m_pBuf->ReadOneBit() )
|
||
|
{
|
||
|
// Expected a zero bit! Force an overflow!
|
||
|
m_pBuf->Seek(-1);
|
||
|
}
|
||
|
}
|
||
|
ForceFinished();
|
||
|
return ~0u;
|
||
|
}
|
||
|
|
||
|
FORCEINLINE void CDeltaBitsReader::SkipPropData( const SendProp *pProp )
|
||
|
{
|
||
|
g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, m_pBuf );
|
||
|
}
|
||
|
|
||
|
FORCEINLINE void CDeltaBitsReader::CopyPropData( bf_write* pOut, const SendProp *pProp )
|
||
|
{
|
||
|
int start = m_pBuf->GetNumBitsRead();
|
||
|
g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, m_pBuf );
|
||
|
int len = m_pBuf->GetNumBitsRead() - start;
|
||
|
m_pBuf->Seek( start );
|
||
|
pOut->WriteBitsFromBuffer( m_pBuf, len );
|
||
|
}
|
||
|
|
||
|
FORCEINLINE int CDeltaBitsReader::ComparePropData( CDeltaBitsReader *pInReader, const SendProp *pProp )
|
||
|
{
|
||
|
bf_read *pIn = pInReader->m_pBuf;
|
||
|
return g_PropTypeFns[pProp->m_Type].CompareDeltas( pProp, m_pBuf, pIn );
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------------------------ //
|
||
|
// CDeltaBitsWriter.
|
||
|
// ------------------------------------------------------------------------------------ //
|
||
|
|
||
|
class CDeltaBitsWriter
|
||
|
{
|
||
|
public:
|
||
|
CDeltaBitsWriter( bf_write *pBuf );
|
||
|
~CDeltaBitsWriter();
|
||
|
|
||
|
// Write the next property index. Returns the number of bits used.
|
||
|
void WritePropIndex( int iProp );
|
||
|
|
||
|
// Access the buffer it's outputting to.
|
||
|
bf_write* GetBitBuf();
|
||
|
|
||
|
private:
|
||
|
bf_write *m_pBuf;
|
||
|
int m_iLastProp;
|
||
|
};
|
||
|
|
||
|
inline CDeltaBitsWriter::CDeltaBitsWriter( bf_write *pBuf )
|
||
|
{
|
||
|
m_pBuf = pBuf;
|
||
|
m_iLastProp = -1;
|
||
|
}
|
||
|
|
||
|
inline bf_write* CDeltaBitsWriter::GetBitBuf()
|
||
|
{
|
||
|
return m_pBuf;
|
||
|
}
|
||
|
|
||
|
FORCEINLINE void CDeltaBitsWriter::WritePropIndex( int iProp )
|
||
|
{
|
||
|
Assert( iProp >= 0 && iProp < MAX_DATATABLE_PROPS );
|
||
|
unsigned int diff = iProp - m_iLastProp;
|
||
|
m_iLastProp = iProp;
|
||
|
Assert( diff > 0 && diff <= MAX_DATATABLE_PROPS );
|
||
|
// Expanded inline for maximum efficiency.
|
||
|
//m_pBuf->WriteOneBit( 1 );
|
||
|
//m_pBuf->WriteUBitVar( diff - 1 );
|
||
|
COMPILE_TIME_ASSERT( MAX_DATATABLE_PROPS <= 0x1000u );
|
||
|
int n = ((diff < 0x11u) ? -1 : 0) + ((diff < 0x101u) ? -1 : 0);
|
||
|
m_pBuf->WriteUBitLong( diff*8 - 8 + 4 + n*2 + 1, 8 + n*4 + 4 + 2 + 1 );
|
||
|
}
|
||
|
|
||
|
inline CDeltaBitsWriter::~CDeltaBitsWriter()
|
||
|
{
|
||
|
m_pBuf->WriteOneBit( 0 );
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------- //
|
||
|
//
|
||
|
// CSendNode
|
||
|
//
|
||
|
// Each datatable gets a tree of CSendNodes. There is one CSendNode
|
||
|
// for each datatable property that was in the original SendTable.
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------- //
|
||
|
|
||
|
class CSendNode
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
CSendNode();
|
||
|
~CSendNode();
|
||
|
|
||
|
int GetNumChildren() const;
|
||
|
CSendNode* GetChild( int i ) const;
|
||
|
|
||
|
|
||
|
// Returns true if the specified prop is in this node or any of its children.
|
||
|
bool IsPropInRecursiveProps( int i ) const;
|
||
|
|
||
|
// Each datatable property (without SPROP_PROXY_ALWAYS_YES set) gets a unique index here.
|
||
|
// The engine stores arrays of CSendProxyRecipients with the results of the proxies and indexes the results
|
||
|
// with this index.
|
||
|
//
|
||
|
// Returns DATATABLE_PROXY_INDEX_NOPROXY if the property has SPROP_PROXY_ALWAYS_YES set.
|
||
|
unsigned short GetDataTableProxyIndex() const;
|
||
|
void SetDataTableProxyIndex( unsigned short val );
|
||
|
|
||
|
// Similar to m_DataTableProxyIndex, but doesn't use DATATABLE_PROXY_INDEX_INVALID,
|
||
|
// so this can be used to index CDataTableStack::m_pProxies.
|
||
|
unsigned short GetRecursiveProxyIndex() const;
|
||
|
void SetRecursiveProxyIndex( unsigned short val );
|
||
|
|
||
|
|
||
|
public:
|
||
|
|
||
|
// Child datatables.
|
||
|
CUtlVector<CSendNode*> m_Children;
|
||
|
|
||
|
// The datatable property that leads us to this CSendNode.
|
||
|
// This indexes the CSendTablePrecalc or CRecvDecoder's m_DatatableProps list.
|
||
|
// The root CSendNode sets this to -1.
|
||
|
short m_iDatatableProp;
|
||
|
|
||
|
// The SendTable that this node represents.
|
||
|
// ALL CSendNodes have this.
|
||
|
const SendTable *m_pTable;
|
||
|
|
||
|
//
|
||
|
// Properties in this table.
|
||
|
//
|
||
|
|
||
|
// m_iFirstRecursiveProp to m_nRecursiveProps defines the list of propertise
|
||
|
// of this node and all its children.
|
||
|
unsigned short m_iFirstRecursiveProp;
|
||
|
unsigned short m_nRecursiveProps;
|
||
|
|
||
|
|
||
|
// See GetDataTableProxyIndex().
|
||
|
unsigned short m_DataTableProxyIndex;
|
||
|
|
||
|
// See GetRecursiveProxyIndex().
|
||
|
unsigned short m_RecursiveProxyIndex;
|
||
|
};
|
||
|
|
||
|
|
||
|
inline int CSendNode::GetNumChildren() const
|
||
|
{
|
||
|
return m_Children.Count();
|
||
|
}
|
||
|
|
||
|
inline CSendNode* CSendNode::GetChild( int i ) const
|
||
|
{
|
||
|
return m_Children[i];
|
||
|
}
|
||
|
|
||
|
|
||
|
inline bool CSendNode::IsPropInRecursiveProps( int i ) const
|
||
|
{
|
||
|
int index = i - (int)m_iFirstRecursiveProp;
|
||
|
return index >= 0 && index < m_nRecursiveProps;
|
||
|
}
|
||
|
|
||
|
inline unsigned short CSendNode::GetDataTableProxyIndex() const
|
||
|
{
|
||
|
Assert( m_DataTableProxyIndex != DATATABLE_PROXY_INDEX_INVALID ); // Make sure it's been set before.
|
||
|
return m_DataTableProxyIndex;
|
||
|
}
|
||
|
|
||
|
inline void CSendNode::SetDataTableProxyIndex( unsigned short val )
|
||
|
{
|
||
|
m_DataTableProxyIndex = val;
|
||
|
}
|
||
|
|
||
|
inline unsigned short CSendNode::GetRecursiveProxyIndex() const
|
||
|
{
|
||
|
return m_RecursiveProxyIndex;
|
||
|
}
|
||
|
|
||
|
inline void CSendNode::SetRecursiveProxyIndex( unsigned short val )
|
||
|
{
|
||
|
m_RecursiveProxyIndex = val;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
class CFastLocalTransferPropInfo
|
||
|
{
|
||
|
public:
|
||
|
unsigned short m_iRecvOffset;
|
||
|
unsigned short m_iSendOffset;
|
||
|
unsigned short m_iProp;
|
||
|
};
|
||
|
|
||
|
|
||
|
class CFastLocalTransferInfo
|
||
|
{
|
||
|
public:
|
||
|
CUtlVector<CFastLocalTransferPropInfo> m_FastInt32;
|
||
|
CUtlVector<CFastLocalTransferPropInfo> m_FastInt16;
|
||
|
CUtlVector<CFastLocalTransferPropInfo> m_FastInt8;
|
||
|
CUtlVector<CFastLocalTransferPropInfo> m_FastVector;
|
||
|
CUtlVector<CFastLocalTransferPropInfo> m_OtherProps; // Props that must be copied slowly (proxies and all).
|
||
|
};
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------- //
|
||
|
// CSendTablePrecalc
|
||
|
// ----------------------------------------------------------------------------- //
|
||
|
class CSendTablePrecalc
|
||
|
{
|
||
|
public:
|
||
|
CSendTablePrecalc();
|
||
|
virtual ~CSendTablePrecalc();
|
||
|
|
||
|
// This function builds the flat property array given a SendTable.
|
||
|
bool SetupFlatPropertyArray();
|
||
|
|
||
|
int GetNumProps() const;
|
||
|
const SendProp* GetProp( int i ) const;
|
||
|
|
||
|
int GetNumDatatableProps() const;
|
||
|
const SendProp* GetDatatableProp( int i ) const;
|
||
|
|
||
|
SendTable* GetSendTable() const;
|
||
|
CSendNode* GetRootNode();
|
||
|
|
||
|
int GetNumDataTableProxies() const;
|
||
|
void SetNumDataTableProxies( int count );
|
||
|
|
||
|
|
||
|
public:
|
||
|
|
||
|
class CProxyPathEntry
|
||
|
{
|
||
|
public:
|
||
|
unsigned short m_iDatatableProp; // Lookup into CSendTablePrecalc or CRecvDecoder::m_DatatableProps.
|
||
|
unsigned short m_iProxy;
|
||
|
};
|
||
|
class CProxyPath
|
||
|
{
|
||
|
public:
|
||
|
unsigned short m_iFirstEntry; // Index into m_ProxyPathEntries.
|
||
|
unsigned short m_nEntries;
|
||
|
};
|
||
|
|
||
|
CUtlVector<CProxyPathEntry> m_ProxyPathEntries; // For each proxy index, this is all the DT proxies that generate it.
|
||
|
CUtlVector<CProxyPath> m_ProxyPaths; // CProxyPathEntries lookup into this.
|
||
|
|
||
|
// These are what CSendNodes reference.
|
||
|
// These are actual data properties (ints, floats, etc).
|
||
|
CUtlVector<const SendProp*> m_Props;
|
||
|
|
||
|
// Each datatable in a SendTable's tree gets a proxy index, and its properties reference that.
|
||
|
CUtlVector<unsigned char> m_PropProxyIndices;
|
||
|
|
||
|
// CSendNode::m_iDatatableProp indexes this.
|
||
|
// These are the datatable properties (SendPropDataTable).
|
||
|
CUtlVector<const SendProp*> m_DatatableProps;
|
||
|
|
||
|
// This is the property hierarchy, with the nodes indexing m_Props.
|
||
|
CSendNode m_Root;
|
||
|
|
||
|
// From whence we came.
|
||
|
SendTable *m_pSendTable;
|
||
|
|
||
|
// For instrumentation.
|
||
|
CDTISendTable *m_pDTITable;
|
||
|
|
||
|
// This is precalculated in single player to allow faster direct copying of the entity data
|
||
|
// from the server entity to the client entity.
|
||
|
CFastLocalTransferInfo m_FastLocalTransfer;
|
||
|
|
||
|
// This tells how many data table properties there are without SPROP_PROXY_ALWAYS_YES.
|
||
|
// Arrays allocated with this size can be indexed by CSendNode::GetDataTableProxyIndex().
|
||
|
int m_nDataTableProxies;
|
||
|
|
||
|
// Map prop offsets to indices for properties that can use it.
|
||
|
CUtlMap<unsigned short, unsigned short> m_PropOffsetToIndexMap;
|
||
|
};
|
||
|
|
||
|
|
||
|
inline int CSendTablePrecalc::GetNumProps() const
|
||
|
{
|
||
|
return m_Props.Count();
|
||
|
}
|
||
|
|
||
|
inline const SendProp* CSendTablePrecalc::GetProp( int i ) const
|
||
|
{
|
||
|
return m_Props[i];
|
||
|
}
|
||
|
|
||
|
inline int CSendTablePrecalc::GetNumDatatableProps() const
|
||
|
{
|
||
|
return m_DatatableProps.Count();
|
||
|
}
|
||
|
|
||
|
inline const SendProp* CSendTablePrecalc::GetDatatableProp( int i ) const
|
||
|
{
|
||
|
return m_DatatableProps[i];
|
||
|
}
|
||
|
|
||
|
inline SendTable* CSendTablePrecalc::GetSendTable() const
|
||
|
{
|
||
|
return m_pSendTable;
|
||
|
}
|
||
|
|
||
|
inline CSendNode* CSendTablePrecalc::GetRootNode()
|
||
|
{
|
||
|
return &m_Root;
|
||
|
}
|
||
|
|
||
|
inline int CSendTablePrecalc::GetNumDataTableProxies() const
|
||
|
{
|
||
|
return m_nDataTableProxies;
|
||
|
}
|
||
|
|
||
|
|
||
|
inline void CSendTablePrecalc::SetNumDataTableProxies( int count )
|
||
|
{
|
||
|
m_nDataTableProxies = count;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ------------------------------------------------------------------------ //
|
||
|
// Helpers.
|
||
|
// ------------------------------------------------------------------------ //
|
||
|
|
||
|
// Used internally by various datatable modules.
|
||
|
void DataTable_Warning( PRINTF_FORMAT_STRING const char *pInMessage, ... ) FMTFUNCTION( 1, 2 );
|
||
|
bool ShouldWatchThisProp( const SendTable *pTable, int objectID, const char *pPropName );
|
||
|
|
||
|
// Same as AreBitArraysEqual but does a trivial test to make sure the
|
||
|
// two arrays are equally sized.
|
||
|
bool CompareBitArrays(
|
||
|
void const *pPacked1,
|
||
|
void const *pPacked2,
|
||
|
int nBits1,
|
||
|
int nBits2
|
||
|
);
|
||
|
|
||
|
// to skip of a Property we just IsEncodedZero to read over it
|
||
|
// this is faster then doing a full Decode()
|
||
|
inline void SkipPropData( bf_read *pIn, const SendProp *pProp )
|
||
|
{
|
||
|
g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, pIn );
|
||
|
}
|
||
|
|
||
|
// This is to be called on SendTables and RecvTables to setup array properties
|
||
|
// to point at their property templates and to set the SPROP_INSIDEARRAY flag
|
||
|
// on the properties inside arrays.
|
||
|
// We make the proptype an explicit template parameter because
|
||
|
// gcc templating cannot deduce typedefs from classes in templates properly
|
||
|
|
||
|
template< class TableType, class PropType >
|
||
|
void SetupArrayProps_R( TableType *pTable )
|
||
|
{
|
||
|
// If this table has already been initialized in here, then jump out.
|
||
|
if ( pTable->IsInitialized() )
|
||
|
return;
|
||
|
|
||
|
pTable->SetInitialized( true );
|
||
|
|
||
|
for ( int i=0; i < pTable->GetNumProps(); i++ )
|
||
|
{
|
||
|
PropType *pProp = pTable->GetProp( i );
|
||
|
|
||
|
if ( pProp->GetType() == DPT_Array )
|
||
|
{
|
||
|
ErrorIfNot( i >= 1,
|
||
|
("SetupArrayProps_R: array prop '%s' is at index zero.", pProp->GetName())
|
||
|
);
|
||
|
|
||
|
// Get the property defining the elements in the array.
|
||
|
PropType *pArrayProp = pTable->GetProp( i-1 );
|
||
|
pArrayProp->SetInsideArray();
|
||
|
pProp->SetArrayProp( pArrayProp );
|
||
|
}
|
||
|
else if ( pProp->GetType() == DPT_DataTable )
|
||
|
{
|
||
|
// Recurse into children datatables.
|
||
|
SetupArrayProps_R<TableType,PropType>( pProp->GetDataTable() );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif // DATATABLE_H
|