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.

560 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Base class for objects that are kept in synch between client and server
  4. //
  5. //=============================================================================
  6. #include "stdafx.h"
  7. #include "gcsdk_gcmessages.pb.h"
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include "tier0/memdbgon.h"
  10. namespace GCSDK
  11. {
  12. //----------------------------------------------------------------------------
  13. // Purpose: Map of all the factory functions for all CSharedObject classes
  14. //----------------------------------------------------------------------------
  15. CUtlMap<int, CSharedObject::SharedObjectInfo_t> CSharedObject::sm_mapFactories(DefLessFunc(int));
  16. //----------------------------------------------------------------------------
  17. // Purpose: Registers a new CSharedObject class
  18. //----------------------------------------------------------------------------
  19. void CSharedObject::RegisterFactory( int nTypeID, SOCreationFunc_t fnFactory, uint32 unFlags, const char *pchClassName )
  20. {
  21. SharedObjectInfo_t info;
  22. info.m_pFactoryFunction = fnFactory;
  23. info.m_unFlags = unFlags;
  24. info.m_pchClassName = pchClassName;
  25. info.m_sBuildCacheSubNodeName.Format( "BuildCacheSubscribed(%s)", pchClassName );
  26. info.m_sCreateNodeName.Format( "Create(%s)", pchClassName );
  27. info.m_sUpdateNodeName.Format( "Update(%s)", pchClassName );
  28. sm_mapFactories.InsertOrReplace( nTypeID, info );
  29. //register this class with our SO stats as well
  30. #ifdef GC
  31. g_SharedObjectStats.RegisterSharedObjectType( nTypeID, pchClassName );
  32. #endif //GC
  33. }
  34. //----------------------------------------------------------------------------
  35. // Purpose: Creates a new CSharedObject instance of the specified type ID
  36. //----------------------------------------------------------------------------
  37. CSharedObject *CSharedObject::Create( int nTypeID )
  38. {
  39. int nIndex = sm_mapFactories.Find( nTypeID );
  40. AssertMsg1( sm_mapFactories.IsValidIndex( nIndex ), "Probably failed to set object type (%d) on the server/client.\n", nTypeID );
  41. if( sm_mapFactories.IsValidIndex( nIndex ) )
  42. {
  43. return sm_mapFactories[nIndex].m_pFactoryFunction();
  44. }
  45. else
  46. {
  47. return NULL;
  48. }
  49. }
  50. //----------------------------------------------------------------------------
  51. // Purpose: Various accessors for static class data
  52. //----------------------------------------------------------------------------
  53. uint32 CSharedObject::GetTypeFlags( int nTypeID )
  54. {
  55. int nIndex = sm_mapFactories.Find( nTypeID );
  56. if( !sm_mapFactories.IsValidIndex( nIndex ) )
  57. return 0;
  58. else
  59. return sm_mapFactories[nIndex].m_unFlags;
  60. }
  61. const char *CSharedObject::PchClassName( int nTypeID )
  62. {
  63. int nIndex = sm_mapFactories.Find( nTypeID );
  64. if( !sm_mapFactories.IsValidIndex( nIndex ) )
  65. return 0;
  66. else
  67. return sm_mapFactories[nIndex].m_pchClassName;
  68. }
  69. const char *CSharedObject::PchClassBuildCacheNodeName( int nTypeID )
  70. {
  71. int nIndex = sm_mapFactories.Find( nTypeID );
  72. if( !sm_mapFactories.IsValidIndex( nIndex ) )
  73. return 0;
  74. else
  75. return sm_mapFactories[nIndex].m_sBuildCacheSubNodeName.Get();
  76. }
  77. const char *CSharedObject::PchClassCreateNodeName( int nTypeID )
  78. {
  79. int nIndex = sm_mapFactories.Find( nTypeID );
  80. if( !sm_mapFactories.IsValidIndex( nIndex ) )
  81. return 0;
  82. else
  83. return sm_mapFactories[nIndex].m_sCreateNodeName.Get();
  84. }
  85. const char *CSharedObject::PchClassUpdateNodeName( int nTypeID )
  86. {
  87. int nIndex = sm_mapFactories.Find( nTypeID );
  88. if( !sm_mapFactories.IsValidIndex( nIndex ) )
  89. return 0;
  90. else
  91. return sm_mapFactories[nIndex].m_sUpdateNodeName.Get();
  92. }
  93. //----------------------------------------------------------------------------
  94. // Purpose: Figures out if the primary keys on these two objects are the same
  95. // using the subclass-defined less function
  96. //----------------------------------------------------------------------------
  97. bool CSharedObject::BIsKeyEqual( const CSharedObject & soRHS ) const
  98. {
  99. // Make sure they are the same type.
  100. if ( GetTypeID() != soRHS.GetTypeID() )
  101. return false;
  102. return !BIsKeyLess( soRHS ) && !soRHS.BIsKeyLess( *this );
  103. }
  104. #ifdef GC
  105. //----------------------------------------------------------------------------
  106. // Purpose: Sends a create message for this shared object to the specified
  107. // steam ID.
  108. //----------------------------------------------------------------------------
  109. bool CSharedObject::BSendCreateToSteamID( const CSteamID & steamID, const CSteamID & steamIDOwner, uint64 ulVersion ) const
  110. {
  111. // Don't send these while shutting down. We'll use higher-level
  112. // connection-oriented messages instead
  113. if ( GGCBase()->GetIsShuttingDown() )
  114. return false;
  115. CProtoBufMsg< CMsgSOSingleObject > msg( k_ESOMsg_Create );
  116. msg.Body().set_owner( steamIDOwner.ConvertToUint64() );
  117. msg.Body().set_type_id( GetTypeID() );
  118. msg.Body().set_version( ulVersion );
  119. if( !BAddToMessage( msg.Body().mutable_object_data() ) )
  120. {
  121. EmitWarning( SPEW_SHAREDOBJ, SPEW_ALWAYS, "Failed to add create fields to message in create" );
  122. return false;
  123. }
  124. return GGCBase()->BSendGCMsgToClient( steamID, msg );
  125. }
  126. //----------------------------------------------------------------------------
  127. // Purpose: Sends a destroy message for this object to the specified steam ID
  128. //----------------------------------------------------------------------------
  129. bool CSharedObject::BSendDestroyToSteamID( const CSteamID & steamID, const CSteamID & steamIDOwner, uint64 ulVersion ) const
  130. {
  131. // Don't send these while shutting down. We'll use higher-level
  132. // connection-oriented messages instead
  133. if ( GGCBase()->GetIsShuttingDown() )
  134. return false;
  135. CProtoBufMsg< CMsgSOSingleObject > msg( k_ESOMsg_Destroy );
  136. msg.Body().set_owner( steamIDOwner.ConvertToUint64() );
  137. msg.Body().set_type_id( GetTypeID() );
  138. msg.Body().set_version( ulVersion );
  139. if( !BAddDestroyToMessage( msg.Body().mutable_object_data() ) )
  140. {
  141. EmitWarning( SPEW_SHAREDOBJ, SPEW_ALWAYS, "Failed to add key to message in create" );
  142. return false;
  143. }
  144. return GGCBase()->BSendGCMsgToClient( steamID, msg );
  145. }
  146. //----------------------------------------------------------------------------
  147. // Purpose: Wraps BYieldingAddInsertToTransaction with a transaction and a
  148. // commit.
  149. //----------------------------------------------------------------------------
  150. bool CSharedObject::BYieldingAddToDatabase()
  151. {
  152. CSQLAccess sqlAccess;
  153. sqlAccess.BBeginTransaction( CFmtStr( "CSharedObject::BYieldingAddToDatabase Type %d", GetTypeID() ) );
  154. if( !BYieldingAddInsertToTransaction( sqlAccess ) )
  155. {
  156. sqlAccess.RollbackTransaction();
  157. return false;
  158. }
  159. return sqlAccess.BCommitTransaction();
  160. }
  161. //----------------------------------------------------------------------------
  162. // Purpose: Wraps BYieldingAddWriteToTransaction with a transaction and a
  163. // commit.
  164. //----------------------------------------------------------------------------
  165. bool CSharedObject::BYieldingWriteToDatabase( const CUtlVector< int > &fields )
  166. {
  167. CSQLAccess sqlAccess;
  168. sqlAccess.BBeginTransaction( CFmtStr( "CSharedObject::BYieldingWriteToDatabase Type %d", GetTypeID() ) );
  169. if( !BYieldingAddWriteToTransaction( sqlAccess, fields ) )
  170. {
  171. sqlAccess.RollbackTransaction();
  172. return false;
  173. }
  174. if( sqlAccess.BCommitTransaction() )
  175. {
  176. return true;
  177. }
  178. else
  179. {
  180. return false;
  181. }
  182. }
  183. //----------------------------------------------------------------------------
  184. // Purpose: Wraps BYieldingAddRemoveToTransaction with a transaction and a
  185. // commit.
  186. //----------------------------------------------------------------------------
  187. bool CSharedObject::BYieldingRemoveFromDatabase()
  188. {
  189. CSQLAccess sqlAccess;
  190. sqlAccess.BBeginTransaction( CFmtStr( "CSharedObject::BYieldingRemoveFromDatabase Type %d", GetTypeID() ) );
  191. if( !BYieldingAddRemoveToTransaction( sqlAccess ) )
  192. {
  193. sqlAccess.RollbackTransaction();
  194. return false;
  195. }
  196. return sqlAccess.BCommitTransaction();
  197. }
  198. //--------------------------------------------------------------------------------------------------------------------------
  199. // CSharedObjectStats
  200. //--------------------------------------------------------------------------------------------------------------------------
  201. //our global stats for our SO objects
  202. CSharedObjectStats g_SharedObjectStats;
  203. CSharedObjectStats::CSharedObjectStats()
  204. : m_bCollectingStats( false )
  205. , m_nMicroSElapsed( 0 )
  206. {
  207. }
  208. CSharedObjectStats::SOStats_t::SOStats_t()
  209. : m_nNumActive( 0 )
  210. {
  211. ResetStats();
  212. }
  213. void CSharedObjectStats::SOStats_t::ResetStats()
  214. {
  215. m_nNumCreated = 0;
  216. m_nNumDestroyed = 0;
  217. m_nNumSends = 0;
  218. m_nRawBytesSent = 0;
  219. m_nMultiplexedBytesSent = 0;
  220. m_nNumSubOwner = 0;
  221. m_nNumSubOtherUsers = 0;
  222. m_nNumSubGameServer = 0;
  223. }
  224. void CSharedObjectStats::StartCollectingStats()
  225. {
  226. //do nothing if already collecting
  227. if( m_bCollectingStats )
  228. return;
  229. m_bCollectingStats = true;
  230. m_CollectTime.SetToJobTime();
  231. }
  232. void CSharedObjectStats::StopCollectingStats()
  233. {
  234. if( !m_bCollectingStats )
  235. return;
  236. m_bCollectingStats = false;
  237. m_nMicroSElapsed = m_CollectTime.CServerMicroSecsPassed();
  238. }
  239. void CSharedObjectStats::RegisterSharedObjectType( int nTypeID, const char* pszTypeName )
  240. {
  241. if( nTypeID < 0 )
  242. {
  243. AssertMsg2( false, "Error registering shared object type %d (%s), negative type ID's are not supported", nTypeID, pszTypeName );
  244. return;
  245. }
  246. //see if we need to grow our list to accommodate this type id
  247. if( nTypeID >= m_vTypeToIndex.Count() )
  248. {
  249. //make sure people aren't getting carried away with index ranges
  250. AssertMsg( nTypeID < 8 * 1024, "Warning: Using a very large type ID which can be inefficient for the shared object stats. Try to keep values to a smaller range" );
  251. int nOldSize = m_vTypeToIndex.Count();
  252. m_vTypeToIndex.AddMultipleToTail( nTypeID + 1 - nOldSize );
  253. for( int nCurrFill = nOldSize; nCurrFill < nTypeID; nCurrFill++ )
  254. {
  255. m_vTypeToIndex[ nCurrFill ] = knInvalidIndex;
  256. }
  257. }
  258. else if( m_vTypeToIndex[ nTypeID ] != knInvalidIndex )
  259. {
  260. //we have already registered something in this slot
  261. AssertMsg2( false, "Error registering shared object type %d (%s), may have multiple registrations of this type, check for conflicts", nTypeID, pszTypeName );
  262. return;
  263. }
  264. //we need to register this type by adding a new record, and updating our index
  265. int nNewIndex = m_Stats.AddToTail();
  266. m_Stats[ nNewIndex ].m_sName = pszTypeName;
  267. m_Stats[ nNewIndex ].m_nTypeID = nTypeID;
  268. m_vTypeToIndex[ nTypeID ] = nNewIndex;
  269. }
  270. void CSharedObjectStats::TrackSharedObjectLifetime( int nTypeID, int32 nCount )
  271. {
  272. uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
  273. if( nIndex != knInvalidIndex )
  274. {
  275. m_Stats[ nIndex ].m_nNumActive += nCount;
  276. }
  277. }
  278. void CSharedObjectStats::TrackSharedObjectSendCreate( int nTypeID, uint32 nCount )
  279. {
  280. uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
  281. if( nIndex != knInvalidIndex )
  282. {
  283. m_Stats[ nIndex ].m_nNumCreated += nCount;
  284. }
  285. }
  286. void CSharedObjectStats::TrackSharedObjectSendDestroy( int nTypeID, uint32 nCount )
  287. {
  288. uint16 nIndex = (m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
  289. if( nIndex != knInvalidIndex )
  290. {
  291. m_Stats[ nIndex ].m_nNumDestroyed += nCount;
  292. }
  293. }
  294. void CSharedObjectStats::TrackSubscription( int nTypeID, uint32 nFlags, uint32 nNumSubscriptions )
  295. {
  296. if( !m_bCollectingStats )
  297. return;
  298. uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
  299. if( nIndex != knInvalidIndex )
  300. {
  301. if( nFlags & k_ESOFlag_SendToOwner )
  302. m_Stats[ nIndex ].m_nNumSubOwner += nNumSubscriptions;
  303. if( nFlags & k_ESOFlag_SendToOtherUsers )
  304. m_Stats[ nIndex ].m_nNumSubOtherUsers += nNumSubscriptions;
  305. if( nFlags & k_ESOFlag_SendToOtherGameservers )
  306. m_Stats[ nIndex ].m_nNumSubGameServer += nNumSubscriptions;
  307. }
  308. }
  309. void CSharedObjectStats::TrackSharedObjectSend( int nTypeID, uint32 nNumClients, uint32 nMsgSize )
  310. {
  311. if( !m_bCollectingStats )
  312. return;
  313. uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
  314. if( nIndex != knInvalidIndex )
  315. {
  316. m_Stats[ nIndex ].m_nNumSends++;
  317. m_Stats[ nIndex ].m_nRawBytesSent += nMsgSize;
  318. m_Stats[ nIndex ].m_nMultiplexedBytesSent += nMsgSize * nNumClients;
  319. }
  320. }
  321. void CSharedObjectStats::ResetStats()
  322. {
  323. FOR_EACH_VEC( m_Stats, nCurrSO )
  324. {
  325. m_Stats[ nCurrSO ].ResetStats();
  326. }
  327. }
  328. bool CSharedObjectStats::SortSOStatsSent( const SOStats_t* pLhs, const SOStats_t* pRhs )
  329. {
  330. //highest bandwidth ones go up top
  331. if( pLhs->m_nMultiplexedBytesSent != pRhs->m_nMultiplexedBytesSent )
  332. return pLhs->m_nMultiplexedBytesSent > pRhs->m_nMultiplexedBytesSent;
  333. //otherwise sort by the name
  334. return pLhs->m_nTypeID < pRhs->m_nTypeID;
  335. }
  336. bool CSharedObjectStats::SortSOStatsSubscribe( const SOStats_t* pLhs, const SOStats_t* pRhs )
  337. {
  338. //sort based on total number of subscriptions
  339. uint32 nLhsSub = pLhs->m_nNumSubOwner + pLhs->m_nNumSubOtherUsers + pLhs->m_nNumSubGameServer;
  340. uint32 nRhsSub = pRhs->m_nNumSubOwner + pRhs->m_nNumSubOtherUsers + pRhs->m_nNumSubGameServer;
  341. if( nLhsSub != nRhsSub )
  342. return nLhsSub > nRhsSub;
  343. //otherwise sort by the name
  344. return pLhs->m_nTypeID < pRhs->m_nTypeID;
  345. }
  346. void CSharedObjectStats::ReportCollectedStats() const
  347. {
  348. //build up a list of our stats, so we can sort them appropriately (also total how many bytes we send)
  349. uint64 nTotalRawBytes = 0;
  350. uint64 nTotalMultiplexBytes = 0;
  351. uint32 nTotalActive = 0;
  352. uint32 nTotalCreates = 0;
  353. uint32 nTotalFrees = 0;
  354. uint32 nTotalSends = 0;
  355. uint32 nTotalSubOwner = 0;
  356. uint32 nTotalSubOtherUsers = 0;
  357. uint32 nTotalSubGameServer = 0;
  358. CUtlVector< const SOStats_t* > sortedStats( 0, m_Stats.Count() );
  359. FOR_EACH_VEC( m_Stats, nCurrSO )
  360. {
  361. sortedStats.AddToTail( &( m_Stats[ nCurrSO ] ) );
  362. nTotalRawBytes += m_Stats[ nCurrSO ].m_nRawBytesSent;
  363. nTotalMultiplexBytes += m_Stats[ nCurrSO ].m_nMultiplexedBytesSent;
  364. nTotalActive += m_Stats[ nCurrSO ].m_nNumActive;
  365. nTotalCreates += m_Stats[ nCurrSO ].m_nNumCreated;
  366. nTotalFrees += m_Stats[ nCurrSO ].m_nNumDestroyed;
  367. nTotalSends += m_Stats[ nCurrSO ].m_nNumSends;
  368. nTotalSubOwner += m_Stats[ nCurrSO ].m_nNumSubOwner;
  369. nTotalSubOtherUsers += m_Stats[ nCurrSO ].m_nNumSubOtherUsers;
  370. nTotalSubGameServer += m_Stats[ nCurrSO ].m_nNumSubGameServer;
  371. }
  372. //determine the time scale to normalize this into per second measurements
  373. uint64 nMicroSElapsed = ( m_bCollectingStats ) ? m_CollectTime.CServerMicroSecsPassed() : m_nMicroSElapsed;
  374. double fSeconds = nMicroSElapsed / 1000000.0;
  375. double fToS = ( nMicroSElapsed > 0 ) ? 1000000.0 / nMicroSElapsed : 1.0;
  376. //-----------------------------------------
  377. // Update stats
  378. std::sort( sortedStats.begin(), sortedStats.end(), SortSOStatsSent );
  379. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
  380. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "SO Cache Transmits - %.2f second capture\n", fSeconds );
  381. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
  382. //now run through and display our report
  383. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "Type Name SendKB % SendKB/S MPlex Create C/S Destroy D/S Update U/S Active U/S (%)\n" );
  384. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ ------- ------ -------- ------ ------- ------- ------- ------- ------- ------- --------- -------\n" );
  385. FOR_EACH_VEC( sortedStats, nCurrSO )
  386. {
  387. const SOStats_t& stats = *sortedStats[ nCurrSO ];
  388. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%4d %-30s %7u %5.1f%% %8.1f %6.2f %7u %7.0f %7u %7.0f %7u %7.0f %9u %6.3f%%\n",
  389. stats.m_nTypeID,
  390. stats.m_sName.Get(),
  391. ( uint32 )( stats.m_nRawBytesSent / 1024 ),
  392. 100.0 * ( double )stats.m_nRawBytesSent / ( double )MAX( 1, nTotalRawBytes ),
  393. ( double )( stats.m_nRawBytesSent / 1024 ) * fToS,
  394. ( double )stats.m_nMultiplexedBytesSent / MAX( 1, stats.m_nRawBytesSent ),
  395. stats.m_nNumCreated,
  396. stats.m_nNumCreated * fToS,
  397. stats.m_nNumDestroyed,
  398. stats.m_nNumDestroyed * fToS,
  399. stats.m_nNumSends,
  400. stats.m_nNumSends * fToS,
  401. stats.m_nNumActive,
  402. 100.0 * stats.m_nNumSends * fToS / MAX( 1, stats.m_nNumActive ) );
  403. }
  404. //close it out with the totals
  405. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ ------- ------ -------- ------ ------- ------- ------- ------- ------- ------- --------- -------\n" );
  406. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, " Totals %7u %5.1f%% %8.1f %6.2f %7u %7.0f %7u %7.0f %7u %7.0f %9u %6.3f%%\n",
  407. ( uint32 )( nTotalRawBytes / 1024 ),
  408. 100.0,
  409. ( double )( nTotalRawBytes / 1024 ) * fToS,
  410. ( double )nTotalMultiplexBytes / ( double )MAX( 1, nTotalRawBytes ),
  411. nTotalCreates,
  412. nTotalCreates * fToS,
  413. nTotalFrees,
  414. nTotalFrees * fToS,
  415. nTotalSends,
  416. nTotalSends * fToS,
  417. nTotalActive,
  418. 100.0 * nTotalSends * fToS / MAX( 1, nTotalActive ) );
  419. //-----------------------------------------
  420. // Subscription stats
  421. std::sort( sortedStats.begin(), sortedStats.end(), SortSOStatsSubscribe );
  422. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
  423. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "SO Cache Subscriptions Sends - %.2f second capture\n", fSeconds );
  424. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
  425. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "Type Name Owner Owner/S Other Other/S Server Server/S\n" );
  426. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ -------- -------- -------- -------- -------- --------\n" );
  427. FOR_EACH_VEC( sortedStats, nCurrSO )
  428. {
  429. const SOStats_t& stats = *sortedStats[ nCurrSO ];
  430. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%4d %-30s %8u %8.0f %8u %8.0f %8u %8.0f\n",
  431. stats.m_nTypeID,
  432. stats.m_sName.Get(),
  433. stats.m_nNumSubOwner,
  434. stats.m_nNumSubOwner * fToS,
  435. stats.m_nNumSubOtherUsers,
  436. stats.m_nNumSubOtherUsers * fToS,
  437. stats.m_nNumSubGameServer,
  438. stats.m_nNumSubGameServer * fToS );
  439. }
  440. //close it out with the totals
  441. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ -------- -------- -------- -------- -------- --------\n" );
  442. EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, " Totals %8u %8.0f %8u %8.0f %8u %8.0f\n",
  443. nTotalSubOwner,
  444. nTotalSubOwner * fToS,
  445. nTotalSubOtherUsers,
  446. nTotalSubOtherUsers * fToS,
  447. nTotalSubGameServer,
  448. nTotalSubGameServer * fToS );
  449. }
  450. #endif // GC
  451. //----------------------------------------------------------------------------
  452. // Purpose: Claims all the memory for the shared object
  453. //----------------------------------------------------------------------------
  454. #ifdef DBGFLAG_VALIDATE
  455. void CSharedObject::Validate( CValidator &validator, const char *pchName )
  456. {
  457. VALIDATE_SCOPE();
  458. }
  459. //----------------------------------------------------------------------------
  460. // Purpose: Claims all the static memory for the shared object (i.e. the
  461. // factory function map.
  462. //----------------------------------------------------------------------------
  463. void CSharedObject::ValidateStatics( CValidator & validator )
  464. {
  465. CValidateAutoPushPop validatorAutoPushPop( validator, NULL, "CSharedObject::ValidateStatics", "CSharedObject::ValidateStatics" );
  466. ValidateObj( sm_mapFactories );
  467. }
  468. #endif
  469. } // namespace GCSDK