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.

485 lines
13 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef DATATABLE_H
  8. #define DATATABLE_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "dt_common.h"
  13. #include "dt_recv_eng.h"
  14. #include "dt_send_eng.h"
  15. #include "utlvector.h"
  16. #include "dt_encode.h"
  17. #include "utlmap.h"
  18. #include "tier1/bitbuf.h"
  19. #include <algorithm>
  20. class SendTable;
  21. class RecvTable;
  22. class CDTISendTable;
  23. // (Temporary.. switch to something more efficient). Number of bits to
  24. // encode property indices in the delta bits.
  25. #define PROP_SENTINEL 0x7FFFFFFF
  26. #define MAX_EXCLUDE_PROPS 512
  27. class ExcludeProp
  28. {
  29. public:
  30. char const *m_pTableName;
  31. char const *m_pPropName;
  32. };
  33. #define PROP_INDICES_COLLECTION_NUM_INDICES 2
  34. struct PropIndicesCollection_t
  35. {
  36. unsigned short m_Indices[PROP_INDICES_COLLECTION_NUM_INDICES];
  37. };
  38. // ------------------------------------------------------------------------------------ //
  39. // CDeltaBitsReader.
  40. // ------------------------------------------------------------------------------------ //
  41. class CDeltaBitsReader
  42. {
  43. public:
  44. CDeltaBitsReader( bf_read *pBuf );
  45. ~CDeltaBitsReader();
  46. // Write the next property index. Returns the number of bits used.
  47. int ReadNextPropIndex();
  48. // If you know you're done but you're not at the end (you haven't called until
  49. // ReadNextPropIndex returns -1), call this so it won't assert in its destructor.
  50. void ForceFinished();
  51. int GetFieldPathBits() const;
  52. private:
  53. bf_read *m_pBuf;
  54. bool m_bFinished;
  55. int m_iLastProp;
  56. int m_nLastFieldPathBits;
  57. bool m_bUsingNewScheme;
  58. };
  59. // ------------------------------------------------------------------------------------ //
  60. // CDeltaBitsWriter.
  61. // ------------------------------------------------------------------------------------ //
  62. class CDeltaBitsWriter
  63. {
  64. public:
  65. CDeltaBitsWriter( bf_write *pBuf );
  66. ~CDeltaBitsWriter();
  67. // Write the next property index. Returns the number of bits used.
  68. void WritePropIndex( int iProp );
  69. // Access the buffer it's outputting to.
  70. bf_write* GetBitBuf();
  71. void Finish();
  72. private:
  73. bf_write *m_pBuf;
  74. int m_iLastProp;
  75. bool m_bUsingNewScheme;
  76. };
  77. inline bf_write* CDeltaBitsWriter::GetBitBuf()
  78. {
  79. return m_pBuf;
  80. }
  81. // ----------------------------------------------------------------------------- //
  82. //
  83. // CSendNode
  84. //
  85. // Each datatable gets a tree of CSendNodes. There is one CSendNode
  86. // for each datatable property that was in the original SendTable.
  87. //
  88. // ----------------------------------------------------------------------------- //
  89. class CSendNode
  90. {
  91. public:
  92. CSendNode();
  93. ~CSendNode();
  94. int GetNumChildren() const;
  95. CSendNode* GetChild( int i ) const;
  96. // Returns true if the specified prop is in this node or any of its children.
  97. bool IsPropInRecursiveProps( int i ) const;
  98. // Each datatable property (without SPROP_PROXY_ALWAYS_YES set) gets a unique index here.
  99. // The engine stores arrays of CSendProxyRecipients with the results of the proxies and indexes the results
  100. // with this index.
  101. //
  102. // Returns DATATABLE_PROXY_INDEX_NOPROXY if the property has SPROP_PROXY_ALWAYS_YES set.
  103. unsigned short GetDataTableProxyIndex() const;
  104. void SetDataTableProxyIndex( unsigned short val );
  105. // Similar to m_DataTableProxyIndex, but doesn't use DATATABLE_PROXY_INDEX_INVALID,
  106. // so this can be used to index CDataTableStack::m_pProxies.
  107. unsigned short GetRecursiveProxyIndex() const;
  108. void SetRecursiveProxyIndex( unsigned short val );
  109. public:
  110. // Child datatables.
  111. CUtlVector<CSendNode*> m_Children;
  112. // The datatable property that leads us to this CSendNode.
  113. // This indexes the CSendTablePrecalc or CRecvDecoder's m_DatatableProps list.
  114. // The root CSendNode sets this to -1.
  115. short m_iDatatableProp;
  116. // The SendTable that this node represents.
  117. // ALL CSendNodes have this.
  118. const SendTable *m_pTable;
  119. //
  120. // Properties in this table.
  121. //
  122. // m_iFirstRecursiveProp to m_nRecursiveProps defines the list of propertise
  123. // of this node and all its children.
  124. unsigned short m_iFirstRecursiveProp;
  125. unsigned short m_nRecursiveProps;
  126. // See GetDataTableProxyIndex().
  127. unsigned short m_DataTableProxyIndex;
  128. // See GetRecursiveProxyIndex().
  129. unsigned short m_RecursiveProxyIndex;
  130. };
  131. inline int CSendNode::GetNumChildren() const
  132. {
  133. return m_Children.Count();
  134. }
  135. inline CSendNode* CSendNode::GetChild( int i ) const
  136. {
  137. return m_Children[i];
  138. }
  139. inline bool CSendNode::IsPropInRecursiveProps( int i ) const
  140. {
  141. int index = i - (int)m_iFirstRecursiveProp;
  142. return index >= 0 && index < m_nRecursiveProps;
  143. }
  144. inline unsigned short CSendNode::GetDataTableProxyIndex() const
  145. {
  146. Assert( m_DataTableProxyIndex != DATATABLE_PROXY_INDEX_INVALID ); // Make sure it's been set before.
  147. return m_DataTableProxyIndex;
  148. }
  149. inline void CSendNode::SetDataTableProxyIndex( unsigned short val )
  150. {
  151. m_DataTableProxyIndex = val;
  152. }
  153. inline unsigned short CSendNode::GetRecursiveProxyIndex() const
  154. {
  155. return m_RecursiveProxyIndex;
  156. }
  157. inline void CSendNode::SetRecursiveProxyIndex( unsigned short val )
  158. {
  159. m_RecursiveProxyIndex = val;
  160. }
  161. class CFastLocalTransferPropInfo
  162. {
  163. public:
  164. unsigned short m_iRecvOffset;
  165. unsigned short m_iSendOffset;
  166. unsigned short m_iProp;
  167. };
  168. class CFastLocalTransferInfo
  169. {
  170. public:
  171. CUtlVector<CFastLocalTransferPropInfo> m_FastInt32;
  172. CUtlVector<CFastLocalTransferPropInfo> m_FastInt16;
  173. CUtlVector<CFastLocalTransferPropInfo> m_FastInt8;
  174. CUtlVector<CFastLocalTransferPropInfo> m_FastVector;
  175. CUtlVector<CFastLocalTransferPropInfo> m_OtherProps; // Props that must be copied slowly (proxies and all).
  176. };
  177. // ----------------------------------------------------------------------------- //
  178. // CSendTablePrecalc
  179. // ----------------------------------------------------------------------------- //
  180. class CSendTablePrecalc
  181. {
  182. public:
  183. CSendTablePrecalc();
  184. virtual ~CSendTablePrecalc();
  185. // This function builds the flat property array given a SendTable.
  186. bool SetupFlatPropertyArray();
  187. int GetNumProps() const;
  188. const SendProp* GetProp( int i ) const;
  189. int GetNumDatatableProps() const;
  190. const SendProp* GetDatatableProp( int i ) const;
  191. SendTable* GetSendTable() const;
  192. CSendNode* GetRootNode();
  193. int GetNumDataTableProxies() const;
  194. void SetNumDataTableProxies( int count );
  195. //given the offset of a property, this will return the property index, or -1 if it is not found
  196. //returns number of prop indexes that match
  197. #define MAX_PROP_INDEX_OFFSETS 4
  198. inline int GetPropertyIndexFromOffset( uint16 nOffset, int propOffsets[MAX_PROP_INDEX_OFFSETS] ) const;
  199. public:
  200. class CProxyPathEntry
  201. {
  202. public:
  203. unsigned short m_iDatatableProp; // Lookup into CSendTablePrecalc or CRecvDecoder::m_DatatableProps.
  204. unsigned short m_iProxy;
  205. };
  206. class CProxyPath
  207. {
  208. public:
  209. unsigned short m_iFirstEntry; // Index into m_ProxyPathEntries.
  210. unsigned short m_nEntries;
  211. };
  212. CUtlVector<CProxyPathEntry> m_ProxyPathEntries; // For each proxy index, this is all the DT proxies that generate it.
  213. CUtlVector<CProxyPath> m_ProxyPaths; // CProxyPathEntries lookup into this.
  214. // These are what CSendNodes reference.
  215. // These are actual data properties (ints, floats, etc).
  216. CUtlVector<const SendProp*> m_Props;
  217. // Each datatable in a SendTable's tree gets a proxy index, and its properties reference that.
  218. CUtlVector<unsigned char> m_PropProxyIndices;
  219. // CSendNode::m_iDatatableProp indexes this.
  220. // These are the datatable properties (SendPropDataTable).
  221. CUtlVector<const SendProp*> m_DatatableProps;
  222. //we need an efficient way to map from a property's byte offset to the property index. To support this,
  223. //we have a sorted (on byte offset) list of property index and offset
  224. struct PropOffset_t
  225. {
  226. bool operator< ( const PropOffset_t& rhs ) const { return m_nOffset < rhs.m_nOffset; }
  227. uint16 m_nOffset;
  228. uint16 m_nIndex;
  229. };
  230. CUtlVector< PropOffset_t > m_PropOffsetToIndex;
  231. // This is the property hierarchy, with the nodes indexing m_Props.
  232. CSendNode m_Root;
  233. // From whence we came.
  234. SendTable *m_pSendTable;
  235. // For instrumentation.
  236. CDTISendTable *m_pDTITable;
  237. // This is precalculated in single player to allow faster direct copying of the entity data
  238. // from the server entity to the client entity.
  239. CFastLocalTransferInfo m_FastLocalTransfer;
  240. // This tells how many data table properties there are without SPROP_PROXY_ALWAYS_YES.
  241. // Arrays allocated with this size can be indexed by CSendNode::GetDataTableProxyIndex().
  242. int m_nDataTableProxies;
  243. // Map prop offsets to indices for properties that can use it.
  244. CUtlMap< unsigned short, PropIndicesCollection_t > m_PropOffsetToIndexMap;
  245. };
  246. inline int CSendTablePrecalc::GetNumProps() const
  247. {
  248. return m_Props.Count();
  249. }
  250. inline const SendProp* CSendTablePrecalc::GetProp( int i ) const
  251. {
  252. return m_Props[i];
  253. }
  254. inline int CSendTablePrecalc::GetNumDatatableProps() const
  255. {
  256. return m_DatatableProps.Count();
  257. }
  258. inline const SendProp* CSendTablePrecalc::GetDatatableProp( int i ) const
  259. {
  260. return m_DatatableProps[i];
  261. }
  262. inline SendTable* CSendTablePrecalc::GetSendTable() const
  263. {
  264. return m_pSendTable;
  265. }
  266. inline CSendNode* CSendTablePrecalc::GetRootNode()
  267. {
  268. return &m_Root;
  269. }
  270. inline int CSendTablePrecalc::GetNumDataTableProxies() const
  271. {
  272. return m_nDataTableProxies;
  273. }
  274. inline void CSendTablePrecalc::SetNumDataTableProxies( int count )
  275. {
  276. m_nDataTableProxies = count;
  277. }
  278. //given the offset of a property, this will return the property index, or -1 if it is not found
  279. inline int CSendTablePrecalc::GetPropertyIndexFromOffset( uint16 nOffset, int propOffsets[MAX_PROP_INDEX_OFFSETS] ) const
  280. {
  281. //do a binary search to find the lowest bound of our value (binary search is just a bool, and range does two checks)
  282. PropOffset_t Lookup;
  283. Lookup.m_nOffset = nOffset;
  284. const PropOffset_t* pBegin = m_PropOffsetToIndex.Base();
  285. const PropOffset_t* pEnd = pBegin + m_PropOffsetToIndex.Count();
  286. const PropOffset_t* pProp = std::lower_bound( pBegin, pEnd, Lookup );
  287. //we can get properties that aren't in our map (such as a disabled var being set), so handle it not being in the map
  288. if( pProp == pEnd )
  289. return 0;
  290. int numMatchingProps = 0;
  291. do
  292. {
  293. propOffsets[numMatchingProps++] = pProp->m_nIndex;
  294. if ( numMatchingProps == MAX_PROP_INDEX_OFFSETS )
  295. {
  296. AssertMsg( false, "Too many properties matching same offset!" );
  297. return numMatchingProps;
  298. }
  299. ++pProp;
  300. } while ( pProp != pEnd && pProp->m_nOffset == nOffset );
  301. return numMatchingProps;
  302. }
  303. // ------------------------------------------------------------------------ //
  304. // Helpers.
  305. // ------------------------------------------------------------------------ //
  306. // Used internally by various datatable modules.
  307. void DataTable_Warning( PRINTF_FORMAT_STRING const char *pInMessage, ... ) FMTFUNCTION( 1, 2 );
  308. bool ShouldWatchThisProp( const SendTable *pTable, int objectID, const char *pPropName );
  309. bool ShouldWatchThisProp( const RecvTable *pTable, int objectID, const char *pPropName );
  310. // Same as AreBitArraysEqual but does a trivial test to make sure the
  311. // two arrays are equally sized.
  312. bool CompareBitArrays(
  313. void const *pPacked1,
  314. void const *pPacked2,
  315. int nBits1,
  316. int nBits2
  317. );
  318. // Helper routines for seeking through encoded buffers.
  319. inline int NextProp( CDeltaBitsReader *pDeltaBitsReader )
  320. {
  321. int iProp = pDeltaBitsReader->ReadNextPropIndex();
  322. if ( iProp >= 0 )
  323. {
  324. return iProp;
  325. }
  326. else
  327. {
  328. return PROP_SENTINEL;
  329. }
  330. }
  331. // to skip of a Property we just IsEncodedZero to read over it
  332. // this is faster then doing a full Decode()
  333. inline void SkipPropData( bf_read *pIn, const SendProp *pProp )
  334. {
  335. g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, pIn );
  336. }
  337. // This is to be called on SendTables and RecvTables to setup array properties
  338. // to point at their property templates and to set the SPROP_INSIDEARRAY flag
  339. // on the properties inside arrays.
  340. // We make the proptype an explicit template parameter because
  341. // gcc templating cannot deduce typedefs from classes in templates properly
  342. template< class TableType, class PropType >
  343. void SetupArrayProps_R( TableType *pTable )
  344. {
  345. // If this table has already been initialized in here, then jump out.
  346. if ( pTable->IsInitialized() )
  347. return;
  348. pTable->SetInitialized( true );
  349. for ( int i=0; i < pTable->GetNumProps(); i++ )
  350. {
  351. PropType *pProp = pTable->GetProp( i );
  352. if ( pProp->GetType() == DPT_Array )
  353. {
  354. ErrorIfNot( i >= 1,
  355. ("SetupArrayProps_R: array prop '%s' is at index zero.", pProp->GetName())
  356. );
  357. // Get the property defining the elements in the array.
  358. PropType *pArrayProp = pTable->GetProp( i-1 );
  359. pArrayProp->SetInsideArray();
  360. pProp->SetArrayProp( pArrayProp );
  361. }
  362. else if ( pProp->GetType() == DPT_DataTable )
  363. {
  364. // Recurse into children datatables.
  365. SetupArrayProps_R<TableType,PropType>( pProp->GetDataTable() );
  366. }
  367. }
  368. }
  369. void FlushDeltaBitsTrackingData();
  370. bool Sendprop_UsingDebugWatch();
  371. #endif // DATATABLE_H