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.

1735 lines
49 KiB

  1. //========= Copyright (c) Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #if !defined( NO_ENTITY_PREDICTION )
  10. #include "igamesystem.h"
  11. #ifndef _PS3
  12. #ifdef WIN32
  13. #include <typeinfo.h>
  14. #else
  15. #include <typeinfo>
  16. #endif
  17. #endif
  18. #include "cdll_int.h"
  19. #ifndef _PS3
  20. #include <memory.h>
  21. #endif
  22. #include <stdarg.h>
  23. #include "tier0/dbg.h"
  24. #include "tier1/strtools.h"
  25. #include "predictioncopy.h"
  26. #include "engine/ivmodelinfo.h"
  27. #include "tier1/fmtstr.h"
  28. #include "utlvector.h"
  29. #include "tier0/vprof.h"
  30. #include "tier1/tokenset.h"
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include "tier0/memdbgon.h"
  33. CClassMemoryPool< optimized_datamap_t > g_OptimizedDataMapPool( 20, CUtlMemoryPool::GROW_SLOW );
  34. // --------------------------------------------------------------
  35. //
  36. // CSave
  37. //
  38. // --------------------------------------------------------------
  39. static const char *g_FieldTypes[ FIELD_TYPECOUNT ] =
  40. {
  41. "FIELD_VOID", // FIELD_VOID
  42. "FIELD_FLOAT", // FIELD_FLOAT
  43. "FIELD_STRING", // FIELD_STRING
  44. "FIELD_VECTOR", // FIELD_VECTOR
  45. "FIELD_QUATERNION", // FIELD_QUATERNION
  46. "FIELD_INTEGER", // FIELD_INTEGER
  47. "FIELD_BOOLEAN", // FIELD_BOOLEAN
  48. "FIELD_SHORT", // FIELD_SHORT
  49. "FIELD_CHARACTER", // FIELD_CHARACTER
  50. "FIELD_COLOR32", // FIELD_COLOR32
  51. "FIELD_EMBEDDED", // FIELD_EMBEDDED (handled specially)
  52. "FIELD_CUSTOM", // FIELD_CUSTOM (handled specially)
  53. "FIELD_CLASSPTR", // FIELD_CLASSPTR
  54. "FIELD_EHANDLE", // FIELD_EHANDLE
  55. "FIELD_EDICT", // FIELD_EDICT
  56. "FIELD_POSITION_VECTOR",// FIELD_POSITION_VECTOR
  57. "FIELD_TIME", // FIELD_TIME
  58. "FIELD_TICK", // FIELD_TICK
  59. "FIELD_MODELNAME", // FIELD_MODELNAME
  60. "FIELD_SOUNDNAME", // FIELD_SOUNDNAME
  61. "FIELD_INPUT", // FIELD_INPUT (uses custom type)
  62. "FIELD_FUNCTION", // FIELD_FUNCTION
  63. "FIELD_VMATRIX",
  64. "FIELD_VMATRIX_WORLDSPACE",
  65. "FIELD_MATRIX3X4_WORLDSPACE",
  66. "FIELD_INTERVAL" // FIELD_INTERVAL
  67. "FIELD_MODELINDEX" // FIELD_MODELINDEX
  68. };
  69. static int g_FieldSizes[FIELD_TYPECOUNT] =
  70. {
  71. 0, // FIELD_VOID
  72. sizeof(float), // FIELD_FLOAT
  73. sizeof(int), // FIELD_STRING
  74. sizeof(Vector), // FIELD_VECTOR
  75. sizeof(Quaternion), // FIELD_QUATERNION
  76. sizeof(int), // FIELD_INTEGER
  77. sizeof(char), // FIELD_BOOLEAN
  78. sizeof(short), // FIELD_SHORT
  79. sizeof(char), // FIELD_CHARACTER
  80. sizeof(color32), // FIELD_COLOR32
  81. sizeof(int), // FIELD_EMBEDDED (handled specially)
  82. sizeof(int), // FIELD_CUSTOM (handled specially)
  83. //---------------------------------
  84. sizeof(int), // FIELD_CLASSPTR
  85. sizeof(EHANDLE), // FIELD_EHANDLE
  86. sizeof(int), // FIELD_EDICT
  87. sizeof(Vector), // FIELD_POSITION_VECTOR
  88. sizeof(float), // FIELD_TIME
  89. sizeof(int), // FIELD_TICK
  90. sizeof(int), // FIELD_MODELNAME
  91. sizeof(int), // FIELD_SOUNDNAME
  92. sizeof(int), // FIELD_INPUT (uses custom type)
  93. sizeof(int *), // FIELD_FUNCTION
  94. sizeof(VMatrix), // FIELD_VMATRIX
  95. sizeof(VMatrix), // FIELD_VMATRIX_WORLDSPACE
  96. sizeof(matrix3x4_t),// FIELD_MATRIX3X4_WORLDSPACE // NOTE: Use array(FIELD_FLOAT, 12) for matrix3x4_t NOT in worldspace
  97. sizeof(interval_t), // FIELD_INTERVAL
  98. sizeof(int), // FIELD_MODELINDEX
  99. };
  100. #define PREDICTIONCOPY_APPLY( func, nFieldType, pCurrentMap, pField, pOutputData, pInputData, fieldSize ) \
  101. switch( nFieldType ) \
  102. { \
  103. case FIELD_EMBEDDED: \
  104. { \
  105. Error( "FIELD_EMBEDDED in flat list!!!" ); \
  106. } \
  107. break; \
  108. case FIELD_FLOAT: \
  109. func( pCurrentMap, pField, (float *)pOutputData, (const float *)pInputData, fieldSize ); \
  110. break; \
  111. case FIELD_STRING: \
  112. func( pCurrentMap, pField, (char *)pOutputData, (const char *)pInputData, fieldSize ); \
  113. break; \
  114. case FIELD_VECTOR: \
  115. func( pCurrentMap, pField, (Vector *)pOutputData, (const Vector *)pInputData, fieldSize ); \
  116. break; \
  117. case FIELD_QUATERNION: \
  118. func( pCurrentMap, pField, (Quaternion *)pOutputData, (const Quaternion *)pInputData, fieldSize );\
  119. break; \
  120. case FIELD_COLOR32: \
  121. func( pCurrentMap, pField, (color32 *)pOutputData, (const color32 *)pInputData, fieldSize ); \
  122. break; \
  123. case FIELD_BOOLEAN: \
  124. func( pCurrentMap, pField, (bool *)pOutputData, (const bool *)pInputData, fieldSize ); \
  125. break; \
  126. case FIELD_INTEGER: \
  127. func( pCurrentMap, pField, (int *)pOutputData, (const int *)pInputData, fieldSize ); \
  128. break; \
  129. case FIELD_SHORT: \
  130. func( pCurrentMap, pField, (short *)pOutputData, (const short *)pInputData, fieldSize ); \
  131. break; \
  132. case FIELD_CHARACTER: \
  133. func( pCurrentMap, pField, (uint8 *)pOutputData, (const uint8 *)pInputData, fieldSize ); \
  134. break; \
  135. case FIELD_EHANDLE: \
  136. func( pCurrentMap, pField, (EHANDLE *)pOutputData, (const EHANDLE *)pInputData, fieldSize );\
  137. break; \
  138. default: \
  139. break; \
  140. }
  141. #define PREDICTIONCOPY_APPLY_NOEMBEDDED( func, nFieldType, pCurrentMap, pField, pOutputData, pInputData, fieldSize ) \
  142. switch( nFieldType ) \
  143. { \
  144. case FIELD_FLOAT: \
  145. func( pCurrentMap, pField, (float *)pOutputData, (const float *)pInputData, fieldSize ); \
  146. break; \
  147. case FIELD_STRING: \
  148. func( pCurrentMap, pField, (char *)pOutputData, (const char *)pInputData, fieldSize ); \
  149. break; \
  150. case FIELD_VECTOR: \
  151. func( pCurrentMap, pField, (Vector *)pOutputData, (const Vector *)pInputData, fieldSize ); \
  152. break; \
  153. case FIELD_QUATERNION: \
  154. func( pCurrentMap, pField, (Quaternion *)pOutputData, (const Quaternion *)pInputData, fieldSize );\
  155. break; \
  156. case FIELD_COLOR32: \
  157. func( pCurrentMap, pField, (color32 *)pOutputData, (const color32 *)pInputData, fieldSize ); \
  158. break; \
  159. case FIELD_BOOLEAN: \
  160. func( pCurrentMap, pField, (bool *)pOutputData, (const bool *)pInputData, fieldSize ); \
  161. break; \
  162. case FIELD_INTEGER: \
  163. func( pCurrentMap, pField, (int *)pOutputData, (const int *)pInputData, fieldSize ); \
  164. break; \
  165. case FIELD_SHORT: \
  166. func( pCurrentMap, pField, (short *)pOutputData, (const short *)pInputData, fieldSize ); \
  167. break; \
  168. case FIELD_CHARACTER: \
  169. func( pCurrentMap, pField, (uint8 *)pOutputData, (const uint8 *)pInputData, fieldSize ); \
  170. break; \
  171. case FIELD_EHANDLE: \
  172. func( pCurrentMap, pField, (EHANDLE *)pOutputData, (const EHANDLE *)pInputData, fieldSize );\
  173. break; \
  174. default: \
  175. break; \
  176. }
  177. CPredictionCopy::CPredictionCopy( int type, byte *dest, bool dest_packed, const byte *src, bool src_packed,
  178. optype_t opType, FN_FIELD_COMPARE func /*= NULL*/ )
  179. {
  180. m_OpType = opType;
  181. m_nType = type;
  182. m_pDest = dest;
  183. m_pSrc = src;
  184. m_nDestOffsetIndex = dest_packed ? TD_OFFSET_PACKED : TD_OFFSET_NORMAL;
  185. m_nSrcOffsetIndex = src_packed ? TD_OFFSET_PACKED : TD_OFFSET_NORMAL;
  186. m_nErrorCount = 0;
  187. m_nEntIndex = -1;
  188. m_pWatchField = NULL;
  189. m_FieldCompareFunc = func;
  190. }
  191. static ConVar cl_pred_error_verbose( "cl_pred_error_verbose", "0", 0, "Show more field info when spewing prediction errors." );
  192. template< class T >
  193. inline void CPredictionCopy::CopyField( difftype_t difftype, T *outvalue, const T *invalue, int count )
  194. {
  195. for ( int i = 0; i < count; ++i )
  196. {
  197. outvalue[ i ] = invalue[ i ];
  198. }
  199. }
  200. // specialized for strings
  201. template<>
  202. inline void CPredictionCopy::CopyField( difftype_t difftype, char *outvalue, const char *invalue, int count )
  203. {
  204. Q_strcpy( outvalue, invalue );
  205. }
  206. template< class T >
  207. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const T *outvalue, int count )
  208. {
  209. Assert( 0 );
  210. }
  211. // Short
  212. template<>
  213. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const short *outvalue, int count )
  214. {
  215. WatchMsg( pField, "short (%i)", (int)(outvalue[0]) );
  216. }
  217. // Int
  218. template<>
  219. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const int *outvalue, int count )
  220. {
  221. bool described = false;
  222. if ( pField->flags & FTYPEDESC_MODELINDEX )
  223. {
  224. int modelindex = outvalue[0];
  225. model_t const *m = modelinfo->GetModel( modelindex );
  226. if ( m )
  227. {
  228. described = true;
  229. char shortfile[ 512 ];
  230. shortfile[ 0 ] = 0;
  231. Q_FileBase( modelinfo->GetModelName( m ), shortfile, sizeof( shortfile ) );
  232. WatchMsg( pField, "integer (%i->%s)", outvalue[0], shortfile );
  233. }
  234. }
  235. if ( !described )
  236. {
  237. WatchMsg( pField, "integer (%i)", outvalue[0] );
  238. }
  239. }
  240. template<>
  241. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const bool *outvalue, int count )
  242. {
  243. WatchMsg( pField, "bool (%s)", (outvalue[0]) ? "true" : "false" );
  244. }
  245. template<>
  246. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const float *outvalue, int count )
  247. {
  248. WatchMsg( pField, "float (%f)", outvalue[ 0 ] );
  249. }
  250. template<>
  251. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const char *outstring, int count )
  252. {
  253. WatchMsg( pField, "string (%s)", outstring );
  254. }
  255. template<>
  256. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const Vector* outValue, int count )
  257. {
  258. WatchMsg( pField, "vector (%f %f %f)", outValue[0].x, outValue[0].y, outValue[0].z );
  259. }
  260. template<>
  261. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const Quaternion* outValue, int count )
  262. {
  263. WatchMsg( pField, "quaternion (%f %f %f %f)", outValue[0].x, outValue[0].y, outValue[0].z, outValue[0].w );
  264. }
  265. template<>
  266. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const EHANDLE *outvalue, int count )
  267. {
  268. C_BaseEntity *ent = outvalue[0].Get();
  269. if ( ent )
  270. {
  271. const char *classname = ent->GetClassname();
  272. if ( !classname[0] )
  273. {
  274. classname = typeid( *ent ).name();
  275. }
  276. WatchMsg( pField, "EHandle (0x%p->%s)", (void *)outvalue[ 0 ], classname );
  277. }
  278. else
  279. {
  280. WatchMsg( pField, "EHandle (NULL)" );
  281. }
  282. }
  283. void CPredictionCopy::DumpWatchField( const typedescription_t *pField, const byte *outvalue, int count )
  284. {
  285. switch ( pField->fieldType )
  286. {
  287. case FIELD_FLOAT:
  288. WatchField( pField, (const float *)outvalue, count );
  289. break;
  290. case FIELD_STRING:
  291. WatchField( pField, (const char *)outvalue, count );
  292. break;
  293. case FIELD_VECTOR:
  294. WatchField( pField, (const Vector *)outvalue, count );
  295. break;
  296. case FIELD_QUATERNION:
  297. WatchField( pField, (const Quaternion *)outvalue, count );
  298. break;
  299. case FIELD_COLOR32:
  300. WatchField( pField, (const color32 *)outvalue, count );
  301. break;
  302. case FIELD_BOOLEAN:
  303. WatchField( pField, (const bool *)outvalue, count );
  304. break;
  305. case FIELD_INTEGER:
  306. WatchField( pField, (const int *)outvalue, count );
  307. break;
  308. case FIELD_SHORT:
  309. WatchField( pField, (const short *)outvalue, count );
  310. break;
  311. case FIELD_CHARACTER:
  312. WatchField( pField, (const uint8 *)outvalue, count );
  313. break;
  314. case FIELD_EHANDLE:
  315. WatchField( pField, (const EHANDLE *)outvalue, count );
  316. break;
  317. default:
  318. break;
  319. }
  320. }
  321. // color32
  322. template<>
  323. inline void CPredictionCopy::WatchField( const typedescription_t *pField, const color32 *outvalue, int count )
  324. {
  325. WatchMsg( pField, "color32 (%d %d %d %d)", outvalue[0].r, outvalue[0].g, outvalue[0].b, outvalue[0].a );
  326. }
  327. inline bool QuaternionCompare( const Quaternion& q1, const Quaternion& q2 )
  328. {
  329. for ( int i = 0; i < 4; ++i )
  330. {
  331. if ( q1[i] != q2[i] )
  332. return false;
  333. }
  334. return true;
  335. }
  336. template< class T >
  337. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const T *outvalue, const T *invalue, int count )
  338. {
  339. for ( int i = 0; i < count; i++ )
  340. {
  341. if ( outvalue[ i ] == invalue[ i ] )
  342. continue;
  343. return DIFFERS;
  344. }
  345. return IDENTICAL;
  346. }
  347. // float uses tolerance
  348. template<>
  349. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const float *outvalue, const float *invalue, int count )
  350. {
  351. difftype_t retval = IDENTICAL;
  352. float tolerance = pField->fieldTolerance;
  353. Assert( tolerance >= 0.0f );
  354. bool usetolerance = tolerance > 0.0f;
  355. if ( usetolerance )
  356. {
  357. for ( int i = 0; i < count; ++i )
  358. {
  359. float diff = fabs( outvalue[ i ] - invalue[ i ] );
  360. if ( diff <= tolerance )
  361. {
  362. retval = WITHINTOLERANCE;
  363. continue;
  364. }
  365. return DIFFERS;
  366. }
  367. }
  368. else
  369. {
  370. for ( int i = 0; i < count; ++i )
  371. {
  372. if ( outvalue[ i ] == invalue[ i ] )
  373. continue;
  374. return DIFFERS;
  375. }
  376. }
  377. return retval;
  378. }
  379. // vector uses tolerance
  380. template<>
  381. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const Vector *outvalue, const Vector *invalue, int count )
  382. {
  383. difftype_t retval = IDENTICAL;
  384. float tolerance = pField->fieldTolerance;
  385. Assert( tolerance >= 0.0f );
  386. bool usetolerance = tolerance > 0.0f;
  387. if ( usetolerance )
  388. {
  389. for ( int i = 0; i < count; ++i )
  390. {
  391. Vector delta = outvalue[ i ] - invalue[ i ];
  392. if ( fabs( delta.x ) <= tolerance &&
  393. fabs( delta.y ) <= tolerance &&
  394. fabs( delta.z ) <= tolerance )
  395. {
  396. retval = WITHINTOLERANCE;
  397. continue;
  398. }
  399. return DIFFERS;
  400. }
  401. }
  402. else
  403. {
  404. for ( int i = 0; i < count; ++i )
  405. {
  406. if ( outvalue[ i ] == invalue[ i ] )
  407. continue;
  408. return DIFFERS;
  409. }
  410. }
  411. return retval;
  412. }
  413. // quaternion uses tolerance
  414. template<>
  415. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const Quaternion *outvalue, const Quaternion *invalue, int count )
  416. {
  417. difftype_t retval = IDENTICAL;
  418. float tolerance = pField->fieldTolerance;
  419. Assert( tolerance >= 0.0f );
  420. bool usetolerance = tolerance > 0.0f;
  421. if ( usetolerance )
  422. {
  423. for ( int i = 0; i < count; ++i )
  424. {
  425. Quaternion delta;
  426. for ( int j = 0; j < 4; j++ )
  427. {
  428. delta[i] = outvalue[i][j] - invalue[i][j];
  429. }
  430. if ( fabs( delta.x ) <= tolerance &&
  431. fabs( delta.y ) <= tolerance &&
  432. fabs( delta.z ) <= tolerance &&
  433. fabs( delta.w ) <= tolerance )
  434. {
  435. retval = WITHINTOLERANCE;
  436. continue;
  437. }
  438. return DIFFERS;
  439. }
  440. }
  441. else
  442. {
  443. for ( int i = 0; i < count; ++i )
  444. {
  445. if ( QuaternionCompare( outvalue[ i ], invalue[ i ] ) )
  446. continue;
  447. return DIFFERS;
  448. }
  449. }
  450. return retval;
  451. }
  452. // string
  453. template<>
  454. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const char *outvalue, const char *invalue, int count )
  455. {
  456. if ( Q_strcmp( outvalue, invalue ) )
  457. {
  458. return DIFFERS;
  459. }
  460. return IDENTICAL;
  461. }
  462. // ehandle
  463. template<>
  464. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const EHANDLE *outvalue, const EHANDLE *invalue, int count )
  465. {
  466. for ( int i = 0; i < count; i++ )
  467. {
  468. if ( outvalue[ i ].Get() == invalue[ i ].Get() )
  469. continue;
  470. return DIFFERS;
  471. }
  472. return IDENTICAL;
  473. }
  474. // color32
  475. template<>
  476. inline CPredictionCopy::difftype_t CPredictionCopy::CompareField( const typedescription_t *pField, const color32 *outvalue, const color32 *invalue, int count )
  477. {
  478. for ( int i = 0; i < count; i++ )
  479. {
  480. if ( outvalue[ i ] != invalue[ i ] )
  481. return DIFFERS;
  482. }
  483. return IDENTICAL;
  484. }
  485. template< class T >
  486. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const T *outvalue, const T *invalue, int count )
  487. {
  488. Assert( 0 );
  489. }
  490. // short
  491. template<>
  492. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const short *outvalue, const short *invalue, int count )
  493. {
  494. if ( difftype == DIFFERS )
  495. {
  496. int i = 0;
  497. ReportFieldsDiffer( pCurrentMap, pField, "short differs (net %i pred %i) diff(%i)\n", (int)(invalue[i]), (int)(outvalue[i]), (int)(outvalue[i] - invalue[i]) );
  498. }
  499. OutputFieldDescription( pCurrentMap, pField, difftype, "short (%i)\n", (int)(outvalue[0]) );
  500. }
  501. // int
  502. template<>
  503. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const int *outvalue, const int *invalue, int count )
  504. {
  505. if ( difftype == DIFFERS )
  506. {
  507. int i = 0;
  508. ReportFieldsDiffer( pCurrentMap, pField, "int differs (net %i pred %i) diff(%i)\n", invalue[i], outvalue[i], outvalue[i] - invalue[i] );
  509. }
  510. bool described = false;
  511. if ( pField->flags & FTYPEDESC_MODELINDEX )
  512. {
  513. int modelindex = outvalue[0];
  514. model_t const *m = modelinfo->GetModel( modelindex );
  515. if ( m )
  516. {
  517. described = true;
  518. char shortfile[ 512 ];
  519. shortfile[ 0 ] = 0;
  520. Q_FileBase( modelinfo->GetModelName( m ), shortfile, sizeof( shortfile ) );
  521. OutputFieldDescription( pCurrentMap, pField, difftype, "integer (%i->%s)\n", outvalue[0], shortfile );
  522. }
  523. }
  524. if ( !described )
  525. {
  526. OutputFieldDescription( pCurrentMap, pField, difftype, "integer (%i)\n", outvalue[0] );
  527. }
  528. }
  529. // bool
  530. template<>
  531. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const bool *outvalue, const bool *invalue, int count )
  532. {
  533. if ( difftype == DIFFERS )
  534. {
  535. int i = 0;
  536. ReportFieldsDiffer( pCurrentMap, pField, "bool differs (net %s pred %s)\n", (invalue[i]) ? "true" : "false", (outvalue[i]) ? "true" : "false" );
  537. }
  538. OutputFieldDescription( pCurrentMap, pField, difftype, "bool (%s)\n", (outvalue[0]) ? "true" : "false" );
  539. }
  540. template<>
  541. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const float *outvalue, const float *invalue, int count )
  542. {
  543. if ( difftype == DIFFERS )
  544. {
  545. int i = 0;
  546. ReportFieldsDiffer( pCurrentMap, pField, "float differs (net %f pred %f) diff(%f)\n", invalue[ i ], outvalue[ i ], outvalue[ i ] - invalue[ i ] );
  547. }
  548. OutputFieldDescription( pCurrentMap, pField, difftype, "float (%f)\n", outvalue[ 0 ] );
  549. }
  550. template<>
  551. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const char *outstring, const char *instring, int count )
  552. {
  553. if ( difftype == DIFFERS )
  554. {
  555. ReportFieldsDiffer( pCurrentMap, pField, "string differs (net %s pred %s)\n", instring, outstring );
  556. }
  557. OutputFieldDescription( pCurrentMap, pField, difftype, "string (%s)\n", outstring );
  558. }
  559. template<>
  560. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const Vector *outValue, const Vector *inValue, int count )
  561. {
  562. if ( difftype == DIFFERS )
  563. {
  564. int i = 0;
  565. Vector delta = outValue[ i ] - inValue[ i ];
  566. ReportFieldsDiffer( pCurrentMap, pField, "vec[] differs (1st diff) (net %f %f %f - pred %f %f %f) delta(%f %f %f)\n",
  567. inValue[i].x, inValue[i].y, inValue[i].z,
  568. outValue[i].x, outValue[i].y, outValue[i].z,
  569. delta.x, delta.y, delta.z );
  570. }
  571. OutputFieldDescription( pCurrentMap, pField, difftype, "vector (%f %f %f)\n",
  572. outValue[0].x, outValue[0].y, outValue[0].z );
  573. }
  574. template<>
  575. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const Quaternion *outValue, const Quaternion *inValue, int count )
  576. {
  577. if ( difftype == DIFFERS )
  578. {
  579. int i = 0;
  580. Quaternion delta;
  581. for ( int j = 0; j < 4; j++ )
  582. {
  583. delta[i] = outValue[i][j] - inValue[i][j];
  584. }
  585. ReportFieldsDiffer( pCurrentMap, pField, "quaternion[] differs (1st diff) (net %f %f %f %f - pred %f %f %f %f) delta(%f %f %f %f)\n",
  586. inValue[i].x, inValue[i].y, inValue[i].z, inValue[i].w,
  587. outValue[i].x, outValue[i].y, outValue[i].z, outValue[i].w,
  588. delta[0], delta[1], delta[2], delta[3] );
  589. }
  590. OutputFieldDescription( pCurrentMap, pField, difftype, "quaternion (%f %f %f %f)\n", outValue[0][0], outValue[0][1], outValue[0][2], outValue[0][3] );
  591. }
  592. template<>
  593. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const EHANDLE *outvalue, EHANDLE const *invalue, int count )
  594. {
  595. if ( difftype == DIFFERS )
  596. {
  597. int i = 0;
  598. ReportFieldsDiffer( pCurrentMap, pField, "EHandles differ (net) 0x%p (pred) 0x%p\n", (void const *)invalue[ i ].Get(), (void *)outvalue[ i ].Get() );
  599. }
  600. C_BaseEntity *ent = outvalue[0].Get();
  601. if ( ent )
  602. {
  603. const char *classname = ent->GetClassname();
  604. if ( !classname[0] )
  605. {
  606. classname = typeid( *ent ).name();
  607. }
  608. OutputFieldDescription( pCurrentMap, pField, difftype, "EHandle (0x%p->%s)", (void *)outvalue[ 0 ], classname );
  609. }
  610. else
  611. {
  612. OutputFieldDescription( pCurrentMap, pField, difftype, "EHandle (NULL)" );
  613. }
  614. }
  615. // color32
  616. template<>
  617. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const color32 *outvalue, const color32 *invalue, int count )
  618. {
  619. if ( difftype == DIFFERS )
  620. {
  621. ReportFieldsDiffer( pCurrentMap, pField, "color differs (net %d %d %d %d pred %d %d %d %d)\n",
  622. outvalue[ 0 ].r,
  623. outvalue[ 0 ].g,
  624. outvalue[ 0 ].b,
  625. outvalue[ 0 ].a,
  626. invalue[ 0 ].r,
  627. invalue[ 0 ].g,
  628. invalue[ 0 ].b,
  629. invalue[ 0 ].a
  630. );
  631. }
  632. OutputFieldDescription( pCurrentMap, pField, difftype, "color (%d %d %d %d)\n",
  633. outvalue[ 0 ].r,
  634. outvalue[ 0 ].g,
  635. outvalue[ 0 ].b,
  636. outvalue[ 0 ].a );
  637. }
  638. template<>
  639. inline void CPredictionCopy::DescribeField( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t difftype, const uint8 *outstring, const uint8 *instring, int count )
  640. {
  641. if ( difftype == DIFFERS )
  642. {
  643. ReportFieldsDiffer( pCurrentMap, pField, "byte differs (net %d pred %d)\n", int(instring[0]), int(outstring[0]) );
  644. }
  645. OutputFieldDescription( pCurrentMap, pField, difftype, "byte (%d)\n", int(outstring[0]) );
  646. }
  647. //-----------------------------------------------------------------------------
  648. // Purpose:
  649. // Input : *fmt -
  650. // ... -
  651. //-----------------------------------------------------------------------------
  652. void CPredictionCopy::ReportFieldsDiffer( const datamap_t *pCurrentMap, const typedescription_t *pField, const char *fmt, ... )
  653. {
  654. ++m_nErrorCount;
  655. if ( m_FieldCompareFunc )
  656. return;
  657. const char *fieldname = "empty";
  658. const char *classname = "empty";
  659. int flags = 0;
  660. if ( pField )
  661. {
  662. flags = pField->flags;
  663. fieldname = pField->fieldName ? pField->fieldName : "NULL";
  664. classname = pCurrentMap->dataClassName;
  665. }
  666. va_list argptr;
  667. char data[ 4096 ];
  668. int len;
  669. va_start(argptr, fmt);
  670. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  671. va_end(argptr);
  672. bool bUseLongName = cl_pred_error_verbose.GetBool();
  673. CUtlString longName;
  674. for ( int i = 0; i < m_FieldStack.Count(); ++i )
  675. {
  676. const typedescription_t *top = m_FieldStack[ i ];
  677. if ( !top )
  678. continue;
  679. if ( top->flags & FTYPEDESC_KEY )
  680. bUseLongName = true;
  681. longName += top->fieldName ? top->fieldName : "NULL";
  682. longName += "/";
  683. }
  684. if ( bUseLongName )
  685. {
  686. Msg( "%2d (%d)%s%s::%s - %s",
  687. m_nErrorCount,
  688. m_nEntIndex,
  689. longName.String(),
  690. classname,
  691. fieldname,
  692. data );
  693. }
  694. else
  695. {
  696. Msg( "%2d (%d)%s::%s - %s",
  697. m_nErrorCount,
  698. m_nEntIndex,
  699. classname,
  700. fieldname,
  701. data );
  702. }
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose:
  706. // Input : *fmt -
  707. // ... -
  708. //-----------------------------------------------------------------------------
  709. void CPredictionCopy::OutputFieldDescription( const datamap_t *pCurrentMap, const typedescription_t *pField, difftype_t dt, const char *fmt, ... )
  710. {
  711. if ( !m_FieldCompareFunc )
  712. return;
  713. const char *fieldname = "empty";
  714. const char *classname = "empty";
  715. int flags = 0;
  716. if ( pField )
  717. {
  718. flags = pField->flags;
  719. fieldname = pField->fieldName ? pField->fieldName : "NULL";
  720. classname = pCurrentMap->dataClassName;
  721. }
  722. va_list argptr;
  723. char data[ 4096 ];
  724. int len;
  725. va_start(argptr, fmt);
  726. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  727. va_end(argptr);
  728. bool isnetworked = ( flags & FTYPEDESC_INSENDTABLE ) ? true : false;
  729. bool isnoterrorchecked = ( flags & FTYPEDESC_NOERRORCHECK ) ? true : false;
  730. ( *m_FieldCompareFunc )(
  731. classname,
  732. fieldname,
  733. g_FieldTypes[ pField->fieldType ],
  734. isnetworked,
  735. isnoterrorchecked,
  736. dt != IDENTICAL ? true : false,
  737. dt == WITHINTOLERANCE ? true : false,
  738. data
  739. );
  740. }
  741. void CPredictionCopy::DescribeFields( const CUtlVector< const datamap_t * > &vecGroups, const datamap_t *pCurrentMap, int nPredictionCopyType )
  742. {
  743. int i;
  744. int flags;
  745. int fieldOffsetSrc;
  746. int fieldOffsetDest;
  747. int fieldSize;
  748. const flattenedoffsets_t &flat = pCurrentMap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  749. int fieldCount = flat.m_Flattened.Count();
  750. const typedescription_t * RESTRICT pField = &flat.m_Flattened[ 0 ];
  751. PREFETCH360(pField, 0);
  752. for ( i = 0; i < fieldCount; ++i, pField++ )
  753. {
  754. #ifdef _GAMECONSOLE
  755. if ( !(i & 0xF) )
  756. {
  757. PREFETCH360(pField, 128);
  758. }
  759. #endif
  760. flags = pField->flags;
  761. int nFieldType = pField->fieldType;
  762. const byte * RESTRICT pOutputData;
  763. const byte * RESTRICT pInputData;
  764. fieldOffsetDest = pField->flatOffset[ m_nSrcOffsetIndex ];
  765. fieldOffsetSrc = pField->flatOffset[ m_nDestOffsetIndex ];
  766. fieldSize = pField->fieldSize;
  767. pOutputData = (m_pDest + fieldOffsetDest );
  768. pInputData = (m_pSrc + fieldOffsetSrc );
  769. const datamap_t *sourceGroup = pCurrentMap;
  770. if ( pField->flatGroup < vecGroups.Count() )
  771. {
  772. sourceGroup = vecGroups[ pField->flatGroup ];
  773. }
  774. PREDICTIONCOPY_APPLY( ProcessField_Describe, nFieldType, sourceGroup, pField, pOutputData, pInputData, fieldSize );
  775. }
  776. }
  777. //-----------------------------------------------------------------------------
  778. // Purpose: static method
  779. // Input : *fieldname -
  780. // *dmap -
  781. // Output : typedescription_t
  782. //-----------------------------------------------------------------------------
  783. // static method
  784. const typedescription_t *CPredictionCopy::FindFlatFieldByName( const char *fieldname, const datamap_t *dmap )
  785. {
  786. PrepareDataMap( const_cast< datamap_t * >( dmap ) );
  787. for ( int i = 0; i < PC_COPYTYPE_COUNT; ++i )
  788. {
  789. const flattenedoffsets_t &flat = dmap->m_pOptimizedDataMap->m_Info[ i ].m_Flat;
  790. int c = flat.m_Flattened.Count();
  791. for ( int j = 0; j < c; ++j )
  792. {
  793. const typedescription_t *td = &flat.m_Flattened[ j ];
  794. if ( !Q_stricmp( td->fieldName, fieldname ) )
  795. {
  796. return td;
  797. }
  798. }
  799. }
  800. return NULL;
  801. }
  802. static ConVar pwatchent( "pwatchent", "-1", FCVAR_CHEAT, "Entity to watch for prediction system changes." );
  803. static ConVar pwatchvar( "pwatchvar", "", FCVAR_CHEAT, "Entity variable to watch in prediction system for changes." );
  804. //-----------------------------------------------------------------------------
  805. // Purpose:
  806. // Input : *fmt -
  807. // ... -
  808. //-----------------------------------------------------------------------------
  809. void CPredictionCopy::WatchMsg( const typedescription_t *pField, const char *fmt, ... )
  810. {
  811. Assert( pField );
  812. Assert( m_pOperation );
  813. va_list argptr;
  814. char data[ 4096 ];
  815. int len;
  816. va_start(argptr, fmt);
  817. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  818. va_end(argptr);
  819. Msg( "%i %s %s : %s\n", gpGlobals->tickcount, m_pOperation, pField->fieldName, data );
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Purpose:
  823. // Input : *operation -
  824. // entindex -
  825. // *dmap -
  826. //-----------------------------------------------------------------------------
  827. void CPredictionCopy::DetermineWatchField( const char *operation, int entindex, const datamap_t *dmap )
  828. {
  829. m_pWatchField = NULL;
  830. m_pOperation = operation;
  831. if ( !m_pOperation || !m_pOperation[0] )
  832. return;
  833. int enttowatch = pwatchent.GetInt();
  834. if ( enttowatch < 0 )
  835. return;
  836. if ( entindex != enttowatch )
  837. return;
  838. // See if they specified a field
  839. if ( pwatchvar.GetString()[0] == 0 )
  840. return;
  841. m_pWatchField = CPredictionCopy::FindFlatFieldByName( pwatchvar.GetString(), dmap );
  842. }
  843. static void RemoveFieldsByName( char const *pchFieldName, CUtlVector< typedescription_t > &build )
  844. {
  845. // Don't start at final field, since it the one we just added with FTYPEDESC_OVERRIDE
  846. for ( int i = build.Count() - 2; i >= 0 ; --i )
  847. {
  848. // Embedded field "offsets" can be the same as their first data field, so don't remove
  849. if ( build[ i ].fieldType == FIELD_EMBEDDED )
  850. continue;
  851. if ( !Q_stricmp( build[ i ].fieldName, pchFieldName ) )
  852. {
  853. // Msg( "Removing %s %d due to override\n", build[ i ]->fieldName, build[ i ]->flatOffset[ TD_OFFSET_NORMAL ] );
  854. build.Remove( i );
  855. }
  856. }
  857. }
  858. static void BuildGroupList_R( int nPredictionCopyType, int nGroup, const datamap_t *dmap, CUtlVector< const datamap_t * > &vecGroups )
  859. {
  860. // Descend to base classes first so FTYPEDESC_OVERRIDE can remove the previous ones
  861. if ( dmap->baseMap )
  862. {
  863. BuildGroupList_R( nPredictionCopyType, nGroup + 1, dmap->baseMap, vecGroups );
  864. }
  865. vecGroups.AddToTail( dmap );
  866. }
  867. static void BuildFlattenedChains_R(
  868. int nPredictionCopyType,
  869. int &nMaxGroupSeen,
  870. int nGroup,
  871. datamap_t *dmap,
  872. CUtlVector< typedescription_t > &build,
  873. int nBaseOffset )
  874. {
  875. // Descend to base classes first so FTYPEDESC_OVERRIDE can remove the previous ones
  876. if ( dmap->baseMap )
  877. {
  878. BuildFlattenedChains_R( nPredictionCopyType, nMaxGroupSeen, nGroup + 1, dmap->baseMap, build, nBaseOffset );
  879. }
  880. if ( nGroup > nMaxGroupSeen )
  881. {
  882. nMaxGroupSeen = nGroup;
  883. }
  884. int c = dmap->dataNumFields;
  885. for ( int i = 0; i < c; i++ )
  886. {
  887. typedescription_t *pField = &dmap->dataDesc[ i ];
  888. if ( pField->fieldType == FIELD_VOID )
  889. continue;
  890. bool bAdd = true;
  891. if ( pField->fieldType != FIELD_EMBEDDED )
  892. {
  893. if ( pField->flags & FTYPEDESC_PRIVATE )
  894. {
  895. if ( pField->flags & FTYPEDESC_OVERRIDE )
  896. {
  897. // Find previous field targeting same offset
  898. RemoveFieldsByName( pField->fieldName, build );
  899. }
  900. continue;
  901. }
  902. // For PC_NON_NETWORKED_ONLYs skip any fields that are present in the network send tables
  903. if ( nPredictionCopyType == PC_NON_NETWORKED_ONLY && ( pField->flags & FTYPEDESC_INSENDTABLE ) )
  904. {
  905. bAdd = false;
  906. }
  907. // For PC_NETWORKED_ONLYs skip any fields that are not present in the network send tables
  908. if ( nPredictionCopyType == PC_NETWORKED_ONLY && !( pField->flags & FTYPEDESC_INSENDTABLE ) )
  909. {
  910. bAdd = false;
  911. }
  912. }
  913. else
  914. {
  915. bAdd = false;
  916. }
  917. pField->flatGroup = nGroup;
  918. pField->flatOffset[ TD_OFFSET_NORMAL ] = nBaseOffset + pField->fieldOffset;
  919. if ( bAdd )
  920. {
  921. build.AddToTail( *pField );
  922. }
  923. // Msg( "Visit %s offset %d\n", pField->fieldName, pField->flatOffset[ nPackType ] );
  924. if ( pField->fieldType == FIELD_EMBEDDED )
  925. {
  926. AssertFatalMsg( !(pField->flags & FTYPEDESC_PTR ), ( "Prediction copy does not support FTYPEDESC_PTR(%d)", pField->fieldName ) );
  927. BuildFlattenedChains_R( nPredictionCopyType, nMaxGroupSeen, nGroup, pField->td, build, pField->flatOffset[ TD_OFFSET_NORMAL ] );
  928. }
  929. if ( pField->flags & FTYPEDESC_OVERRIDE )
  930. {
  931. // Find previous field targeting same offset
  932. RemoveFieldsByName( pField->fieldName, build );
  933. }
  934. }
  935. }
  936. static int __cdecl CompareFlattenedOffsets( const void *pv1, const void *pv2 )
  937. {
  938. const typedescription_t *td1 = (const typedescription_t *)pv1;
  939. const typedescription_t *td2 = (const typedescription_t *)pv2;
  940. if ( td1->flatOffset[ TD_OFFSET_NORMAL ] < td2->flatOffset[ TD_OFFSET_NORMAL ] )
  941. return -1;
  942. else if ( td1->flatOffset[ TD_OFFSET_NORMAL ] > td2->flatOffset[ TD_OFFSET_NORMAL ] )
  943. return 1;
  944. if ( td1->flatGroup < td2->flatGroup )
  945. return -1;
  946. else if ( td1->flatGroup > td2->flatGroup )
  947. return 1;
  948. return 0;
  949. }
  950. static int BuildPackedFlattenedOffsets( int nStartOffset, flattenedoffsets_t &flat )
  951. {
  952. int current_position = nStartOffset;
  953. for ( int i = 0; i < flat.m_Flattened.Count(); ++i )
  954. {
  955. typedescription_t *field = &flat.m_Flattened[ i ];
  956. switch ( field->fieldType )
  957. {
  958. default:
  959. case FIELD_MODELINDEX:
  960. case FIELD_MODELNAME:
  961. case FIELD_SOUNDNAME:
  962. case FIELD_TIME:
  963. case FIELD_TICK:
  964. case FIELD_CUSTOM:
  965. case FIELD_CLASSPTR:
  966. case FIELD_EDICT:
  967. case FIELD_POSITION_VECTOR:
  968. case FIELD_FUNCTION:
  969. Assert( 0 );
  970. break;
  971. case FIELD_EMBEDDED:
  972. {
  973. Error( "Not expecting FIELD_EMBEDDED in flattened list (%s)", field->fieldName );
  974. }
  975. break;
  976. case FIELD_FLOAT:
  977. case FIELD_VECTOR:
  978. case FIELD_QUATERNION:
  979. case FIELD_INTEGER:
  980. case FIELD_EHANDLE:
  981. case FIELD_COLOR32:
  982. case FIELD_VMATRIX:
  983. case FIELD_VECTOR4D:
  984. {
  985. current_position = ALIGN_VALUE( current_position, 4 );
  986. field->flatOffset[ TD_OFFSET_PACKED ] = current_position;
  987. current_position += field->fieldSizeInBytes;
  988. }
  989. break;
  990. case FIELD_SHORT:
  991. {
  992. current_position = ALIGN_VALUE( current_position, 2 );
  993. field->flatOffset[ TD_OFFSET_PACKED ] = current_position;
  994. current_position += field->fieldSizeInBytes;
  995. }
  996. break;
  997. case FIELD_STRING:
  998. case FIELD_BOOLEAN:
  999. case FIELD_CHARACTER:
  1000. {
  1001. field->flatOffset[ TD_OFFSET_PACKED ] = current_position;
  1002. current_position += field->fieldSizeInBytes;
  1003. }
  1004. break;
  1005. case FIELD_VOID:
  1006. {
  1007. // Special case, just skip it
  1008. }
  1009. break;
  1010. }
  1011. // Msg( "%s packed to %d size %d\n", field->fieldName, field->flatOffset[ TD_OFFSET_PACKED ], field->fieldSizeInBytes );
  1012. }
  1013. flat.m_nPackedStartOffset = nStartOffset;
  1014. flat.m_nPackedSize = current_position - nStartOffset;
  1015. current_position = ALIGN_VALUE( current_position, 4 );
  1016. return current_position;
  1017. }
  1018. static void BuildDataRuns( datamap_t *dmap )
  1019. {
  1020. for ( int pc = 0; pc < PC_COPYTYPE_COUNT; ++pc )
  1021. {
  1022. datamapinfo_t &info = dmap->m_pOptimizedDataMap->m_Info[ pc ];
  1023. datacopyruns_t *runs = &info.m_CopyRuns;
  1024. Assert( !info.m_CopyRuns.m_vecRuns.Count() );
  1025. const flattenedoffsets_t &flat = info.m_Flat;
  1026. int nRunStartField = 0;
  1027. int nCurrentRunStartOffset = 0;
  1028. int nLastFieldEndOffset = 0;
  1029. CUtlVector< datarun_t > &vecRuns = runs->m_vecRuns;
  1030. int i;
  1031. for ( i = 0; i < flat.m_Flattened.Count(); ++i )
  1032. {
  1033. const typedescription_t *td = &flat.m_Flattened[ i ];
  1034. int offset = td->flatOffset[ TD_OFFSET_NORMAL ];
  1035. if ( i == 0 )
  1036. {
  1037. nRunStartField = i;
  1038. nLastFieldEndOffset = offset;
  1039. nCurrentRunStartOffset = offset;
  1040. }
  1041. if ( td->fieldType == FIELD_EMBEDDED )
  1042. {
  1043. Assert( 0 );
  1044. continue;
  1045. }
  1046. if ( nLastFieldEndOffset != offset )
  1047. {
  1048. datarun_t run;
  1049. run.m_nStartFlatField = nRunStartField;
  1050. run.m_nEndFlatField = i - 1;
  1051. Assert( nCurrentRunStartOffset == flat.m_Flattened[ nRunStartField ].flatOffset[ TD_OFFSET_NORMAL ] );
  1052. run.m_nStartOffset[ TD_OFFSET_NORMAL ] = nCurrentRunStartOffset;
  1053. run.m_nStartOffset[ TD_OFFSET_PACKED ] = flat.m_Flattened[ nRunStartField ].flatOffset[ TD_OFFSET_PACKED ];
  1054. run.m_nLength = nLastFieldEndOffset - nCurrentRunStartOffset;
  1055. #ifdef _GAMECONSOLE
  1056. if ( vecRuns.Count() > 0 )
  1057. {
  1058. for ( int td = 0; td < TD_OFFSET_COUNT; ++td )
  1059. {
  1060. vecRuns[ vecRuns.Count() - 1 ].m_nPrefetchOffset[ td ] = run.m_nStartOffset[ td ];
  1061. }
  1062. }
  1063. #endif
  1064. vecRuns.AddToTail( run );
  1065. nRunStartField = i;
  1066. nCurrentRunStartOffset = offset;
  1067. }
  1068. nLastFieldEndOffset = td->flatOffset[ TD_OFFSET_NORMAL ] + td->fieldSizeInBytes;
  1069. }
  1070. // Close off last run
  1071. if ( nLastFieldEndOffset != nCurrentRunStartOffset )
  1072. {
  1073. datarun_t run;
  1074. run.m_nStartFlatField = nRunStartField;
  1075. run.m_nEndFlatField = i - 1;
  1076. Assert( nCurrentRunStartOffset == flat.m_Flattened[ nRunStartField ].flatOffset[ TD_OFFSET_NORMAL ] );
  1077. run.m_nStartOffset[ TD_OFFSET_NORMAL ] = nCurrentRunStartOffset;
  1078. run.m_nStartOffset[ TD_OFFSET_PACKED ] = flat.m_Flattened[ nRunStartField ].flatOffset[ TD_OFFSET_PACKED ];
  1079. run.m_nLength = nLastFieldEndOffset - nCurrentRunStartOffset;
  1080. #ifdef _GAMECONSOLE
  1081. if ( vecRuns.Count() > 0 )
  1082. {
  1083. for ( int td = 0; td < TD_OFFSET_COUNT; ++td )
  1084. {
  1085. vecRuns[ vecRuns.Count() - 1 ].m_nPrefetchOffset[ td ] = run.m_nStartOffset[ td ];
  1086. }
  1087. }
  1088. #endif
  1089. vecRuns.AddToTail( run );
  1090. }
  1091. }
  1092. }
  1093. static void BuildFlattenedChains( datamap_t *dmap )
  1094. {
  1095. if ( dmap->m_pOptimizedDataMap )
  1096. return;
  1097. dmap->m_pOptimizedDataMap = g_OptimizedDataMapPool.AllocZero();
  1098. int nMaxGroupSeen[ PC_COPYTYPE_COUNT ] = { 0 };
  1099. for ( int nPredictionCopyType = 0; nPredictionCopyType < PC_COPYTYPE_COUNT; ++nPredictionCopyType )
  1100. {
  1101. CUtlVector< typedescription_t > &build = dmap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat.m_Flattened;
  1102. int nGroupCount = 0;
  1103. int nBaseOffset = 0;
  1104. BuildFlattenedChains_R(
  1105. nPredictionCopyType,
  1106. nMaxGroupSeen[ nPredictionCopyType ],
  1107. nGroupCount,
  1108. dmap,
  1109. build,
  1110. nBaseOffset );
  1111. // Msg( "%d == %d entries\n", nPredictionCopyType, build[ nPredictionCopyType ].Count() );
  1112. }
  1113. for ( int nPredictionCopyType = 0; nPredictionCopyType < PC_COPYTYPE_COUNT; ++nPredictionCopyType )
  1114. {
  1115. int nMaxGroup = nMaxGroupSeen[ nPredictionCopyType ];
  1116. CUtlVector< typedescription_t > &build = dmap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat.m_Flattened;
  1117. for ( int i = 0; i < build.Count(); ++i )
  1118. {
  1119. typedescription_t *field = &build[ i ];
  1120. field->flatGroup = nMaxGroup - field->flatGroup;
  1121. }
  1122. }
  1123. int nPackedDataStartOffset = 0;
  1124. for ( int nPredictionCopyType = 0; nPredictionCopyType < PC_COPYTYPE_COUNT; ++nPredictionCopyType )
  1125. {
  1126. flattenedoffsets_t &flat = dmap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  1127. qsort( flat.m_Flattened.Base(), flat.m_Flattened.Count(), sizeof( typedescription_t ), (int (__cdecl *)(const void *, const void *))CompareFlattenedOffsets );
  1128. nPackedDataStartOffset = BuildPackedFlattenedOffsets( nPackedDataStartOffset, flat );
  1129. dmap->m_nPackedSize = nPackedDataStartOffset;
  1130. }
  1131. BuildDataRuns( dmap );
  1132. }
  1133. const tokenset_t< int > s_PredCopyType[] =
  1134. {
  1135. { "Non-Sendtable" , PC_NON_NETWORKED_ONLY },
  1136. { "SendTable" , PC_NETWORKED_ONLY },
  1137. { "Everything" , PC_EVERYTHING },
  1138. { NULL, -1 }
  1139. };
  1140. const tokenset_t< int > s_PredPackType[] =
  1141. {
  1142. { "Normal" , TD_OFFSET_NORMAL },
  1143. { "Packed" , TD_OFFSET_PACKED },
  1144. { NULL, -1 }
  1145. };
  1146. static void DescribeRuns( const datamap_t *dmap, int nPredictionCopyType, int packType )
  1147. {
  1148. const flattenedoffsets_t *flat;
  1149. const datarun_t *run;
  1150. const datacopyruns_t &runs = dmap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_CopyRuns;
  1151. flat = &dmap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  1152. Msg( " Runs for copy type: %s, packing: %s\n", s_PredCopyType->GetNameByToken( nPredictionCopyType ), s_PredPackType->GetNameByToken( packType ) );
  1153. for ( int i = 0; i < runs.m_vecRuns.Count(); ++i )
  1154. {
  1155. run = &runs.m_vecRuns[ i ];
  1156. Msg( " %5d: %5d -> %5d (%5d bytes): %s to %s\n",
  1157. i, run->m_nStartOffset[ packType ], run->m_nStartOffset[ packType ] + run->m_nLength, run->m_nLength,
  1158. flat->m_Flattened[ run->m_nStartFlatField ].fieldName,
  1159. flat->m_Flattened[ run->m_nEndFlatField ].fieldName );
  1160. }
  1161. }
  1162. static void DescribeFlattenedList( const datamap_t *dmap, int nPredictionCopyType, int packType )
  1163. {
  1164. char const *prefix;
  1165. prefix = dmap->dataClassName;
  1166. Msg( "->Sorted %s for copy type: %s, packing: %s\n", prefix, s_PredCopyType->GetNameByToken( nPredictionCopyType ), s_PredPackType->GetNameByToken( packType ) );
  1167. // Now dump the flattened list
  1168. int nLastFieldEnd = 0;
  1169. int nCurrentRunStartOffset = 0;
  1170. int nRuns = 0;
  1171. int nBytesInRuns = 0;
  1172. int offset = 0;
  1173. const flattenedoffsets_t &list = dmap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  1174. for ( int i = 0; i < list.m_Flattened.Count(); ++i )
  1175. {
  1176. const typedescription_t *td = &list.m_Flattened[ i ];
  1177. offset = td->flatOffset[ packType ];
  1178. if ( i == 0 )
  1179. {
  1180. nLastFieldEnd = offset;
  1181. nCurrentRunStartOffset = offset;
  1182. }
  1183. if ( td->fieldType != FIELD_EMBEDDED )
  1184. {
  1185. if ( nLastFieldEnd != offset )
  1186. {
  1187. Msg( " gap of %d bytes [last run %d]\n", offset - nLastFieldEnd, ( nLastFieldEnd - nCurrentRunStartOffset ) );
  1188. ++nRuns;
  1189. nBytesInRuns += ( nLastFieldEnd - nCurrentRunStartOffset );
  1190. nCurrentRunStartOffset = offset;
  1191. }
  1192. nLastFieldEnd = td->flatOffset[ packType ] + td->fieldSizeInBytes;
  1193. }
  1194. Msg( "group %s [flat %d] [sort %d] %d bytes\n",
  1195. td->fieldName,
  1196. td->flatOffset[ packType ],
  1197. td->flatOffset[ TD_OFFSET_NORMAL ],
  1198. td->fieldSizeInBytes );
  1199. }
  1200. // Close off last run
  1201. if ( nLastFieldEnd != nCurrentRunStartOffset )
  1202. {
  1203. Msg( "Last run %d\n", nLastFieldEnd - nCurrentRunStartOffset );
  1204. ++nRuns;
  1205. nBytesInRuns += ( nLastFieldEnd - nCurrentRunStartOffset );
  1206. }
  1207. if ( nRuns > 0 )
  1208. {
  1209. Msg( "%d runs, %d bytes in runs, %f avg bytes per run\n",
  1210. nRuns, nBytesInRuns, nBytesInRuns/(float)nRuns );
  1211. }
  1212. Msg( "->\n" );
  1213. DescribeRuns( dmap, nPredictionCopyType, packType );
  1214. }
  1215. void CPredictionCopy::CopyFlatFieldsUsingRuns( const datamap_t *pCurrentMap, int nPredictionCopyType )
  1216. {
  1217. int fieldOffsetSrc;
  1218. int fieldOffsetDest;
  1219. byte * RESTRICT pOutputData;
  1220. const byte * RESTRICT pInputData;
  1221. const datacopyruns_t &runs = pCurrentMap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_CopyRuns;
  1222. byte * RESTRICT pDest = ( byte * RESTRICT )m_pDest;
  1223. const byte * RESTRICT pSrc = (const byte * RESTRICT)m_pSrc;
  1224. PREFETCH360( pSrc, 0 );
  1225. PREFETCH360( pDest, 0 );
  1226. int c = runs.m_vecRuns.Count();
  1227. for ( int i = 0; i < c; ++i )
  1228. {
  1229. const datarun_t * RESTRICT run = &runs.m_vecRuns[ i ];
  1230. fieldOffsetDest = run->m_nStartOffset[ m_nDestOffsetIndex ];
  1231. fieldOffsetSrc = run->m_nStartOffset[ m_nSrcOffsetIndex ];
  1232. pOutputData = pDest + fieldOffsetDest;
  1233. pInputData = pSrc + fieldOffsetSrc;
  1234. #ifdef _GAMECONSOLE
  1235. PREFETCH360( pDest + run->m_nPrefetchOffset[ m_nDestOffsetIndex ], 0 );
  1236. PREFETCH360( pSrc + run->m_nPrefetchOffset[ m_nSrcOffsetIndex ], 0 );
  1237. #endif
  1238. Q_memcpy( pOutputData, pInputData, run->m_nLength );
  1239. }
  1240. }
  1241. void CPredictionCopy::CopyFlatFields( const datamap_t *pCurrentMap, int nPredictionCopyType )
  1242. {
  1243. int fieldOffsetSrc;
  1244. int fieldOffsetDest;
  1245. byte * RESTRICT pOutputData;
  1246. const byte * RESTRICT pInputData;
  1247. byte * RESTRICT pDest = (byte * RESTRICT)m_pDest;
  1248. const byte * RESTRICT pSrc = (const byte * RESTRICT)m_pSrc;
  1249. PREFETCH360( pSrc, 0 );
  1250. PREFETCH360( pDest, 0 );
  1251. const flattenedoffsets_t &flat = pCurrentMap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  1252. int fieldCount = flat.m_Flattened.Count();
  1253. for ( int i = 0; i < fieldCount; ++i )
  1254. {
  1255. const typedescription_t *pField = &flat.m_Flattened[ i ];
  1256. fieldOffsetDest = pField->flatOffset[ m_nDestOffsetIndex ];
  1257. fieldOffsetSrc = pField->flatOffset[ m_nSrcOffsetIndex ];
  1258. pOutputData = pDest + fieldOffsetDest;
  1259. PREFETCH360( pOutputData, 0 );
  1260. pInputData = pSrc + fieldOffsetSrc;
  1261. PREFETCH360( pInputData, 0 );
  1262. Q_memcpy( pOutputData, pInputData, pField->fieldSizeInBytes );
  1263. }
  1264. }
  1265. void CPredictionCopy::ErrorCheckFlatFields_NoSpew( const datamap_t *pCurrentMap, int nPredictionCopyType )
  1266. {
  1267. int i;
  1268. int flags;
  1269. int fieldOffsetSrc;
  1270. int fieldOffsetDest;
  1271. int fieldSize;
  1272. const flattenedoffsets_t &flat = pCurrentMap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  1273. const typedescription_t *pBase = &flat.m_Flattened[ 0 ];
  1274. PREFETCH360( pBase, 0 );
  1275. int fieldCount = flat.m_Flattened.Count();
  1276. const byte * RESTRICT pDest = (const byte * RESTRICT)m_pDest;
  1277. const byte * RESTRICT pSrc = (const byte * RESTRICT)m_pSrc;
  1278. const byte *pOutputData;
  1279. const byte *pInputData;
  1280. PREFETCH360( pSrc, 0 );
  1281. PREFETCH360( pDest, 0 );
  1282. for ( i = 0; i < fieldCount && !m_nErrorCount; ++i )
  1283. {
  1284. const typedescription_t * RESTRICT pField = &pBase[ i ];
  1285. flags = pField->flags;
  1286. if ( flags & FTYPEDESC_NOERRORCHECK )
  1287. continue;
  1288. #ifdef _GAMECONSOLE
  1289. if ( !(i & 0xF) )
  1290. {
  1291. PREFETCH360(pField, 128);
  1292. }
  1293. #endif
  1294. fieldOffsetDest = pField->flatOffset[ m_nDestOffsetIndex ];
  1295. fieldOffsetSrc = pField->flatOffset[ m_nSrcOffsetIndex ];
  1296. pOutputData = pDest + fieldOffsetDest;
  1297. PREFETCH360( pOutputData, 0 );
  1298. pInputData = pSrc + fieldOffsetSrc;
  1299. PREFETCH360( pInputData, 0 );
  1300. fieldSize = pField->fieldSize;
  1301. int nFieldType = pField->fieldType;
  1302. PREDICTIONCOPY_APPLY( ProcessField_Compare_NoSpew, nFieldType, pCurrentMap, pField, pOutputData, pInputData, fieldSize );
  1303. }
  1304. }
  1305. void CPredictionCopy::ErrorCheckFlatFields_Spew( const datamap_t *pCurrentMap, int nPredictionCopyType )
  1306. {
  1307. int i;
  1308. int flags;
  1309. int fieldOffsetSrc;
  1310. int fieldOffsetDest;
  1311. int fieldSize;
  1312. const flattenedoffsets_t &flat = pCurrentMap->m_pOptimizedDataMap->m_Info[ nPredictionCopyType ].m_Flat;
  1313. const typedescription_t *pBase = &flat.m_Flattened[ 0 ];
  1314. PREFETCH360( pBase, 0 );
  1315. int fieldCount = flat.m_Flattened.Count();
  1316. const byte * RESTRICT pDest = m_pDest;
  1317. const byte * RESTRICT pSrc = m_pSrc;
  1318. const byte *pOutputData;
  1319. const byte *pInputData;
  1320. PREFETCH360( pSrc, 0 );
  1321. PREFETCH360( pDest, 0 );
  1322. for ( i = 0; i < fieldCount ; ++i )
  1323. {
  1324. const typedescription_t * RESTRICT pField = &pBase[ i ];
  1325. flags = pField->flags;
  1326. if ( flags & FTYPEDESC_NOERRORCHECK )
  1327. continue;
  1328. #ifdef _GAMECONSOLE
  1329. if ( !(i & 0xF) )
  1330. {
  1331. PREFETCH360(pField, 128);
  1332. }
  1333. #endif
  1334. fieldOffsetDest = pField->flatOffset[ m_nDestOffsetIndex ];
  1335. fieldOffsetSrc = pField->flatOffset[ m_nSrcOffsetIndex ];
  1336. pOutputData = pDest + fieldOffsetDest;
  1337. PREFETCH360( pOutputData, 0 );
  1338. pInputData = pSrc + fieldOffsetSrc;
  1339. PREFETCH360( pInputData, 0 );
  1340. fieldSize = pField->fieldSize;
  1341. flags = pField->flags;
  1342. int nFieldType = pField->fieldType;
  1343. PREDICTIONCOPY_APPLY( ProcessField_Compare_Spew, nFieldType, pCurrentMap, pField, pOutputData, pInputData, fieldSize );
  1344. }
  1345. }
  1346. bool CPredictionCopy::PrepareDataMap( datamap_t *dmap )
  1347. {
  1348. bool bPerformedPrepare = false;
  1349. if ( dmap && !dmap->m_pOptimizedDataMap )
  1350. {
  1351. bPerformedPrepare = true;
  1352. BuildFlattenedChains( dmap );
  1353. dmap = dmap->baseMap;
  1354. }
  1355. return bPerformedPrepare;
  1356. }
  1357. CON_COMMAND( cl_predictioncopy_describe, "Describe datamap_t for entindex" )
  1358. {
  1359. if ( args.ArgC() <= 1 )
  1360. {
  1361. Msg( "Usage: %s <entindex>", args[ 0 ] );
  1362. return;
  1363. }
  1364. int entindex = Q_atoi( args[ 1 ] );
  1365. C_BaseEntity *ent = C_BaseEntity::Instance( entindex );
  1366. if ( !ent )
  1367. {
  1368. Msg( "cl_predictioncopy_describe: no such entity %d\n", entindex );
  1369. return;
  1370. }
  1371. datamap_t *dmap = ent->GetPredDescMap();
  1372. if ( !dmap )
  1373. {
  1374. return;
  1375. }
  1376. CPredictionCopy::PrepareDataMap( dmap );
  1377. for ( int nPredictionCopyType = 0; nPredictionCopyType < PC_COPYTYPE_COUNT; ++nPredictionCopyType )
  1378. {
  1379. //for ( int i = 0; i < TD_OFFSET_COUNT; ++i )
  1380. {
  1381. DescribeFlattenedList( dmap, nPredictionCopyType, 0 );
  1382. }
  1383. }
  1384. }
  1385. // 0 PC_NON_NETWORKED_ONLY = (1<<0) or (1)
  1386. // 1 PC_NETWORKED_ONLY = (1<<1) or (2)
  1387. // 2 PC_EVERYTHING = ( PC_NON_NETWORKED_ONLY | PC_NETWORKED_ONLY ) or 3
  1388. // So for these three options, we just take the type and add one!!!
  1389. FORCEINLINE int ComputeTypeMask( int nType )
  1390. {
  1391. return nType + 1;
  1392. }
  1393. #if 0 // Enable this for perf testing
  1394. static ConVar cl_predictioncopy_runs( "cl_predictioncopy_runs", "1" );
  1395. static ConVar cl_predictioncopy_repeats( "cl_predictioncopy_repeats", "1" );
  1396. void CPredictionCopy::TransferDataCopyOnly( datamap_t *dmap )
  1397. {
  1398. int repeat = cl_predictioncopy_repeats.GetInt();
  1399. for ( int k = 0; k < repeat; ++k )
  1400. {
  1401. int types = ComputeTypeMask( m_nType );
  1402. for ( int i = 0; i < PC_COPYTYPE_COUNT; ++i )
  1403. {
  1404. if ( types & (1<<i) )
  1405. {
  1406. if ( !cl_predictioncopy_runs.GetBool() )
  1407. {
  1408. CopyFlatFields( dmap, i );
  1409. }
  1410. else
  1411. {
  1412. CopyFlatFieldsUsingRuns( dmap, i );
  1413. }
  1414. }
  1415. }
  1416. }
  1417. }
  1418. #else
  1419. void CPredictionCopy::TransferDataCopyOnly( const datamap_t *dmap )
  1420. {
  1421. int types = ComputeTypeMask( m_nType );
  1422. for ( int i = 0; i < PC_COPYTYPE_COUNT; ++i )
  1423. {
  1424. if ( types & (1<<i) )
  1425. {
  1426. CopyFlatFieldsUsingRuns( dmap, i );
  1427. }
  1428. }
  1429. }
  1430. #endif
  1431. // Stop at first error
  1432. void CPredictionCopy::TransferDataErrorCheckNoSpew( char const *pchOperation, const datamap_t *dmap )
  1433. {
  1434. int types = ComputeTypeMask( m_nType );
  1435. for ( int i = 0; i < PC_COPYTYPE_COUNT && !m_nErrorCount; ++i )
  1436. {
  1437. if ( types & (1<<i) )
  1438. {
  1439. ErrorCheckFlatFields_NoSpew( dmap, i );
  1440. }
  1441. }
  1442. }
  1443. void CPredictionCopy::TransferDataErrorCheckSpew( char const *pchOperation, const datamap_t *dmap )
  1444. {
  1445. int types = ComputeTypeMask( m_nType );
  1446. for ( int i = 0; i < PC_COPYTYPE_COUNT; ++i )
  1447. {
  1448. if ( types & (1<<i) )
  1449. {
  1450. ErrorCheckFlatFields_Spew( dmap, i );
  1451. }
  1452. }
  1453. }
  1454. void CPredictionCopy::TransferDataDescribe( char const *pchOperation, const datamap_t *dmap )
  1455. {
  1456. // Copy from here first, then base classes
  1457. int types = ComputeTypeMask( m_nType );
  1458. for ( int i = 0; i < PC_COPYTYPE_COUNT; ++i )
  1459. {
  1460. if ( types & (1<<i) )
  1461. {
  1462. CUtlVector< const datamap_t * > vecGroups;
  1463. int nGroup = 0;
  1464. BuildGroupList_R( i, nGroup, dmap, vecGroups );
  1465. DescribeFields( vecGroups, dmap, i );
  1466. }
  1467. }
  1468. }
  1469. int CPredictionCopy::TransferData( const char *operation, int entindex, datamap_t *dmap )
  1470. {
  1471. m_nEntIndex = entindex;
  1472. PrepareDataMap( dmap );
  1473. switch ( m_OpType )
  1474. {
  1475. default:
  1476. Assert( 0 );
  1477. case TRANSFERDATA_COPYONLY: // Data copying only (uses runs)
  1478. {
  1479. // Watch is based on "destination" of any write operation
  1480. DetermineWatchField( operation, entindex, dmap );
  1481. TransferDataCopyOnly( dmap );
  1482. }
  1483. break;
  1484. case TRANSFERDATA_ERRORCHECK_NOSPEW: // Checks for errors, returns after first error found
  1485. {
  1486. TransferDataErrorCheckNoSpew( operation, dmap );
  1487. }
  1488. break;
  1489. case TRANSFERDATA_ERRORCHECK_SPEW: // checks for errors, reports all errors to console
  1490. {
  1491. TransferDataErrorCheckSpew( operation, dmap );
  1492. }
  1493. break;
  1494. case TRANSFERDATA_ERRORCHECK_DESCRIBE:
  1495. {
  1496. TransferDataDescribe( operation, dmap );
  1497. }
  1498. break;
  1499. }
  1500. if ( m_pWatchField )
  1501. {
  1502. // Watch is based on "destination" of any write operation
  1503. DumpWatchField( m_pWatchField, m_pDest + m_pWatchField->flatOffset[ m_nDestOffsetIndex ], m_pWatchField->fieldSize );
  1504. }
  1505. return m_nErrorCount;
  1506. }
  1507. #endif