mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 06:06:50 +00:00
561 lines
19 KiB
C++
561 lines
19 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Base class for objects that are kept in synch between client and server
|
|
//
|
|
//=============================================================================
|
|
#include "stdafx.h"
|
|
#include "gcsdk_gcmessages.pb.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
namespace GCSDK
|
|
{
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Map of all the factory functions for all CSharedObject classes
|
|
//----------------------------------------------------------------------------
|
|
CUtlMap<int, CSharedObject::SharedObjectInfo_t> CSharedObject::sm_mapFactories(DefLessFunc(int));
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Registers a new CSharedObject class
|
|
//----------------------------------------------------------------------------
|
|
void CSharedObject::RegisterFactory( int nTypeID, SOCreationFunc_t fnFactory, uint32 unFlags, const char *pchClassName )
|
|
{
|
|
SharedObjectInfo_t info;
|
|
info.m_pFactoryFunction = fnFactory;
|
|
info.m_unFlags = unFlags;
|
|
info.m_pchClassName = pchClassName;
|
|
info.m_sBuildCacheSubNodeName.Format( "BuildCacheSubscribed(%s)", pchClassName );
|
|
info.m_sCreateNodeName.Format( "Create(%s)", pchClassName );
|
|
info.m_sUpdateNodeName.Format( "Update(%s)", pchClassName );
|
|
sm_mapFactories.InsertOrReplace( nTypeID, info );
|
|
|
|
//register this class with our SO stats as well
|
|
#ifdef GC
|
|
g_SharedObjectStats.RegisterSharedObjectType( nTypeID, pchClassName );
|
|
#endif //GC
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Creates a new CSharedObject instance of the specified type ID
|
|
//----------------------------------------------------------------------------
|
|
CSharedObject *CSharedObject::Create( int nTypeID )
|
|
{
|
|
int nIndex = sm_mapFactories.Find( nTypeID );
|
|
AssertMsg1( sm_mapFactories.IsValidIndex( nIndex ), "Probably failed to set object type (%d) on the server/client.\n", nTypeID );
|
|
if( sm_mapFactories.IsValidIndex( nIndex ) )
|
|
{
|
|
return sm_mapFactories[nIndex].m_pFactoryFunction();
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Various accessors for static class data
|
|
//----------------------------------------------------------------------------
|
|
uint32 CSharedObject::GetTypeFlags( int nTypeID )
|
|
{
|
|
int nIndex = sm_mapFactories.Find( nTypeID );
|
|
if( !sm_mapFactories.IsValidIndex( nIndex ) )
|
|
return 0;
|
|
else
|
|
return sm_mapFactories[nIndex].m_unFlags;
|
|
}
|
|
|
|
const char *CSharedObject::PchClassName( int nTypeID )
|
|
{
|
|
int nIndex = sm_mapFactories.Find( nTypeID );
|
|
if( !sm_mapFactories.IsValidIndex( nIndex ) )
|
|
return 0;
|
|
else
|
|
return sm_mapFactories[nIndex].m_pchClassName;
|
|
|
|
}
|
|
|
|
const char *CSharedObject::PchClassBuildCacheNodeName( int nTypeID )
|
|
{
|
|
int nIndex = sm_mapFactories.Find( nTypeID );
|
|
if( !sm_mapFactories.IsValidIndex( nIndex ) )
|
|
return 0;
|
|
else
|
|
return sm_mapFactories[nIndex].m_sBuildCacheSubNodeName.Get();
|
|
}
|
|
|
|
const char *CSharedObject::PchClassCreateNodeName( int nTypeID )
|
|
{
|
|
int nIndex = sm_mapFactories.Find( nTypeID );
|
|
if( !sm_mapFactories.IsValidIndex( nIndex ) )
|
|
return 0;
|
|
else
|
|
return sm_mapFactories[nIndex].m_sCreateNodeName.Get();
|
|
}
|
|
|
|
const char *CSharedObject::PchClassUpdateNodeName( int nTypeID )
|
|
{
|
|
int nIndex = sm_mapFactories.Find( nTypeID );
|
|
if( !sm_mapFactories.IsValidIndex( nIndex ) )
|
|
return 0;
|
|
else
|
|
return sm_mapFactories[nIndex].m_sUpdateNodeName.Get();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Figures out if the primary keys on these two objects are the same
|
|
// using the subclass-defined less function
|
|
//----------------------------------------------------------------------------
|
|
bool CSharedObject::BIsKeyEqual( const CSharedObject & soRHS ) const
|
|
{
|
|
// Make sure they are the same type.
|
|
if ( GetTypeID() != soRHS.GetTypeID() )
|
|
return false;
|
|
|
|
return !BIsKeyLess( soRHS ) && !soRHS.BIsKeyLess( *this );
|
|
}
|
|
|
|
|
|
|
|
#ifdef GC
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Sends a create message for this shared object to the specified
|
|
// steam ID.
|
|
//----------------------------------------------------------------------------
|
|
bool CSharedObject::BSendCreateToSteamID( const CSteamID & steamID, const CSteamID & steamIDOwner, uint64 ulVersion ) const
|
|
{
|
|
// Don't send these while shutting down. We'll use higher-level
|
|
// connection-oriented messages instead
|
|
if ( GGCBase()->GetIsShuttingDown() )
|
|
return false;
|
|
|
|
CProtoBufMsg< CMsgSOSingleObject > msg( k_ESOMsg_Create );
|
|
msg.Body().set_owner( steamIDOwner.ConvertToUint64() );
|
|
msg.Body().set_type_id( GetTypeID() );
|
|
msg.Body().set_version( ulVersion );
|
|
if( !BAddToMessage( msg.Body().mutable_object_data() ) )
|
|
{
|
|
EmitWarning( SPEW_SHAREDOBJ, SPEW_ALWAYS, "Failed to add create fields to message in create" );
|
|
return false;
|
|
}
|
|
|
|
return GGCBase()->BSendGCMsgToClient( steamID, msg );
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Sends a destroy message for this object to the specified steam ID
|
|
//----------------------------------------------------------------------------
|
|
bool CSharedObject::BSendDestroyToSteamID( const CSteamID & steamID, const CSteamID & steamIDOwner, uint64 ulVersion ) const
|
|
{
|
|
// Don't send these while shutting down. We'll use higher-level
|
|
// connection-oriented messages instead
|
|
if ( GGCBase()->GetIsShuttingDown() )
|
|
return false;
|
|
|
|
CProtoBufMsg< CMsgSOSingleObject > msg( k_ESOMsg_Destroy );
|
|
msg.Body().set_owner( steamIDOwner.ConvertToUint64() );
|
|
msg.Body().set_type_id( GetTypeID() );
|
|
msg.Body().set_version( ulVersion );
|
|
if( !BAddDestroyToMessage( msg.Body().mutable_object_data() ) )
|
|
{
|
|
EmitWarning( SPEW_SHAREDOBJ, SPEW_ALWAYS, "Failed to add key to message in create" );
|
|
return false;
|
|
}
|
|
return GGCBase()->BSendGCMsgToClient( steamID, msg );
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Wraps BYieldingAddInsertToTransaction with a transaction and a
|
|
// commit.
|
|
//----------------------------------------------------------------------------
|
|
bool CSharedObject::BYieldingAddToDatabase()
|
|
{
|
|
CSQLAccess sqlAccess;
|
|
sqlAccess.BBeginTransaction( CFmtStr( "CSharedObject::BYieldingAddToDatabase Type %d", GetTypeID() ) );
|
|
if( !BYieldingAddInsertToTransaction( sqlAccess ) )
|
|
{
|
|
sqlAccess.RollbackTransaction();
|
|
return false;
|
|
}
|
|
|
|
return sqlAccess.BCommitTransaction();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Wraps BYieldingAddWriteToTransaction with a transaction and a
|
|
// commit.
|
|
//----------------------------------------------------------------------------
|
|
bool CSharedObject::BYieldingWriteToDatabase( const CUtlVector< int > &fields )
|
|
{
|
|
CSQLAccess sqlAccess;
|
|
sqlAccess.BBeginTransaction( CFmtStr( "CSharedObject::BYieldingWriteToDatabase Type %d", GetTypeID() ) );
|
|
if( !BYieldingAddWriteToTransaction( sqlAccess, fields ) )
|
|
{
|
|
sqlAccess.RollbackTransaction();
|
|
return false;
|
|
}
|
|
|
|
if( sqlAccess.BCommitTransaction() )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Wraps BYieldingAddRemoveToTransaction with a transaction and a
|
|
// commit.
|
|
//----------------------------------------------------------------------------
|
|
bool CSharedObject::BYieldingRemoveFromDatabase()
|
|
{
|
|
CSQLAccess sqlAccess;
|
|
sqlAccess.BBeginTransaction( CFmtStr( "CSharedObject::BYieldingRemoveFromDatabase Type %d", GetTypeID() ) );
|
|
if( !BYieldingAddRemoveToTransaction( sqlAccess ) )
|
|
{
|
|
sqlAccess.RollbackTransaction();
|
|
return false;
|
|
}
|
|
|
|
return sqlAccess.BCommitTransaction();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------------------------
|
|
// CSharedObjectStats
|
|
//--------------------------------------------------------------------------------------------------------------------------
|
|
|
|
//our global stats for our SO objects
|
|
CSharedObjectStats g_SharedObjectStats;
|
|
|
|
|
|
CSharedObjectStats::CSharedObjectStats()
|
|
: m_bCollectingStats( false )
|
|
, m_nMicroSElapsed( 0 )
|
|
{
|
|
}
|
|
|
|
CSharedObjectStats::SOStats_t::SOStats_t()
|
|
: m_nNumActive( 0 )
|
|
{
|
|
ResetStats();
|
|
}
|
|
|
|
void CSharedObjectStats::SOStats_t::ResetStats()
|
|
{
|
|
m_nNumCreated = 0;
|
|
m_nNumDestroyed = 0;
|
|
m_nNumSends = 0;
|
|
m_nRawBytesSent = 0;
|
|
m_nMultiplexedBytesSent = 0;
|
|
m_nNumSubOwner = 0;
|
|
m_nNumSubOtherUsers = 0;
|
|
m_nNumSubGameServer = 0;
|
|
}
|
|
|
|
void CSharedObjectStats::StartCollectingStats()
|
|
{
|
|
//do nothing if already collecting
|
|
if( m_bCollectingStats )
|
|
return;
|
|
|
|
m_bCollectingStats = true;
|
|
m_CollectTime.SetToJobTime();
|
|
}
|
|
|
|
void CSharedObjectStats::StopCollectingStats()
|
|
{
|
|
if( !m_bCollectingStats )
|
|
return;
|
|
|
|
m_bCollectingStats = false;
|
|
m_nMicroSElapsed = m_CollectTime.CServerMicroSecsPassed();
|
|
}
|
|
|
|
void CSharedObjectStats::RegisterSharedObjectType( int nTypeID, const char* pszTypeName )
|
|
{
|
|
if( nTypeID < 0 )
|
|
{
|
|
AssertMsg2( false, "Error registering shared object type %d (%s), negative type ID's are not supported", nTypeID, pszTypeName );
|
|
return;
|
|
}
|
|
|
|
//see if we need to grow our list to accommodate this type id
|
|
if( nTypeID >= m_vTypeToIndex.Count() )
|
|
{
|
|
//make sure people aren't getting carried away with index ranges
|
|
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" );
|
|
int nOldSize = m_vTypeToIndex.Count();
|
|
m_vTypeToIndex.AddMultipleToTail( nTypeID + 1 - nOldSize );
|
|
for( int nCurrFill = nOldSize; nCurrFill < nTypeID; nCurrFill++ )
|
|
{
|
|
m_vTypeToIndex[ nCurrFill ] = knInvalidIndex;
|
|
}
|
|
}
|
|
else if( m_vTypeToIndex[ nTypeID ] != knInvalidIndex )
|
|
{
|
|
//we have already registered something in this slot
|
|
AssertMsg2( false, "Error registering shared object type %d (%s), may have multiple registrations of this type, check for conflicts", nTypeID, pszTypeName );
|
|
return;
|
|
}
|
|
|
|
//we need to register this type by adding a new record, and updating our index
|
|
int nNewIndex = m_Stats.AddToTail();
|
|
m_Stats[ nNewIndex ].m_sName = pszTypeName;
|
|
m_Stats[ nNewIndex ].m_nTypeID = nTypeID;
|
|
m_vTypeToIndex[ nTypeID ] = nNewIndex;
|
|
}
|
|
|
|
void CSharedObjectStats::TrackSharedObjectLifetime( int nTypeID, int32 nCount )
|
|
{
|
|
uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
|
|
if( nIndex != knInvalidIndex )
|
|
{
|
|
m_Stats[ nIndex ].m_nNumActive += nCount;
|
|
}
|
|
}
|
|
|
|
void CSharedObjectStats::TrackSharedObjectSendCreate( int nTypeID, uint32 nCount )
|
|
{
|
|
uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
|
|
if( nIndex != knInvalidIndex )
|
|
{
|
|
m_Stats[ nIndex ].m_nNumCreated += nCount;
|
|
}
|
|
}
|
|
|
|
void CSharedObjectStats::TrackSharedObjectSendDestroy( int nTypeID, uint32 nCount )
|
|
{
|
|
uint16 nIndex = (m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
|
|
if( nIndex != knInvalidIndex )
|
|
{
|
|
m_Stats[ nIndex ].m_nNumDestroyed += nCount;
|
|
}
|
|
}
|
|
|
|
void CSharedObjectStats::TrackSubscription( int nTypeID, uint32 nFlags, uint32 nNumSubscriptions )
|
|
{
|
|
if( !m_bCollectingStats )
|
|
return;
|
|
|
|
uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
|
|
if( nIndex != knInvalidIndex )
|
|
{
|
|
if( nFlags & k_ESOFlag_SendToOwner )
|
|
m_Stats[ nIndex ].m_nNumSubOwner += nNumSubscriptions;
|
|
if( nFlags & k_ESOFlag_SendToOtherUsers )
|
|
m_Stats[ nIndex ].m_nNumSubOtherUsers += nNumSubscriptions;
|
|
if( nFlags & k_ESOFlag_SendToOtherGameservers )
|
|
m_Stats[ nIndex ].m_nNumSubGameServer += nNumSubscriptions;
|
|
}
|
|
|
|
}
|
|
|
|
void CSharedObjectStats::TrackSharedObjectSend( int nTypeID, uint32 nNumClients, uint32 nMsgSize )
|
|
{
|
|
if( !m_bCollectingStats )
|
|
return;
|
|
|
|
uint16 nIndex = ( m_vTypeToIndex.IsValidIndex( nTypeID ) ) ? m_vTypeToIndex[ nTypeID ] : knInvalidIndex;
|
|
if( nIndex != knInvalidIndex )
|
|
{
|
|
m_Stats[ nIndex ].m_nNumSends++;
|
|
m_Stats[ nIndex ].m_nRawBytesSent += nMsgSize;
|
|
m_Stats[ nIndex ].m_nMultiplexedBytesSent += nMsgSize * nNumClients;
|
|
}
|
|
}
|
|
|
|
void CSharedObjectStats::ResetStats()
|
|
{
|
|
FOR_EACH_VEC( m_Stats, nCurrSO )
|
|
{
|
|
m_Stats[ nCurrSO ].ResetStats();
|
|
}
|
|
}
|
|
|
|
bool CSharedObjectStats::SortSOStatsSent( const SOStats_t* pLhs, const SOStats_t* pRhs )
|
|
{
|
|
//highest bandwidth ones go up top
|
|
if( pLhs->m_nMultiplexedBytesSent != pRhs->m_nMultiplexedBytesSent )
|
|
return pLhs->m_nMultiplexedBytesSent > pRhs->m_nMultiplexedBytesSent;
|
|
|
|
//otherwise sort by the name
|
|
return pLhs->m_nTypeID < pRhs->m_nTypeID;
|
|
}
|
|
|
|
bool CSharedObjectStats::SortSOStatsSubscribe( const SOStats_t* pLhs, const SOStats_t* pRhs )
|
|
{
|
|
//sort based on total number of subscriptions
|
|
uint32 nLhsSub = pLhs->m_nNumSubOwner + pLhs->m_nNumSubOtherUsers + pLhs->m_nNumSubGameServer;
|
|
uint32 nRhsSub = pRhs->m_nNumSubOwner + pRhs->m_nNumSubOtherUsers + pRhs->m_nNumSubGameServer;
|
|
if( nLhsSub != nRhsSub )
|
|
return nLhsSub > nRhsSub;
|
|
|
|
//otherwise sort by the name
|
|
return pLhs->m_nTypeID < pRhs->m_nTypeID;
|
|
}
|
|
|
|
void CSharedObjectStats::ReportCollectedStats() const
|
|
{
|
|
//build up a list of our stats, so we can sort them appropriately (also total how many bytes we send)
|
|
uint64 nTotalRawBytes = 0;
|
|
uint64 nTotalMultiplexBytes = 0;
|
|
uint32 nTotalActive = 0;
|
|
uint32 nTotalCreates = 0;
|
|
uint32 nTotalFrees = 0;
|
|
uint32 nTotalSends = 0;
|
|
uint32 nTotalSubOwner = 0;
|
|
uint32 nTotalSubOtherUsers = 0;
|
|
uint32 nTotalSubGameServer = 0;
|
|
|
|
CUtlVector< const SOStats_t* > sortedStats( 0, m_Stats.Count() );
|
|
FOR_EACH_VEC( m_Stats, nCurrSO )
|
|
{
|
|
sortedStats.AddToTail( &( m_Stats[ nCurrSO ] ) );
|
|
|
|
nTotalRawBytes += m_Stats[ nCurrSO ].m_nRawBytesSent;
|
|
nTotalMultiplexBytes += m_Stats[ nCurrSO ].m_nMultiplexedBytesSent;
|
|
nTotalActive += m_Stats[ nCurrSO ].m_nNumActive;
|
|
nTotalCreates += m_Stats[ nCurrSO ].m_nNumCreated;
|
|
nTotalFrees += m_Stats[ nCurrSO ].m_nNumDestroyed;
|
|
nTotalSends += m_Stats[ nCurrSO ].m_nNumSends;
|
|
nTotalSubOwner += m_Stats[ nCurrSO ].m_nNumSubOwner;
|
|
nTotalSubOtherUsers += m_Stats[ nCurrSO ].m_nNumSubOtherUsers;
|
|
nTotalSubGameServer += m_Stats[ nCurrSO ].m_nNumSubGameServer;
|
|
}
|
|
|
|
//determine the time scale to normalize this into per second measurements
|
|
uint64 nMicroSElapsed = ( m_bCollectingStats ) ? m_CollectTime.CServerMicroSecsPassed() : m_nMicroSElapsed;
|
|
double fSeconds = nMicroSElapsed / 1000000.0;
|
|
double fToS = ( nMicroSElapsed > 0 ) ? 1000000.0 / nMicroSElapsed : 1.0;
|
|
|
|
//-----------------------------------------
|
|
// Update stats
|
|
|
|
std::sort( sortedStats.begin(), sortedStats.end(), SortSOStatsSent );
|
|
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "SO Cache Transmits - %.2f second capture\n", fSeconds );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
|
|
|
|
//now run through and display our report
|
|
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" );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ ------- ------ -------- ------ ------- ------- ------- ------- ------- ------- --------- -------\n" );
|
|
|
|
FOR_EACH_VEC( sortedStats, nCurrSO )
|
|
{
|
|
const SOStats_t& stats = *sortedStats[ nCurrSO ];
|
|
|
|
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",
|
|
stats.m_nTypeID,
|
|
stats.m_sName.Get(),
|
|
( uint32 )( stats.m_nRawBytesSent / 1024 ),
|
|
100.0 * ( double )stats.m_nRawBytesSent / ( double )MAX( 1, nTotalRawBytes ),
|
|
( double )( stats.m_nRawBytesSent / 1024 ) * fToS,
|
|
( double )stats.m_nMultiplexedBytesSent / MAX( 1, stats.m_nRawBytesSent ),
|
|
stats.m_nNumCreated,
|
|
stats.m_nNumCreated * fToS,
|
|
stats.m_nNumDestroyed,
|
|
stats.m_nNumDestroyed * fToS,
|
|
stats.m_nNumSends,
|
|
stats.m_nNumSends * fToS,
|
|
stats.m_nNumActive,
|
|
100.0 * stats.m_nNumSends * fToS / MAX( 1, stats.m_nNumActive ) );
|
|
}
|
|
|
|
//close it out with the totals
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ ------- ------ -------- ------ ------- ------- ------- ------- ------- ------- --------- -------\n" );
|
|
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",
|
|
( uint32 )( nTotalRawBytes / 1024 ),
|
|
100.0,
|
|
( double )( nTotalRawBytes / 1024 ) * fToS,
|
|
( double )nTotalMultiplexBytes / ( double )MAX( 1, nTotalRawBytes ),
|
|
nTotalCreates,
|
|
nTotalCreates * fToS,
|
|
nTotalFrees,
|
|
nTotalFrees * fToS,
|
|
nTotalSends,
|
|
nTotalSends * fToS,
|
|
nTotalActive,
|
|
100.0 * nTotalSends * fToS / MAX( 1, nTotalActive ) );
|
|
|
|
//-----------------------------------------
|
|
// Subscription stats
|
|
|
|
std::sort( sortedStats.begin(), sortedStats.end(), SortSOStatsSubscribe );
|
|
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "SO Cache Subscriptions Sends - %.2f second capture\n", fSeconds );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\n" );
|
|
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "Type Name Owner Owner/S Other Other/S Server Server/S\n" );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ -------- -------- -------- -------- -------- --------\n" );
|
|
|
|
FOR_EACH_VEC( sortedStats, nCurrSO )
|
|
{
|
|
const SOStats_t& stats = *sortedStats[ nCurrSO ];
|
|
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%4d %-30s %8u %8.0f %8u %8.0f %8u %8.0f\n",
|
|
stats.m_nTypeID,
|
|
stats.m_sName.Get(),
|
|
stats.m_nNumSubOwner,
|
|
stats.m_nNumSubOwner * fToS,
|
|
stats.m_nNumSubOtherUsers,
|
|
stats.m_nNumSubOtherUsers * fToS,
|
|
stats.m_nNumSubGameServer,
|
|
stats.m_nNumSubGameServer * fToS );
|
|
}
|
|
|
|
//close it out with the totals
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "%s", "---- ------------------------------ -------- -------- -------- -------- -------- --------\n" );
|
|
EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, " Totals %8u %8.0f %8u %8.0f %8u %8.0f\n",
|
|
nTotalSubOwner,
|
|
nTotalSubOwner * fToS,
|
|
nTotalSubOtherUsers,
|
|
nTotalSubOtherUsers * fToS,
|
|
nTotalSubGameServer,
|
|
nTotalSubGameServer * fToS );
|
|
|
|
}
|
|
|
|
#endif // GC
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Claims all the memory for the shared object
|
|
//----------------------------------------------------------------------------
|
|
#ifdef DBGFLAG_VALIDATE
|
|
void CSharedObject::Validate( CValidator &validator, const char *pchName )
|
|
{
|
|
VALIDATE_SCOPE();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Claims all the static memory for the shared object (i.e. the
|
|
// factory function map.
|
|
//----------------------------------------------------------------------------
|
|
void CSharedObject::ValidateStatics( CValidator & validator )
|
|
{
|
|
CValidateAutoPushPop validatorAutoPushPop( validator, NULL, "CSharedObject::ValidateStatics", "CSharedObject::ValidateStatics" );
|
|
ValidateObj( sm_mapFactories );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
} // namespace GCSDK
|
|
|
|
|
|
|