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.

2242 lines
54 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #if !defined( NO_ENTITY_PREDICTION )
  10. #if defined( CLIENT_DLL )
  11. #include "igamesystem.h"
  12. #endif
  13. #include <memory.h>
  14. #include <stdarg.h>
  15. #include "tier0/dbg.h"
  16. #include "tier1/strtools.h"
  17. #include "predictioncopy.h"
  18. #include "engine/ivmodelinfo.h"
  19. #include "tier1/fmtstr.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. // --------------------------------------------------------------
  23. //
  24. // CSave
  25. //
  26. // --------------------------------------------------------------
  27. static const char *g_FieldTypes[ FIELD_TYPECOUNT ] =
  28. {
  29. "FIELD_VOID", // FIELD_VOID
  30. "FIELD_FLOAT", // FIELD_FLOAT
  31. "FIELD_STRING", // FIELD_STRING
  32. "FIELD_VECTOR", // FIELD_VECTOR
  33. "FIELD_QUATERNION", // FIELD_QUATERNION
  34. "FIELD_INTEGER", // FIELD_INTEGER
  35. "FIELD_BOOLEAN", // FIELD_BOOLEAN
  36. "FIELD_SHORT", // FIELD_SHORT
  37. "FIELD_CHARACTER", // FIELD_CHARACTER
  38. "FIELD_COLOR32", // FIELD_COLOR32
  39. "FIELD_EMBEDDED", // FIELD_EMBEDDED (handled specially)
  40. "FIELD_CUSTOM", // FIELD_CUSTOM (handled specially)
  41. "FIELD_CLASSPTR", // FIELD_CLASSPTR
  42. "FIELD_EHANDLE", // FIELD_EHANDLE
  43. "FIELD_EDICT", // FIELD_EDICT
  44. "FIELD_POSITION_VECTOR",// FIELD_POSITION_VECTOR
  45. "FIELD_TIME", // FIELD_TIME
  46. "FIELD_TICK", // FIELD_TICK
  47. "FIELD_MODELNAME", // FIELD_MODELNAME
  48. "FIELD_SOUNDNAME", // FIELD_SOUNDNAME
  49. "FIELD_INPUT", // FIELD_INPUT (uses custom type)
  50. "FIELD_FUNCTION", // FIELD_FUNCTION
  51. "FIELD_VMATRIX",
  52. "FIELD_VMATRIX_WORLDSPACE",
  53. "FIELD_MATRIX3X4_WORLDSPACE",
  54. "FIELD_INTERVAL" // FIELD_INTERVAL
  55. "FIELD_MODELINDEX" // FIELD_MODELINDEX
  56. };
  57. CPredictionCopy::CPredictionCopy( int type, void *dest, bool dest_packed, void const *src, bool src_packed,
  58. bool counterrors /*= false*/, bool reporterrors /*= false*/, bool performcopy /*= true*/,
  59. bool describefields /*= false*/, FN_FIELD_COMPARE func /*= NULL*/ )
  60. {
  61. m_nType = type;
  62. m_pDest = dest;
  63. m_pSrc = src;
  64. m_nDestOffsetIndex = dest_packed ? TD_OFFSET_PACKED : TD_OFFSET_NORMAL;
  65. m_nSrcOffsetIndex = src_packed ? TD_OFFSET_PACKED : TD_OFFSET_NORMAL;
  66. m_bErrorCheck = counterrors;
  67. m_bReportErrors = reporterrors;
  68. m_bPerformCopy = performcopy;
  69. m_bDescribeFields = describefields;
  70. m_pCurrentField = NULL;
  71. m_pCurrentMap = NULL;
  72. m_pCurrentClassName = NULL;
  73. m_bShouldReport = false;
  74. m_bShouldDescribe = false;
  75. m_nErrorCount = 0;
  76. m_FieldCompareFunc = func;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. // Input : *fmt -
  81. // ... -
  82. //-----------------------------------------------------------------------------
  83. void CPredictionCopy::ReportFieldsDiffer( const char *fmt, ... )
  84. {
  85. ++m_nErrorCount;
  86. if ( !m_bShouldReport )
  87. return;
  88. if ( m_bDescribeFields && m_FieldCompareFunc )
  89. return;
  90. Assert( m_pCurrentMap );
  91. Assert( m_pCurrentClassName );
  92. const char *fieldname = "empty";
  93. int flags = 0;
  94. if ( m_pCurrentField )
  95. {
  96. flags = m_pCurrentField->flags;
  97. fieldname = m_pCurrentField->fieldName ? m_pCurrentField->fieldName : "NULL";
  98. }
  99. va_list argptr;
  100. char data[ 4096 ];
  101. int len;
  102. va_start(argptr, fmt);
  103. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  104. va_end(argptr);
  105. if ( m_nErrorCount == 1 )
  106. {
  107. Msg( "\n" );
  108. }
  109. Msg( "%03i %s::%s - %s",
  110. m_nErrorCount,
  111. m_pCurrentClassName,
  112. fieldname,
  113. data );
  114. m_bShouldReport = false;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. // Input : *fmt -
  119. // ... -
  120. //-----------------------------------------------------------------------------
  121. void CPredictionCopy::DescribeFields( difftype_t dt, const char *fmt, ... )
  122. {
  123. if ( !m_bShouldDescribe )
  124. return;
  125. if ( !m_FieldCompareFunc )
  126. return;
  127. Assert( m_pCurrentMap );
  128. Assert( m_pCurrentClassName );
  129. const char *fieldname = "empty";
  130. int flags = 0;
  131. if ( m_pCurrentField )
  132. {
  133. flags = m_pCurrentField->flags;
  134. fieldname = m_pCurrentField->fieldName ? m_pCurrentField->fieldName : "NULL";
  135. }
  136. va_list argptr;
  137. char data[ 4096 ];
  138. int len;
  139. va_start(argptr, fmt);
  140. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  141. va_end(argptr);
  142. bool isnetworked = ( flags & FTYPEDESC_INSENDTABLE ) ? true : false;
  143. bool isnoterrorchecked = ( flags & FTYPEDESC_NOERRORCHECK ) ? true : false;
  144. ( *m_FieldCompareFunc )(
  145. m_pCurrentClassName,
  146. fieldname,
  147. g_FieldTypes[ m_pCurrentField->fieldType ],
  148. isnetworked,
  149. isnoterrorchecked,
  150. dt != IDENTICAL ? true : false,
  151. dt == WITHINTOLERANCE ? true : false,
  152. data
  153. );
  154. m_bShouldDescribe = false;
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose:
  158. // Output : Returns true on success, false on failure.
  159. //-----------------------------------------------------------------------------
  160. bool CPredictionCopy::CanCheck( void )
  161. {
  162. Assert( m_pCurrentField );
  163. if ( m_pCurrentField->flags & FTYPEDESC_NOERRORCHECK )
  164. {
  165. return false;
  166. }
  167. return true;
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. // Input : size -
  172. // *outdata -
  173. // *indata -
  174. //-----------------------------------------------------------------------------
  175. /*
  176. void CPredictionCopy::CopyData( difftype_t dt, int size, char *outdata, const char *indata )
  177. {
  178. if ( !m_bPerformCopy )
  179. return;
  180. if ( dt == IDENTICAL )
  181. return;
  182. memcpy( outdata, indata, size );
  183. }
  184. */
  185. CPredictionCopy::difftype_t CPredictionCopy::CompareData( int size, char *outdata, const char *indata )
  186. {
  187. if ( !m_bErrorCheck )
  188. return DIFFERS;
  189. if ( CanCheck() )
  190. {
  191. if ( memcmp( outdata, indata, size ) )
  192. {
  193. return DIFFERS;
  194. }
  195. else
  196. {
  197. // No difference, so no need to copy
  198. return IDENTICAL;
  199. }
  200. }
  201. // Fields differ
  202. return IDENTICAL;
  203. }
  204. void CPredictionCopy::DescribeData( difftype_t dt, int size, char *outdata, const char *indata )
  205. {
  206. if ( !m_bErrorCheck )
  207. return;
  208. if ( dt == DIFFERS )
  209. {
  210. ReportFieldsDiffer( "binary data differs (%i bytes)\n", size );
  211. }
  212. DescribeFields( dt, "binary (%i bytes)\n", size );
  213. }
  214. void CPredictionCopy::WatchData( difftype_t dt, int size, char *outdata, const char *indata )
  215. {
  216. if ( m_pWatchField != m_pCurrentField )
  217. return;
  218. WatchMsg( "binary (%i bytes)", size );
  219. }
  220. void CPredictionCopy::DescribeShort( difftype_t dt, short *outvalue, const short *invalue, int count )
  221. {
  222. if ( !m_bErrorCheck )
  223. return;
  224. if ( dt == DIFFERS )
  225. {
  226. int i = 0;
  227. ReportFieldsDiffer( "short differs (net %i pred %i) diff(%i)\n", (int)(invalue[i]), (int)(outvalue[i]), (int)(outvalue[i] - invalue[i]) );
  228. }
  229. DescribeFields( dt, "short (%i)\n", (int)(outvalue[0]) );
  230. }
  231. void CPredictionCopy::WatchShort( difftype_t dt, short *outvalue, const short *invalue, int count )
  232. {
  233. if ( m_pWatchField != m_pCurrentField )
  234. return;
  235. WatchMsg( "short (%i)", (int)(outvalue[0]) );
  236. }
  237. #if defined( CLIENT_DLL )
  238. #include "cdll_int.h"
  239. #endif
  240. void CPredictionCopy::DescribeInt( difftype_t dt, int *outvalue, const int *invalue, int count )
  241. {
  242. if ( !m_bErrorCheck )
  243. return;
  244. if ( dt == DIFFERS )
  245. {
  246. int i = 0;
  247. ReportFieldsDiffer( "int differs (net %i pred %i) diff(%i)\n", invalue[i], outvalue[i], outvalue[i] - invalue[i] );
  248. }
  249. #if defined( CLIENT_DLL )
  250. bool described = false;
  251. if ( m_pCurrentField->flags & FTYPEDESC_MODELINDEX )
  252. {
  253. int modelindex = outvalue[0];
  254. model_t const *m = modelinfo->GetModel( modelindex );
  255. if ( m )
  256. {
  257. described = true;
  258. char shortfile[ 512 ];
  259. shortfile[ 0 ] = 0;
  260. Q_FileBase( modelinfo->GetModelName( m ), shortfile, sizeof( shortfile ) );
  261. DescribeFields( dt, "integer (%i->%s)\n", outvalue[0], shortfile );
  262. }
  263. }
  264. if ( !described )
  265. {
  266. DescribeFields( dt, "integer (%i)\n", outvalue[0] );
  267. }
  268. #else
  269. DescribeFields( dt, "integer (%i)\n", outvalue[0] );
  270. #endif
  271. }
  272. void CPredictionCopy::WatchInt( difftype_t dt, int *outvalue, const int *invalue, int count )
  273. {
  274. if ( m_pWatchField != m_pCurrentField )
  275. return;
  276. #if defined( CLIENT_DLL )
  277. bool described = false;
  278. if ( m_pCurrentField->flags & FTYPEDESC_MODELINDEX )
  279. {
  280. int modelindex = outvalue[0];
  281. model_t const *m = modelinfo->GetModel( modelindex );
  282. if ( m )
  283. {
  284. described = true;
  285. char shortfile[ 512 ];
  286. shortfile[ 0 ] = 0;
  287. Q_FileBase( modelinfo->GetModelName( m ), shortfile, sizeof( shortfile ) );
  288. WatchMsg( "integer (%i->%s)", outvalue[0], shortfile );
  289. }
  290. }
  291. if ( !described )
  292. {
  293. WatchMsg( "integer (%i)", outvalue[0] );
  294. }
  295. #else
  296. WatchMsg( "integer (%i)", outvalue[0] );
  297. #endif
  298. }
  299. void CPredictionCopy::DescribeBool( difftype_t dt, bool *outvalue, const bool *invalue, int count )
  300. {
  301. if ( !m_bErrorCheck )
  302. return;
  303. if ( dt == DIFFERS )
  304. {
  305. int i = 0;
  306. ReportFieldsDiffer( "bool differs (net %s pred %s)\n", (invalue[i]) ? "true" : "false", (outvalue[i]) ? "true" : "false" );
  307. }
  308. DescribeFields( dt, "bool (%s)\n", (outvalue[0]) ? "true" : "false" );
  309. }
  310. void CPredictionCopy::WatchBool( difftype_t dt, bool *outvalue, const bool *invalue, int count )
  311. {
  312. if ( m_pWatchField != m_pCurrentField )
  313. return;
  314. WatchMsg( "bool (%s)", (outvalue[0]) ? "true" : "false" );
  315. }
  316. void CPredictionCopy::DescribeFloat( difftype_t dt, float *outvalue, const float *invalue, int count )
  317. {
  318. if ( !m_bErrorCheck )
  319. return;
  320. if ( dt == DIFFERS )
  321. {
  322. int i = 0;
  323. ReportFieldsDiffer( "float differs (net %f pred %f) diff(%f)\n", invalue[ i ], outvalue[ i ], outvalue[ i ] - invalue[ i ] );
  324. }
  325. DescribeFields( dt, "float (%f)\n", outvalue[ 0 ] );
  326. }
  327. void CPredictionCopy::WatchFloat( difftype_t dt, float *outvalue, const float *invalue, int count )
  328. {
  329. if ( m_pWatchField != m_pCurrentField )
  330. return;
  331. WatchMsg( "float (%f)", outvalue[ 0 ] );
  332. }
  333. void CPredictionCopy::DescribeString( difftype_t dt, char *outstring, const char *instring )
  334. {
  335. if ( !m_bErrorCheck )
  336. return;
  337. if ( dt == DIFFERS )
  338. {
  339. ReportFieldsDiffer( "string differs (net %s pred %s)\n", instring, outstring );
  340. }
  341. DescribeFields( dt, "string (%s)\n", outstring );
  342. }
  343. void CPredictionCopy::WatchString( difftype_t dt, char *outstring, const char *instring )
  344. {
  345. if ( m_pWatchField != m_pCurrentField )
  346. return;
  347. WatchMsg( "string (%s)", outstring );
  348. }
  349. void CPredictionCopy::DescribeVector( difftype_t dt, Vector& outValue, const Vector &inValue )
  350. {
  351. if ( !m_bErrorCheck )
  352. return;
  353. if ( dt == DIFFERS )
  354. {
  355. Vector delta = outValue - inValue;
  356. ReportFieldsDiffer( "vec differs (net %f %f %f - pred %f %f %f) delta(%f %f %f)\n",
  357. inValue.x, inValue.y, inValue.z,
  358. outValue.x, outValue.y, outValue.z,
  359. delta.x, delta.y, delta.z );
  360. }
  361. DescribeFields( dt, "vector (%f %f %f)\n",
  362. outValue.x, outValue.y, outValue.z );
  363. }
  364. void CPredictionCopy::DescribeVector( difftype_t dt, Vector* outValue, const Vector *inValue, int count )
  365. {
  366. if ( !m_bErrorCheck )
  367. return;
  368. if ( dt == DIFFERS )
  369. {
  370. int i = 0;
  371. Vector delta = outValue[ i ] - inValue[ i ];
  372. ReportFieldsDiffer( "vec[] differs (1st diff) (net %f %f %f - pred %f %f %f) delta(%f %f %f)\n",
  373. inValue[i].x, inValue[i].y, inValue[i].z,
  374. outValue[i].x, outValue[i].y, outValue[i].z,
  375. delta.x, delta.y, delta.z );
  376. }
  377. DescribeFields( dt, "vector (%f %f %f)\n",
  378. outValue[0].x, outValue[0].y, outValue[0].z );
  379. }
  380. void CPredictionCopy::WatchVector( difftype_t dt, Vector& outValue, const Vector &inValue )
  381. {
  382. if ( m_pWatchField != m_pCurrentField )
  383. return;
  384. WatchMsg( "vector (%f %f %f)", outValue.x, outValue.y, outValue.z );
  385. }
  386. void CPredictionCopy::WatchVector( difftype_t dt, Vector* outValue, const Vector *inValue, int count )
  387. {
  388. if ( m_pWatchField != m_pCurrentField )
  389. return;
  390. WatchMsg( "vector (%f %f %f)", outValue[0].x, outValue[0].y, outValue[0].z );
  391. }
  392. void CPredictionCopy::DescribeQuaternion( difftype_t dt, Quaternion& outValue, const Quaternion &inValue )
  393. {
  394. if ( !m_bErrorCheck )
  395. return;
  396. if ( dt == DIFFERS )
  397. {
  398. Quaternion delta;
  399. for ( int i = 0; i < 4; i++ )
  400. {
  401. delta[i] = outValue[i] - inValue[i];
  402. }
  403. ReportFieldsDiffer( "quaternion differs (net %f %f %f %f - pred %f %f %f %f) delta(%f %f %f %f)\n",
  404. inValue[0], inValue[1], inValue[2], inValue[3],
  405. outValue[0], outValue[1], outValue[2], outValue[3],
  406. delta[0], delta[1], delta[2], delta[3] );
  407. }
  408. DescribeFields( dt, "quaternion (%f %f %f %f)\n",
  409. outValue[0], outValue[1], outValue[2], outValue[3] );
  410. }
  411. void CPredictionCopy::DescribeQuaternion( difftype_t dt, Quaternion* outValue, const Quaternion *inValue, int count )
  412. {
  413. if ( !m_bErrorCheck )
  414. return;
  415. if ( dt == DIFFERS )
  416. {
  417. int i = 0;
  418. Quaternion delta;
  419. for ( int j = 0; j < 4; j++ )
  420. {
  421. delta[j] = outValue[i][j] - inValue[i][j];
  422. }
  423. ReportFieldsDiffer( "quaternion[] differs (1st diff) (net %f %f %f %f - pred %f %f %f %f) delta(%f %f %f %f)\n",
  424. (float)inValue[i][0], (float)inValue[i][1], (float)inValue[i][2], (float)inValue[i][3],
  425. (float)outValue[i][0], (float)outValue[i][1], (float)outValue[i][2], (float)outValue[i][3],
  426. delta[0], delta[1], delta[2], delta[3] );
  427. }
  428. DescribeFields( dt, "quaternion (%f %f %f %f)\n",
  429. (float)outValue[0][0], (float)outValue[0][1], (float)outValue[0][2], (float)outValue[0][3] );
  430. }
  431. void CPredictionCopy::WatchQuaternion( difftype_t dt, Quaternion& outValue, const Quaternion &inValue )
  432. {
  433. if ( m_pWatchField != m_pCurrentField )
  434. return;
  435. WatchMsg( "quaternion (%f %f %f %f)", (float)outValue[0], (float)outValue[1], (float)outValue[2], (float)outValue[3] );
  436. }
  437. void CPredictionCopy::WatchQuaternion( difftype_t dt, Quaternion* outValue, const Quaternion *inValue, int count )
  438. {
  439. if ( m_pWatchField != m_pCurrentField )
  440. return;
  441. WatchMsg( "quaternion (%f %f %f %f)", outValue[0][0], outValue[0][1], outValue[0][2], outValue[0][3] );
  442. }
  443. void CPredictionCopy::DescribeEHandle( difftype_t dt, EHANDLE *outvalue, EHANDLE const *invalue, int count )
  444. {
  445. if ( !m_bErrorCheck )
  446. return;
  447. if ( dt == DIFFERS )
  448. {
  449. int i = 0;
  450. ReportFieldsDiffer( "EHandles differ (net) 0x%p (pred) 0x%p\n", (void const *)invalue[ i ].Get(), (void *)outvalue[ i ].Get() );
  451. }
  452. #if defined( CLIENT_DLL )
  453. C_BaseEntity *ent = outvalue[0].Get();
  454. if ( ent )
  455. {
  456. const char *classname = ent->GetClassname();
  457. if ( !classname[0] )
  458. {
  459. classname = typeid( *ent ).name();
  460. }
  461. DescribeFields( dt, "EHandle (0x%p->%s)", (void *)outvalue[ 0 ], classname );
  462. }
  463. else
  464. {
  465. DescribeFields( dt, "EHandle (NULL)" );
  466. }
  467. #else
  468. DescribeFields( dt, "EHandle (0x%p)", (void *)outvalue[ 0 ] );
  469. #endif
  470. }
  471. void CPredictionCopy::WatchEHandle( difftype_t dt, EHANDLE *outvalue, EHANDLE const *invalue, int count )
  472. {
  473. if ( m_pWatchField != m_pCurrentField )
  474. return;
  475. #if defined( CLIENT_DLL )
  476. C_BaseEntity *ent = outvalue[0].Get();
  477. if ( ent )
  478. {
  479. const char *classname = ent->GetClassname();
  480. if ( !classname[0] )
  481. {
  482. classname = typeid( *ent ).name();
  483. }
  484. WatchMsg( "EHandle (0x%p->%s)", (void *)outvalue[ 0 ], classname );
  485. }
  486. else
  487. {
  488. WatchMsg( "EHandle (NULL)" );
  489. }
  490. #else
  491. WatchMsg( "EHandle (0x%p)", (void *)outvalue[ 0 ] );
  492. #endif
  493. }
  494. void CPredictionCopy::CopyShort( difftype_t dt, short *outvalue, const short *invalue, int count )
  495. {
  496. if ( !m_bPerformCopy )
  497. return;
  498. if ( dt == IDENTICAL )
  499. return;
  500. CopyData( dt, sizeof(short) * count, (char *)outvalue, (const char *)invalue );
  501. }
  502. CPredictionCopy::difftype_t CPredictionCopy::CompareShort( short *outvalue, const short *invalue, int count )
  503. {
  504. if ( !m_bErrorCheck )
  505. return DIFFERS;
  506. if ( CanCheck() )
  507. {
  508. for ( int i = 0; i < count; i++ )
  509. {
  510. if ( outvalue[ i ] == invalue[ i ] )
  511. continue;
  512. return DIFFERS;
  513. }
  514. }
  515. return IDENTICAL;
  516. }
  517. void CPredictionCopy::CopyInt( difftype_t dt, int *outvalue, const int *invalue, int count )
  518. {
  519. if ( !m_bPerformCopy )
  520. return;
  521. if ( dt == IDENTICAL )
  522. return;
  523. CopyData( dt, sizeof(int) * count, (char *)outvalue, (const char *)invalue );
  524. }
  525. CPredictionCopy::difftype_t CPredictionCopy::CompareInt( int *outvalue, const int *invalue, int count )
  526. {
  527. if ( !m_bErrorCheck )
  528. return DIFFERS;
  529. if ( CanCheck() )
  530. {
  531. for ( int i = 0; i < count; i++ )
  532. {
  533. if ( outvalue[ i ] == invalue[ i ] )
  534. continue;
  535. ReportFieldsDiffer( "int differs (net %i pred %i) diff(%i)\n", invalue[i], outvalue[i], outvalue[i] - invalue[i] );
  536. return DIFFERS;
  537. }
  538. }
  539. return IDENTICAL;
  540. }
  541. void CPredictionCopy::CopyBool( difftype_t dt, bool *outvalue, const bool *invalue, int count )
  542. {
  543. if ( !m_bPerformCopy )
  544. return;
  545. if ( dt == IDENTICAL )
  546. return;
  547. CopyData( dt, sizeof( bool ) * count, (char *)outvalue, (const char *)invalue );
  548. }
  549. CPredictionCopy::difftype_t CPredictionCopy::CompareBool( bool *outvalue, const bool *invalue, int count )
  550. {
  551. if ( !m_bErrorCheck )
  552. return DIFFERS;
  553. if ( CanCheck() )
  554. {
  555. for ( int i = 0; i < count; i++ )
  556. {
  557. if ( outvalue[ i ] == invalue[ i ] )
  558. continue;
  559. return DIFFERS;
  560. }
  561. }
  562. return IDENTICAL;
  563. }
  564. void CPredictionCopy::CopyFloat( difftype_t dt, float *outvalue, const float *invalue, int count )
  565. {
  566. if ( !m_bPerformCopy )
  567. return;
  568. if ( dt == IDENTICAL )
  569. return;
  570. CopyData( dt, sizeof( float ) * count, (char *)outvalue, (const char *)invalue );
  571. }
  572. CPredictionCopy::difftype_t CPredictionCopy::CompareFloat( float *outvalue, const float *invalue, int count )
  573. {
  574. if ( !m_bErrorCheck )
  575. return DIFFERS;
  576. difftype_t retval = IDENTICAL;
  577. if ( CanCheck() )
  578. {
  579. float tolerance = m_pCurrentField->fieldTolerance;
  580. Assert( tolerance >= 0.0f );
  581. bool usetolerance = tolerance > 0.0f;
  582. for ( int i = 0; i < count; i++ )
  583. {
  584. if ( outvalue[ i ] == invalue[ i ] )
  585. continue;
  586. if ( usetolerance &&
  587. ( fabs( outvalue[ i ] - invalue[ i ] ) <= tolerance ) )
  588. {
  589. retval = WITHINTOLERANCE;
  590. continue;
  591. }
  592. return DIFFERS;
  593. }
  594. }
  595. return retval;
  596. }
  597. void CPredictionCopy::CopyString( difftype_t dt, char *outstring, const char *instring )
  598. {
  599. if ( !m_bPerformCopy )
  600. return;
  601. if ( dt == IDENTICAL )
  602. return;
  603. CopyData( dt, Q_strlen( instring ) + 1, (char *)outstring, (const char *)instring );
  604. }
  605. CPredictionCopy::difftype_t CPredictionCopy::CompareString( char *outstring, const char *instring )
  606. {
  607. if ( !m_bErrorCheck )
  608. return DIFFERS;
  609. if ( CanCheck() )
  610. {
  611. if ( Q_strcmp( outstring, instring ) )
  612. {
  613. return DIFFERS;
  614. }
  615. }
  616. return IDENTICAL;
  617. }
  618. void CPredictionCopy::CopyVector( difftype_t dt, Vector& outValue, const Vector &inValue )
  619. {
  620. CopyVector( dt, &outValue, &inValue, 1 );
  621. }
  622. void CPredictionCopy::CopyQuaternion( difftype_t dt, Quaternion& outValue, const Quaternion &inValue )
  623. {
  624. CopyQuaternion( dt, &outValue, &inValue, 1 );
  625. }
  626. CPredictionCopy::difftype_t CPredictionCopy::CompareVector( Vector& outValue, const Vector &inValue )
  627. {
  628. if ( !m_bErrorCheck )
  629. return DIFFERS;
  630. if ( CanCheck() )
  631. {
  632. float tolerance = m_pCurrentField->fieldTolerance;
  633. Assert( tolerance >= 0.0f );
  634. if ( outValue != inValue && ( tolerance > 0.0f ) )
  635. {
  636. Vector delta = outValue - inValue;
  637. if ( fabs( delta.x ) <= tolerance &&
  638. fabs( delta.y ) <= tolerance &&
  639. fabs( delta.z ) <= tolerance )
  640. {
  641. return WITHINTOLERANCE;
  642. }
  643. }
  644. return DIFFERS;
  645. }
  646. return IDENTICAL;
  647. }
  648. static int QuaternionCompare (const Quaternion& q1, const Quaternion& q2 )
  649. {
  650. for ( int i = 0; i < 4; i++ )
  651. {
  652. if ( q1[i] != q2[i] )
  653. return 0;
  654. }
  655. return 1;
  656. }
  657. CPredictionCopy::difftype_t CPredictionCopy::CompareQuaternion( Quaternion& outValue, const Quaternion &inValue )
  658. {
  659. if ( !m_bErrorCheck )
  660. return DIFFERS;
  661. if ( CanCheck() )
  662. {
  663. float tolerance = m_pCurrentField->fieldTolerance;
  664. Assert( tolerance >= 0.0f );
  665. if ( QuaternionCompare( outValue, inValue ) == 0
  666. && ( tolerance > 0.0f ) )
  667. {
  668. Quaternion delta;
  669. for ( int j = 0; j < 4; j++ )
  670. {
  671. delta[j] = outValue[j] - inValue[j];
  672. }
  673. if ( fabs( delta[0] ) <= tolerance &&
  674. fabs( delta[1] ) <= tolerance &&
  675. fabs( delta[2] ) <= tolerance &&
  676. fabs( delta[3] ) <= tolerance )
  677. {
  678. return WITHINTOLERANCE;
  679. }
  680. }
  681. return DIFFERS;
  682. }
  683. return IDENTICAL;
  684. }
  685. void CPredictionCopy::CopyVector( difftype_t dt, Vector* outValue, const Vector *inValue, int count )
  686. {
  687. if ( !m_bPerformCopy )
  688. return;
  689. if ( dt == IDENTICAL )
  690. return;
  691. CopyData( dt, sizeof( Vector ) * count, (char *)outValue, (const char *)inValue );
  692. }
  693. void CPredictionCopy::CopyQuaternion( difftype_t dt, Quaternion* outValue, const Quaternion *inValue, int count )
  694. {
  695. if ( !m_bPerformCopy )
  696. return;
  697. if ( dt == IDENTICAL )
  698. return;
  699. CopyData( dt, sizeof( Quaternion ) * count, (char *)outValue, (const char *)inValue );
  700. }
  701. CPredictionCopy::difftype_t CPredictionCopy::CompareVector( Vector* outValue, const Vector *inValue, int count )
  702. {
  703. if ( !m_bErrorCheck )
  704. return DIFFERS;
  705. difftype_t retval = IDENTICAL;
  706. if ( CanCheck() )
  707. {
  708. float tolerance = m_pCurrentField->fieldTolerance;
  709. Assert( tolerance >= 0.0f );
  710. for ( int i = 0; i < count; i++ )
  711. {
  712. if ( outValue[ i ] == inValue[ i ] )
  713. continue;
  714. Vector delta = outValue[ i ] - inValue[ i ];
  715. if ( tolerance > 0.0f )
  716. {
  717. if ( fabs( delta.x ) <= tolerance &&
  718. fabs( delta.y ) <= tolerance &&
  719. fabs( delta.z ) <= tolerance )
  720. {
  721. retval = WITHINTOLERANCE;
  722. continue;
  723. }
  724. }
  725. return DIFFERS;
  726. }
  727. }
  728. return retval;
  729. }
  730. CPredictionCopy::difftype_t CPredictionCopy::CompareQuaternion( Quaternion* outValue, const Quaternion *inValue, int count )
  731. {
  732. if ( !m_bErrorCheck )
  733. return DIFFERS;
  734. difftype_t retval = IDENTICAL;
  735. if ( CanCheck() )
  736. {
  737. float tolerance = m_pCurrentField->fieldTolerance;
  738. Assert( tolerance >= 0.0f );
  739. for ( int i = 0; i < count; i++ )
  740. {
  741. if ( QuaternionCompare( outValue[ i ], inValue[ i ] ) )
  742. continue;
  743. Quaternion delta;
  744. for ( int j = 0; j < 4; j++ )
  745. {
  746. delta[j] = outValue[i][j] - inValue[i][j];
  747. }
  748. if ( tolerance > 0.0f )
  749. {
  750. if ( fabs( delta[0] ) <= tolerance &&
  751. fabs( delta[1] ) <= tolerance &&
  752. fabs( delta[2] ) <= tolerance &&
  753. fabs( delta[3] ) <= tolerance )
  754. {
  755. retval = WITHINTOLERANCE;
  756. continue;
  757. }
  758. }
  759. return DIFFERS;
  760. }
  761. }
  762. return retval;
  763. }
  764. void CPredictionCopy::CopyEHandle( difftype_t dt, EHANDLE *outvalue, EHANDLE const *invalue, int count )
  765. {
  766. if ( !m_bPerformCopy )
  767. return;
  768. if ( dt == IDENTICAL )
  769. return;
  770. for ( int i = 0; i < count; i++ )
  771. {
  772. outvalue[ i ] = invalue[ i ];
  773. }
  774. }
  775. CPredictionCopy::difftype_t CPredictionCopy::CompareEHandle( EHANDLE *outvalue, EHANDLE const *invalue, int count )
  776. {
  777. if ( !m_bErrorCheck )
  778. return DIFFERS;
  779. int i;
  780. if ( CanCheck() )
  781. {
  782. for ( i = 0; i < count; i++ )
  783. {
  784. if ( outvalue[ i ].Get() == invalue[ i ].Get() )
  785. continue;
  786. return DIFFERS;
  787. }
  788. }
  789. return IDENTICAL;
  790. }
  791. void CPredictionCopy::CopyFields( int chain_count, datamap_t *pRootMap, typedescription_t *pFields, int fieldCount )
  792. {
  793. int i;
  794. int flags;
  795. int fieldOffsetSrc;
  796. int fieldOffsetDest;
  797. int fieldSize;
  798. m_pCurrentMap = pRootMap;
  799. if ( !m_pCurrentClassName )
  800. {
  801. m_pCurrentClassName = pRootMap->dataClassName;
  802. }
  803. for ( i = 0; i < fieldCount; i++ )
  804. {
  805. m_pCurrentField = &pFields[ i ];
  806. flags = m_pCurrentField->flags;
  807. // Mark any subchains first
  808. if ( m_pCurrentField->override_field != NULL )
  809. {
  810. m_pCurrentField->override_field->override_count = chain_count;
  811. }
  812. // Skip this field?
  813. if ( m_pCurrentField->override_count == chain_count )
  814. {
  815. continue;
  816. }
  817. // Always recurse into embeddeds
  818. if ( m_pCurrentField->fieldType != FIELD_EMBEDDED )
  819. {
  820. // Don't copy fields that are private to server or client
  821. if ( flags & FTYPEDESC_PRIVATE )
  822. continue;
  823. // For PC_NON_NETWORKED_ONLYs skip any fields that are present in the network send tables
  824. if ( m_nType == PC_NON_NETWORKED_ONLY && ( flags & FTYPEDESC_INSENDTABLE ) )
  825. continue;
  826. // For PC_NETWORKED_ONLYs skip any fields that are not present in the network send tables
  827. if ( m_nType == PC_NETWORKED_ONLY && !( flags & FTYPEDESC_INSENDTABLE ) )
  828. continue;
  829. }
  830. void *pOutputData;
  831. void const *pInputData;
  832. fieldOffsetDest = m_pCurrentField->fieldOffset[ m_nDestOffsetIndex ];
  833. fieldOffsetSrc = m_pCurrentField->fieldOffset[ m_nSrcOffsetIndex ];
  834. fieldSize = m_pCurrentField->fieldSize;
  835. pOutputData = (void *)((char *)m_pDest + fieldOffsetDest );
  836. pInputData = (void const *)((char *)m_pSrc + fieldOffsetSrc );
  837. // Assume we can report
  838. m_bShouldReport = m_bReportErrors;
  839. m_bShouldDescribe = true;
  840. bool bShouldWatch = m_pWatchField == m_pCurrentField;
  841. difftype_t difftype;
  842. switch( m_pCurrentField->fieldType )
  843. {
  844. case FIELD_EMBEDDED:
  845. {
  846. typedescription_t *save = m_pCurrentField;
  847. void *saveDest = m_pDest;
  848. void const *saveSrc = m_pSrc;
  849. const char *saveName = m_pCurrentClassName;
  850. m_pCurrentClassName = m_pCurrentField->td->dataClassName;
  851. // FIXME: Should this be done outside the FIELD_EMBEDDED case??
  852. // Don't follow the pointer if we're reading from a compressed packet
  853. m_pSrc = pInputData;
  854. if ( ( flags & FTYPEDESC_PTR ) && (m_nSrcOffsetIndex == PC_DATA_NORMAL) )
  855. {
  856. m_pSrc = *((void**)m_pSrc);
  857. }
  858. m_pDest = pOutputData;
  859. if ( ( flags & FTYPEDESC_PTR ) && (m_nDestOffsetIndex == PC_DATA_NORMAL) )
  860. {
  861. m_pDest = *((void**)m_pDest);
  862. }
  863. CopyFields( chain_count, pRootMap, m_pCurrentField->td->dataDesc, m_pCurrentField->td->dataNumFields );
  864. m_pCurrentClassName = saveName;
  865. m_pCurrentField = save;
  866. m_pDest = saveDest;
  867. m_pSrc = saveSrc;
  868. }
  869. break;
  870. case FIELD_FLOAT:
  871. {
  872. difftype = CompareFloat( (float *)pOutputData, (float const *)pInputData, fieldSize );
  873. CopyFloat( difftype, (float *)pOutputData, (float const *)pInputData, fieldSize );
  874. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeFloat( difftype, (float *)pOutputData, (float const *)pInputData, fieldSize );
  875. if ( bShouldWatch ) WatchFloat( difftype, (float *)pOutputData, (float const *)pInputData, fieldSize );
  876. }
  877. break;
  878. case FIELD_TIME:
  879. case FIELD_TICK:
  880. Assert( 0 );
  881. break;
  882. case FIELD_STRING:
  883. {
  884. difftype = CompareString( (char *)pOutputData, (char const*)pInputData );
  885. CopyString( difftype, (char *)pOutputData, (char const*)pInputData );
  886. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeString( difftype,(char *)pOutputData, (char const*)pInputData );
  887. if ( bShouldWatch ) WatchString( difftype,(char *)pOutputData, (char const*)pInputData );
  888. }
  889. break;
  890. case FIELD_MODELINDEX:
  891. Assert( 0 );
  892. break;
  893. case FIELD_MODELNAME:
  894. case FIELD_SOUNDNAME:
  895. Assert( 0 );
  896. break;
  897. case FIELD_CUSTOM:
  898. Assert( 0 );
  899. break;
  900. case FIELD_CLASSPTR:
  901. case FIELD_EDICT:
  902. Assert( 0 );
  903. break;
  904. case FIELD_POSITION_VECTOR:
  905. Assert( 0 );
  906. break;
  907. case FIELD_VECTOR:
  908. {
  909. difftype = CompareVector( (Vector *)pOutputData, (Vector const *)pInputData, fieldSize );
  910. CopyVector( difftype, (Vector *)pOutputData, (Vector const *)pInputData, fieldSize );
  911. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeVector( difftype, (Vector *)pOutputData, (Vector const *)pInputData, fieldSize );
  912. if ( bShouldWatch ) WatchVector( difftype, (Vector *)pOutputData, (Vector const *)pInputData, fieldSize );
  913. }
  914. break;
  915. case FIELD_QUATERNION:
  916. {
  917. difftype = CompareQuaternion( (Quaternion *)pOutputData, (Quaternion const *)pInputData, fieldSize );
  918. CopyQuaternion( difftype, (Quaternion *)pOutputData, (Quaternion const *)pInputData, fieldSize );
  919. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeQuaternion( difftype, (Quaternion *)pOutputData, (Quaternion const *)pInputData, fieldSize );
  920. if ( bShouldWatch ) WatchQuaternion( difftype, (Quaternion *)pOutputData, (Quaternion const *)pInputData, fieldSize );
  921. }
  922. break;
  923. case FIELD_COLOR32:
  924. {
  925. difftype = CompareData( 4*fieldSize, (char *)pOutputData, (const char *)pInputData );
  926. CopyData( difftype, 4*fieldSize, (char *)pOutputData, (const char *)pInputData );
  927. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeData( difftype, 4*fieldSize, (char *)pOutputData, (const char *)pInputData );
  928. if ( bShouldWatch ) WatchData( difftype, 4*fieldSize, (char *)pOutputData, (const char *)pInputData );
  929. }
  930. break;
  931. case FIELD_BOOLEAN:
  932. {
  933. difftype = CompareBool( (bool *)pOutputData, (bool const *)pInputData, fieldSize );
  934. CopyBool( difftype, (bool *)pOutputData, (bool const *)pInputData, fieldSize );
  935. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeBool( difftype, (bool *)pOutputData, (bool const *)pInputData, fieldSize );
  936. if ( bShouldWatch ) WatchBool( difftype, (bool *)pOutputData, (bool const *)pInputData, fieldSize );
  937. }
  938. break;
  939. case FIELD_INTEGER:
  940. {
  941. difftype = CompareInt( (int *)pOutputData, (int const *)pInputData, fieldSize );
  942. CopyInt( difftype, (int *)pOutputData, (int const *)pInputData, fieldSize );
  943. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeInt( difftype, (int *)pOutputData, (int const *)pInputData, fieldSize );
  944. if ( bShouldWatch ) WatchInt( difftype, (int *)pOutputData, (int const *)pInputData, fieldSize );
  945. }
  946. break;
  947. case FIELD_SHORT:
  948. {
  949. difftype = CompareShort( (short *)pOutputData, (short const *)pInputData, fieldSize );
  950. CopyShort( difftype, (short *)pOutputData, (short const *)pInputData, fieldSize );
  951. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeShort( difftype, (short *)pOutputData, (short const *)pInputData, fieldSize );
  952. if ( bShouldWatch ) WatchShort( difftype, (short *)pOutputData, (short const *)pInputData, fieldSize );
  953. }
  954. break;
  955. case FIELD_CHARACTER:
  956. {
  957. difftype = CompareData( fieldSize, ((char *)pOutputData), (const char *)pInputData );
  958. CopyData( difftype, fieldSize, ((char *)pOutputData), (const char *)pInputData );
  959. int valOut = *((char *)pOutputData);
  960. int valIn = *((const char *)pInputData);
  961. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeInt( difftype, &valOut, &valIn, fieldSize );
  962. if ( bShouldWatch ) WatchData( difftype, fieldSize, ((char *)pOutputData), (const char *)pInputData );
  963. }
  964. break;
  965. case FIELD_EHANDLE:
  966. {
  967. difftype = CompareEHandle( (EHANDLE *)pOutputData, (EHANDLE const *)pInputData, fieldSize );
  968. CopyEHandle( difftype, (EHANDLE *)pOutputData, (EHANDLE const *)pInputData, fieldSize );
  969. if ( m_bErrorCheck && m_bShouldDescribe ) DescribeEHandle( difftype, (EHANDLE *)pOutputData, (EHANDLE const *)pInputData, fieldSize );
  970. if ( bShouldWatch ) WatchEHandle( difftype, (EHANDLE *)pOutputData, (EHANDLE const *)pInputData, fieldSize );
  971. }
  972. break;
  973. case FIELD_FUNCTION:
  974. {
  975. Assert( 0 );
  976. }
  977. break;
  978. case FIELD_VOID:
  979. {
  980. // Don't do anything, it's an empty data description
  981. }
  982. break;
  983. default:
  984. {
  985. Warning( "Bad field type\n" );
  986. Assert(0);
  987. }
  988. break;
  989. }
  990. }
  991. m_pCurrentClassName = NULL;
  992. }
  993. void CPredictionCopy::TransferData_R( int chaincount, datamap_t *dmap )
  994. {
  995. // Copy from here first, then baseclasses
  996. CopyFields( chaincount, dmap, dmap->dataDesc, dmap->dataNumFields );
  997. if ( dmap->baseMap )
  998. {
  999. TransferData_R( chaincount, dmap->baseMap );
  1000. }
  1001. }
  1002. static int g_nChainCount = 1;
  1003. static typedescription_t *FindFieldByName_R( const char *fieldname, datamap_t *dmap )
  1004. {
  1005. int c = dmap->dataNumFields;
  1006. for ( int i = 0; i < c; i++ )
  1007. {
  1008. typedescription_t *td = &dmap->dataDesc[ i ];
  1009. if ( td->fieldType == FIELD_VOID )
  1010. continue;
  1011. if ( td->fieldType == FIELD_EMBEDDED )
  1012. {
  1013. // TODO: this will only find the first subclass with the variable of the specified name
  1014. // At some point we might want to support multiple levels of overriding automatically
  1015. typedescription_t *ret = FindFieldByName_R( fieldname, td->td );
  1016. if ( ret )
  1017. {
  1018. return ret;
  1019. }
  1020. }
  1021. if ( !V_stricmp( td->fieldName, fieldname ) )
  1022. {
  1023. return td;
  1024. }
  1025. }
  1026. if ( dmap->baseMap )
  1027. {
  1028. return FindFieldByName_R( fieldname, dmap->baseMap );
  1029. }
  1030. return NULL;
  1031. }
  1032. void ValidateChains_R( datamap_t *dmap )
  1033. {
  1034. dmap->chains_validated = true;
  1035. int c = dmap->dataNumFields;
  1036. for ( int i = 0; i < c; i++ )
  1037. {
  1038. typedescription_t *td = &dmap->dataDesc[ i ];
  1039. if ( td->fieldType == FIELD_VOID )
  1040. continue;
  1041. if ( td->fieldType == FIELD_EMBEDDED )
  1042. {
  1043. ValidateChains_R( td->td );
  1044. continue;
  1045. }
  1046. if ( !( td->flags & FTYPEDESC_OVERRIDE ) )
  1047. continue;
  1048. if ( dmap->baseMap )
  1049. {
  1050. typedescription_t *basefield = FindFieldByName_R( td->fieldName, dmap->baseMap );
  1051. if ( basefield )
  1052. {
  1053. td->override_field = basefield;
  1054. }
  1055. }
  1056. }
  1057. if ( dmap->baseMap )
  1058. {
  1059. if ( !dmap->baseMap->chains_validated )
  1060. {
  1061. ValidateChains_R( dmap->baseMap );
  1062. }
  1063. }
  1064. }
  1065. //-----------------------------------------------------------------------------
  1066. // Purpose:
  1067. // Input : *fieldname -
  1068. // *dmap -
  1069. // Output : typedescription_t
  1070. //-----------------------------------------------------------------------------
  1071. typedescription_t *FindFieldByName( const char *fieldname, datamap_t *dmap )
  1072. {
  1073. return FindFieldByName_R( fieldname, dmap );
  1074. }
  1075. static ConVar pwatchent( "pwatchent", "-1", FCVAR_CHEAT, "Entity to watch for prediction system changes." );
  1076. static ConVar pwatchvar( "pwatchvar", "", FCVAR_CHEAT, "Entity variable to watch in prediction system for changes." );
  1077. //-----------------------------------------------------------------------------
  1078. // Purpose:
  1079. // Input : *fmt -
  1080. // ... -
  1081. //-----------------------------------------------------------------------------
  1082. void CPredictionCopy::WatchMsg( const char *fmt, ... )
  1083. {
  1084. Assert( m_pCurrentField && (m_pCurrentField == m_pWatchField) );
  1085. Assert( m_pOperation );
  1086. va_list argptr;
  1087. char data[ 4096 ];
  1088. int len;
  1089. va_start(argptr, fmt);
  1090. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  1091. va_end(argptr);
  1092. Msg( "%i %s %s : %s\n", gpGlobals->tickcount, m_pOperation, m_pCurrentField->fieldName, data );
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // Purpose:
  1096. // Input : *operation -
  1097. // entindex -
  1098. // *dmap -
  1099. //-----------------------------------------------------------------------------
  1100. void CPredictionCopy::DetermineWatchField( const char *operation, int entindex, datamap_t *dmap )
  1101. {
  1102. m_pWatchField = NULL;
  1103. m_pOperation = operation;
  1104. if ( !m_pOperation || !m_pOperation[0] )
  1105. return;
  1106. int enttowatch = pwatchent.GetInt();
  1107. if ( enttowatch < 0 )
  1108. return;
  1109. if ( entindex != enttowatch )
  1110. return;
  1111. // See if they specified a field
  1112. if ( pwatchvar.GetString()[0] == 0 )
  1113. return;
  1114. m_pWatchField = FindFieldByName( pwatchvar.GetString(), dmap );
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Purpose:
  1118. // Input : *operation -
  1119. // entindex -
  1120. // *dmap -
  1121. // Output : int
  1122. //-----------------------------------------------------------------------------
  1123. int CPredictionCopy::TransferData( const char *operation, int entindex, datamap_t *dmap )
  1124. {
  1125. ++g_nChainCount;
  1126. if ( !dmap->chains_validated )
  1127. {
  1128. ValidateChains_R( dmap );
  1129. }
  1130. DetermineWatchField( operation, entindex, dmap );
  1131. TransferData_R( g_nChainCount, dmap );
  1132. return m_nErrorCount;
  1133. }
  1134. /*
  1135. //-----------------------------------------------------------------------------
  1136. // Purpose: Simply dumps all data fields in object
  1137. //-----------------------------------------------------------------------------
  1138. class CPredictionDescribeData
  1139. {
  1140. public:
  1141. CPredictionDescribeData( void const *src );
  1142. void DescribeShort( const short *invalue, int count );
  1143. void DescribeInt( const int *invalue, int count );
  1144. void DescribeBool( const bool *invalue, int count );
  1145. void DescribeFloat( const float *invalue, int count );
  1146. void DescribeData( int size, const char *indata );
  1147. void DescribeString( const char *instring );
  1148. void DescribeVector( const Vector &inValue );
  1149. void DescribeVector( const Vector *inValue, int count );
  1150. void DescribeEHandle( EHANDLE const *invalue, int count );
  1151. void DescribeFields( datamap_t *pMap, typedescription_t *pFields, int fieldCount );
  1152. private:
  1153. void const *m_pSrc;
  1154. void Describe( const char *fmt, ... );
  1155. typedescription_t *m_pCurrentField;
  1156. char const *m_pCurrentClassName;
  1157. datamap_t *m_pCurrentMap;
  1158. };
  1159. */
  1160. CPredictionDescribeData::CPredictionDescribeData( void const *src, bool src_packed, FN_FIELD_DESCRIPTION func /*= 0*/ )
  1161. {
  1162. m_pSrc = src;
  1163. m_nSrcOffsetIndex = src_packed ? TD_OFFSET_PACKED : TD_OFFSET_NORMAL;
  1164. m_pCurrentField = NULL;
  1165. m_pCurrentMap = NULL;
  1166. m_pCurrentClassName = NULL;
  1167. m_bShouldReport = false;
  1168. m_FieldDescFunc = func;
  1169. }
  1170. //-----------------------------------------------------------------------------
  1171. // Purpose:
  1172. // Input : *fmt -
  1173. // ... -
  1174. //-----------------------------------------------------------------------------
  1175. void CPredictionDescribeData::Describe( const char *fmt, ... )
  1176. {
  1177. // if ( !m_bShouldReport )
  1178. // return;
  1179. Assert( m_pCurrentMap );
  1180. Assert( m_pCurrentClassName );
  1181. const char *fieldname = "empty";
  1182. int flags = 0;
  1183. if ( m_pCurrentField )
  1184. {
  1185. flags = m_pCurrentField->flags;
  1186. fieldname = m_pCurrentField->fieldName ? m_pCurrentField->fieldName : "NULL";
  1187. }
  1188. va_list argptr;
  1189. char data[ 4096 ];
  1190. int len;
  1191. va_start(argptr, fmt);
  1192. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  1193. va_end(argptr);
  1194. bool isprivate = ( flags & FTYPEDESC_PRIVATE ) ? true : false;
  1195. bool isnetworked = ( flags & FTYPEDESC_INSENDTABLE ) ? true : false;
  1196. if ( m_FieldDescFunc )
  1197. {
  1198. (*m_FieldDescFunc)(
  1199. m_pCurrentClassName,
  1200. m_pCurrentField->fieldName,
  1201. g_FieldTypes[ m_pCurrentField->fieldType ],
  1202. isnetworked,
  1203. data );
  1204. }
  1205. else
  1206. {
  1207. char suffix[ 128 ];
  1208. suffix[ 0 ] = 0;
  1209. if ( isprivate )
  1210. {
  1211. Q_strncat( suffix, "private", sizeof( suffix ), COPY_ALL_CHARACTERS );
  1212. }
  1213. if ( isnetworked )
  1214. {
  1215. if ( suffix[ 0 ] )
  1216. {
  1217. Q_strncat( suffix, " - ", sizeof( suffix ), COPY_ALL_CHARACTERS );
  1218. }
  1219. Q_strncat( suffix, "net", sizeof( suffix ), COPY_ALL_CHARACTERS );
  1220. }
  1221. if ( suffix[ 0 ] )
  1222. {
  1223. Msg( "%s::%s(%s) - %s",
  1224. m_pCurrentClassName,
  1225. fieldname,
  1226. suffix,
  1227. data );
  1228. }
  1229. else
  1230. {
  1231. Msg( "%s::%s - %s",
  1232. m_pCurrentClassName,
  1233. fieldname,
  1234. data );
  1235. }
  1236. }
  1237. m_bShouldReport = false;
  1238. }
  1239. //-----------------------------------------------------------------------------
  1240. // Purpose:
  1241. // Input : size -
  1242. // *outdata -
  1243. // *indata -
  1244. //-----------------------------------------------------------------------------
  1245. void CPredictionDescribeData::DescribeData( int size, const char *indata )
  1246. {
  1247. if ( !indata )
  1248. return;
  1249. Describe( "binary (%i bytes)\n", size );
  1250. }
  1251. void CPredictionDescribeData::DescribeShort( const short *invalue, int count )
  1252. {
  1253. Describe( "short (%i)\n", (int)(invalue[0]) );
  1254. }
  1255. void CPredictionDescribeData::DescribeInt( const int *invalue, int count )
  1256. {
  1257. for ( int i = 0; i < count; ++i )
  1258. {
  1259. Describe( "[%i] integer (%i)\n", i, invalue[i] );
  1260. }
  1261. }
  1262. void CPredictionDescribeData::DescribeBool( const bool *invalue, int count )
  1263. {
  1264. Describe( "bool (%s)\n", (invalue[0]) ? "true" : "false" );
  1265. }
  1266. void CPredictionDescribeData::DescribeFloat( const float *invalue, int count )
  1267. {
  1268. Describe( "float (%f)\n", invalue[ 0 ] );
  1269. }
  1270. void CPredictionDescribeData::DescribeString( const char *instring )
  1271. {
  1272. Describe( "string (%s)\n", instring );
  1273. }
  1274. void CPredictionDescribeData::DescribeVector( const Vector &inValue )
  1275. {
  1276. Describe( "vector (%f %f %f)\n",
  1277. inValue.x, inValue.y, inValue.z );
  1278. }
  1279. void CPredictionDescribeData::DescribeVector( const Vector *inValue, int count )
  1280. {
  1281. Describe( "vector (%f %f %f)\n",
  1282. inValue[0].x, inValue[0].y, inValue[0].z );
  1283. }
  1284. void CPredictionDescribeData::DescribeQuaternion( const Quaternion &inValue )
  1285. {
  1286. Describe( "quaternion (%f %f %f %f)\n",
  1287. inValue[0], inValue[1], inValue[2], inValue[3] );
  1288. }
  1289. void CPredictionDescribeData::DescribeQuaternion( const Quaternion *inValue, int count )
  1290. {
  1291. Describe( "quaternion (%f %f %f %f)\n",
  1292. inValue[0][0], inValue[0][1], inValue[0][2], inValue[0][3] );
  1293. }
  1294. void CPredictionDescribeData::DescribeEHandle( EHANDLE const *invalue, int count )
  1295. {
  1296. Describe( "EHandle (%p)\n", (void *)invalue[ 0 ] );
  1297. }
  1298. void CPredictionDescribeData::DescribeFields_R( int chain_count, datamap_t *pRootMap, typedescription_t *pFields, int fieldCount )
  1299. {
  1300. int i;
  1301. int flags;
  1302. int fieldOffsetSrc;
  1303. int fieldSize;
  1304. m_pCurrentMap = pRootMap;
  1305. if ( !m_pCurrentClassName )
  1306. {
  1307. m_pCurrentClassName = pRootMap->dataClassName;
  1308. }
  1309. for ( i = 0; i < fieldCount; i++ )
  1310. {
  1311. m_pCurrentField = &pFields[ i ];
  1312. flags = m_pCurrentField->flags;
  1313. // Mark any subchains first
  1314. if ( m_pCurrentField->override_field != NULL )
  1315. {
  1316. m_pCurrentField->override_field->override_count = chain_count;
  1317. }
  1318. // Skip this field?
  1319. if ( m_pCurrentField->override_count == chain_count )
  1320. {
  1321. continue;
  1322. }
  1323. void const *pInputData;
  1324. fieldOffsetSrc = m_pCurrentField->fieldOffset[ m_nSrcOffsetIndex ];
  1325. fieldSize = m_pCurrentField->fieldSize;
  1326. pInputData = (void const *)((char *)m_pSrc + fieldOffsetSrc );
  1327. // Assume we can report
  1328. m_bShouldReport = true;
  1329. switch( m_pCurrentField->fieldType )
  1330. {
  1331. case FIELD_EMBEDDED:
  1332. {
  1333. typedescription_t *save = m_pCurrentField;
  1334. void const *saveSrc = m_pSrc;
  1335. const char *saveName = m_pCurrentClassName;
  1336. m_pCurrentClassName = m_pCurrentField->td->dataClassName;
  1337. m_pSrc = pInputData;
  1338. if ( ( flags & FTYPEDESC_PTR ) && (m_nSrcOffsetIndex == PC_DATA_NORMAL) )
  1339. {
  1340. m_pSrc = *((void**)m_pSrc);
  1341. }
  1342. DescribeFields_R( chain_count, pRootMap, m_pCurrentField->td->dataDesc, m_pCurrentField->td->dataNumFields );
  1343. m_pCurrentClassName = saveName;
  1344. m_pCurrentField = save;
  1345. m_pSrc = saveSrc;
  1346. }
  1347. break;
  1348. case FIELD_FLOAT:
  1349. DescribeFloat( (float const *)pInputData, fieldSize );
  1350. break;
  1351. case FIELD_TIME:
  1352. case FIELD_TICK:
  1353. Assert( 0 );
  1354. break;
  1355. case FIELD_STRING:
  1356. DescribeString( (char const*)pInputData );
  1357. break;
  1358. case FIELD_MODELNAME:
  1359. case FIELD_SOUNDNAME:
  1360. Assert( 0 );
  1361. break;
  1362. case FIELD_MODELINDEX:
  1363. Assert( 0 );
  1364. break;
  1365. case FIELD_CUSTOM:
  1366. Assert( 0 );
  1367. break;
  1368. case FIELD_CLASSPTR:
  1369. case FIELD_EDICT:
  1370. break;
  1371. case FIELD_POSITION_VECTOR:
  1372. Assert( 0 );
  1373. break;
  1374. case FIELD_VECTOR:
  1375. DescribeVector( (const Vector *)pInputData, fieldSize );
  1376. break;
  1377. case FIELD_QUATERNION:
  1378. DescribeQuaternion( ( const Quaternion * )pInputData, fieldSize );
  1379. break;
  1380. case FIELD_COLOR32:
  1381. DescribeData( 4*fieldSize, (const char *)pInputData );
  1382. break;
  1383. case FIELD_BOOLEAN:
  1384. DescribeBool( (bool const *)pInputData, fieldSize );
  1385. break;
  1386. case FIELD_INTEGER:
  1387. DescribeInt( (int const *)pInputData, fieldSize );
  1388. break;
  1389. case FIELD_SHORT:
  1390. DescribeShort( (short const *)pInputData, fieldSize );
  1391. break;
  1392. case FIELD_CHARACTER:
  1393. DescribeData( fieldSize, (const char *)pInputData );
  1394. break;
  1395. case FIELD_EHANDLE:
  1396. DescribeEHandle( (EHANDLE const *)pInputData, fieldSize );
  1397. break;
  1398. case FIELD_FUNCTION:
  1399. Assert( 0 );
  1400. break;
  1401. case FIELD_VOID:
  1402. Describe( "FIELD_VOID: empty field\n" );
  1403. break;
  1404. default:
  1405. Warning( "Bad field type\n" );
  1406. Assert(0);
  1407. break;
  1408. }
  1409. }
  1410. m_pCurrentClassName = NULL;
  1411. }
  1412. void CPredictionDescribeData::DumpDescription( datamap_t *pMap )
  1413. {
  1414. ++g_nChainCount;
  1415. if ( !pMap->chains_validated )
  1416. {
  1417. ValidateChains_R( pMap );
  1418. }
  1419. while ( pMap )
  1420. {
  1421. DescribeFields_R( g_nChainCount, pMap, pMap->dataDesc, pMap->dataNumFields );
  1422. pMap = pMap->baseMap;
  1423. }
  1424. }
  1425. #if defined( CLIENT_DLL )
  1426. CValueChangeTracker::CValueChangeTracker() :
  1427. m_bActive( false ),
  1428. m_bTracking( false )
  1429. {
  1430. Q_memset( m_OrigValueBuf, 0, sizeof( m_OrigValueBuf ) );
  1431. }
  1432. C_BaseEntity *CValueChangeTracker::GetEntity()
  1433. {
  1434. return m_hEntityToTrack.Get();
  1435. }
  1436. void CValueChangeTracker::GetValue( char *buf, size_t bufsize )
  1437. {
  1438. buf[ 0 ] = 0;
  1439. Assert( IsActive() );
  1440. if ( !m_hEntityToTrack.Get() )
  1441. return;
  1442. void const *pInputData = ( const void * )m_hEntityToTrack.Get();
  1443. typedescription_t *td = NULL;
  1444. for ( int i = 0; i < m_FieldStack.Count(); ++i )
  1445. {
  1446. td = m_FieldStack[ i ];
  1447. Assert( ( i == ( m_FieldStack.Count() -1 ) ) ||
  1448. ( td->fieldType & FIELD_EMBEDDED ) );
  1449. int fieldOffsetSrc = td->fieldOffset[ TD_OFFSET_NORMAL ];
  1450. const void *pSaveSrc = (const void *)( (char *)pInputData + fieldOffsetSrc );
  1451. if ( ( td->flags & FTYPEDESC_PTR ) &&
  1452. ( td->fieldType & FIELD_EMBEDDED ) )
  1453. {
  1454. pInputData = *(const void **)pSaveSrc;
  1455. }
  1456. else
  1457. {
  1458. pInputData = (void const *)((char *)pSaveSrc );
  1459. }
  1460. }
  1461. if ( !td || !pInputData )
  1462. return;
  1463. int fieldType = td->fieldType;
  1464. switch( fieldType )
  1465. {
  1466. default:
  1467. case FIELD_EMBEDDED:
  1468. case FIELD_MODELNAME:
  1469. case FIELD_SOUNDNAME:
  1470. case FIELD_CUSTOM:
  1471. case FIELD_CLASSPTR:
  1472. case FIELD_EDICT:
  1473. case FIELD_POSITION_VECTOR:
  1474. case FIELD_VOID:
  1475. case FIELD_FUNCTION:
  1476. {
  1477. Assert( 0 );
  1478. }
  1479. break;
  1480. case FIELD_FLOAT:
  1481. case FIELD_TIME:
  1482. Q_snprintf( buf, bufsize, "%f", *(float const *)pInputData );
  1483. break;
  1484. case FIELD_STRING:
  1485. Q_snprintf( buf, bufsize, "%s", (char const*)pInputData );
  1486. break;
  1487. case FIELD_VECTOR:
  1488. {
  1489. const Vector *pVec = (const Vector *)pInputData;
  1490. Q_snprintf( buf, bufsize, "%f %f %f", pVec->x, pVec->y, pVec->z );
  1491. }
  1492. break;
  1493. case FIELD_QUATERNION:
  1494. {
  1495. const Quaternion *p = ( const Quaternion * )pInputData;
  1496. Q_snprintf( buf, bufsize, "%f %f %f %f", p->x, p->y, p->z, p->w );
  1497. }
  1498. break;
  1499. case FIELD_COLOR32:
  1500. {
  1501. const Color *color = ( const Color * )pInputData;
  1502. Q_snprintf( buf, bufsize, "%d %d %d %d", color->r(), color->g(), color->b(), color->a() );
  1503. }
  1504. break;
  1505. case FIELD_BOOLEAN:
  1506. Q_snprintf( buf, bufsize, "%s", (*(const bool *)pInputData) ? "true" : "false" );
  1507. break;
  1508. case FIELD_INTEGER:
  1509. case FIELD_TICK:
  1510. case FIELD_MODELINDEX:
  1511. Q_snprintf( buf, bufsize, "%i", *(const int*)pInputData );
  1512. break;
  1513. case FIELD_SHORT:
  1514. Q_snprintf( buf, bufsize, "%i", (int)*(const short*)pInputData );
  1515. break;
  1516. case FIELD_CHARACTER:
  1517. Q_snprintf( buf, bufsize, "%c", *(const char *)pInputData );
  1518. break;
  1519. case FIELD_EHANDLE:
  1520. Q_snprintf( buf, bufsize, "eh 0x%p", (void const *)((const EHANDLE *)pInputData)->Get() );
  1521. break;
  1522. }
  1523. }
  1524. void CValueChangeTracker::StartTrack( char const *pchContext )
  1525. {
  1526. if ( !IsActive() )
  1527. return;
  1528. m_strContext = pchContext;
  1529. // Grab current value into scratch buffer
  1530. GetValue( m_OrigValueBuf, sizeof( m_OrigValueBuf ) );
  1531. m_bTracking = true;
  1532. }
  1533. void CValueChangeTracker::EndTrack()
  1534. {
  1535. if ( !IsActive() )
  1536. return;
  1537. if ( !m_bTracking )
  1538. return;
  1539. m_bTracking = false;
  1540. char final[ eChangeTrackerBufSize ];
  1541. GetValue( final, sizeof( final ) );
  1542. CUtlString *history = &m_History[ m_History.AddToTail() ];
  1543. if ( Q_stricmp( final, m_OrigValueBuf ) )
  1544. {
  1545. history->Set( CFmtStr( "+++ %-20.20s: %s (was %s)", m_strContext.String(), final, m_OrigValueBuf ) );
  1546. }
  1547. else
  1548. {
  1549. history->Set( CFmtStr( " %-20.20s: %s", m_strContext.String(), final ) );
  1550. }
  1551. Msg( ":%s\n", history->String() );
  1552. }
  1553. void CValueChangeTracker::ClearTracking()
  1554. {
  1555. m_bActive = false;
  1556. m_bTracking = false;
  1557. m_hEntityToTrack = NULL;
  1558. m_strFieldName = "";
  1559. m_History.RemoveAll();
  1560. m_FieldStack.RemoveAll();
  1561. }
  1562. static bool FindFieldStackByName_R( const char *fieldname, datamap_t *dmap, CUtlVector< typedescription_t * >& stack )
  1563. {
  1564. int c = dmap->dataNumFields;
  1565. for ( int i = 0; i < c; i++ )
  1566. {
  1567. typedescription_t *td = &dmap->dataDesc[ i ];
  1568. if ( td->fieldType == FIELD_VOID )
  1569. continue;
  1570. stack.AddToTail( td );
  1571. if ( td->fieldType == FIELD_EMBEDDED )
  1572. {
  1573. // TODO: this will only find the first subclass with the variable of the specified name
  1574. // At some point we might want to support multiple levels of overriding automatically
  1575. bool ret = FindFieldStackByName_R( fieldname, td->td, stack );
  1576. if ( ret )
  1577. {
  1578. return ret;
  1579. }
  1580. }
  1581. if ( !Q_stricmp( td->fieldName, fieldname ) )
  1582. {
  1583. return true;
  1584. }
  1585. stack.FindAndRemove( td );
  1586. }
  1587. if ( dmap->baseMap )
  1588. {
  1589. return FindFieldStackByName_R( fieldname, dmap->baseMap, stack );
  1590. }
  1591. return false;
  1592. }
  1593. void CValueChangeTracker::SetupTracking( C_BaseEntity *ent, char const *pchFieldName )
  1594. {
  1595. ClearTracking();
  1596. // Find the field
  1597. datamap_t *dmap = ent->GetPredDescMap();
  1598. if ( !dmap )
  1599. {
  1600. Msg( "No prediction datamap_t for entity %d/%s\n", ent->index, ent->GetClassname() );
  1601. return;
  1602. }
  1603. bool bFound = FindFieldStackByName_R( pchFieldName, dmap, m_FieldStack );
  1604. if ( !bFound || !m_FieldStack.Count() )
  1605. {
  1606. Msg( "No field '%s' in datamap_t for entity %d/%s\n", pchFieldName, ent->index, ent->GetClassname() );
  1607. return;
  1608. }
  1609. m_hEntityToTrack = ent;
  1610. m_strFieldName = pchFieldName;
  1611. m_bActive = true;
  1612. }
  1613. void CValueChangeTracker::Reset()
  1614. {
  1615. m_History.RemoveAll();
  1616. }
  1617. bool CValueChangeTracker::IsActive() const
  1618. {
  1619. return m_bActive;
  1620. }
  1621. void CValueChangeTracker::Spew()
  1622. {
  1623. if ( IsActive() )
  1624. {
  1625. for ( int i = 0 ; i < m_History.Count(); ++i )
  1626. {
  1627. Msg( "%s\n", m_History[ i ].String() );
  1628. }
  1629. }
  1630. Reset();
  1631. }
  1632. static CValueChangeTracker g_ChangeTracker;
  1633. CValueChangeTracker *g_pChangeTracker = &g_ChangeTracker;
  1634. CON_COMMAND_F( cl_pred_track, "<entindex> <fieldname>: Track changes to entity index entindex, for field fieldname.", 0 )
  1635. {
  1636. g_pChangeTracker->ClearTracking();
  1637. if ( args.ArgC() != 3 )
  1638. {
  1639. Msg( "cl_pred_track <entindex> <fieldname>\n" );
  1640. return;
  1641. }
  1642. int iEntIndex = Q_atoi( args[1] );
  1643. C_BaseEntity *ent = cl_entitylist->GetBaseEntity( iEntIndex );
  1644. if ( !ent )
  1645. {
  1646. Msg( "cl_pred_track: Unknown ent index %d\n", iEntIndex );
  1647. return;
  1648. }
  1649. g_pChangeTracker->SetupTracking( ent, args[2] );
  1650. }
  1651. #endif
  1652. #if defined( CLIENT_DLL ) && defined( COPY_CHECK_STRESSTEST )
  1653. class CPredictionCopyTester : public IGameSystem
  1654. {
  1655. public:
  1656. // Init, shutdown
  1657. virtual void Init()
  1658. {
  1659. RunTests();
  1660. Remove( this );
  1661. }
  1662. virtual void Shutdown() {}
  1663. // Level init, shutdown
  1664. virtual void LevelInit() {}
  1665. // The level is shutdown in two parts
  1666. virtual void LevelShutdownPreEntity() {}
  1667. // Entities are deleted / released here...
  1668. virtual void LevelShutdownPostEntity() {}
  1669. // end of level shutdown
  1670. // Called before rendering
  1671. virtual void PreRender ( ) {}
  1672. // Called after rendering
  1673. virtual void PostRender() {}
  1674. // Gets called each frame
  1675. virtual void Update( float frametime ) {}
  1676. private:
  1677. void RunTests( void );
  1678. };
  1679. IGameSystem* GetPredictionCopyTester( void )
  1680. {
  1681. static CPredictionCopyTester s_PredictionCopyTesterSystem;
  1682. return &s_PredictionCopyTesterSystem;
  1683. }
  1684. class CCopyTesterData
  1685. {
  1686. public:
  1687. CCopyTesterData()
  1688. {
  1689. m_CharValue = 'a';
  1690. m_ShortValue = (short)100;
  1691. m_IntValue = (int)100;
  1692. m_FloatValue = 1.0f;
  1693. Q_strncpy( m_szValue, "primarydata", sizeof( m_szValue ) );
  1694. m_Vector = Vector( 100, 100, 100 );
  1695. m_Bool = false;
  1696. m_Clr.r = m_Clr.g = m_Clr.b = m_Clr.a = 255;
  1697. m_Ptr = (void *)0xfedcba98;
  1698. // m_hEHandle = NULL;
  1699. }
  1700. void MakeDifferent( void )
  1701. {
  1702. m_CharValue = 'd';
  1703. m_ShortValue = (short)400;
  1704. m_IntValue = (int)400;
  1705. m_FloatValue = 4.0f;
  1706. Q_strncpy( m_szValue, "secondarydata", sizeof( m_szValue ) );
  1707. m_Vector = Vector( 400, 400, 400 );
  1708. m_Bool = true;
  1709. m_Clr.r = m_Clr.g = m_Clr.b = m_Clr.a = 1;
  1710. m_Ptr = (void *)0x00000001;
  1711. // m_hEHandle = (C_BaseEntity *)0x00000001;
  1712. }
  1713. DECLARE_PREDICTABLE();
  1714. char m_CharValue;
  1715. short m_ShortValue;
  1716. int m_IntValue;
  1717. float m_FloatValue;
  1718. char m_szValue[ 128 ];
  1719. Vector m_Vector;
  1720. bool m_Bool;
  1721. color32 m_Clr;
  1722. void *m_Ptr;
  1723. // EHANDLE m_hEHandle;
  1724. };
  1725. BEGIN_PREDICTION_DATA_NO_BASE( CCopyTesterData )
  1726. DEFINE_FIELD( CCopyTesterData, m_CharValue, FIELD_CHARACTER ),
  1727. DEFINE_FIELD( CCopyTesterData, m_ShortValue, FIELD_SHORT ),
  1728. DEFINE_FIELD( CCopyTesterData, m_IntValue, FIELD_INTEGER ),
  1729. DEFINE_FIELD( CCopyTesterData, m_FloatValue, FIELD_FLOAT ),
  1730. DEFINE_FIELD( CCopyTesterData, m_szValue, FIELD_STRING ),
  1731. DEFINE_FIELD( CCopyTesterData, m_Vector, FIELD_VECTOR ),
  1732. DEFINE_FIELD( CCopyTesterData, m_Bool, FIELD_BOOLEAN ),
  1733. DEFINE_FIELD( CCopyTesterData, m_Clr, FIELD_COLOR32 ),
  1734. // DEFINE_FIELD( CCopyTesterData, m_hEHandle, FIELD_EHANDLE ),
  1735. END_PREDICTION_DATA()
  1736. class CCopyTesterData2 : public C_BaseEntity
  1737. {
  1738. DECLARE_CLASS( CCopyTesterData2, C_BaseEntity );
  1739. public:
  1740. CCopyTesterData2()
  1741. {
  1742. CONSTRUCT_PREDICTABLE( CCopyTesterData2 );
  1743. m_CharValue = 'b';
  1744. m_ShortValue = (short)200;
  1745. m_IntValue = (int)200;
  1746. m_FloatValue = 2.0f;
  1747. }
  1748. void MakeDifferent( void )
  1749. {
  1750. m_CharValue = 'e';
  1751. m_ShortValue = (short)500;
  1752. m_IntValue = (int)500;
  1753. m_FloatValue = 5.0f;
  1754. m_FooData.MakeDifferent();
  1755. }
  1756. DECLARE_PREDICTABLE();
  1757. char m_CharValue;
  1758. short m_ShortValue;
  1759. int m_IntValue;
  1760. float m_FloatValue;
  1761. CCopyTesterData m_FooData;
  1762. };
  1763. BEGIN_PREDICTION_DATA_NO_BASE( CCopyTesterData2 )
  1764. DEFINE_FIELD( CCopyTesterData2, m_CharValue, FIELD_CHARACTER ),
  1765. DEFINE_FIELD( CCopyTesterData2, m_ShortValue, FIELD_SHORT ),
  1766. DEFINE_PRED_TYPEDESCRIPTION( CCopyTesterData2, m_FooData, CCopyTesterData ),
  1767. DEFINE_FIELD( CCopyTesterData2, m_IntValue, FIELD_INTEGER ),
  1768. DEFINE_FIELD( CCopyTesterData2, m_FloatValue, FIELD_FLOAT ),
  1769. END_PREDICTION_DATA()
  1770. void CPredictionCopyTester::RunTests( void )
  1771. {
  1772. CCopyTesterData2 *foo1, *foo2, *foo3;
  1773. foo1 = new CCopyTesterData2;
  1774. foo2 = new CCopyTesterData2;
  1775. foo3 = new CCopyTesterData2;
  1776. foo2->MakeDifferent();
  1777. {
  1778. Msg( "Comparing and copying == objects, should have zero diffcount\n" );
  1779. CPredictionCopy tester( PC_NON_NETWORKED_ONLY, foo1, false, foo3, false, true );
  1780. int diff_count = 0;
  1781. diff_count = tester.TransferData( foo3->GetPredDescMap(), foo1->GetPredDescMap()->dataDesc, foo1->GetPredDescMap()->dataNumFields );
  1782. Msg( "diff_count == %i\n", diff_count );
  1783. Assert( !diff_count );
  1784. }
  1785. {
  1786. Msg( "Simple compare of != objects, should spew and have non-zero diffcount\n" );
  1787. CPredictionCopy tester( PC_NON_NETWORKED_ONLY, foo1, false, foo2, false, true, false );
  1788. int diff_count = 0;
  1789. diff_count = tester.TransferData( foo2->GetPredDescMap(), foo1->GetPredDescMap()->dataDesc, foo1->GetPredDescMap()->dataNumFields );
  1790. Msg( "diff_count == %i (should be 12)\n", diff_count );
  1791. Assert( diff_count == 12 );
  1792. }
  1793. {
  1794. Msg( "Comparing and coyping same != objects, should spew and have non-zero diffcount\n" );
  1795. CPredictionCopy tester( PC_NON_NETWORKED_ONLY, foo1, false, foo2, false, true );
  1796. int diff_count = 0;
  1797. diff_count = tester.TransferData( foo2->GetPredDescMap(), foo1->GetPredDescMap()->dataDesc, foo1->GetPredDescMap()->dataNumFields );
  1798. Msg( "diff_count == %i (should be 12)\n", diff_count );
  1799. Assert( diff_count == 12 );
  1800. }
  1801. {
  1802. Msg( "Comparing and copying objects which were just made to coincide, should have zero diffcount\n" );
  1803. CPredictionCopy tester( PC_NON_NETWORKED_ONLY, foo1, false, foo2, false, true );
  1804. int diff_count = 0;
  1805. diff_count = tester.TransferData( foo2->GetPredDescMap(), foo1->GetPredDescMap()->dataDesc, foo1->GetPredDescMap()->dataNumFields );
  1806. Msg( "diff_count == %i\n", diff_count );
  1807. Assert( !diff_count );
  1808. }
  1809. {
  1810. CPredictionDescribeData describe( foo1, false );
  1811. describe.DumpDescription( foo1->GetPredDescMap(), foo1->GetPredDescMap()->dataDesc, foo1->GetPredDescMap()->dataNumFields );
  1812. }
  1813. delete foo3;
  1814. delete foo2;
  1815. delete foo1;
  1816. }
  1817. #endif // CLIENT_DLL
  1818. #endif // !NO_ENTITY_PREDICTION )