Counter Strike : Global Offensive Source Code
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.

293 lines
8.9 KiB

  1. //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
  2. //
  3. //
  4. //
  5. //==================================================================================================
  6. #ifndef SERIALIZEDENTITY_H
  7. #define SERIALIZEDENTITY_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "tier1/utlmap.h"
  12. #include "tier1/utlvector.h"
  13. #include "dt.h"
  14. #include "iclientnetworkable.h"
  15. #include "ents_shared.h"
  16. typedef int CFieldPath; // It's just an index into the flattened SendProp list!!!
  17. //#define PARANOID_SERIALIZEDENTITY
  18. class CSerializedEntity
  19. {
  20. public:
  21. CSerializedEntity();
  22. ~CSerializedEntity();
  23. //gets the number of fields contained within this serialized entity
  24. int GetFieldCount() const { return m_nFieldCount; }
  25. //determines the total number of bits used to hold all the field data
  26. uint32 GetFieldDataBitCount() const { return m_nFieldDataBits; }
  27. //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
  28. bool IsPacked() const { return ( m_nNumReservedFields == knPacked ); }
  29. //given an index, this will return the 'path' or identifier for that field
  30. CFieldPath GetFieldPath( int nIndex ) const { Assert( nIndex < m_nFieldCount ); return m_pFields[ nIndex ]; }
  31. void SetFieldPath( int nIndex, CFieldPath path ) { Assert( nIndex < m_nFieldCount ); m_pFields[ nIndex ] = path; }
  32. //given a field index, this will return the starting bit within the field data for that field
  33. uint32 GetFieldDataBitOffset( int nIndex ) const { Assert( nIndex < m_nFieldCount ); return m_pFieldDataOffsets[ nIndex ]; }
  34. uint32 GetFieldDataBitEndOffset( int nIndex ) const { Assert( nIndex < m_nFieldCount ); return ( nIndex + 1 < m_nFieldCount ) ? m_pFieldDataOffsets[ nIndex + 1 ] : m_nFieldDataBits; }
  35. void SetFieldDataBitOffset( int nIndex, uint32 nOffset ) { Assert( nIndex < m_nFieldCount ); m_pFieldDataOffsets[ nIndex ] = nOffset; }
  36. //access to the direct memory buffers for those that need direct access
  37. uint8* GetFieldData() { return m_pFieldData; }
  38. const uint8* GetFieldData() const { return m_pFieldData; }
  39. short* GetFieldPaths() { return m_pFields; }
  40. const short* GetFieldPaths() const { return m_pFields; }
  41. uint32* GetFieldDataBitOffsets() { return m_pFieldDataOffsets; }
  42. const uint32* GetFieldDataBitOffsets() const { return m_pFieldDataOffsets; }
  43. //given another serialized entity, this will just copy over the contents of the other entity, making its own copy
  44. void Copy( const CSerializedEntity &other );
  45. //given another serialized entity, this will handle swapping the contents of this one with the other serialized entity
  46. void Swap( CSerializedEntity& other );
  47. //clears all the contents of this serialized entity
  48. void Clear();
  49. //this sets up the memory within this serialized entity for the specified number of fields and total data size. This is useful
  50. //for in place writing of results to avoid intermediate allocations, but care should be taken that the entity is already cleared
  51. //prior to this call
  52. void SetupPackMemory( int nNumFields, int nDataBits );
  53. //given a field index, this will return all the information associated with it
  54. void GetField( int nFieldIndex, CFieldPath &path, int *pnDataOffset, int *pnNextDataOffset ) const
  55. {
  56. path = GetFieldPath( nFieldIndex );
  57. *pnDataOffset = GetFieldDataBitOffset( nFieldIndex );
  58. *pnNextDataOffset = GetFieldDataBitEndOffset( nFieldIndex );
  59. }
  60. //---------------------------------------------------------------
  61. //the following are only valid on unpacked serialized entities. When done with adding data, they should be packed with their field data
  62. //called to reserve an amount of memory for the path and offset information
  63. void ReservePathAndOffsetMemory( uint32 nNumElements );
  64. //adds a path and offset to the list of fields in this set
  65. void AddPathAndOffset( const CFieldPath &path, int nStartBit )
  66. {
  67. //inlined for performance when packing snapshots for networking (called for EVERY property)
  68. Assert( !IsPacked() );
  69. if ( m_nFieldCount == m_nNumReservedFields )
  70. Grow();
  71. m_pFields[m_nFieldCount] = path;
  72. m_pFieldDataOffsets[m_nFieldCount] = nStartBit;
  73. ++m_nFieldCount;
  74. }
  75. //called to read the path and offset information form the field path, adding them to the list
  76. bool ReadFieldPaths( bf_read *pBuf, CUtlVector< int > *pvecFieldPathBits = NULL ); // pvecFieldPathBits needed for DTI modes
  77. //called to seal a dynamic list, packing it into a compact memory block along with its actual value data
  78. void PackWithFieldData( void *pData, int nDataBits );
  79. void PackWithFieldData( bf_read &buf, int nDataBits );
  80. //---------------------------------------------------------------
  81. // Sets up reading from the m_pFieldData
  82. void StartReading( bf_read& bitReader ) const;
  83. void StartWriting( bf_write& bitWriter );
  84. //given an index (assumed in range), this will determine the size in bits of that field's data
  85. int GetFieldDataSizeInBits( int nField ) const { return GetFieldDataBitEndOffset( nField ) - GetFieldDataBitOffset( nField ); }
  86. static void DumpMemInfo();
  87. bool operator ==( const CSerializedEntity &other ) const
  88. {
  89. if ( this == &other )
  90. return true;
  91. if ( m_nFieldCount != other.m_nFieldCount )
  92. return false;
  93. if ( m_nFieldDataBits != other.m_nFieldDataBits )
  94. return false;
  95. if ( V_memcmp( m_pFieldData, other.m_pFieldData, Bits2Bytes( m_nFieldDataBits ) ) )
  96. return false;
  97. for ( int i = 0; i < m_nFieldCount; ++i )
  98. {
  99. if ( m_pFields[ i ] != other.m_pFields[ i ] )
  100. return false;
  101. }
  102. return true;
  103. }
  104. #ifndef PARANOID_SERIALIZEDENTITY
  105. // Hack to make these accessible to helper classes/functions when using PARANOID_SERIALIZEDENTITY
  106. private:
  107. #endif
  108. //constant used to designate when this entity is in a packed state or not
  109. static const uint16 knPacked = (uint16)0xFFFF;
  110. //the total number of fields that we have
  111. uint16 m_nFieldCount;
  112. //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
  113. uint16 m_nNumReservedFields;
  114. //the number of bits for our data
  115. uint32 m_nFieldDataBits;
  116. //the following fields are laid out in a memory block in the following order when packed, so only the first should be freed
  117. short *m_pFields;
  118. uint32 *m_pFieldDataOffsets;
  119. uint8 *m_pFieldData;
  120. //memory tracking information for development builds
  121. #ifdef PARANOID_SERIALIZEDENTITY
  122. char const *m_File;
  123. int m_Line;
  124. #endif
  125. void Grow();
  126. void Pack( short *pFields, uint32 *pFieldDataOffsets, int fieldCount, uint32 nFieldDataBits, uint8 *pFieldData );
  127. CSerializedEntity( const CSerializedEntity &other );
  128. DISALLOW_OPERATOR_EQUAL( CSerializedEntity );
  129. DECLARE_FIXEDSIZE_ALLOCATOR_MT( CSerializedEntity );
  130. };
  131. class CSerializedEntityFieldIterator
  132. {
  133. public:
  134. CSerializedEntityFieldIterator( CSerializedEntity *pEntity ) :
  135. m_pEntity( pEntity )
  136. , m_entityFieldCount( pEntity ? pEntity->GetFieldCount() : 0 )
  137. , m_nFieldIndex( -1 )
  138. , m_pCurrent( NULL )
  139. {
  140. m_Sentinel = PROP_SENTINEL;
  141. }
  142. const CFieldPath &First()
  143. {
  144. m_nFieldIndex = 0;
  145. Update();
  146. return GetField();
  147. }
  148. const CFieldPath *FirstPtr()
  149. {
  150. m_nFieldIndex = 0;
  151. Update();
  152. return GetFieldPtr();
  153. }
  154. const CFieldPath &Prev()
  155. {
  156. --m_nFieldIndex;
  157. Update();
  158. return GetField();
  159. }
  160. const CFieldPath *PrevPtr()
  161. {
  162. --m_nFieldIndex;
  163. Update();
  164. return GetFieldPtr();
  165. }
  166. const CFieldPath &Next()
  167. {
  168. ++m_nFieldIndex;
  169. Update();
  170. return GetField();
  171. }
  172. const CFieldPath *NextPtr()
  173. {
  174. ++m_nFieldIndex;
  175. Update();
  176. return GetFieldPtr();
  177. }
  178. bool IsValid() const
  179. {
  180. // Use unsigned math so there is only one comparison.
  181. return (unsigned)m_nFieldIndex < (unsigned)m_entityFieldCount;
  182. }
  183. int GetIndex() const
  184. {
  185. return m_nFieldIndex;
  186. }
  187. CFieldPath SetIndex( int nFieldIndex )
  188. {
  189. m_nFieldIndex = nFieldIndex;
  190. Update();
  191. return GetField();
  192. }
  193. const CFieldPath &GetField() const
  194. {
  195. return *m_pCurrent;
  196. }
  197. const CFieldPath *GetFieldPtr() const
  198. {
  199. return m_pCurrent;
  200. }
  201. int GetOffset() const
  202. {
  203. return m_nOffset;
  204. }
  205. int GetLength() const
  206. {
  207. return m_nNextOffset - m_nOffset;
  208. }
  209. int GetNextOffset() const
  210. {
  211. return m_nNextOffset;
  212. }
  213. private:
  214. void Update()
  215. {
  216. if ( !IsValid() )
  217. {
  218. Assert( m_Sentinel == PROP_SENTINEL );
  219. m_pCurrent = &m_Sentinel;
  220. m_nOffset = m_nNextOffset = -1;
  221. }
  222. else
  223. {
  224. m_pCurrent = &m_Current;
  225. m_pEntity->GetField( m_nFieldIndex, m_Current, &m_nOffset, &m_nNextOffset );
  226. }
  227. }
  228. CSerializedEntity * const m_pEntity;
  229. // Cache the entity field count to avoid extra branches and pointer dereferences in IsValid()
  230. const int m_entityFieldCount;
  231. int m_nFieldIndex;
  232. CFieldPath m_Sentinel;
  233. CFieldPath *m_pCurrent;
  234. CFieldPath m_Current;
  235. int m_nOffset;
  236. int m_nNextOffset;
  237. };
  238. #endif // SERIALIZEDENTITY_H