|
|
//===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
//
//
//
//==================================================================================================
#ifndef SERIALIZEDENTITY_H
#define SERIALIZEDENTITY_H
#ifdef _WIN32
#pragma once
#endif
#include "tier1/utlmap.h"
#include "tier1/utlvector.h"
#include "dt.h"
#include "iclientnetworkable.h"
#include "ents_shared.h"
typedef int CFieldPath; // It's just an index into the flattened SendProp list!!!
//#define PARANOID_SERIALIZEDENTITY
class CSerializedEntity { public: CSerializedEntity(); ~CSerializedEntity();
//gets the number of fields contained within this serialized entity
int GetFieldCount() const { return m_nFieldCount; } //determines the total number of bits used to hold all the field data
uint32 GetFieldDataBitCount() const { return m_nFieldDataBits; } //determines if this entity is in a packed state. If so, it must be cleared and reallocated to change the size of any of the fields
bool IsPacked() const { return ( m_nNumReservedFields == knPacked ); }
//given an index, this will return the 'path' or identifier for that field
CFieldPath GetFieldPath( int nIndex ) const { Assert( nIndex < m_nFieldCount ); return m_pFields[ nIndex ]; } void SetFieldPath( int nIndex, CFieldPath path ) { Assert( nIndex < m_nFieldCount ); m_pFields[ nIndex ] = path; }
//given a field index, this will return the starting bit within the field data for that field
uint32 GetFieldDataBitOffset( int nIndex ) const { Assert( nIndex < m_nFieldCount ); return m_pFieldDataOffsets[ nIndex ]; } uint32 GetFieldDataBitEndOffset( int nIndex ) const { Assert( nIndex < m_nFieldCount ); return ( nIndex + 1 < m_nFieldCount ) ? m_pFieldDataOffsets[ nIndex + 1 ] : m_nFieldDataBits; } void SetFieldDataBitOffset( int nIndex, uint32 nOffset ) { Assert( nIndex < m_nFieldCount ); m_pFieldDataOffsets[ nIndex ] = nOffset; }
//access to the direct memory buffers for those that need direct access
uint8* GetFieldData() { return m_pFieldData; } const uint8* GetFieldData() const { return m_pFieldData; } short* GetFieldPaths() { return m_pFields; } const short* GetFieldPaths() const { return m_pFields; } uint32* GetFieldDataBitOffsets() { return m_pFieldDataOffsets; } const uint32* GetFieldDataBitOffsets() const { return m_pFieldDataOffsets; } //given another serialized entity, this will just copy over the contents of the other entity, making its own copy
void Copy( const CSerializedEntity &other );
//given another serialized entity, this will handle swapping the contents of this one with the other serialized entity
void Swap( CSerializedEntity& other );
//clears all the contents of this serialized entity
void Clear();
//this sets up the memory within this serialized entity for the specified number of fields and total data size. This is useful
//for in place writing of results to avoid intermediate allocations, but care should be taken that the entity is already cleared
//prior to this call
void SetupPackMemory( int nNumFields, int nDataBits );
//given a field index, this will return all the information associated with it
void GetField( int nFieldIndex, CFieldPath &path, int *pnDataOffset, int *pnNextDataOffset ) const { path = GetFieldPath( nFieldIndex ); *pnDataOffset = GetFieldDataBitOffset( nFieldIndex ); *pnNextDataOffset = GetFieldDataBitEndOffset( nFieldIndex ); }
//---------------------------------------------------------------
//the following are only valid on unpacked serialized entities. When done with adding data, they should be packed with their field data
//called to reserve an amount of memory for the path and offset information
void ReservePathAndOffsetMemory( uint32 nNumElements ); //adds a path and offset to the list of fields in this set
void AddPathAndOffset( const CFieldPath &path, int nStartBit ) { //inlined for performance when packing snapshots for networking (called for EVERY property)
Assert( !IsPacked() ); if ( m_nFieldCount == m_nNumReservedFields ) Grow();
m_pFields[m_nFieldCount] = path; m_pFieldDataOffsets[m_nFieldCount] = nStartBit; ++m_nFieldCount; }
//called to read the path and offset information form the field path, adding them to the list
bool ReadFieldPaths( bf_read *pBuf, CUtlVector< int > *pvecFieldPathBits = NULL ); // pvecFieldPathBits needed for DTI modes
//called to seal a dynamic list, packing it into a compact memory block along with its actual value data
void PackWithFieldData( void *pData, int nDataBits ); void PackWithFieldData( bf_read &buf, int nDataBits ); //---------------------------------------------------------------
// Sets up reading from the m_pFieldData
void StartReading( bf_read& bitReader ) const; void StartWriting( bf_write& bitWriter );
//given an index (assumed in range), this will determine the size in bits of that field's data
int GetFieldDataSizeInBits( int nField ) const { return GetFieldDataBitEndOffset( nField ) - GetFieldDataBitOffset( nField ); } static void DumpMemInfo();
bool operator ==( const CSerializedEntity &other ) const { if ( this == &other ) return true;
if ( m_nFieldCount != other.m_nFieldCount ) return false;
if ( m_nFieldDataBits != other.m_nFieldDataBits ) return false;
if ( V_memcmp( m_pFieldData, other.m_pFieldData, Bits2Bytes( m_nFieldDataBits ) ) ) return false;
for ( int i = 0; i < m_nFieldCount; ++i ) { if ( m_pFields[ i ] != other.m_pFields[ i ] ) return false; }
return true; }
#ifndef PARANOID_SERIALIZEDENTITY
// Hack to make these accessible to helper classes/functions when using PARANOID_SERIALIZEDENTITY
private: #endif
//constant used to designate when this entity is in a packed state or not
static const uint16 knPacked = (uint16)0xFFFF;
//the total number of fields that we have
uint16 m_nFieldCount; //this is the internal count of how many fields we have preallocated, should always be >= field count. This will be knPacked if we are in a packed format
uint16 m_nNumReservedFields; //the number of bits for our data
uint32 m_nFieldDataBits; //the following fields are laid out in a memory block in the following order when packed, so only the first should be freed
short *m_pFields; uint32 *m_pFieldDataOffsets; uint8 *m_pFieldData;
//memory tracking information for development builds
#ifdef PARANOID_SERIALIZEDENTITY
char const *m_File; int m_Line; #endif
void Grow(); void Pack( short *pFields, uint32 *pFieldDataOffsets, int fieldCount, uint32 nFieldDataBits, uint8 *pFieldData );
CSerializedEntity( const CSerializedEntity &other ); DISALLOW_OPERATOR_EQUAL( CSerializedEntity );
DECLARE_FIXEDSIZE_ALLOCATOR_MT( CSerializedEntity ); };
class CSerializedEntityFieldIterator { public: CSerializedEntityFieldIterator( CSerializedEntity *pEntity ) : m_pEntity( pEntity ) , m_entityFieldCount( pEntity ? pEntity->GetFieldCount() : 0 ) , m_nFieldIndex( -1 ) , m_pCurrent( NULL ) { m_Sentinel = PROP_SENTINEL; }
const CFieldPath &First() { m_nFieldIndex = 0; Update(); return GetField(); }
const CFieldPath *FirstPtr() { m_nFieldIndex = 0; Update(); return GetFieldPtr(); }
const CFieldPath &Prev() { --m_nFieldIndex; Update(); return GetField(); }
const CFieldPath *PrevPtr() { --m_nFieldIndex; Update(); return GetFieldPtr(); }
const CFieldPath &Next() { ++m_nFieldIndex; Update(); return GetField(); }
const CFieldPath *NextPtr() { ++m_nFieldIndex; Update(); return GetFieldPtr(); }
bool IsValid() const { // Use unsigned math so there is only one comparison.
return (unsigned)m_nFieldIndex < (unsigned)m_entityFieldCount; }
int GetIndex() const { return m_nFieldIndex; }
CFieldPath SetIndex( int nFieldIndex ) { m_nFieldIndex = nFieldIndex; Update(); return GetField(); }
const CFieldPath &GetField() const { return *m_pCurrent; }
const CFieldPath *GetFieldPtr() const { return m_pCurrent; }
int GetOffset() const { return m_nOffset; }
int GetLength() const { return m_nNextOffset - m_nOffset; }
int GetNextOffset() const { return m_nNextOffset; }
private:
void Update() { if ( !IsValid() ) { Assert( m_Sentinel == PROP_SENTINEL ); m_pCurrent = &m_Sentinel; m_nOffset = m_nNextOffset = -1; } else { m_pCurrent = &m_Current; m_pEntity->GetField( m_nFieldIndex, m_Current, &m_nOffset, &m_nNextOffset ); } }
CSerializedEntity * const m_pEntity; // Cache the entity field count to avoid extra branches and pointer dereferences in IsValid()
const int m_entityFieldCount; int m_nFieldIndex;
CFieldPath m_Sentinel; CFieldPath *m_pCurrent; CFieldPath m_Current; int m_nOffset; int m_nNextOffset; };
#endif // SERIALIZEDENTITY_H
|