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.

824 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #ifndef CS_GAMESTATS_SHARED_H
  7. #define CS_GAMESTATS_SHARED_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "cbase.h"
  12. // #include "tier1/utlvector.h"
  13. // #include "tier1/utldict.h"
  14. #include "shareddefs.h"
  15. #include "cs_shareddefs.h"
  16. #include "cs_weapon_parse.h"
  17. #include "fmtstr.h"
  18. #define CS_NUM_LEVELS 18
  19. //=============================================================================
  20. // Helper class for simple manipulation of bit arrays.
  21. // Used for server->client packets containing delta stats
  22. //=============================================================================
  23. template <int BitLength>
  24. class BitArray
  25. {
  26. enum { ByteLength = (BitLength + 7) / 8 };
  27. public:
  28. BitArray() { ClearAll(); }
  29. void SetBit(int n) { m_bytes[n / 8] |= 1 << (n & 7); }
  30. void ClearBit(int n) { m_bytes[n / 8] &= (~(1 << (n & 7))); }
  31. bool IsBitSet(int n) const { return (m_bytes[n / 8] & (1 << (n & 7))) != 0;}
  32. void ClearAll() { V_memset(m_bytes, 0, sizeof(m_bytes)); }
  33. int NumBits() { return BitLength; }
  34. int NumBytes() { return ByteLength; }
  35. byte* RawPointer() { return m_bytes; }
  36. private:
  37. byte m_bytes[ByteLength];
  38. };
  39. //=============================================================================
  40. //
  41. // CS Game Stats Enums
  42. //
  43. // WARNING! ANY CHANGE TO THE ORDERING OR NUMBER OF STATS WILL REQUIRE
  44. // SYNCHRONOUS UPDATE OF CLIENT AND SERVER DLLS. If you change these enums
  45. // (including adding new stats) without forcing an update of both the client
  46. // and server, stats will become corrupted on the game client and these
  47. // corrupted values will be uploaded to steam, which is very very bad.
  48. //
  49. // If you add new stats, if will be safest to add them at the end of the enum
  50. // (although this will still require a server update); make sure you also add
  51. // the stats to the CSStatProperty_Table in cs_gamestats_shared.cpp at the
  52. // appropriate location.
  53. enum CSStatType_t
  54. {
  55. CSSTAT_UNDEFINED = -1,
  56. CSSTAT_SHOTS_HIT,
  57. CSSTAT_SHOTS_FIRED,
  58. CSSTAT_KILLS,
  59. CSSTAT_DEATHS,
  60. CSSTAT_DAMAGE,
  61. CSSTAT_NUM_BOMBS_PLANTED,
  62. CSSTAT_NUM_BOMBS_DEFUSED,
  63. CSSTAT_PLAYTIME,
  64. CSSTAT_ROUNDS_WON,
  65. CSSTAT_T_ROUNDS_WON,
  66. CSSTAT_CT_ROUNDS_WON,
  67. CSSTAT_ROUNDS_PLAYED,
  68. CSSTAT_PISTOLROUNDS_WON,
  69. CSSTAT_MONEY_EARNED,
  70. CSSTAT_OBJECTIVES_COMPLETED,
  71. CSSTAT_BOMBS_DEFUSED_WITHKIT,
  72. CSSTAT_KILLS_DEAGLE,
  73. CSSTAT_KILLS_USP,
  74. CSSTAT_KILLS_GLOCK,
  75. CSSTAT_KILLS_P228,
  76. CSSTAT_KILLS_ELITE,
  77. CSSTAT_KILLS_FIVESEVEN,
  78. CSSTAT_KILLS_AWP,
  79. CSSTAT_KILLS_AK47,
  80. CSSTAT_KILLS_M4A1,
  81. CSSTAT_KILLS_AUG,
  82. CSSTAT_KILLS_SG552,
  83. CSSTAT_KILLS_SG550,
  84. CSSTAT_KILLS_GALIL,
  85. CSSTAT_KILLS_FAMAS,
  86. CSSTAT_KILLS_SCOUT,
  87. CSSTAT_KILLS_G3SG1,
  88. CSSTAT_KILLS_P90,
  89. CSSTAT_KILLS_MP5NAVY,
  90. CSSTAT_KILLS_TMP,
  91. CSSTAT_KILLS_MAC10,
  92. CSSTAT_KILLS_UMP45,
  93. CSSTAT_KILLS_M3,
  94. CSSTAT_KILLS_XM1014,
  95. CSSTAT_KILLS_M249,
  96. CSSTAT_KILLS_KNIFE,
  97. CSSTAT_KILLS_HEGRENADE,
  98. CSSTAT_SHOTS_DEAGLE,
  99. CSSTAT_SHOTS_USP,
  100. CSSTAT_SHOTS_GLOCK,
  101. CSSTAT_SHOTS_P228,
  102. CSSTAT_SHOTS_ELITE,
  103. CSSTAT_SHOTS_FIVESEVEN,
  104. CSSTAT_SHOTS_AWP,
  105. CSSTAT_SHOTS_AK47,
  106. CSSTAT_SHOTS_M4A1,
  107. CSSTAT_SHOTS_AUG,
  108. CSSTAT_SHOTS_SG552,
  109. CSSTAT_SHOTS_SG550,
  110. CSSTAT_SHOTS_GALIL,
  111. CSSTAT_SHOTS_FAMAS,
  112. CSSTAT_SHOTS_SCOUT,
  113. CSSTAT_SHOTS_G3SG1,
  114. CSSTAT_SHOTS_P90,
  115. CSSTAT_SHOTS_MP5NAVY,
  116. CSSTAT_SHOTS_TMP,
  117. CSSTAT_SHOTS_MAC10,
  118. CSSTAT_SHOTS_UMP45,
  119. CSSTAT_SHOTS_M3,
  120. CSSTAT_SHOTS_XM1014,
  121. CSSTAT_SHOTS_M249,
  122. CSSTAT_SHOTS_KNIFE,
  123. CSSTAT_SHOTS_HEGRENADE,
  124. CSSTAT_HITS_DEAGLE,
  125. CSSTAT_HITS_USP,
  126. CSSTAT_HITS_GLOCK,
  127. CSSTAT_HITS_P228,
  128. CSSTAT_HITS_ELITE,
  129. CSSTAT_HITS_FIVESEVEN,
  130. CSSTAT_HITS_AWP,
  131. CSSTAT_HITS_AK47,
  132. CSSTAT_HITS_M4A1,
  133. CSSTAT_HITS_AUG,
  134. CSSTAT_HITS_SG552,
  135. CSSTAT_HITS_SG550,
  136. CSSTAT_HITS_GALIL,
  137. CSSTAT_HITS_FAMAS,
  138. CSSTAT_HITS_SCOUT,
  139. CSSTAT_HITS_G3SG1,
  140. CSSTAT_HITS_P90,
  141. CSSTAT_HITS_MP5NAVY,
  142. CSSTAT_HITS_TMP,
  143. CSSTAT_HITS_MAC10,
  144. CSSTAT_HITS_UMP45,
  145. CSSTAT_HITS_M3,
  146. CSSTAT_HITS_XM1014,
  147. CSSTAT_HITS_M249,
  148. CSSTAT_HITS_KNIFE,
  149. CSSTAT_HITS_HEGRENADE,
  150. CSSTAT_DAMAGE_DEAGLE,
  151. CSSTAT_DAMAGE_USP,
  152. CSSTAT_DAMAGE_GLOCK,
  153. CSSTAT_DAMAGE_P228,
  154. CSSTAT_DAMAGE_ELITE,
  155. CSSTAT_DAMAGE_FIVESEVEN,
  156. CSSTAT_DAMAGE_AWP,
  157. CSSTAT_DAMAGE_AK47,
  158. CSSTAT_DAMAGE_M4A1,
  159. CSSTAT_DAMAGE_AUG,
  160. CSSTAT_DAMAGE_SG552,
  161. CSSTAT_DAMAGE_SG550,
  162. CSSTAT_DAMAGE_GALIL,
  163. CSSTAT_DAMAGE_FAMAS,
  164. CSSTAT_DAMAGE_SCOUT,
  165. CSSTAT_DAMAGE_G3SG1,
  166. CSSTAT_DAMAGE_P90,
  167. CSSTAT_DAMAGE_MP5NAVY,
  168. CSSTAT_DAMAGE_TMP,
  169. CSSTAT_DAMAGE_MAC10,
  170. CSSTAT_DAMAGE_UMP45,
  171. CSSTAT_DAMAGE_M3,
  172. CSSTAT_DAMAGE_XM1014,
  173. CSSTAT_DAMAGE_M249,
  174. CSSTAT_DAMAGE_KNIFE,
  175. CSSTAT_DAMAGE_HEGRENADE,
  176. CSSTAT_KILLS_HEADSHOT,
  177. CSSTAT_KILLS_ENEMY_BLINDED,
  178. CSSTAT_KILLS_WHILE_BLINDED,
  179. CSSTAT_KILLS_WITH_LAST_ROUND,
  180. CSSTAT_KILLS_ENEMY_WEAPON,
  181. CSSTAT_KILLS_KNIFE_FIGHT,
  182. CSSTAT_KILLS_WHILE_DEFENDING_BOMB,
  183. CSSTAT_DECAL_SPRAYS,
  184. CSSTAT_TOTAL_JUMPS,
  185. CSSTAT_NIGHTVISION_DAMAGE,
  186. CSSTAT_KILLS_WHILE_LAST_PLAYER_ALIVE,
  187. CSSTAT_KILLS_ENEMY_WOUNDED,
  188. CSSTAT_FALL_DAMAGE,
  189. CSSTAT_NUM_HOSTAGES_RESCUED,
  190. CSSTAT_NUM_BROKEN_WINDOWS,
  191. CSSTAT_PROPSBROKEN_ALL,
  192. CSSTAT_PROPSBROKEN_MELON,
  193. CSSTAT_PROPSBROKEN_OFFICEELECTRONICS,
  194. CSSTAT_PROPSBROKEN_OFFICERADIO,
  195. CSSTAT_PROPSBROKEN_OFFICEJUNK,
  196. CSSTAT_PROPSBROKEN_ITALY_MELON,
  197. CSSTAT_KILLS_AGAINST_ZOOMED_SNIPER,
  198. CSSTAT_WEAPONS_DONATED,
  199. CSSTAT_ITEMS_PURCHASED,
  200. CSSTAT_MONEY_SPENT,
  201. CSSTAT_DOMINATIONS,
  202. CSSTAT_DOMINATION_OVERKILLS,
  203. CSSTAT_REVENGES,
  204. CSSTAT_MVPS,
  205. CSSTAT_GRENADE_DAMAGE,
  206. CSSTAT_GRENADE_POSTHUMOUSKILLS,
  207. CSSTAT_GRENADES_THROWN,
  208. CSTAT_ITEMS_DROPPED_VALUE,
  209. //Map win stats
  210. CSSTAT_MAP_WINS_CS_ASSAULT,
  211. CSSTAT_MAP_WINS_CS_COMPOUND,
  212. CSSTAT_MAP_WINS_CS_HAVANA,
  213. CSSTAT_MAP_WINS_CS_ITALY,
  214. CSSTAT_MAP_WINS_CS_MILITIA,
  215. CSSTAT_MAP_WINS_CS_OFFICE,
  216. CSSTAT_MAP_WINS_DE_AZTEC,
  217. CSSTAT_MAP_WINS_DE_CBBLE,
  218. CSSTAT_MAP_WINS_DE_CHATEAU,
  219. CSSTAT_MAP_WINS_DE_DUST2,
  220. CSSTAT_MAP_WINS_DE_DUST,
  221. CSSTAT_MAP_WINS_DE_INFERNO,
  222. CSSTAT_MAP_WINS_DE_NUKE,
  223. CSSTAT_MAP_WINS_DE_PIRANESI,
  224. CSSTAT_MAP_WINS_DE_PORT,
  225. CSSTAT_MAP_WINS_DE_PRODIGY,
  226. CSSTAT_MAP_WINS_DE_TIDES,
  227. CSSTAT_MAP_WINS_DE_TRAIN,
  228. CSSTAT_MAP_ROUNDS_CS_ASSAULT,
  229. CSSTAT_MAP_ROUNDS_CS_COMPOUND,
  230. CSSTAT_MAP_ROUNDS_CS_HAVANA,
  231. CSSTAT_MAP_ROUNDS_CS_ITALY,
  232. CSSTAT_MAP_ROUNDS_CS_MILITIA,
  233. CSSTAT_MAP_ROUNDS_CS_OFFICE,
  234. CSSTAT_MAP_ROUNDS_DE_AZTEC,
  235. CSSTAT_MAP_ROUNDS_DE_CBBLE,
  236. CSSTAT_MAP_ROUNDS_DE_CHATEAU,
  237. CSSTAT_MAP_ROUNDS_DE_DUST2,
  238. CSSTAT_MAP_ROUNDS_DE_DUST,
  239. CSSTAT_MAP_ROUNDS_DE_INFERNO,
  240. CSSTAT_MAP_ROUNDS_DE_NUKE,
  241. CSSTAT_MAP_ROUNDS_DE_PIRANESI,
  242. CSSTAT_MAP_ROUNDS_DE_PORT,
  243. CSSTAT_MAP_ROUNDS_DE_PRODIGY,
  244. CSSTAT_MAP_ROUNDS_DE_TIDES,
  245. CSSTAT_MAP_ROUNDS_DE_TRAIN,
  246. CSSTAT_LASTMATCH_T_ROUNDS_WON,
  247. CSSTAT_LASTMATCH_CT_ROUNDS_WON,
  248. CSSTAT_LASTMATCH_ROUNDS_WON,
  249. CSSTAT_LASTMATCH_KILLS,
  250. CSSTAT_LASTMATCH_DEATHS,
  251. CSSTAT_LASTMATCH_MVPS,
  252. CSSTAT_LASTMATCH_DAMAGE,
  253. CSSTAT_LASTMATCH_MONEYSPENT,
  254. CSSTAT_LASTMATCH_DOMINATIONS,
  255. CSSTAT_LASTMATCH_REVENGES,
  256. CSSTAT_LASTMATCH_MAX_PLAYERS,
  257. CSSTAT_LASTMATCH_FAVWEAPON_ID,
  258. CSSTAT_LASTMATCH_FAVWEAPON_SHOTS,
  259. CSSTAT_LASTMATCH_FAVWEAPON_HITS,
  260. CSSTAT_LASTMATCH_FAVWEAPON_KILLS,
  261. CSSTAT_MAX //Must be last entry.
  262. };
  263. #define CSSTAT_FIRST (CSSTAT_UNDEFINED+1)
  264. #define CSSTAT_LAST (CSSTAT_MAX-1)
  265. //
  266. // CS Game Stats Flags
  267. //
  268. #define CSSTAT_PRIORITY_MASK 0x000F
  269. #define CSSTAT_PRIORITY_NEVER 0x0000 // not sent to client
  270. #define CSSTAT_PRIORITY_ENDROUND 0x0001 // sent at end of round
  271. #define CSSTAT_PRIORITY_LOW 0x0002 // sent every 2500ms
  272. #define CSSTAT_PRIORITY_HIGH 0x0003 // sent every 250ms
  273. struct CSStatProperty
  274. {
  275. int statId; // verify that table ordering is correct
  276. const char* szSteamName; // name of the stat on steam
  277. const char* szLocalizationToken; // localization token for the stat
  278. uint flags; // priority flags for sending to client
  279. };
  280. extern CSStatProperty CSStatProperty_Table[];
  281. //=============================================================================
  282. //
  283. // CS Player Round Stats
  284. //
  285. struct StatsCollection_t
  286. {
  287. StatsCollection_t() { Reset(); }
  288. inline int Get( int i ) const
  289. {
  290. AssertMsg( i >= CSSTAT_FIRST && i < CSSTAT_MAX, "Stat index out of range!" );
  291. if ( i >= 0 )
  292. return m_iValue[ i ];
  293. return 0;
  294. }
  295. inline void Set( int i, int nValue )
  296. {
  297. AssertMsg( i >= CSSTAT_FIRST && i < CSSTAT_MAX, "Stat index out of range!" );
  298. if ( i >= 0 )
  299. m_iValue[ i ] = nValue;
  300. }
  301. void Reset()
  302. {
  303. for ( int i = 0; i < ARRAYSIZE( m_iValue ); i++ )
  304. {
  305. m_iValue[i] = 0;
  306. }
  307. }
  308. int operator[] ( int index ) const
  309. {
  310. Assert(index >= 0 && index < ARRAYSIZE(m_iValue));
  311. return m_iValue[index];
  312. }
  313. int& operator[] ( int index )
  314. {
  315. Assert(index >= 0 && index < ARRAYSIZE(m_iValue));
  316. return m_iValue[index];
  317. }
  318. void Aggregate( const StatsCollection_t& other );
  319. private:
  320. int m_iValue[CSSTAT_MAX];
  321. };
  322. //=============================================================================
  323. // HPE_BEGIN:
  324. // [tj] A couple variations on the RoundStats structure to handle extra operations
  325. // for averaging and accumulating
  326. //=============================================================================
  327. struct RoundStatsDirectAverage_t
  328. {
  329. float m_fStat[CSSTAT_MAX];
  330. RoundStatsDirectAverage_t()
  331. {
  332. Reset();
  333. }
  334. void Reset()
  335. {
  336. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  337. {
  338. m_fStat[i] = 0;
  339. }
  340. }
  341. RoundStatsDirectAverage_t& operator +=( const StatsCollection_t &other )
  342. {
  343. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  344. {
  345. m_fStat[i] += other[i];
  346. }
  347. return *this;
  348. }
  349. RoundStatsDirectAverage_t& operator /=( const float &divisor)
  350. {
  351. if (divisor > 0)
  352. {
  353. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  354. {
  355. m_fStat[i] /= divisor;
  356. }
  357. }
  358. return *this;
  359. }
  360. RoundStatsDirectAverage_t& operator *=( const float &divisor)
  361. {
  362. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  363. {
  364. m_fStat[i] *= divisor;
  365. }
  366. return *this;
  367. }
  368. };
  369. struct RoundStatsRollingAverage_t
  370. {
  371. float m_fStat[CSSTAT_MAX];
  372. int m_numberOfDataSets;
  373. RoundStatsRollingAverage_t()
  374. {
  375. Reset();
  376. }
  377. void Reset()
  378. {
  379. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  380. {
  381. m_fStat[i] = 0;
  382. }
  383. m_numberOfDataSets = 0;
  384. }
  385. RoundStatsRollingAverage_t& operator +=( const RoundStatsRollingAverage_t &other )
  386. {
  387. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  388. {
  389. m_fStat[i] += other.m_fStat[i];
  390. }
  391. return *this;
  392. }
  393. RoundStatsRollingAverage_t& operator +=( const StatsCollection_t &other )
  394. {
  395. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  396. {
  397. m_fStat[i] += other[i];
  398. }
  399. return *this;
  400. }
  401. RoundStatsRollingAverage_t& operator /=( const float &divisor)
  402. {
  403. if (divisor > 0)
  404. {
  405. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  406. {
  407. m_fStat[i] /= divisor;
  408. }
  409. }
  410. return *this;
  411. }
  412. void RollDataSetIntoAverage ( const RoundStatsRollingAverage_t &other )
  413. {
  414. for ( int i = 0; i < ARRAYSIZE( m_fStat ); i++ )
  415. {
  416. m_fStat[i] *= m_numberOfDataSets;
  417. m_fStat[i] += other.m_fStat[i];
  418. m_fStat[i] /= (m_numberOfDataSets + 1);
  419. }
  420. m_numberOfDataSets++;
  421. }
  422. };
  423. //=============================================================================
  424. // HPE_END
  425. //=============================================================================
  426. enum CSGameStatsVersions_t
  427. {
  428. CS_GAMESTATS_FILE_VERSION = 006,
  429. CS_GAMESTATS_MAGIC = 0xDEADBEEF
  430. };
  431. struct CS_Gamestats_Version_t
  432. {
  433. int m_iMagic; // always CS_GAMESTATS_MAGIC
  434. int m_iVersion;
  435. };
  436. struct KillStats_t
  437. {
  438. KillStats_t() { Reset(); }
  439. void Reset()
  440. {
  441. Q_memset( iNumKilled, 0, sizeof( iNumKilled ) );
  442. Q_memset( iNumKilledBy, 0, sizeof( iNumKilledBy ) );
  443. Q_memset( iNumKilledByUnanswered, 0, sizeof( iNumKilledByUnanswered ) );
  444. }
  445. int iNumKilled[MAX_PLAYERS+1]; // how many times this player has killed each other player
  446. int iNumKilledBy[MAX_PLAYERS+1]; // how many times this player has been killed by each other player
  447. int iNumKilledByUnanswered[MAX_PLAYERS+1]; // how many unanswered kills this player has been dealt by each other player
  448. };
  449. //=============================================================================
  450. //
  451. // CS Player Stats
  452. //
  453. struct PlayerStats_t
  454. {
  455. PlayerStats_t()
  456. {
  457. Reset();
  458. }
  459. void Reset()
  460. {
  461. statsDelta.Reset();
  462. statsCurrentRound.Reset();
  463. statsCurrentMatch.Reset();
  464. statsKills.Reset();
  465. }
  466. PlayerStats_t( const PlayerStats_t &other )
  467. {
  468. statsDelta = other.statsDelta;
  469. statsCurrentRound = other.statsCurrentRound;
  470. statsCurrentMatch = other.statsCurrentMatch;
  471. }
  472. StatsCollection_t statsDelta;
  473. StatsCollection_t statsCurrentRound;
  474. StatsCollection_t statsCurrentMatch;
  475. KillStats_t statsKills;
  476. };
  477. struct WeaponName_StatId
  478. {
  479. CSWeaponID weaponId;
  480. CSStatType_t killStatId;
  481. CSStatType_t shotStatId;
  482. CSStatType_t hitStatId;
  483. CSStatType_t damageStatId;
  484. };
  485. struct MapName_MapStatId
  486. {
  487. const char* szMapName;
  488. CSStatType_t statWinsId;
  489. CSStatType_t statRoundsId;
  490. };
  491. extern const MapName_MapStatId MapName_StatId_Table[];
  492. //A mapping from weapon names to weapon stat IDs
  493. extern const WeaponName_StatId WeaponName_StatId_Table[];
  494. //Used to look up the appropriate entry by the ID of the actual weapon
  495. const WeaponName_StatId& GetWeaponTableEntryFromWeaponId(CSWeaponID id);
  496. #include "steamworks_gamestats.h"
  497. //=============================================================================
  498. //
  499. // Helper functions for creating key values
  500. //
  501. void AddDataToKV( KeyValues* pKV, const char* name, int data );
  502. void AddDataToKV( KeyValues* pKV, const char* name, uint64 data );
  503. void AddDataToKV( KeyValues* pKV, const char* name, float data );
  504. void AddDataToKV( KeyValues* pKV, const char* name, bool data );
  505. void AddDataToKV( KeyValues* pKV, const char* name, const char* data );
  506. void AddDataToKV( KeyValues* pKV, const char* name, const Color& data );
  507. void AddDataToKV( KeyValues* pKV, const char* name, short data );
  508. void AddDataToKV( KeyValues* pKV, const char* name, unsigned data );
  509. void AddDataToKV( KeyValues* pKV, const char* name, const Vector& data );
  510. void AddPositionDataToKV( KeyValues* pKV, const char* name, const Vector &data );
  511. //=============================================================================
  512. //=============================================================================
  513. //
  514. // Helper functions for creating key values from arrays
  515. //
  516. void AddArrayDataToKV( KeyValues* pKV, const char* name, const short *data, unsigned size );
  517. void AddArrayDataToKV( KeyValues* pKV, const char* name, const byte *data, unsigned size );
  518. void AddArrayDataToKV( KeyValues* pKV, const char* name, const unsigned *data, unsigned size );
  519. void AddStringDataToKV( KeyValues* pKV, const char* name, const char *data );
  520. //=============================================================================
  521. // Macros to ease the creation of SendData method for stats structs/classes
  522. #define BEGIN_STAT_TABLE( tableName ) \
  523. static const char* GetStatTableName( void ) { return tableName; } \
  524. void BuildGamestatDataTable( KeyValues* pKV ) \
  525. { \
  526. pKV->SetName( GetStatTableName() );
  527. #define REGISTER_STAT( varName ) \
  528. AddDataToKV(pKV, #varName, varName);
  529. #define REGISTER_STAT_NAMED( varName, dbName ) \
  530. AddDataToKV(pKV, dbName, varName);
  531. #define REGISTER_STAT_POSITION( varName ) \
  532. AddPositionDataToKV(pKV, #varName, varName);
  533. #define REGISTER_STAT_POSITION_NAMED( varName, dbName ) \
  534. AddPositionDataToKV(pKV, dbName, varName);
  535. #define REGISTER_STAT_ARRAY( varName ) \
  536. AddArrayDataToKV( pKV, #varName, varName, ARRAYSIZE( varName ) );
  537. #define REGISTER_STAT_ARRAY_NAMED( varName, dbName ) \
  538. AddArrayDataToKV( pKV, dbName, varName, ARRAYSIZE( varName ) );
  539. #define REGISTER_STAT_STRING( varName ) \
  540. AddStringDataToKV( pKV, #varName, varName );
  541. #define REGISTER_STAT_STRING_NAMED( varName, dbName ) \
  542. AddStringDataToKV( pKV, dbName, varName );
  543. #define AUTO_STAT_TABLE_KEY() \
  544. pKV->SetInt( "TimeSubmitted", GetUniqueIDForStatTable( *this ) );
  545. #define END_STAT_TABLE() \
  546. pKV->SetUint64( ::BaseStatData::m_bUseGlobalData ? "TimeSubmitted" : "SessionTime", ::BaseStatData::TimeSubmitted ); \
  547. GetSteamWorksSGameStatsUploader().AddStatsForUpload( pKV ); \
  548. }
  549. //-----------------------------------------------------------------------------
  550. // Purpose: Templatized class for getting unique ID's for stat tables that need
  551. // to be submitted multiple times per-session.
  552. //-----------------------------------------------------------------------------
  553. template < typename T >
  554. class UniqueStatID_t
  555. {
  556. public:
  557. static unsigned GetNext( void )
  558. {
  559. return ++s_nLastID;
  560. }
  561. static void Reset( void )
  562. {
  563. s_nLastID = 0;
  564. }
  565. private:
  566. static unsigned s_nLastID;
  567. };
  568. template < typename T >
  569. unsigned UniqueStatID_t< T >::s_nLastID = 0;
  570. template < typename T >
  571. unsigned GetUniqueIDForStatTable( const T &table )
  572. {
  573. return UniqueStatID_t< T >::GetNext();
  574. }
  575. //=============================================================================
  576. //
  577. // An interface for tracking gamestats.
  578. //
  579. class IGameStatTracker
  580. {
  581. public:
  582. //-----------------------------------------------------------------------------
  583. // Templatized methods to track a per-mission stat.
  584. // The stat is copied, then deleted after it's sent to the SQL server.
  585. //-----------------------------------------------------------------------------
  586. template < typename T >
  587. void SubmitStat( T& stat )
  588. {
  589. // Make a copy of the stat. All of the stat lists require pointers,
  590. // so we need to protect against a stat allocated on the stack
  591. T* pT = new T();
  592. if( !pT )
  593. return;
  594. *pT = stat;
  595. SubmitStat( pT );
  596. }
  597. //-----------------------------------------------------------------------------
  598. // Templatized methods to track a per-mission stat (by pointer)
  599. // The stat is deleted after it's sent to the SQL server
  600. //-----------------------------------------------------------------------------
  601. template < typename T >
  602. void SubmitStat( T* pStat )
  603. {
  604. // Get the static stat table for this type and add the stat to it
  605. GetStatTable<T>()->AddToTail( pStat );
  606. }
  607. //-----------------------------------------------------------------------------
  608. // Add all stats to an existing key value file for submit.
  609. //-----------------------------------------------------------------------------
  610. virtual void SubmitGameStats( KeyValues *pKV ) = 0;
  611. //-----------------------------------------------------------------------------
  612. // Prints the memory usage of all of the stats being tracked
  613. //-----------------------------------------------------------------------------
  614. void PrintGamestatMemoryUsage( void );
  615. protected:
  616. //=============================================================================
  617. //
  618. // Used as a base interface to store a list of all templatized stat containers
  619. //
  620. class IStatContainer
  621. {
  622. public:
  623. virtual void SendData( KeyValues *pKV ) = 0;
  624. virtual void Clear( void ) = 0;
  625. virtual void PrintMemoryUsage( void ) = 0;
  626. };
  627. // Defines a list of stat containers.
  628. typedef CUtlVector< IStatContainer* > StatContainerList_t;
  629. //-----------------------------------------------------------------------------
  630. // Used to get a list of all stats containers being tracked by the deriving class
  631. //-----------------------------------------------------------------------------
  632. virtual StatContainerList_t* GetStatContainerList( void ) = 0;
  633. private:
  634. //=============================================================================
  635. //
  636. // Templatized list of stats submitted
  637. //
  638. template < typename T >
  639. class CGameStatList : public IStatContainer, public CUtlVector< T* >
  640. {
  641. public:
  642. //-----------------------------------------------------------------------------
  643. // Get data ready to send to the SQL server
  644. //-----------------------------------------------------------------------------
  645. virtual void SendData( KeyValues *pKV )
  646. {
  647. //ASSERT( pKV != NULL );
  648. // Duplicate the master KeyValue for each stat instance
  649. for( int i=0; i < this->m_Size; ++i )
  650. {
  651. // Make a copy of the master key value and build the stat table
  652. KeyValues *pKVCopy = this->operator [](i)->m_bUseGlobalData ? pKV->MakeCopy() : new KeyValues( "" );
  653. this->operator [](i)->BuildGamestatDataTable( pKVCopy );
  654. }
  655. // Reset unique ID counter for the stat type
  656. UniqueStatID_t< T >::Reset();
  657. }
  658. //-----------------------------------------------------------------------------
  659. // Clear and delete every stat in this list
  660. //-----------------------------------------------------------------------------
  661. virtual void Clear( void )
  662. {
  663. this->PurgeAndDeleteElements();
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Print out details about this lists memory usage
  667. //-----------------------------------------------------------------------------
  668. virtual void PrintMemoryUsage( void )
  669. {
  670. if( this->m_Size == 0 )
  671. return;
  672. // Compute the memory used as the size of type times the list count
  673. unsigned uMemoryUsed = this->m_Size * ( sizeof( T ) );
  674. Msg( " %d\tbytes used by %s table\n", uMemoryUsed, T::GetStatTableName() );
  675. }
  676. };
  677. //-----------------------------------------------------------------------------
  678. // Templatized method to get a single instance of a stat list per data type.
  679. //-----------------------------------------------------------------------------
  680. template < typename T >
  681. CGameStatList< T >* GetStatTable( void )
  682. {
  683. static CGameStatList< T > *s_vecOfType = 0;
  684. if( s_vecOfType == 0 )
  685. {
  686. s_vecOfType = new CGameStatList< T >();
  687. GetStatContainerList()->AddToTail( s_vecOfType );
  688. }
  689. return s_vecOfType;
  690. }
  691. };
  692. struct BaseStatData
  693. {
  694. BaseStatData( bool bUseGlobalData = true ) : m_bUseGlobalData( bUseGlobalData )
  695. {
  696. TimeSubmitted = GetSteamWorksSGameStatsUploader().GetTimeSinceEpoch();
  697. }
  698. bool m_bUseGlobalData;
  699. uint64 TimeSubmitted;
  700. };
  701. extern ConVar sv_noroundstats;
  702. #endif // CS_GAMESTATS_SHARED_H