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.

1044 lines
29 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // ---------------------------------------------------------------------------------------- //
  9. // This is a datatable test case.
  10. // It is run in debug mode when the engine starts to catch any bugs in datatable code.
  11. // This can also serve as a simple example of how datatables work separately from the
  12. // intricacies of the entity system.
  13. // ---------------------------------------------------------------------------------------- //
  14. // This is also a good place to test new code since it's run right when the engine
  15. // starts up. It can also be put into standalone apps easily.
  16. // ---------------------------------------------------------------------------------------- //
  17. // Things it tests:
  18. // - Data transmission integrity.
  19. // - Delta calculation.
  20. // - Strings, floats, vectors, recursive datatables, and ints.
  21. // - Fixed-length arrays.
  22. // - Variable-length arrays.
  23. // - Exclude props.
  24. // - Recursive datatables.
  25. // - Datatable proxies returning false.
  26. // - CUtlVectors of regular types (like floats) and data tables.
  27. // ---------------------------------------------------------------------------------------- //
  28. // Things it does not test:
  29. // - Quantization.
  30. // - Clamping.
  31. // - The entity system's usage of data tables.
  32. // - Stress testing - too many properties, maxing out delta bits.
  33. // - Built-in and custom client and server proxies.
  34. // ---------------------------------------------------------------------------------------- //
  35. // At a high level, the test is setup as such:
  36. // - Server structure and datatable.
  37. // - Client structure and datatable.
  38. // - A function table with a function to modify and compare each element.
  39. // - A function that initializes the server structure and tries random changes to it and
  40. // verifies that the client receives the deltas and changes correctly.
  41. // ---------------------------------------------------------------------------------------- //
  42. // Eventually it would be nice to stress-test the entities with tests for:
  43. // - Misordered proxy callbacks and missing data.
  44. // ---------------------------------------------------------------------------------------- //
  45. #include "quakedef.h"
  46. #include "dt.h"
  47. #include "dt_send.h"
  48. #include "dt_recv.h"
  49. #include "tier0/dbg.h"
  50. #include "dt_utlvector_send.h"
  51. #include "dt_utlvector_recv.h"
  52. #include "vstdlib/random.h"
  53. #include "ents_shared.h"
  54. #include "netmessages.h"
  55. // memdbgon must be the last include file in a .cpp file!!!
  56. #include "tier0/memdbgon.h"
  57. // If datatables support these again, then uncomment this to have them tested.
  58. //#define SUPPORT_ARRAYS_OF_DATATABLES
  59. #ifdef _DEBUG
  60. class DTTestSub2Sub
  61. {
  62. public:
  63. int m_Int2;
  64. };
  65. class DTTestSub2
  66. {
  67. public:
  68. int m_Int;
  69. DTTestSub2Sub m_Sub;
  70. };
  71. class CTestStruct
  72. {
  73. public:
  74. int a,b;
  75. float f;
  76. };
  77. #define MAX_STRUCTARRAY_ELEMENTS 11
  78. #define MAX_FLOATARRAY_ELEMENTS 18
  79. #define MAX_CHARARRAY_ELEMENTS 22
  80. // ------------------------------------------------------------------------------------------- //
  81. // DTTestServerSub and its DataTable.
  82. // ------------------------------------------------------------------------------------------- //
  83. class DTTestServerSub
  84. {
  85. public:
  86. float m_FloatArray[3];
  87. char m_Strings[2][64];
  88. CUtlVector<CTestStruct> m_UtlVectorStruct;
  89. CUtlVector<float> m_UtlVectorFloat;
  90. CUtlVector<char> m_UtlVectorChar;
  91. };
  92. void SendProxy_DTTestServerSubString( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
  93. {
  94. SendProxy_StringToString( pProp, pStruct, pData, pOut, iElement, objectID);
  95. }
  96. BEGIN_SEND_TABLE_NOBASE( CTestStruct, DT_TestStruct )
  97. SendPropInt( SENDINFO_NOCHECK( a ) ),
  98. SendPropInt( SENDINFO_NOCHECK( b ) ),
  99. SendPropFloat( SENDINFO_NOCHECK( f ) )
  100. END_SEND_TABLE()
  101. BEGIN_SEND_TABLE_NOBASE(DTTestServerSub, DT_DTTestSub)
  102. // - Auto type conversions (receiving an array of floats into an array of ints).
  103. SendPropArray(
  104. SendPropFloat(SENDINFO_NOCHECK(m_FloatArray[0]), 0, SPROP_NOSCALE),
  105. m_FloatArray),
  106. SendPropUtlVectorDataTable( m_UtlVectorStruct, MAX_STRUCTARRAY_ELEMENTS, DT_TestStruct ),
  107. SendPropArray(
  108. SendPropString(SENDINFO_NOCHECK(m_Strings[0]), 0, SendProxy_DTTestServerSubString),
  109. m_Strings ),
  110. SendPropUtlVector(
  111. SENDINFO_UTLVECTOR( m_UtlVectorChar ),
  112. MAX_CHARARRAY_ELEMENTS,
  113. SendPropInt( NULL, 0, sizeof( char ), 0 ) ),
  114. SendPropUtlVector(
  115. SENDINFO_UTLVECTOR( m_UtlVectorFloat ),
  116. MAX_FLOATARRAY_ELEMENTS, // max elements
  117. SendPropFloat( NULL, 0, 0, 0, SPROP_NOSCALE ) )
  118. END_SEND_TABLE()
  119. BEGIN_SEND_TABLE_NOBASE(DTTestSub2Sub, DT_DTTestSub2Sub)
  120. SendPropInt( SENDINFO_NOCHECK( m_Int2 ), 32 ),
  121. END_SEND_TABLE()
  122. BEGIN_SEND_TABLE_NOBASE(DTTestSub2, DT_DTTestSub2)
  123. SendPropDataTable(SENDINFO_DT(m_Sub), &REFERENCE_SEND_TABLE(DT_DTTestSub2Sub)),
  124. SendPropInt( SENDINFO_NOCHECK( m_Int ), 32 ),
  125. END_SEND_TABLE()
  126. // ------------------------------------------------------------------------------------------- //
  127. // DTTestServer and its DataTable.
  128. // ------------------------------------------------------------------------------------------- //
  129. class DTTestServer
  130. {
  131. public:
  132. DTTestServerSub m_Sub;
  133. DTTestSub2 m_Sub2;
  134. float m_Float;
  135. #if defined( SUPPORT_ARRAYS_OF_DATATABLES )
  136. DTTestServerSub m_SubArray[2];
  137. #endif
  138. Vector m_Vector;
  139. char m_String[64];
  140. int m_Int;
  141. int m_IntArray[32]; // Note that the server and client array length are different.
  142. char m_CharArray[8];
  143. int m_VLALength;
  144. int m_VLA[16];
  145. };
  146. void SendProxy_DTTestServerFloat( const SendProp *pProp, void *pStruct, void *pData, DVariant *pOut, int iElement, int objectID )
  147. {
  148. SendProxy_FloatToFloat(pProp, pStruct, pData, pOut, iElement, objectID);
  149. }
  150. void SendProxy_DTTestServerVector( const SendProp *pProp, void *pStruct, void *pData, DVariant *pOut, int iElement, int objectID )
  151. {
  152. SendProxy_VectorToVector(pProp, pStruct, pData, pOut, iElement, objectID);
  153. }
  154. void SendProxy_DTTestServerString( const SendProp *pProp, void *pStruct, void *pData, DVariant *pOut, int iElement, int objectID )
  155. {
  156. SendProxy_StringToString(pProp, pStruct, pData, pOut, iElement, objectID);
  157. }
  158. void SendProxy_DTTestServerInt( const SendProp *pProp, void *pStruct, void *pData, DVariant *pOut, int iElement, int objectID )
  159. {
  160. SendProxy_Int32ToInt32(pProp, pStruct, pData, pOut, iElement, objectID);
  161. }
  162. bool g_bSendSub = true;
  163. void* SendProxy_DTTestServerSub( const SendProp *pProp, const void *pStruct, const void *pData, CSendProxyRecipients *pRecipients, int objectID )
  164. {
  165. if( !g_bSendSub )
  166. return NULL;
  167. return SendProxy_DataTableToDataTable( pProp, pStruct, pData, pRecipients, objectID );
  168. }
  169. REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( SendProxy_DTTestServerSub );
  170. int ArrayLengthSendProxy_VLALength( const void *pStruct, int objectID )
  171. {
  172. DTTestServer *pServer = (DTTestServer*)pStruct;
  173. return pServer->m_VLALength;
  174. }
  175. BEGIN_SEND_TABLE_NOBASE(DTTestServer, DT_DTTest)
  176. SendPropVariableLengthArray(
  177. ArrayLengthSendProxy_VLALength,
  178. SendPropInt( SENDINFO_NOCHECK( m_VLA[0] ) ),
  179. m_VLA ),
  180. // Test exclude props.
  181. SendPropExclude( "DT_DTTest", "m_Int" ),
  182. SendPropDataTable(SENDINFO_DT(m_Sub), &REFERENCE_SEND_TABLE(DT_DTTestSub), SendProxy_DTTestServerSub),
  183. SendPropFloat (SENDINFO_NOCHECK(m_Float), 32, SPROP_NOSCALE),
  184. SendPropDataTable(SENDINFO_DT(m_Sub2), &REFERENCE_SEND_TABLE(DT_DTTestSub2)),
  185. SendPropInt (SENDINFO_NOCHECK(m_Int), 23, SPROP_UNSIGNED),
  186. SendPropExclude( "DT_DTTestSub", "m_FloatArray" ),
  187. SendPropString(SENDINFO_NOCHECK(m_String)),
  188. SendPropArray(
  189. SendPropInt(SENDINFO_NOCHECK(m_CharArray[0]), 8),
  190. m_CharArray),
  191. SendPropArray(
  192. SendPropInt (SENDINFO_NOCHECK(m_IntArray[0]), 23, SPROP_UNSIGNED),
  193. m_IntArray),
  194. #if defined( SUPPORT_ARRAYS_OF_DATATABLES )
  195. SendPropArray(
  196. SendPropDataTable(SENDINFO_DT(m_SubArray[0]), &REFERENCE_SEND_TABLE(DT_DTTestSub), SendProxy_DTTestServerSub),
  197. m_SubArray ),
  198. #endif
  199. SendPropVector(SENDINFO_NOCHECK(m_Vector), 32, SPROP_NOSCALE)
  200. END_SEND_TABLE()
  201. // ------------------------------------------------------------------------------------------- //
  202. // DTTestClientSub and its DataTable.
  203. // ------------------------------------------------------------------------------------------- //
  204. class DTTestClientSub
  205. {
  206. public:
  207. char m_Strings[2][64];
  208. float m_FloatArray[3];
  209. CUtlVector<CTestStruct> m_UtlVectorStruct;
  210. CUtlVector<float> m_UtlVectorFloat;
  211. CUtlVector<char> m_UtlVectorChar;
  212. };
  213. void RecvProxy_DTTestClientSubString( const CRecvProxyData *pData, void *pStruct, void *pOut )
  214. {
  215. RecvProxy_StringToString( pData, pStruct, pOut );
  216. }
  217. BEGIN_RECV_TABLE_NOBASE( CTestStruct, DT_TestStruct )
  218. RecvPropInt( RECVINFO( a ) ),
  219. RecvPropInt( RECVINFO( b ) ),
  220. RecvPropFloat( RECVINFO( f ) ),
  221. END_RECV_TABLE()
  222. BEGIN_RECV_TABLE_NOBASE(DTTestClientSub, DT_DTTestSub)
  223. // - Auto type conversions (receiving an array of floats into an array of ints).
  224. RecvPropArray(
  225. RecvPropFloat(RECVINFO(m_FloatArray[0])),
  226. m_FloatArray),
  227. RecvPropUtlVector( RECVINFO_UTLVECTOR( m_UtlVectorFloat ), MAX_FLOATARRAY_ELEMENTS, RecvPropFloat(NULL,0,0) ),
  228. RecvPropUtlVectorDataTable( m_UtlVectorStruct, MAX_STRUCTARRAY_ELEMENTS, DT_TestStruct ),
  229. RecvPropUtlVector(
  230. RECVINFO_UTLVECTOR( m_UtlVectorChar ),
  231. MAX_CHARARRAY_ELEMENTS,
  232. RecvPropInt( NULL, 0, sizeof( char ) ) ),
  233. RecvPropArray(
  234. RecvPropString(RECVINFO(m_Strings[0]), 0, RecvProxy_DTTestClientSubString),
  235. m_Strings),
  236. END_RECV_TABLE()
  237. BEGIN_RECV_TABLE_NOBASE(DTTestSub2Sub, DT_DTTestSub2Sub)
  238. RecvPropInt( RECVINFO( m_Int2 ), 32 ),
  239. END_RECV_TABLE()
  240. BEGIN_RECV_TABLE_NOBASE(DTTestSub2, DT_DTTestSub2)
  241. RecvPropDataTable(RECVINFO_DT(m_Sub), 0, &REFERENCE_RECV_TABLE(DT_DTTestSub2Sub)),
  242. RecvPropInt( RECVINFO( m_Int ) ),
  243. END_RECV_TABLE()
  244. // ------------------------------------------------------------------------------------------- //
  245. // DTTestClient and DataTable.
  246. // ------------------------------------------------------------------------------------------- //
  247. class DTTestClient
  248. {
  249. public:
  250. DTTestClientSub m_Sub;
  251. long m_Guard1;
  252. DTTestSub2 m_Sub2;
  253. long m_Guard2;
  254. #if defined( SUPPORT_ARRAYS_OF_DATATABLES )
  255. DTTestClientSub m_SubArray[2];
  256. #endif
  257. long m_Guard3;
  258. float m_Float;
  259. long m_Guard4;
  260. Vector m_Vector;
  261. long m_Guard5;
  262. char m_String[64];
  263. long m_Guard6;
  264. int m_Int;
  265. long m_Guard7;
  266. int m_IntArray[32]; // Note that the server and client array length are different.
  267. long m_Guard8;
  268. char m_CharArray[8];
  269. long m_Guard9;
  270. int m_VLALength;
  271. int m_VLA[16];
  272. };
  273. void RecvProxyArrayLength_VLA( void *pStruct, int objectID, int currentArrayLength )
  274. {
  275. DTTestClient *pClient = (DTTestClient*)pStruct;
  276. pClient->m_VLALength = currentArrayLength;
  277. }
  278. BEGIN_RECV_TABLE_NOBASE(DTTestClient, DT_DTTest)
  279. #if defined( SUPPORT_ARRAYS_OF_DATATABLES )
  280. RecvPropArray(
  281. RecvPropDataTable(RECVINFO_DT(m_SubArray[0]), 0, &REFERENCE_RECV_TABLE(DT_DTTestSub), RecvProxy_DTTestClientSub),
  282. m_SubArray ),
  283. #endif
  284. RecvPropFloat (RECVINFO(m_Float), 0),
  285. RecvPropDataTable(RECVINFO_DT(m_Sub), 0, &REFERENCE_RECV_TABLE(DT_DTTestSub)),
  286. RecvPropDataTable(RECVINFO_DT(m_Sub2), 0, &REFERENCE_RECV_TABLE(DT_DTTestSub2)),
  287. // - Arrays with and without the SPROP_ONEBITDELTA flag.
  288. RecvPropArray(
  289. RecvPropInt (RECVINFO(m_CharArray[0]), 8),
  290. m_CharArray),
  291. RecvPropVector(RECVINFO(m_Vector), 0),
  292. RecvPropString(RECVINFO_STRING(m_String), 0),
  293. RecvPropInt (RECVINFO(m_Int), 0),
  294. // - Arrays with and without the SPROP_ONEBITDELTA flag.
  295. // - Array size mismatches between the client and the server.
  296. RecvPropArray(
  297. RecvPropInt (RECVINFO(m_IntArray[0]), 0),
  298. m_IntArray),
  299. RecvPropInt( RECVINFO( m_VLALength ) ),
  300. RecvPropVariableLengthArray(
  301. RecvProxyArrayLength_VLA,
  302. RecvPropInt( RECVINFO( m_VLA[0] ) ),
  303. m_VLA )
  304. END_RECV_TABLE()
  305. // ------------------------------------------------------------------------------------------- //
  306. // Functions that act on the data.
  307. // ------------------------------------------------------------------------------------------- //
  308. typedef bool (*CompareElementFn)(DTTestClient *pClient, DTTestServer *pServer);
  309. typedef void (*RandomlyChangeElementFn)(DTTestServer *pServer);
  310. float FRand(double minVal, double maxVal)
  311. {
  312. return (float)(((double)rand() / VALVE_RAND_MAX) * (maxVal - minVal) + minVal);
  313. }
  314. void RandomlyChangeStringGeneric(char *str, int size)
  315. {
  316. for(int i=0; i < size-1; i++)
  317. str[i] = (char)rand();
  318. str[size-1] = 0;
  319. }
  320. bool CompareTestSubString0(DTTestClient *pClient, DTTestServer *pServer)
  321. {
  322. return strcmp(pClient->m_Sub.m_Strings[0], pServer->m_Sub.m_Strings[0]) == 0;
  323. }
  324. void RandomlyChangeSubString0(DTTestServer *pServer)
  325. {
  326. if( g_bSendSub )
  327. RandomlyChangeStringGeneric(pServer->m_Sub.m_Strings[0], sizeof(pServer->m_Sub.m_Strings[0]));
  328. }
  329. bool CompareTestSubString1(DTTestClient *pClient, DTTestServer *pServer)
  330. {
  331. return strcmp(pClient->m_Sub.m_Strings[1], pServer->m_Sub.m_Strings[1]) == 0;
  332. }
  333. void RandomlyChangeSubString1(DTTestServer *pServer)
  334. {
  335. if( g_bSendSub )
  336. RandomlyChangeStringGeneric(pServer->m_Sub.m_Strings[1], sizeof(pServer->m_Sub.m_Strings[1]));
  337. }
  338. bool CompareFloat(DTTestClient *pClient, DTTestServer *pServer)
  339. {
  340. return pClient->m_Float == pServer->m_Float;
  341. }
  342. void RandomlyChangeFloat(DTTestServer *pServer)
  343. {
  344. pServer->m_Float = FRand(-500000, 500000);
  345. }
  346. bool CompareVector(DTTestClient *pClient, DTTestServer *pServer)
  347. {
  348. return pClient->m_Vector.x == pServer->m_Vector.x &&
  349. pClient->m_Vector.y == pServer->m_Vector.y &&
  350. pClient->m_Vector.z == pServer->m_Vector.z;
  351. }
  352. void RandomlyChangeVector(DTTestServer *pServer)
  353. {
  354. pServer->m_Vector.x = FRand(-500000, 500000);
  355. pServer->m_Vector.y = FRand(-500000, 500000);
  356. pServer->m_Vector.z = FRand(-500000, 500000);
  357. }
  358. bool CompareString(DTTestClient *pClient, DTTestServer *pServer)
  359. {
  360. return strcmp(pClient->m_String, pServer->m_String) == 0;
  361. }
  362. void RandomlyChangeString(DTTestServer *pServer)
  363. {
  364. //memset( pServer->m_String, , sizeof( pServer->m_String ) );
  365. Q_strncpy( pServer->m_String, "a", sizeof( pServer->m_String ) );
  366. //RandomlyChangeStringGeneric(pServer->m_String, sizeof(pServer->m_String));
  367. }
  368. bool CompareInt(DTTestClient *pClient, DTTestServer *pServer)
  369. {
  370. // (m_Int is the exclude prop we're testing)
  371. // return pClient->m_Int == pServer->m_Int;
  372. return true;
  373. }
  374. void RandomlyChangeInt(DTTestServer *pServer)
  375. {
  376. pServer->m_Int = (int)rand();
  377. }
  378. bool CompareIntArray(DTTestClient *pClient, DTTestServer *pServer)
  379. {
  380. // Just verify however much of the data we can.
  381. int leastElements = (sizeof(pClient->m_IntArray) < sizeof(pServer->m_IntArray)) ? (sizeof(pClient->m_IntArray)/sizeof(pClient->m_IntArray[0])) : (sizeof(pServer->m_IntArray)/sizeof(pServer->m_IntArray[0]));
  382. return memcmp(pClient->m_IntArray, pServer->m_IntArray, leastElements*sizeof(int)) == 0;
  383. }
  384. void RandomlyChangeIntArray(DTTestServer *pServer)
  385. {
  386. // Change a random subset of the array.
  387. int nElements = sizeof(pServer->m_IntArray) / sizeof(pServer->m_IntArray[0]);
  388. int nChanges = 4 + rand() % nElements;
  389. for(int i=0; i < nChanges; i++)
  390. {
  391. pServer->m_IntArray[rand() % nElements] = (int)rand();
  392. }
  393. }
  394. bool CompareFloatArray(DTTestClient *pClient, DTTestServer *pServer)
  395. {
  396. // m_FloatArray is an ExcludeProp.
  397. /*
  398. int leastElements = (sizeof(pClient->m_Sub.m_FloatArray) < sizeof(pServer->m_Sub.m_FloatArray)) ? (sizeof(pClient->m_Sub.m_FloatArray)/sizeof(pClient->m_Sub.m_FloatArray[0])) : (sizeof(pServer->m_Sub.m_FloatArray)/sizeof(pServer->m_Sub.m_FloatArray[0]));
  399. for(int i=0; i < leastElements; i++)
  400. {
  401. if(pClient->m_Sub.m_FloatArray[i] != pServer->m_Sub.m_FloatArray[i])
  402. return false;
  403. }
  404. */
  405. return true;
  406. }
  407. void RandomlyChangeFloatArray(DTTestServer *pServer)
  408. {
  409. // Change a random subset of the array.
  410. int nElements = sizeof(pServer->m_Sub.m_FloatArray) / sizeof(pServer->m_Sub.m_FloatArray[0]);
  411. int nChanges = 4 + rand() % nElements;
  412. for(int i=0; i < nChanges; i++)
  413. {
  414. pServer->m_Sub.m_FloatArray[rand() % nElements] = (float)rand() * 0.943123f;
  415. }
  416. }
  417. bool CompareCharArray(DTTestClient *pClient, DTTestServer *pServer)
  418. {
  419. return memcmp(pClient->m_CharArray, pServer->m_CharArray, sizeof(pClient->m_CharArray)) == 0;
  420. }
  421. void RandomlyChangeCharArray(DTTestServer *pServer)
  422. {
  423. for(int i=0; i < (sizeof(pServer->m_CharArray) / sizeof(pServer->m_CharArray[0])); i++)
  424. pServer->m_CharArray[i] = (char)rand();
  425. }
  426. bool CompareSubArray(DTTestClient *pClient, DTTestServer *pServer )
  427. {
  428. #if defined( SUPPORT_ARRAYS_OF_DATATABLES )
  429. for( int i=0; i < 2; i++ )
  430. {
  431. for( int z=0; z < sizeof(pServer->m_SubArray[0].m_FloatArray) / sizeof(pServer->m_SubArray[0].m_FloatArray[0]); z++ )
  432. {
  433. if( pServer->m_SubArray[i].m_FloatArray[z] != pClient->m_SubArray[i].m_FloatArray[z] )
  434. return false;
  435. }
  436. for( int iString=0; iString < sizeof(pServer->m_SubArray[0].m_Strings) / sizeof(pServer->m_SubArray[0].m_Strings[0]); iString++ )
  437. {
  438. for( z=0; z < sizeof(pServer->m_SubArray[0].m_Strings[0]) / sizeof(pServer->m_SubArray[0].m_Strings[0][0]); z++ )
  439. {
  440. if( pServer->m_SubArray[i].m_Strings[iString][z] != pClient->m_SubArray[i].m_Strings[iString][z] )
  441. return false;
  442. // Check for null termination.
  443. if( pServer->m_SubArray[i].m_Strings[iString][z] == 0 )
  444. break;
  445. }
  446. }
  447. }
  448. #endif
  449. return true;
  450. }
  451. void RandomlyChangeSubArray(DTTestServer *pServer)
  452. {
  453. #if defined( SUPPORT_ARRAYS_OF_DATATABLES )
  454. if( !g_bSendSub )
  455. return;
  456. for( int i=0; i < 2; i++ )
  457. {
  458. int index = rand() & 1;
  459. for( int z=0; z < sizeof(pServer->m_SubArray[0].m_FloatArray) / sizeof(pServer->m_SubArray[0].m_FloatArray[0]); z++ )
  460. pServer->m_SubArray[index].m_FloatArray[z] = rand() * 0.932f;
  461. for( int iString=0; iString < sizeof(pServer->m_SubArray[0].m_Strings) / sizeof(pServer->m_SubArray[0].m_Strings[0]); iString++ )
  462. {
  463. int stringLen = sizeof(pServer->m_SubArray[0].m_Strings[0]) / sizeof(pServer->m_SubArray[0].m_Strings[0][0]);
  464. for( z=0; z < stringLen; z++ )
  465. pServer->m_SubArray[index].m_Strings[iString][z] = (char)rand();
  466. // null-terminate it
  467. pServer->m_SubArray[index].m_Strings[iString][stringLen-1] = 0;
  468. }
  469. }
  470. #endif
  471. }
  472. bool CompareSub2( DTTestClient *pClient, DTTestServer *pServer )
  473. {
  474. return memcmp( &pClient->m_Sub2, &pServer->m_Sub2, sizeof( pClient->m_Sub2 ) ) == 0;
  475. }
  476. void RandomlyChangeSub2( DTTestServer *pServer )
  477. {
  478. pServer->m_Sub2.m_Int = rand();
  479. }
  480. bool CompareSub2Sub( DTTestClient *pClient, DTTestServer *pServer )
  481. {
  482. return pClient->m_Sub2.m_Sub.m_Int2 == pServer->m_Sub2.m_Sub.m_Int2;
  483. }
  484. void RandomlyChangeSub2Sub( DTTestServer *pServer )
  485. {
  486. pServer->m_Sub2.m_Sub.m_Int2 = rand();
  487. }
  488. bool CompareVLA( DTTestClient *pClient, DTTestServer *pServer )
  489. {
  490. if ( pClient->m_VLALength != pServer->m_VLALength )
  491. return false;
  492. for ( int i=0; i < pClient->m_VLALength; i++ )
  493. {
  494. if ( pClient->m_VLA[i] != pServer->m_VLA[i] )
  495. return false;
  496. }
  497. return true;
  498. }
  499. void RandomlyChangeVLA( DTTestServer *pServer )
  500. {
  501. pServer->m_VLALength = rand() % ARRAYSIZE( pServer->m_VLA );
  502. for ( int i=0; i < pServer->m_VLALength; i++ )
  503. pServer->m_VLA[i] = rand() * rand();
  504. }
  505. bool CompareUtlVectorStruct( DTTestClient *pClient, DTTestServer *pServer )
  506. {
  507. CUtlVector<CTestStruct> &c = pClient->m_Sub.m_UtlVectorStruct;
  508. CUtlVector<CTestStruct> &s = pServer->m_Sub.m_UtlVectorStruct;
  509. if ( c.Count() != s.Count() )
  510. return false;
  511. for ( int i=0; i < c.Count(); i++ )
  512. {
  513. if ( c[i].a != s[i].a || c[i].b != s[i].b || c[i].f != s[i].f )
  514. return false;
  515. }
  516. return true;
  517. }
  518. void RandomlyChangeUtlVectorStruct( DTTestServer *pServer )
  519. {
  520. if ( !g_bSendSub )
  521. return;
  522. int nElements = rand() % MAX_STRUCTARRAY_ELEMENTS;
  523. pServer->m_Sub.m_UtlVectorStruct.SetSize( nElements );
  524. for ( int i=0; i < nElements; i++ )
  525. {
  526. pServer->m_Sub.m_UtlVectorStruct[i].a = rand();
  527. pServer->m_Sub.m_UtlVectorStruct[i].b = rand();
  528. pServer->m_Sub.m_UtlVectorStruct[i].f = rand();
  529. }
  530. }
  531. bool CompareUtlVectorFloat( DTTestClient *pClient, DTTestServer *pServer )
  532. {
  533. CUtlVector<float> &c = pClient->m_Sub.m_UtlVectorFloat;
  534. CUtlVector<float> &s = pServer->m_Sub.m_UtlVectorFloat;
  535. if ( c.Count() != s.Count() )
  536. return false;
  537. for ( int i=0; i < c.Count(); i++ )
  538. {
  539. if ( c[i] != s[i] )
  540. return false;
  541. }
  542. return true;
  543. }
  544. void RandomlyChangeUtlVectorChar( DTTestServer *pServer )
  545. {
  546. if ( !g_bSendSub )
  547. return;
  548. int nElements = rand() % MAX_CHARARRAY_ELEMENTS;
  549. pServer->m_Sub.m_UtlVectorChar.SetSize( nElements );
  550. for ( int i=0; i < nElements; i++ )
  551. pServer->m_Sub.m_UtlVectorChar[i] = (char)rand();
  552. }
  553. bool CompareUtlVectorChar( DTTestClient *pClient, DTTestServer *pServer )
  554. {
  555. CUtlVector<char> &c = pClient->m_Sub.m_UtlVectorChar;
  556. CUtlVector<char> &s = pServer->m_Sub.m_UtlVectorChar;
  557. if ( c.Count() != s.Count() )
  558. return false;
  559. for ( int i=0; i < c.Count(); i++ )
  560. {
  561. if ( c[i] != s[i] )
  562. return false;
  563. }
  564. return true;
  565. }
  566. void RandomlyChangeUtlVectorFloat( DTTestServer *pServer )
  567. {
  568. if ( !g_bSendSub )
  569. return;
  570. int nElements = rand() % MAX_FLOATARRAY_ELEMENTS;
  571. pServer->m_Sub.m_UtlVectorFloat.SetSize( nElements );
  572. for ( int i=0; i < nElements; i++ )
  573. pServer->m_Sub.m_UtlVectorFloat[i] = rand() / 0.93;
  574. }
  575. typedef struct
  576. {
  577. CompareElementFn m_CompareFn;
  578. RandomlyChangeElementFn m_ChangeFn;
  579. } VarTestInfo;
  580. VarTestInfo g_VarTestInfos[] =
  581. {
  582. {CompareVLA, RandomlyChangeVLA},
  583. {CompareUtlVectorStruct,RandomlyChangeUtlVectorStruct},
  584. {CompareUtlVectorFloat, RandomlyChangeUtlVectorFloat},
  585. {CompareUtlVectorChar, RandomlyChangeUtlVectorChar},
  586. {CompareFloat, RandomlyChangeFloat},
  587. {CompareSub2, RandomlyChangeSub2},
  588. {CompareSub2Sub, RandomlyChangeSub2Sub},
  589. {CompareInt, RandomlyChangeInt},
  590. {CompareFloatArray, RandomlyChangeFloatArray},
  591. {CompareTestSubString0, RandomlyChangeSubString0},
  592. {CompareTestSubString1, RandomlyChangeSubString1},
  593. {CompareCharArray, RandomlyChangeCharArray},
  594. {CompareVector, RandomlyChangeVector},
  595. {CompareString, RandomlyChangeString},
  596. {CompareIntArray, RandomlyChangeIntArray},
  597. {CompareSubArray, RandomlyChangeSubArray}
  598. };
  599. #define NUMVARTESTINFOS (sizeof(g_VarTestInfos) / sizeof(g_VarTestInfos[0]))
  600. int g_GuardOffsets[] =
  601. {
  602. offsetof( DTTestClient, m_Guard1 ),
  603. offsetof( DTTestClient, m_Guard2 ),
  604. offsetof( DTTestClient, m_Guard3 ),
  605. offsetof( DTTestClient, m_Guard4 ),
  606. offsetof( DTTestClient, m_Guard5 ),
  607. offsetof( DTTestClient, m_Guard6 ),
  608. offsetof( DTTestClient, m_Guard7 ),
  609. offsetof( DTTestClient, m_Guard8 ),
  610. offsetof( DTTestClient, m_Guard9 )
  611. };
  612. int g_nGuardOffsets = sizeof( g_GuardOffsets ) / sizeof( g_GuardOffsets[0] );
  613. void SetGuardBytes( DTTestClient *pClient )
  614. {
  615. for( int i=0; i < g_nGuardOffsets; i++ )
  616. {
  617. unsigned char *pDest = ((unsigned char *)pClient) + g_GuardOffsets[i];
  618. *((long*)pDest) = i;
  619. }
  620. }
  621. void CheckGuardBytes( DTTestClient *pClient )
  622. {
  623. for( int i=0; i < g_nGuardOffsets; i++ )
  624. {
  625. unsigned char *pDest = ((unsigned char *)pClient) + g_GuardOffsets[i];
  626. Assert( *((long*)pDest) == i );
  627. }
  628. }
  629. // ------------------------------------------------------------------------------------------- //
  630. // TEST CODE
  631. // ------------------------------------------------------------------------------------------- //
  632. bool CompareDTTest(DTTestClient *pClient, DTTestServer *pServer)
  633. {
  634. for(int iVar=0; iVar < NUMVARTESTINFOS; iVar++)
  635. {
  636. if(!g_VarTestInfos[iVar].m_CompareFn(pClient, pServer))
  637. {
  638. Assert( !"CompareDTTest: comparison failed. There is a new datatable bug." );
  639. return false;
  640. }
  641. }
  642. return true;
  643. }
  644. bool WriteSendTable_R( SendTable *pTable, bf_write &bfWrite, bool bNeedsDecoder )
  645. {
  646. if( pTable->GetWriteFlag() )
  647. return true;
  648. pTable->SetWriteFlag( true );
  649. if( !SendTable_WriteInfos( pTable, bfWrite, bNeedsDecoder, false ) )
  650. return false;
  651. for( int i=0; i < pTable->m_nProps; i++ )
  652. {
  653. SendProp *pProp = &pTable->m_pProps[i];
  654. if( pProp->m_Type == DPT_DataTable )
  655. if( !WriteSendTable_R( pProp->GetDataTable(), bfWrite, false ) )
  656. return false;
  657. }
  658. return true;
  659. }
  660. void TestDeltaBitEncoders()
  661. {
  662. ALIGN4 char tempData[8192] ALIGN4_POST;
  663. bf_write bfw( "", tempData, sizeof( tempData ) );
  664. int nSamples = 500;
  665. CUtlVector<int> written;
  666. written.SetSize( nSamples );
  667. RandomSeed( 4 );
  668. {
  669. CDeltaBitsWriter deltaw( &bfw );
  670. int nProp = 1;
  671. for ( int i=0; i < nSamples; i++ )
  672. {
  673. nProp += RandomInt( 1, 5 );
  674. deltaw.WritePropIndex( nProp );
  675. written[i] = nProp;
  676. }
  677. }
  678. bf_read bfr( tempData, sizeof( tempData ) );
  679. CDeltaBitsReader deltar( &bfr );
  680. int nCurProp = 0;
  681. while ( 1 )
  682. {
  683. int nTestIndex = deltar.ReadNextPropIndex();
  684. if ( nTestIndex == -1 )
  685. {
  686. Assert( nCurProp == nSamples );
  687. break;
  688. }
  689. else
  690. {
  691. Assert( nTestIndex == written[nCurProp++] );
  692. }
  693. }
  694. Assert( nCurProp == nSamples );
  695. }
  696. void RunDataTableTest()
  697. {
  698. TestDeltaBitEncoders();
  699. RecvTable *pRecvTable = &REFERENCE_RECV_TABLE(DT_DTTest);
  700. SendTable *pSendTable = &REFERENCE_SEND_TABLE(DT_DTTest);
  701. // Initialize the send and receive modules.
  702. SendTable_Init( &pSendTable, 1 );
  703. RecvTable_Init( &pRecvTable, 1 );
  704. pSendTable->SetWriteFlag( false );
  705. // Send DataTable info to the client.
  706. ALIGN4 unsigned char commBuf[8192] ALIGN4_POST;
  707. bf_write bfWrite( "RunDataTableTest->commBuf", commBuf, sizeof(commBuf) );
  708. if( !WriteSendTable_R( pSendTable, bfWrite, true ) )
  709. {
  710. Assert( !"RunDataTableTest: SendTable_SendInfo failed." );
  711. }
  712. // Signal no more send tables.
  713. SendTable_WriteInfos( NULL, bfWrite, false, true );
  714. // Receive the SendTable's info.
  715. CSVCMsg_SendTable_t msg;
  716. bf_read bfRead( "RunDataTableTest->bfRead", commBuf, sizeof(commBuf));
  717. while ( 1 )
  718. {
  719. int type = bfRead.ReadVarInt32();
  720. if( !msg.ReadFromBuffer( bfRead ) )
  721. {
  722. Assert( !"RunDataTableTest: ReadFromBuffer failed." );
  723. break;
  724. }
  725. int msgType = msg.GetType();
  726. if ( type != msgType )
  727. {
  728. Assert( !"RunDataTableTest: ReadFromBuffer failed." );
  729. break;
  730. }
  731. if( msg.is_end() )
  732. break;
  733. if( !RecvTable_RecvClassInfos( msg ) )
  734. {
  735. Assert( !"RunDataTableTest: RecvTable_ReadInfos failed." );
  736. break;
  737. }
  738. }
  739. // Register our receive table.
  740. if( !RecvTable_CreateDecoders( NULL, false ) )
  741. {
  742. Assert(false);
  743. }
  744. // Setup the data with all zeros.
  745. DTTestServer dtServer;
  746. DTTestClient dtClient;
  747. ALIGN4 unsigned char prevEncoded[4096] ALIGN4_POST;
  748. ALIGN4 unsigned char fullEncoded[4096] ALIGN4_POST;
  749. memset(&dtServer, 0, sizeof(dtServer));
  750. memset(&dtClient, 0, sizeof(dtClient));
  751. memset(prevEncoded, 0, sizeof(prevEncoded));
  752. SetGuardBytes( &dtClient );
  753. SerializedEntityHandle_t startEntity = g_pSerializedEntities->AllocateSerializedEntity( __FILE__, __LINE__ );
  754. SerializedEntityHandle_t endEntity = g_pSerializedEntities->AllocateSerializedEntity( __FILE__, __LINE__ );
  755. SerializedEntityHandle_t received = g_pSerializedEntities->AllocateSerializedEntity( __FILE__, __LINE__ );
  756. // Now loop around, changing the data a little bit each time and send/recv deltas.
  757. int nIterations = 25;
  758. for( int iIteration=0; iIteration < nIterations; iIteration++ )
  759. {
  760. // Change the server's data.
  761. g_bSendSub = true;
  762. if( (iIteration % 5) == 0 )
  763. {
  764. g_bSendSub = false; // every 8th time, don't send the subtable
  765. }
  766. if( (iIteration & 3) == 0 )
  767. {
  768. // Every once in a while, change ALL the properties.
  769. for( int iChange=0; iChange < NUMVARTESTINFOS; iChange++ )
  770. g_VarTestInfos[iChange].m_ChangeFn( &dtServer );
  771. }
  772. else
  773. {
  774. int nChanges = 3 + rand() % NUMVARTESTINFOS;
  775. for( int iChange=0; iChange < nChanges; iChange++ )
  776. {
  777. int iInfo = rand() % NUMVARTESTINFOS;
  778. g_VarTestInfos[iInfo].m_ChangeFn( &dtServer );
  779. }
  780. }
  781. if( !SendTable_Encode( pSendTable, startEntity, &dtServer, -1, NULL ) )
  782. {
  783. Assert(false);
  784. }
  785. // Fully encode it.
  786. bf_write bfFullEncoded( "RunDataTableTest->bfFullEncoded", fullEncoded, sizeof(fullEncoded) );
  787. SendTable_WritePropList( pSendTable, startEntity, &bfFullEncoded, -1, NULL );
  788. ALIGN4 unsigned char deltaEncoded[4096] ALIGN4_POST;
  789. bf_write bfDeltaEncoded( "RunDataTableTest->bfDeltaEncoded", deltaEncoded, sizeof(deltaEncoded) );
  790. if ( iIteration == 0 )
  791. {
  792. if( !SendTable_Encode( pSendTable, endEntity, &dtServer, -11111, NULL ) )
  793. {
  794. Assert(false);
  795. }
  796. SendTable_WritePropList( pSendTable, endEntity, &bfDeltaEncoded, -1111, NULL );
  797. }
  798. else
  799. {
  800. // Figure out the delta between the newly encoded one and the previously encoded one.
  801. CalcDeltaResultsList_t deltaProps;
  802. SendTable_CalcDelta( pSendTable, startEntity, endEntity, -1111, deltaProps );
  803. SendTable_WritePropList( pSendTable, endEntity, &bfDeltaEncoded, -1, &deltaProps );
  804. }
  805. memcpy( prevEncoded, fullEncoded, sizeof( prevEncoded ) );
  806. bf_read bfDecode( "RunDataTableTest->copyEncoded", prevEncoded, sizeof( prevEncoded ) );
  807. // This step isn't necessary to have the client decode the data but it's here to test
  808. // RecvTable_CopyEncoding (and RecvTable_MergeDeltas). This call should just make an exact
  809. // copy of the encoded data.
  810. if ( !RecvTable_ReadFieldList( pRecvTable, bfDecode, received, 1111, false ) )
  811. {
  812. Assert( false );
  813. }
  814. if ( !RecvTable_Decode( pRecvTable, &dtClient, received, 1111 ) )
  815. {
  816. Assert(false);
  817. }
  818. // Make sure it didn't go into memory it shouldn't have.
  819. CheckGuardBytes( &dtClient );
  820. // Verify that only the changed properties were sent and that they were received correctly.
  821. CompareDTTest( &dtClient, &dtServer );
  822. }
  823. g_pSerializedEntities->ReleaseSerializedEntity( received );
  824. g_pSerializedEntities->ReleaseSerializedEntity( endEntity );
  825. g_pSerializedEntities->ReleaseSerializedEntity( startEntity );
  826. SendTable_Term();
  827. RecvTable_Term();
  828. }
  829. #endif