Team Fortress 2 Source Code as on 22/4/2020
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.

521 lines
13 KiB

  1. //========= Copyright 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. class SendTable;
  20. class RecvTable;
  21. class CDTISendTable;
  22. #define MAX_EXCLUDE_PROPS 512
  23. // Bit counts used to encode the information about a property.
  24. #define PROPINFOBITS_NUMPROPS 10
  25. #define PROPINFOBITS_TYPE 5
  26. #define PROPINFOBITS_FLAGS SPROP_NUMFLAGBITS_NETWORKED
  27. #define PROPINFOBITS_STRINGBUFFERLEN 10
  28. #define PROPINFOBITS_NUMBITS 7
  29. #define PROPINFOBITS_RIGHTSHIFT 6
  30. #define PROPINFOBITS_NUMELEMENTS 10 // For arrays.
  31. class ExcludeProp
  32. {
  33. public:
  34. char const *m_pTableName;
  35. char const *m_pPropName;
  36. };
  37. // ------------------------------------------------------------------------------------ //
  38. // CDeltaBitsReader.
  39. // ------------------------------------------------------------------------------------ //
  40. class CDeltaBitsReader
  41. {
  42. public:
  43. CDeltaBitsReader( bf_read *pBuf );
  44. ~CDeltaBitsReader();
  45. // Write the next property index. Returns the number of bits used.
  46. unsigned int ReadNextPropIndex();
  47. unsigned int ReadNextPropIndex_Continued();
  48. void SkipPropData( const SendProp *pProp );
  49. int ComparePropData( CDeltaBitsReader* pOut, const SendProp *pProp );
  50. void CopyPropData( bf_write* pOut, const SendProp *pProp );
  51. // If you know you're done but you're not at the end (you haven't called until
  52. // ReadNextPropIndex returns -1), call this so it won't assert in its destructor.
  53. void ForceFinished();
  54. private:
  55. bf_read *m_pBuf;
  56. int m_iLastProp;
  57. };
  58. FORCEINLINE CDeltaBitsReader::CDeltaBitsReader( bf_read *pBuf )
  59. {
  60. m_pBuf = pBuf;
  61. m_iLastProp = -1;
  62. }
  63. FORCEINLINE CDeltaBitsReader::~CDeltaBitsReader()
  64. {
  65. // Make sure they read to the end unless they specifically said they don't care.
  66. Assert( !m_pBuf );
  67. }
  68. FORCEINLINE void CDeltaBitsReader::ForceFinished()
  69. {
  70. #ifdef DBGFLAG_ASSERT
  71. m_pBuf = NULL;
  72. #endif
  73. }
  74. FORCEINLINE unsigned int CDeltaBitsReader::ReadNextPropIndex()
  75. {
  76. Assert( m_pBuf );
  77. // Expanded and optimized version of
  78. // if ( m_pBuf->ReadOneBit() )
  79. // {
  80. // m_iLastProp += 1 + m_pBuf->ReadUBitVar();
  81. // return m_iLastProp;
  82. // }
  83. // return ~0u;
  84. if ( m_pBuf->GetNumBitsLeft() >= 7 )
  85. {
  86. uint bits = m_pBuf->ReadUBitLong( 7 );
  87. if ( bits & 1 )
  88. {
  89. uint delta = bits >> 3;
  90. if ( bits & 6 )
  91. {
  92. delta = m_pBuf->ReadUBitVarInternal( (bits & 6) >> 1 );
  93. }
  94. m_iLastProp = m_iLastProp + 1 + delta;
  95. Assert( m_iLastProp < MAX_DATATABLE_PROPS );
  96. return m_iLastProp;
  97. }
  98. m_pBuf->m_iCurBit -= 6; // Unread six bits we shouldn't have looked at
  99. }
  100. else
  101. {
  102. // Not enough bits for a property index.
  103. if ( m_pBuf->ReadOneBit() )
  104. {
  105. // Expected a zero bit! Force an overflow!
  106. m_pBuf->Seek(-1);
  107. }
  108. }
  109. ForceFinished();
  110. return ~0u;
  111. }
  112. FORCEINLINE void CDeltaBitsReader::SkipPropData( const SendProp *pProp )
  113. {
  114. g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, m_pBuf );
  115. }
  116. FORCEINLINE void CDeltaBitsReader::CopyPropData( bf_write* pOut, const SendProp *pProp )
  117. {
  118. int start = m_pBuf->GetNumBitsRead();
  119. g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, m_pBuf );
  120. int len = m_pBuf->GetNumBitsRead() - start;
  121. m_pBuf->Seek( start );
  122. pOut->WriteBitsFromBuffer( m_pBuf, len );
  123. }
  124. FORCEINLINE int CDeltaBitsReader::ComparePropData( CDeltaBitsReader *pInReader, const SendProp *pProp )
  125. {
  126. bf_read *pIn = pInReader->m_pBuf;
  127. return g_PropTypeFns[pProp->m_Type].CompareDeltas( pProp, m_pBuf, pIn );
  128. }
  129. // ------------------------------------------------------------------------------------ //
  130. // CDeltaBitsWriter.
  131. // ------------------------------------------------------------------------------------ //
  132. class CDeltaBitsWriter
  133. {
  134. public:
  135. CDeltaBitsWriter( bf_write *pBuf );
  136. ~CDeltaBitsWriter();
  137. // Write the next property index. Returns the number of bits used.
  138. void WritePropIndex( int iProp );
  139. // Access the buffer it's outputting to.
  140. bf_write* GetBitBuf();
  141. private:
  142. bf_write *m_pBuf;
  143. int m_iLastProp;
  144. };
  145. inline CDeltaBitsWriter::CDeltaBitsWriter( bf_write *pBuf )
  146. {
  147. m_pBuf = pBuf;
  148. m_iLastProp = -1;
  149. }
  150. inline bf_write* CDeltaBitsWriter::GetBitBuf()
  151. {
  152. return m_pBuf;
  153. }
  154. FORCEINLINE void CDeltaBitsWriter::WritePropIndex( int iProp )
  155. {
  156. Assert( iProp >= 0 && iProp < MAX_DATATABLE_PROPS );
  157. unsigned int diff = iProp - m_iLastProp;
  158. m_iLastProp = iProp;
  159. Assert( diff > 0 && diff <= MAX_DATATABLE_PROPS );
  160. // Expanded inline for maximum efficiency.
  161. //m_pBuf->WriteOneBit( 1 );
  162. //m_pBuf->WriteUBitVar( diff - 1 );
  163. COMPILE_TIME_ASSERT( MAX_DATATABLE_PROPS <= 0x1000u );
  164. int n = ((diff < 0x11u) ? -1 : 0) + ((diff < 0x101u) ? -1 : 0);
  165. m_pBuf->WriteUBitLong( diff*8 - 8 + 4 + n*2 + 1, 8 + n*4 + 4 + 2 + 1 );
  166. }
  167. inline CDeltaBitsWriter::~CDeltaBitsWriter()
  168. {
  169. m_pBuf->WriteOneBit( 0 );
  170. }
  171. // ----------------------------------------------------------------------------- //
  172. //
  173. // CSendNode
  174. //
  175. // Each datatable gets a tree of CSendNodes. There is one CSendNode
  176. // for each datatable property that was in the original SendTable.
  177. //
  178. // ----------------------------------------------------------------------------- //
  179. class CSendNode
  180. {
  181. public:
  182. CSendNode();
  183. ~CSendNode();
  184. int GetNumChildren() const;
  185. CSendNode* GetChild( int i ) const;
  186. // Returns true if the specified prop is in this node or any of its children.
  187. bool IsPropInRecursiveProps( int i ) const;
  188. // Each datatable property (without SPROP_PROXY_ALWAYS_YES set) gets a unique index here.
  189. // The engine stores arrays of CSendProxyRecipients with the results of the proxies and indexes the results
  190. // with this index.
  191. //
  192. // Returns DATATABLE_PROXY_INDEX_NOPROXY if the property has SPROP_PROXY_ALWAYS_YES set.
  193. unsigned short GetDataTableProxyIndex() const;
  194. void SetDataTableProxyIndex( unsigned short val );
  195. // Similar to m_DataTableProxyIndex, but doesn't use DATATABLE_PROXY_INDEX_INVALID,
  196. // so this can be used to index CDataTableStack::m_pProxies.
  197. unsigned short GetRecursiveProxyIndex() const;
  198. void SetRecursiveProxyIndex( unsigned short val );
  199. public:
  200. // Child datatables.
  201. CUtlVector<CSendNode*> m_Children;
  202. // The datatable property that leads us to this CSendNode.
  203. // This indexes the CSendTablePrecalc or CRecvDecoder's m_DatatableProps list.
  204. // The root CSendNode sets this to -1.
  205. short m_iDatatableProp;
  206. // The SendTable that this node represents.
  207. // ALL CSendNodes have this.
  208. const SendTable *m_pTable;
  209. //
  210. // Properties in this table.
  211. //
  212. // m_iFirstRecursiveProp to m_nRecursiveProps defines the list of propertise
  213. // of this node and all its children.
  214. unsigned short m_iFirstRecursiveProp;
  215. unsigned short m_nRecursiveProps;
  216. // See GetDataTableProxyIndex().
  217. unsigned short m_DataTableProxyIndex;
  218. // See GetRecursiveProxyIndex().
  219. unsigned short m_RecursiveProxyIndex;
  220. };
  221. inline int CSendNode::GetNumChildren() const
  222. {
  223. return m_Children.Count();
  224. }
  225. inline CSendNode* CSendNode::GetChild( int i ) const
  226. {
  227. return m_Children[i];
  228. }
  229. inline bool CSendNode::IsPropInRecursiveProps( int i ) const
  230. {
  231. int index = i - (int)m_iFirstRecursiveProp;
  232. return index >= 0 && index < m_nRecursiveProps;
  233. }
  234. inline unsigned short CSendNode::GetDataTableProxyIndex() const
  235. {
  236. Assert( m_DataTableProxyIndex != DATATABLE_PROXY_INDEX_INVALID ); // Make sure it's been set before.
  237. return m_DataTableProxyIndex;
  238. }
  239. inline void CSendNode::SetDataTableProxyIndex( unsigned short val )
  240. {
  241. m_DataTableProxyIndex = val;
  242. }
  243. inline unsigned short CSendNode::GetRecursiveProxyIndex() const
  244. {
  245. return m_RecursiveProxyIndex;
  246. }
  247. inline void CSendNode::SetRecursiveProxyIndex( unsigned short val )
  248. {
  249. m_RecursiveProxyIndex = val;
  250. }
  251. class CFastLocalTransferPropInfo
  252. {
  253. public:
  254. unsigned short m_iRecvOffset;
  255. unsigned short m_iSendOffset;
  256. unsigned short m_iProp;
  257. };
  258. class CFastLocalTransferInfo
  259. {
  260. public:
  261. CUtlVector<CFastLocalTransferPropInfo> m_FastInt32;
  262. CUtlVector<CFastLocalTransferPropInfo> m_FastInt16;
  263. CUtlVector<CFastLocalTransferPropInfo> m_FastInt8;
  264. CUtlVector<CFastLocalTransferPropInfo> m_FastVector;
  265. CUtlVector<CFastLocalTransferPropInfo> m_OtherProps; // Props that must be copied slowly (proxies and all).
  266. };
  267. // ----------------------------------------------------------------------------- //
  268. // CSendTablePrecalc
  269. // ----------------------------------------------------------------------------- //
  270. class CSendTablePrecalc
  271. {
  272. public:
  273. CSendTablePrecalc();
  274. virtual ~CSendTablePrecalc();
  275. // This function builds the flat property array given a SendTable.
  276. bool SetupFlatPropertyArray();
  277. int GetNumProps() const;
  278. const SendProp* GetProp( int i ) const;
  279. int GetNumDatatableProps() const;
  280. const SendProp* GetDatatableProp( int i ) const;
  281. SendTable* GetSendTable() const;
  282. CSendNode* GetRootNode();
  283. int GetNumDataTableProxies() const;
  284. void SetNumDataTableProxies( int count );
  285. public:
  286. class CProxyPathEntry
  287. {
  288. public:
  289. unsigned short m_iDatatableProp; // Lookup into CSendTablePrecalc or CRecvDecoder::m_DatatableProps.
  290. unsigned short m_iProxy;
  291. };
  292. class CProxyPath
  293. {
  294. public:
  295. unsigned short m_iFirstEntry; // Index into m_ProxyPathEntries.
  296. unsigned short m_nEntries;
  297. };
  298. CUtlVector<CProxyPathEntry> m_ProxyPathEntries; // For each proxy index, this is all the DT proxies that generate it.
  299. CUtlVector<CProxyPath> m_ProxyPaths; // CProxyPathEntries lookup into this.
  300. // These are what CSendNodes reference.
  301. // These are actual data properties (ints, floats, etc).
  302. CUtlVector<const SendProp*> m_Props;
  303. // Each datatable in a SendTable's tree gets a proxy index, and its properties reference that.
  304. CUtlVector<unsigned char> m_PropProxyIndices;
  305. // CSendNode::m_iDatatableProp indexes this.
  306. // These are the datatable properties (SendPropDataTable).
  307. CUtlVector<const SendProp*> m_DatatableProps;
  308. // This is the property hierarchy, with the nodes indexing m_Props.
  309. CSendNode m_Root;
  310. // From whence we came.
  311. SendTable *m_pSendTable;
  312. // For instrumentation.
  313. CDTISendTable *m_pDTITable;
  314. // This is precalculated in single player to allow faster direct copying of the entity data
  315. // from the server entity to the client entity.
  316. CFastLocalTransferInfo m_FastLocalTransfer;
  317. // This tells how many data table properties there are without SPROP_PROXY_ALWAYS_YES.
  318. // Arrays allocated with this size can be indexed by CSendNode::GetDataTableProxyIndex().
  319. int m_nDataTableProxies;
  320. // Map prop offsets to indices for properties that can use it.
  321. CUtlMap<unsigned short, unsigned short> m_PropOffsetToIndexMap;
  322. };
  323. inline int CSendTablePrecalc::GetNumProps() const
  324. {
  325. return m_Props.Count();
  326. }
  327. inline const SendProp* CSendTablePrecalc::GetProp( int i ) const
  328. {
  329. return m_Props[i];
  330. }
  331. inline int CSendTablePrecalc::GetNumDatatableProps() const
  332. {
  333. return m_DatatableProps.Count();
  334. }
  335. inline const SendProp* CSendTablePrecalc::GetDatatableProp( int i ) const
  336. {
  337. return m_DatatableProps[i];
  338. }
  339. inline SendTable* CSendTablePrecalc::GetSendTable() const
  340. {
  341. return m_pSendTable;
  342. }
  343. inline CSendNode* CSendTablePrecalc::GetRootNode()
  344. {
  345. return &m_Root;
  346. }
  347. inline int CSendTablePrecalc::GetNumDataTableProxies() const
  348. {
  349. return m_nDataTableProxies;
  350. }
  351. inline void CSendTablePrecalc::SetNumDataTableProxies( int count )
  352. {
  353. m_nDataTableProxies = count;
  354. }
  355. // ------------------------------------------------------------------------ //
  356. // Helpers.
  357. // ------------------------------------------------------------------------ //
  358. // Used internally by various datatable modules.
  359. void DataTable_Warning( PRINTF_FORMAT_STRING const char *pInMessage, ... ) FMTFUNCTION( 1, 2 );
  360. bool ShouldWatchThisProp( const SendTable *pTable, int objectID, const char *pPropName );
  361. // Same as AreBitArraysEqual but does a trivial test to make sure the
  362. // two arrays are equally sized.
  363. bool CompareBitArrays(
  364. void const *pPacked1,
  365. void const *pPacked2,
  366. int nBits1,
  367. int nBits2
  368. );
  369. // to skip of a Property we just IsEncodedZero to read over it
  370. // this is faster then doing a full Decode()
  371. inline void SkipPropData( bf_read *pIn, const SendProp *pProp )
  372. {
  373. g_PropTypeFns[ pProp->GetType() ].SkipProp( pProp, pIn );
  374. }
  375. // This is to be called on SendTables and RecvTables to setup array properties
  376. // to point at their property templates and to set the SPROP_INSIDEARRAY flag
  377. // on the properties inside arrays.
  378. // We make the proptype an explicit template parameter because
  379. // gcc templating cannot deduce typedefs from classes in templates properly
  380. template< class TableType, class PropType >
  381. void SetupArrayProps_R( TableType *pTable )
  382. {
  383. // If this table has already been initialized in here, then jump out.
  384. if ( pTable->IsInitialized() )
  385. return;
  386. pTable->SetInitialized( true );
  387. for ( int i=0; i < pTable->GetNumProps(); i++ )
  388. {
  389. PropType *pProp = pTable->GetProp( i );
  390. if ( pProp->GetType() == DPT_Array )
  391. {
  392. ErrorIfNot( i >= 1,
  393. ("SetupArrayProps_R: array prop '%s' is at index zero.", pProp->GetName())
  394. );
  395. // Get the property defining the elements in the array.
  396. PropType *pArrayProp = pTable->GetProp( i-1 );
  397. pArrayProp->SetInsideArray();
  398. pProp->SetArrayProp( pArrayProp );
  399. }
  400. else if ( pProp->GetType() == DPT_DataTable )
  401. {
  402. // Recurse into children datatables.
  403. SetupArrayProps_R<TableType,PropType>( pProp->GetDataTable() );
  404. }
  405. }
  406. }
  407. #endif // DATATABLE_H