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.

922 lines
22 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. //#define LOG_DELTA_BITS_TO_FILE
  8. #ifdef LOG_DELTA_BITS_TO_FILE
  9. #undef fopen
  10. #endif
  11. #include "tier1/tokenset.h"
  12. #include <algorithm>
  13. #include <stdarg.h>
  14. #include "dt_send.h"
  15. #include "dt.h"
  16. #include "dt_recv.h"
  17. #include "dt_encode.h"
  18. #include "convar.h"
  19. #include "commonmacros.h"
  20. #include "tier1/strtools.h"
  21. #include "tier0/dbg.h"
  22. #include "dt_stack.h"
  23. #include "filesystem_engine.h"
  24. #include "filesystem.h"
  25. // memdbgon must be the last include file in a .cpp file!!!
  26. #include "tier0/memdbgon.h"
  27. #define PROPINDEX_NUMBITS 12
  28. #define MAX_TOTAL_SENDTABLE_PROPS ( (1 << PROPINDEX_NUMBITS) - 1 ) // one value reserved for end marker
  29. #define PROPINDEX_END_MARKER ( ( 1 << PROPINDEX_NUMBITS ) - 1 )
  30. ConVar g_CV_DTWatchEnt( "dtwatchent", "-1", 0, "Watch this entities data table encoding." );
  31. ConVar g_CV_DTWatchVar( "dtwatchvar", "", 0, "Watch the named variable." );
  32. ConVar g_CV_DTWarning( "dtwarning", "0", 0, "Print data table warnings?" );
  33. ConVar g_CV_DTWatchClass( "dtwatchclass", "", 0, "Watch all fields encoded with this table." );
  34. ConVar g_CV_DTEncode( "dtwatchencode", "1", 0, "When watching show encode." );
  35. ConVar g_CV_DTDecode( "dtwatchdecode", "1", 0, "When watching show decode." );
  36. ConVar sv_new_delta_bits( "sv_new_delta_bits", "1" );
  37. #ifdef LOG_DELTA_BITS_TO_FILE
  38. class CDeltaBitsRun
  39. {
  40. public:
  41. CUtlVector<int> m_Props;
  42. CUtlVector<int> m_BitCounts;
  43. };
  44. CUtlVector<CDeltaBitsRun*> g_DeltaBitsRuns;
  45. CDeltaBitsRun *g_pDeltaBitsRun = NULL;
  46. inline void LogDeltaBitsStart()
  47. {
  48. if ( g_pDeltaBitsRun )
  49. Error( "LogDeltaBitsStart" );
  50. g_pDeltaBitsRun = new CDeltaBitsRun;
  51. g_DeltaBitsRuns.AddToTail( g_pDeltaBitsRun );
  52. }
  53. inline void LogDeltaBitsEnd()
  54. {
  55. if ( !g_pDeltaBitsRun )
  56. Error( "LogDeltaBitsEnd" );
  57. g_pDeltaBitsRun = NULL;
  58. }
  59. inline void LogDeltaBitsEntry( int iProp, int nBits )
  60. {
  61. g_pDeltaBitsRun->m_Props.AddToTail( iProp );
  62. g_pDeltaBitsRun->m_BitCounts.AddToTail( nBits );
  63. }
  64. void FlushDeltaBitsTrackingData()
  65. {
  66. FILE *fp = fopen( "c:\\deltabits.txt", "wt" );
  67. fprintf( fp, "%d\n", g_DeltaBitsRuns.Count() );
  68. for ( int i=0; i < g_DeltaBitsRuns.Count(); i++ )
  69. {
  70. CDeltaBitsRun *pRun = g_DeltaBitsRuns[i];
  71. fprintf( fp, "%d ", pRun->m_Props.Count() );
  72. for ( int z=0; z < pRun->m_Props.Count(); z++ )
  73. {
  74. fprintf( fp, "%d %d ", pRun->m_Props[z], pRun->m_BitCounts[z] );
  75. }
  76. fprintf( fp, "\n" );
  77. }
  78. fclose( fp );
  79. }
  80. #else
  81. inline void LogDeltaBitsStart() {}
  82. inline void LogDeltaBitsEnd() {}
  83. inline void LogDeltaBitsEntry( int iProp, int nBits ) {}
  84. void FlushDeltaBitsTrackingData() {}
  85. #endif
  86. // ----------------------------------------------------------------------------- //
  87. //
  88. // CBuildHierarchyStruct
  89. //
  90. // Used while building a CSendNode hierarchy.
  91. //
  92. // ----------------------------------------------------------------------------- //
  93. class CBuildHierarchyStruct
  94. {
  95. public:
  96. const ExcludeProp *m_pExcludeProps;
  97. int m_nExcludeProps;
  98. const SendProp *m_pDatatableProps[MAX_TOTAL_SENDTABLE_PROPS];
  99. int m_nDatatableProps;
  100. const SendProp *m_pProps[MAX_TOTAL_SENDTABLE_PROPS];
  101. unsigned char m_PropProxyIndices[MAX_TOTAL_SENDTABLE_PROPS];
  102. int m_nProps;
  103. unsigned char m_nPropProxies;
  104. };
  105. // ------------------------------------------------------------------------------------ //
  106. // CDeltaBitsWriter.
  107. // ------------------------------------------------------------------------------------ //
  108. static FORCEINLINE unsigned int ReadPropIndex( bf_read *pBuf, bool bNewScheme )
  109. {
  110. if ( bNewScheme )
  111. {
  112. if ( pBuf->ReadOneBit() )
  113. {
  114. return pBuf->ReadUBitLong( 3 );
  115. }
  116. }
  117. int ret = pBuf->ReadUBitLong( 7 );
  118. switch( ret & ( 32 | 64 ) )
  119. {
  120. case 32:
  121. ret = ( ret &~96 ) | ( pBuf->ReadUBitLong( 2 ) << 5 );
  122. Assert( ret >= 32);
  123. break;
  124. case 64:
  125. ret = ( ret &~96 ) | ( pBuf->ReadUBitLong( 4 ) << 5 );
  126. Assert( ret >= 128);
  127. break;
  128. case 96:
  129. ret = ( ret &~96 ) | ( pBuf->ReadUBitLong( 7 ) << 5 );
  130. Assert( ret >= 512);
  131. break;
  132. }
  133. return ret;
  134. }
  135. FORCEINLINE void WritePropIndex( bf_write *pBuf, unsigned int n, bool bNewScheme )
  136. {
  137. Assert( n < (1 << PROPINDEX_NUMBITS ) );
  138. Assert( ( n & 0xfff ) == n );
  139. if ( bNewScheme )
  140. {
  141. if ( n < 8 )
  142. {
  143. pBuf->WriteOneBit( 1 );
  144. pBuf->WriteUBitLong( n, 3 );
  145. return;
  146. }
  147. else
  148. {
  149. pBuf->WriteOneBit( 0 );
  150. }
  151. }
  152. if ( n < 32 )
  153. pBuf->WriteUBitLong( n, 7 );
  154. else
  155. if ( n < 128 )
  156. pBuf->WriteUBitLong( ( n & 31 ) | 32 | ( ( n & ( 64 | 32 ) ) << 2 ), 9 );
  157. else
  158. if ( n < 512 )
  159. pBuf->WriteUBitLong( ( n & 31 ) | 64 | ( ( n & ( 256 | 128 | 64 | 32 ) ) << 2 ), 11 );
  160. else
  161. pBuf->WriteUBitLong( ( n & 31 ) | 96 |
  162. ( ( n & ( 2048 | 1024 | 512 | 256 | 128 | 64 | 32 ) ) << 2 ), 14 );
  163. }
  164. CDeltaBitsWriter::CDeltaBitsWriter( bf_write *pBuf )
  165. {
  166. m_pBuf = pBuf;
  167. m_iLastProp = -1;
  168. LogDeltaBitsStart();
  169. //TODO: Get rid of this..
  170. m_bUsingNewScheme = sv_new_delta_bits.GetBool();
  171. if ( m_bUsingNewScheme )
  172. pBuf->WriteOneBit( 1 );
  173. else
  174. pBuf->WriteOneBit( 0 );
  175. }
  176. CDeltaBitsWriter::~CDeltaBitsWriter()
  177. {
  178. if ( m_pBuf )
  179. Finish();
  180. }
  181. void CDeltaBitsWriter::Finish()
  182. {
  183. m_pBuf->WriteOneBit( 0 );
  184. ::WritePropIndex( m_pBuf, PROPINDEX_END_MARKER, m_bUsingNewScheme );
  185. LogDeltaBitsEnd();
  186. m_pBuf = NULL;
  187. }
  188. void CDeltaBitsWriter::WritePropIndex( int iProp )
  189. {
  190. int diff = iProp - m_iLastProp;
  191. m_iLastProp = iProp;
  192. Assert( iProp < MAX_DATATABLE_PROPS );
  193. Assert( diff > 0 && diff < MAX_DATATABLE_PROPS );
  194. --diff; // It's always at least 1 so subtract 1.
  195. int startbit = m_pBuf->GetNumBitsWritten();
  196. if ( m_bUsingNewScheme )
  197. {
  198. if ( diff == 0 )
  199. {
  200. m_pBuf->WriteOneBit( 1 );
  201. }
  202. else
  203. {
  204. m_pBuf->WriteOneBit( 0 );
  205. ::WritePropIndex( m_pBuf, diff, m_bUsingNewScheme );
  206. }
  207. }
  208. else
  209. {
  210. ::WritePropIndex( m_pBuf, diff, m_bUsingNewScheme );
  211. }
  212. int nBitsToEncode = m_pBuf->GetNumBitsWritten() - startbit;
  213. LogDeltaBitsEntry( iProp, nBitsToEncode );
  214. }
  215. // ------------------------------------------------------------------------------------ //
  216. // CDeltaBitsReader.
  217. // ------------------------------------------------------------------------------------ //
  218. CDeltaBitsReader::CDeltaBitsReader( bf_read *pBuf ) : m_nLastFieldPathBits( 0 )
  219. {
  220. m_pBuf = pBuf;
  221. m_bFinished = false;
  222. m_iLastProp = -1;
  223. if ( pBuf )
  224. m_bUsingNewScheme = (pBuf->ReadOneBit() != 0);
  225. else
  226. m_bUsingNewScheme = false;
  227. }
  228. CDeltaBitsReader::~CDeltaBitsReader()
  229. {
  230. // Make sure they read to the end unless they specifically said they don't care.
  231. if ( m_pBuf )
  232. {
  233. Assert( m_bFinished );
  234. }
  235. }
  236. int CDeltaBitsReader::GetFieldPathBits() const
  237. {
  238. return m_nLastFieldPathBits;
  239. }
  240. int CDeltaBitsReader::ReadNextPropIndex()
  241. {
  242. Assert( !m_bFinished );
  243. if ( m_bUsingNewScheme )
  244. {
  245. if ( m_pBuf->ReadOneBit() )
  246. {
  247. m_iLastProp++;
  248. m_nLastFieldPathBits = 1;
  249. return m_iLastProp;
  250. }
  251. }
  252. int nStartBit = m_pBuf->GetNumBitsRead();
  253. int nRead = ReadPropIndex( m_pBuf, m_bUsingNewScheme );
  254. m_nLastFieldPathBits = m_pBuf->GetNumBitsRead() - nStartBit;
  255. if ( nRead == PROPINDEX_END_MARKER )
  256. {
  257. m_bFinished = true;
  258. return -1;
  259. }
  260. int prop = 1 + nRead;
  261. prop += m_iLastProp;
  262. m_iLastProp = prop;
  263. Assert( m_iLastProp < MAX_DATATABLE_PROPS );
  264. return prop;
  265. }
  266. void CDeltaBitsReader::ForceFinished()
  267. {
  268. m_bFinished = true;
  269. m_pBuf = NULL;
  270. }
  271. // ----------------------------------------------------------------------------- //
  272. // CSendNode.
  273. // ----------------------------------------------------------------------------- //
  274. CSendNode::CSendNode()
  275. {
  276. m_iDatatableProp = -1;
  277. m_pTable = NULL;
  278. m_iFirstRecursiveProp = m_nRecursiveProps = 0;
  279. m_DataTableProxyIndex = DATATABLE_PROXY_INDEX_INVALID; // set it to a questionable value.
  280. }
  281. CSendNode::~CSendNode()
  282. {
  283. int c = GetNumChildren();
  284. for ( int i = c - 1 ; i >= 0 ; i-- )
  285. {
  286. delete GetChild( i );
  287. }
  288. m_Children.Purge();
  289. }
  290. // ----------------------------------------------------------------------------- //
  291. // CSendTablePrecalc
  292. // ----------------------------------------------------------------------------- //
  293. bool PropOffsetLT( const unsigned short &a, const unsigned short &b )
  294. {
  295. return a < b;
  296. }
  297. CSendTablePrecalc::CSendTablePrecalc() :
  298. m_PropOffsetToIndexMap( 0, 0, PropOffsetLT )
  299. {
  300. m_pDTITable = NULL;
  301. m_pSendTable = 0;
  302. m_nDataTableProxies = 0;
  303. }
  304. CSendTablePrecalc::~CSendTablePrecalc()
  305. {
  306. if ( m_pSendTable )
  307. m_pSendTable->m_pPrecalc = 0;
  308. }
  309. const ExcludeProp* FindExcludeProp(
  310. char const *pTableName,
  311. char const *pPropName,
  312. const ExcludeProp *pExcludeProps,
  313. int nExcludeProps)
  314. {
  315. for ( int i=0; i < nExcludeProps; i++ )
  316. {
  317. if ( stricmp(pExcludeProps[i].m_pTableName, pTableName) == 0 && stricmp(pExcludeProps[i].m_pPropName, pPropName ) == 0 )
  318. return &pExcludeProps[i];
  319. }
  320. return NULL;
  321. }
  322. // Fill in a list of all the excluded props.
  323. static bool SendTable_GetPropsExcluded( const SendTable *pTable, ExcludeProp *pExcludeProps, int &nExcludeProps, int nMaxExcludeProps )
  324. {
  325. for(int i=0; i < pTable->m_nProps; i++)
  326. {
  327. SendProp *pProp = &pTable->m_pProps[i];
  328. if ( pProp->IsExcludeProp() )
  329. {
  330. char const *pName = pProp->GetExcludeDTName();
  331. ErrorIfNot( pName,
  332. ("Found an exclude prop missing a name.")
  333. );
  334. ErrorIfNot( nExcludeProps < nMaxExcludeProps,
  335. ("SendTable_GetPropsExcluded: Overflowed max exclude props with %s.", pName)
  336. );
  337. pExcludeProps[nExcludeProps].m_pTableName = pName;
  338. pExcludeProps[nExcludeProps].m_pPropName = pProp->GetName();
  339. nExcludeProps++;
  340. }
  341. else if ( pProp->GetDataTable() )
  342. {
  343. if( !SendTable_GetPropsExcluded( pProp->GetDataTable(), pExcludeProps, nExcludeProps, nMaxExcludeProps ) )
  344. return false;
  345. }
  346. }
  347. return true;
  348. }
  349. // Set the datatable proxy indices in all datatable SendProps.
  350. static void SetDataTableProxyIndices_R(
  351. CSendTablePrecalc *pMainTable,
  352. CSendNode *pCurTable,
  353. CBuildHierarchyStruct *bhs )
  354. {
  355. for ( int i=0; i < pCurTable->GetNumChildren(); i++ )
  356. {
  357. CSendNode *pNode = pCurTable->GetChild( i );
  358. const SendProp *pProp = bhs->m_pDatatableProps[pNode->m_iDatatableProp];
  359. if ( pProp->GetFlags() & SPROP_PROXY_ALWAYS_YES )
  360. {
  361. pNode->SetDataTableProxyIndex( DATATABLE_PROXY_INDEX_NOPROXY );
  362. }
  363. else
  364. {
  365. pNode->SetDataTableProxyIndex( pMainTable->GetNumDataTableProxies() );
  366. pMainTable->SetNumDataTableProxies( pMainTable->GetNumDataTableProxies() + 1 );
  367. }
  368. SetDataTableProxyIndices_R( pMainTable, pNode, bhs );
  369. }
  370. }
  371. // Set the datatable proxy indices in all datatable SendProps.
  372. static void SetRecursiveProxyIndices_R(
  373. SendTable *pBaseTable,
  374. CSendNode *pCurTable,
  375. int &iCurProxyIndex )
  376. {
  377. if ( iCurProxyIndex >= CDatatableStack::MAX_PROXY_RESULTS )
  378. Error( "Too many proxies for datatable %s.", pBaseTable->GetName() );
  379. pCurTable->SetRecursiveProxyIndex( iCurProxyIndex );
  380. iCurProxyIndex++;
  381. for ( int i=0; i < pCurTable->GetNumChildren(); i++ )
  382. {
  383. CSendNode *pNode = pCurTable->GetChild( i );
  384. SetRecursiveProxyIndices_R( pBaseTable, pNode, iCurProxyIndex );
  385. }
  386. }
  387. void SendTable_BuildHierarchy(
  388. CSendNode *pNode,
  389. const SendTable *pTable,
  390. CBuildHierarchyStruct *bhs
  391. );
  392. void SendTable_BuildHierarchy_IterateProps(
  393. CSendNode *pNode,
  394. const SendTable *pTable,
  395. CBuildHierarchyStruct *bhs,
  396. const SendProp *pNonDatatableProps[MAX_TOTAL_SENDTABLE_PROPS],
  397. int &nNonDatatableProps )
  398. {
  399. int i;
  400. for ( i=0; i < pTable->m_nProps; i++ )
  401. {
  402. const SendProp *pProp = &pTable->m_pProps[i];
  403. if ( pProp->IsExcludeProp() ||
  404. pProp->IsInsideArray() ||
  405. FindExcludeProp( pTable->GetName(), pProp->GetName(), bhs->m_pExcludeProps, bhs->m_nExcludeProps ) )
  406. {
  407. continue;
  408. }
  409. if ( pProp->GetType() == DPT_DataTable )
  410. {
  411. if ( pProp->GetFlags() & SPROP_COLLAPSIBLE )
  412. {
  413. // This is a base class.. no need to make a new CSendNode (and trigger a bunch of
  414. // unnecessary send proxy calls in the datatable stacks).
  415. SendTable_BuildHierarchy_IterateProps(
  416. pNode,
  417. pProp->GetDataTable(),
  418. bhs,
  419. pNonDatatableProps,
  420. nNonDatatableProps );
  421. }
  422. else
  423. {
  424. // Setup a child datatable reference.
  425. CSendNode *pChild = new CSendNode;
  426. // Setup a datatable prop for this node to reference (so the recursion
  427. // routines can get at the proxy).
  428. if ( bhs->m_nDatatableProps >= ARRAYSIZE( bhs->m_pDatatableProps ) )
  429. Error( "Overflowed datatable prop list in SendTable '%s'.", pTable->GetName() );
  430. bhs->m_pDatatableProps[bhs->m_nDatatableProps] = pProp;
  431. pChild->m_iDatatableProp = bhs->m_nDatatableProps;
  432. ++bhs->m_nDatatableProps;
  433. pNode->m_Children.AddToTail( pChild );
  434. // Recurse into the new child datatable.
  435. SendTable_BuildHierarchy( pChild, pProp->GetDataTable(), bhs );
  436. }
  437. }
  438. else
  439. {
  440. if ( nNonDatatableProps >= MAX_TOTAL_SENDTABLE_PROPS )
  441. Error( "SendTable_BuildHierarchy: overflowed non-datatable props with '%s'.", pProp->GetName() );
  442. pNonDatatableProps[nNonDatatableProps] = pProp;
  443. ++nNonDatatableProps;
  444. }
  445. }
  446. }
  447. void SendTable_BuildHierarchy(
  448. CSendNode *pNode,
  449. const SendTable *pTable,
  450. CBuildHierarchyStruct *bhs
  451. )
  452. {
  453. pNode->m_pTable = pTable;
  454. pNode->m_iFirstRecursiveProp = bhs->m_nProps;
  455. if ( bhs->m_nPropProxies >= 255 )
  456. {
  457. Error( "Exceeded max number of datatable proxies in SendTable_BuildHierarchy()" );
  458. }
  459. unsigned char curPropProxy = bhs->m_nPropProxies;
  460. ++bhs->m_nPropProxies;
  461. const SendProp *pNonDatatableProps[MAX_TOTAL_SENDTABLE_PROPS];
  462. int nNonDatatableProps = 0;
  463. // First add all the child datatables.
  464. SendTable_BuildHierarchy_IterateProps(
  465. pNode,
  466. pTable,
  467. bhs,
  468. pNonDatatableProps,
  469. nNonDatatableProps );
  470. // Now add the properties.
  471. // Make sure there's room, then just copy the pointers from the loop above.
  472. ErrorIfNot( bhs->m_nProps + nNonDatatableProps < ARRAYSIZE( bhs->m_pProps ),
  473. ("SendTable_BuildHierarchy: overflowed prop buffer.")
  474. );
  475. for ( int i=0; i < nNonDatatableProps; i++ )
  476. {
  477. bhs->m_pProps[bhs->m_nProps] = pNonDatatableProps[i];
  478. bhs->m_PropProxyIndices[bhs->m_nProps] = curPropProxy;
  479. ++bhs->m_nProps;
  480. }
  481. pNode->m_nRecursiveProps = bhs->m_nProps - pNode->m_iFirstRecursiveProp;
  482. }
  483. static int __cdecl SendProp_SortPriorities( const byte *p1, const byte *p2 )
  484. {
  485. return *p1 > *p2;
  486. }
  487. void SendTable_SortByPriority(CBuildHierarchyStruct *bhs)
  488. {
  489. CUtlVector<byte> priorities;
  490. // Build a list of priorities
  491. // Default entry for SPROP_CHANGES_OFTEN
  492. priorities.AddToTail( SENDPROP_CHANGES_OFTEN_PRIORITY );
  493. for ( int i = 0; i < bhs->m_nProps; i++ )
  494. {
  495. const SendProp *p = bhs->m_pProps[i];
  496. if ( priorities.Find( p->GetPriority() ) < 0 )
  497. {
  498. priorities.AddToTail( p->GetPriority() );
  499. }
  500. }
  501. // We're using this one because CUtlVector::Sort utilizes qsort, which has different behavior on Windows than on Linux
  502. std::stable_sort( priorities.Base(), priorities.Base() + priorities.Count() );
  503. int start = 0;
  504. for ( int priorityIndex = 0; priorityIndex < priorities.Count(); ++priorityIndex )
  505. {
  506. byte priority = priorities[priorityIndex];
  507. int i;
  508. while( true )
  509. {
  510. for ( i = start; i < bhs->m_nProps; i++ )
  511. {
  512. const SendProp *p = bhs->m_pProps[i];
  513. unsigned char c = bhs->m_PropProxyIndices[i];
  514. if ( p->GetPriority() == priority ||
  515. ( ( p->GetFlags() & SPROP_CHANGES_OFTEN ) && priority == SENDPROP_CHANGES_OFTEN_PRIORITY ) )
  516. {
  517. if ( i != start )
  518. {
  519. bhs->m_pProps[i] = bhs->m_pProps[start];
  520. bhs->m_PropProxyIndices[i] = bhs->m_PropProxyIndices[start];
  521. bhs->m_pProps[start] = p;
  522. bhs->m_PropProxyIndices[start] = c;
  523. }
  524. start++;
  525. break;
  526. }
  527. }
  528. if ( i == bhs->m_nProps )
  529. break;
  530. }
  531. }
  532. }
  533. void CalcPathLengths_R( CSendNode *pNode, CUtlVector<int> &pathLengths, int curPathLength, int &totalPathLengths )
  534. {
  535. pathLengths[pNode->GetRecursiveProxyIndex()] = curPathLength;
  536. totalPathLengths += curPathLength;
  537. for ( int i=0; i < pNode->GetNumChildren(); i++ )
  538. {
  539. CalcPathLengths_R( pNode->GetChild( i ), pathLengths, curPathLength+1, totalPathLengths );
  540. }
  541. }
  542. void FillPathEntries_R( CSendTablePrecalc *pPrecalc, CSendNode *pNode, CSendNode *pParent, int &iCurEntry )
  543. {
  544. // Fill in this node's path.
  545. CSendTablePrecalc::CProxyPath &outProxyPath = pPrecalc->m_ProxyPaths[ pNode->GetRecursiveProxyIndex() ];
  546. outProxyPath.m_iFirstEntry = (unsigned short)iCurEntry;
  547. // Copy all the proxies leading to the parent.
  548. if ( pParent )
  549. {
  550. CSendTablePrecalc::CProxyPath &parentProxyPath = pPrecalc->m_ProxyPaths[pParent->GetRecursiveProxyIndex()];
  551. outProxyPath.m_nEntries = parentProxyPath.m_nEntries + 1;
  552. for ( int i=0; i < parentProxyPath.m_nEntries; i++ )
  553. pPrecalc->m_ProxyPathEntries[iCurEntry++] = pPrecalc->m_ProxyPathEntries[parentProxyPath.m_iFirstEntry+i];
  554. // Now add this node's own proxy.
  555. pPrecalc->m_ProxyPathEntries[iCurEntry].m_iProxy = pNode->GetRecursiveProxyIndex();
  556. pPrecalc->m_ProxyPathEntries[iCurEntry].m_iDatatableProp = pNode->m_iDatatableProp;
  557. ++iCurEntry;
  558. }
  559. else
  560. {
  561. outProxyPath.m_nEntries = 0;
  562. }
  563. for ( int i=0; i < pNode->GetNumChildren(); i++ )
  564. {
  565. FillPathEntries_R( pPrecalc, pNode->GetChild( i ), pNode, iCurEntry );
  566. }
  567. }
  568. void SendTable_GenerateProxyPaths( CSendTablePrecalc *pPrecalc, int nProxyIndices )
  569. {
  570. // Initialize the array.
  571. pPrecalc->m_ProxyPaths.SetSize( nProxyIndices );
  572. for ( int i=0; i < nProxyIndices; i++ )
  573. pPrecalc->m_ProxyPaths[i].m_iFirstEntry = pPrecalc->m_ProxyPaths[i].m_nEntries = 0xFFFF;
  574. // Figure out how long the path down the tree is to each node.
  575. int totalPathLengths = 0;
  576. CUtlVector<int> pathLengths;
  577. pathLengths.SetSize( nProxyIndices );
  578. memset( pathLengths.Base(), 0, sizeof( pathLengths[0] ) * nProxyIndices );
  579. CalcPathLengths_R( pPrecalc->GetRootNode(), pathLengths, 0, totalPathLengths );
  580. //
  581. int iCurEntry = 0;
  582. pPrecalc->m_ProxyPathEntries.SetSize( totalPathLengths );
  583. FillPathEntries_R( pPrecalc, pPrecalc->GetRootNode(), NULL, iCurEntry );
  584. }
  585. bool CSendTablePrecalc::SetupFlatPropertyArray()
  586. {
  587. SendTable *pTable = GetSendTable();
  588. // First go through and set SPROP_INSIDEARRAY when appropriate, and set array prop pointers.
  589. SetupArrayProps_R<SendTable, SendTable::PropType>( pTable );
  590. // Make a list of which properties are excluded.
  591. ExcludeProp excludeProps[MAX_EXCLUDE_PROPS];
  592. int nExcludeProps = 0;
  593. if( !SendTable_GetPropsExcluded( pTable, excludeProps, nExcludeProps, MAX_EXCLUDE_PROPS ) )
  594. return false;
  595. // Now build the hierarchy.
  596. CBuildHierarchyStruct bhs;
  597. bhs.m_pExcludeProps = excludeProps;
  598. bhs.m_nExcludeProps = nExcludeProps;
  599. bhs.m_nProps = bhs.m_nDatatableProps = 0;
  600. bhs.m_nPropProxies = 0;
  601. SendTable_BuildHierarchy( GetRootNode(), pTable, &bhs );
  602. SendTable_SortByPriority( &bhs );
  603. // Copy the SendProp pointers into the precalc.
  604. MEM_ALLOC_CREDIT();
  605. m_Props.CopyArray( bhs.m_pProps, bhs.m_nProps );
  606. m_DatatableProps.CopyArray( bhs.m_pDatatableProps, bhs.m_nDatatableProps );
  607. m_PropProxyIndices.CopyArray( bhs.m_PropProxyIndices, bhs.m_nProps );
  608. // Assign the datatable proxy indices.
  609. SetNumDataTableProxies( 0 );
  610. SetDataTableProxyIndices_R( this, GetRootNode(), &bhs );
  611. int nProxyIndices = 0;
  612. SetRecursiveProxyIndices_R( pTable, GetRootNode(), nProxyIndices );
  613. SendTable_GenerateProxyPaths( this, nProxyIndices );
  614. return true;
  615. }
  616. // ---------------------------------------------------------------------------------------- //
  617. // Helpers.
  618. // ---------------------------------------------------------------------------------------- //
  619. // Compares two arrays of bits.
  620. // Returns true if they are equal.
  621. bool AreBitArraysEqual(
  622. void const *pvBits1,
  623. void const *pvBits2,
  624. int nBits )
  625. {
  626. int i, nBytes, bit1, bit2;
  627. unsigned char const *pBits1 = (unsigned char*)pvBits1;
  628. unsigned char const *pBits2 = (unsigned char*)pvBits2;
  629. // Compare bytes.
  630. nBytes = nBits >> 3;
  631. if( memcmp( pBits1, pBits2, nBytes ) != 0 )
  632. return false;
  633. // Compare remaining bits.
  634. for(i=nBytes << 3; i < nBits; i++)
  635. {
  636. bit1 = pBits1[i >> 3] & (1 << (i & 7));
  637. bit2 = pBits2[i >> 3] & (1 << (i & 7));
  638. if(bit1 != bit2)
  639. return false;
  640. }
  641. return true;
  642. }
  643. // Does a fast memcmp-based test to determine if the two bit arrays are different.
  644. // Returns true if they are equal.
  645. bool CompareBitArrays(
  646. void const *pPacked1,
  647. void const *pPacked2,
  648. int nBits1,
  649. int nBits2
  650. )
  651. {
  652. if( nBits1 >= 0 && nBits1 == nBits2 )
  653. {
  654. if ( pPacked1 == pPacked2 )
  655. {
  656. return true;
  657. }
  658. else
  659. {
  660. return AreBitArraysEqual( pPacked1, pPacked2, nBits1 );
  661. }
  662. }
  663. else
  664. return false;
  665. }
  666. // Looks at the DTWatchEnt and DTWatchProp console variables and returns true
  667. // if the user wants to watch this property.
  668. bool ShouldWatchThisProp( const SendTable *pTable, int objectID, const char *pPropName )
  669. {
  670. if ( !g_CV_DTEncode.GetBool() )
  671. {
  672. return false;
  673. }
  674. if(g_CV_DTWatchEnt.GetInt() != -1 &&
  675. g_CV_DTWatchEnt.GetInt() == objectID)
  676. {
  677. const char *pStr = g_CV_DTWatchVar.GetString();
  678. if ( pStr && pStr[0] != 0 )
  679. {
  680. return stricmp( pStr, pPropName ) == 0;
  681. }
  682. else
  683. {
  684. return true;
  685. }
  686. }
  687. if ( g_CV_DTWatchClass.GetString()[ 0 ] && Q_stristr( pTable->GetName(), g_CV_DTWatchClass.GetString() ) )
  688. return true;
  689. return false;
  690. }
  691. // Looks at the DTWatchEnt and DTWatchProp console variables and returns true
  692. // if the user wants to watch this property.
  693. bool ShouldWatchThisProp( const RecvTable *pTable, int objectID, const char *pPropName )
  694. {
  695. if ( !g_CV_DTDecode.GetBool() )
  696. {
  697. return false;
  698. }
  699. if(g_CV_DTWatchEnt.GetInt() != -1 &&
  700. g_CV_DTWatchEnt.GetInt() == objectID)
  701. {
  702. const char *pStr = g_CV_DTWatchVar.GetString();
  703. if ( pStr && pStr[0] != 0 )
  704. {
  705. return stricmp( pStr, pPropName ) == 0;
  706. }
  707. else
  708. {
  709. return true;
  710. }
  711. }
  712. if ( g_CV_DTWatchClass.GetString()[ 0 ] && Q_stristr( pTable->GetName(), g_CV_DTWatchClass.GetString() ) )
  713. return true;
  714. return false;
  715. }
  716. bool Sendprop_UsingDebugWatch()
  717. {
  718. if ( g_CV_DTWatchEnt.GetInt() != -1 )
  719. return true;
  720. if ( g_CV_DTWatchClass.GetString()[ 0 ] )
  721. return true;
  722. return false;
  723. }
  724. // Prints a datatable warning into the console.
  725. void DataTable_Warning( const char *pInMessage, ... )
  726. {
  727. char msg[4096];
  728. va_list marker;
  729. #if 0
  730. #if !defined(_DEBUG)
  731. if(!g_CV_DTWarning.GetInt())
  732. return;
  733. #endif
  734. #endif
  735. va_start(marker, pInMessage);
  736. Q_vsnprintf( msg, sizeof( msg ), pInMessage, marker);
  737. va_end(marker);
  738. Warning( "DataTable warning: %s", msg );
  739. }