////////////////////////////////////////////////////////////////
//
// CEffectTemplateImpl::GetTicksSinceLastBeingUsed
//
//
//
////////////////////////////////////////////////////////////////
int CEffectTemplateImpl::GetTicksSinceLastUsed ( void )
{
    if ( !m_CloneList.empty () )
        return 0;   // Used right now

    CTickCount delta = CTickCount::Now ( true ) - m_TickCountLastUsed;
    return static_cast < int > ( delta.ToLongLong () );
}
///////////////////////////////////////////////////////////////
//
// CPerfStatDebugInfoImpl::DoPulse
//
//
//
///////////////////////////////////////////////////////////////
void CPerfStatDebugInfoImpl::DoPulse ( void )
{
    // Check if time to auto deactivate
    if ( m_bActive )
    {
        CTickCount timeSinceLastGetStats = CTickCount::Now () - m_LastGetStatsTime;

        if ( timeSinceLastGetStats.ToLongLong () > 10000 )
            m_bActive = false;
    }
}
示例#3
0
///////////////////////////////////////////////////////////////
//
// CDatabaseJobQueueImpl::UpdateDebugData
//
// Update info relevant to debugging database jobs
//
///////////////////////////////////////////////////////////////
void CDatabaseJobQueueImpl::UpdateDebugData ( void )
{
    // Update once every 10 seconds
    if ( m_JobCountElpasedTime.Get () < 10000 )
        return;

    shared.m_Mutex.Lock ();

    // Log to console if connection count is creeping up
    if ( shared.m_HandleConnectionMap.size() > m_uiConnectionCountWarnThresh )
    {
        m_uiConnectionCountWarnThresh = shared.m_HandleConnectionMap.size() * 2;
        CLogger::LogPrintf( "Notice: There are now %d database connections\n", shared.m_HandleConnectionMap.size() );
    }

    // Log to console if job count is creeping up
    m_uiJobCount10sMin = std::min < uint > ( m_uiJobCount10sMin, m_ActiveJobHandles.size () );
    if ( m_uiJobCount10sMin > m_uiJobCountWarnThresh )
    {
        m_uiJobCountWarnThresh = m_uiJobCount10sMin * 2;
        CLogger::LogPrintf ( "Notice: %d database query handles active in the last 10 seconds\n", m_uiJobCount10sMin );
    }
    m_JobCountElpasedTime.Reset ();
    m_uiJobCount10sMin = m_ActiveJobHandles.size ();

    CTickCount timeNow = CTickCount::Now ( true );

    // Log old uncollected queries
    for ( CJobQueueType::iterator iter = shared.m_ResultQueue.begin () ; iter != shared.m_ResultQueue.end () ; iter++ )
    {
        CDbJobData* pJobData = *iter;
        if ( !pJobData->result.bLoggedWarning )
        {
            CTickCount age = timeNow - pJobData->result.timeReady;
            if ( age.ToLongLong () > 1000 * 60 * 5 )
            {
                shared.m_Mutex.Unlock ();
                g_pGame->GetScriptDebugging()->LogWarning( pJobData->m_LuaDebugInfo, "Database result uncollected after 5 minutes. [Query: %s]", *pJobData->GetCommandStringForLog() );
                shared.m_Mutex.Lock ();
                pJobData->result.bLoggedWarning = true;
                break;
            }
        }
    }

    shared.m_Mutex.Unlock ();
}
示例#4
0
int CLuaTimerDefs::GetTimers ( lua_State* luaVM )
{
    //  table getTimers ( [ time ] )
    double dTime;

    CScriptArgReader argStream ( luaVM );
    argStream.ReadNumber ( dTime, 0 );

    if ( !argStream.HasErrors () )
    {
        // Find our VM
        CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine ( luaVM );
        if ( pLuaMain )
        {
            // Create a new table
            lua_newtable ( luaVM );

            // Add all the timers with less than ulTime left
            CLuaTimerManager* pLuaTimerManager = pLuaMain->GetTimerManager ();
            CTickCount llCurrentTime = CTickCount::Now ();
            unsigned int uiIndex = 0;
            CFastList < CLuaTimer* > ::const_iterator iter = pLuaTimerManager->IterBegin ();
            for ( ; iter != pLuaTimerManager->IterEnd (); iter++ )
            {
                CLuaTimer* pLuaTimer = *iter;

                // If the time left is less than the time specified, or the time specifed is 0
                CTickCount llTimeLeft = ( pLuaTimer->GetStartTime () + pLuaTimer->GetDelay () ) - llCurrentTime;
                if ( dTime == 0 || llTimeLeft.ToDouble () <= dTime )
                {
                    // Add it to the table
                    lua_pushnumber ( luaVM, ++uiIndex );
                    lua_pushtimer ( luaVM, pLuaTimer );
                    lua_settable ( luaVM, -3 );
                }
            }
            return 1;
        }
    }
    else
        m_pScriptDebugging->LogCustom ( luaVM, argStream.GetFullErrorMessage () );

    lua_pushboolean ( luaVM, false );
    return 1;
}
示例#5
0
void LuaTimerManager::GetTimers( CTickCount time, LuaMain *main )
{
    // We expect a table on the stack
    CTickCount curTime = CTickCount::Now();
    std::list <LuaTimer*>::const_iterator iter = m_list.begin();
    unsigned int n = 0;

    for ( ; iter != m_list.end(); ++iter )
    {
        // If the time left is less than the time specified, or the time specifed is 0
        if ( time.ToLongLong() != 0 && ( (*iter)->GetStartTime () + (*iter)->GetDelay () ) - curTime > time )
            continue;

        lua_State *L = main->GetVirtualMachine();
        lua_pushnumber( L, ++n );
        (*iter)->PushStack( L );
        lua_settable( L, -3 );
    }
}
示例#6
0
void CLuaTimerManager::GetTimers ( CTickCount llTime, lua_State* luaVM )
{
    assert ( luaVM );

    CTickCount llCurrentTime = CTickCount::Now ();
    // Add all the timers to the table
    unsigned int uiIndex = 0;
    list < CLuaTimer* > ::const_iterator iter = m_TimerList.begin ();
    for ( ; iter != m_TimerList.end () ; iter++ )
    {
        // If the time left is less than the time specified, or the time specifed is 0
        CTickCount llTimeLeft = ( (*iter)->GetStartTime () + (*iter)->GetDelay () ) - llCurrentTime;
        if ( llTime.ToLongLong () == 0 || llTimeLeft <= llTime )
        {
            // Add it to the table
            lua_pushnumber ( luaVM, ++uiIndex );
            lua_pushtimer ( luaVM, *iter );
            lua_settable ( luaVM, -3 );
        }
    }
}
///////////////////////////////////////////////////////////////
//
// CPerfStatBandwidthReductionImpl::GetStats
//
//
//
///////////////////////////////////////////////////////////////
void CPerfStatBandwidthReductionImpl::GetStats ( CPerfStatResult* pResult, const std::map < SString, int >& strOptionMap, const SString& strFilter )
{
    // Calculate current rates
    SStatData stats1Sec = m_Stats5Sec;
    for ( uint i = 0 ; i < ZONE_MAX ; i++ )
    {
        CPerfStatManager::ToPerSecond ( stats1Sec.puresync.llSentPacketsByZone [ i ], m_DeltaTickCount.ToLongLong () );
        CPerfStatManager::ToPerSecond ( stats1Sec.puresync.llSentBytesByZone [ i ], m_DeltaTickCount.ToLongLong () );
        CPerfStatManager::ToPerSecond ( stats1Sec.puresync.llSkippedPacketsByZone [ i ], m_DeltaTickCount.ToLongLong () );
        CPerfStatManager::ToPerSecond ( stats1Sec.puresync.llSkippedBytesByZone [ i ], m_DeltaTickCount.ToLongLong () );
    }
    CPerfStatManager::ToPerSecond ( stats1Sec.lightsync.llLightSyncPacketsSent, m_DeltaTickCount.ToLongLong () );
    CPerfStatManager::ToPerSecond ( stats1Sec.lightsync.llLightSyncBytesSent, m_DeltaTickCount.ToLongLong () );
    CPerfStatManager::ToPerSecond ( stats1Sec.lightsync.llSyncPacketsSkipped, m_DeltaTickCount.ToLongLong () );
    CPerfStatManager::ToPerSecond ( stats1Sec.lightsync.llSyncBytesSkipped, m_DeltaTickCount.ToLongLong () );


    //
    // Set option flags
    //
    bool bHelp = MapContains ( strOptionMap, "h" );

    //
    // Process help
    //
    if ( bHelp )
    {
        pResult->AddColumn ( "Bandwidth reduction help" );
        pResult->AddRow ()[0] ="Option h - This help";
        return;
    }

    // Add columns
    pResult->AddColumn ( "Zone" );
    pResult->AddColumn ( "Current rate - pure/light sync.Bytes/sec sent" );
    pResult->AddColumn ( "Current rate - pure/light sync.Bytes/sec skipped" );
    pResult->AddColumn ( "Current rate - pure/light sync.Msgs/sec sent" );
    pResult->AddColumn ( "Current rate - pure/light sync.Msgs/sec skipped" );

    pResult->AddColumn ( "Total - pure/light sync.Bytes sent" );
    pResult->AddColumn ( "Total - pure/light sync.Bytes skipped" );
    pResult->AddColumn ( "Total - pure/light sync.Messages sent" );
    pResult->AddColumn ( "Total - pure/light sync.Messages skipped" );


    SFixedArray < long long, 8 > llTotals = { { 0, 0, 0, 0, 0, 0, 0, 0 } };
    SFixedArray < const char*, 4 > szDesc = { { "Very near/in FOV", "Near/close FOV", "Near/out FOV", "Far" } };

    // Add puresync skipping zones
    for ( uint i = 0 ; i < ZONE_MAX ; i++ )
    {
        SString* row = pResult->AddRow ();

        int c = 0;
        row[c++] = SString ( "%d) %s", i, szDesc[i] );
        row[c++] = CPerfStatManager::GetScaledByteString ( stats1Sec.puresync.llSentBytesByZone[i] );
        row[c++] = CPerfStatManager::GetScaledByteString ( stats1Sec.puresync.llSkippedBytesByZone[i] );
        row[c++] = SString ( "%lld", stats1Sec.puresync.llSentPacketsByZone[i] );
        row[c++] = SString ( "%lld", stats1Sec.puresync.llSkippedPacketsByZone[i] );

        row[c++] = CPerfStatManager::GetScaledByteString ( m_StatsTotal.puresync.llSentBytesByZone[i] );
        row[c++] = CPerfStatManager::GetScaledByteString ( m_StatsTotal.puresync.llSkippedBytesByZone[i] );
        row[c++] = SString ( "%lld", m_StatsTotal.puresync.llSentPacketsByZone[i] );
        row[c++] = SString ( "%lld", m_StatsTotal.puresync.llSkippedPacketsByZone[i] );

        llTotals[0] += stats1Sec.puresync.llSentBytesByZone[i];
        llTotals[1] += stats1Sec.puresync.llSkippedBytesByZone[i];
        llTotals[2] += stats1Sec.puresync.llSentPacketsByZone[i];
        llTotals[3] += stats1Sec.puresync.llSkippedPacketsByZone[i];

        llTotals[4] += m_StatsTotal.puresync.llSentBytesByZone[i];
        llTotals[5] += m_StatsTotal.puresync.llSkippedBytesByZone[i];
        llTotals[6] += m_StatsTotal.puresync.llSentPacketsByZone[i];
        llTotals[7] += m_StatsTotal.puresync.llSkippedPacketsByZone[i];
    }

    // Add lightsync row
    {
        SString* row = pResult->AddRow ();

        int c = 0;
        row[c++] = "Light sync";
        row[c++] = CPerfStatManager::GetScaledByteString ( stats1Sec.lightsync.llLightSyncBytesSent );
        row[c++] = CPerfStatManager::GetScaledByteString ( stats1Sec.lightsync.llSyncBytesSkipped );
        row[c++] = SString ( "%lld", stats1Sec.lightsync.llLightSyncPacketsSent );
        row[c++] = SString ( "%lld", stats1Sec.lightsync.llSyncPacketsSkipped );

        row[c++] = CPerfStatManager::GetScaledByteString ( m_StatsTotal.lightsync.llLightSyncBytesSent );
        row[c++] = CPerfStatManager::GetScaledByteString ( m_StatsTotal.lightsync.llSyncBytesSkipped );
        row[c++] = SString ( "%lld", m_StatsTotal.lightsync.llLightSyncPacketsSent );
        row[c++] = SString ( "%lld", m_StatsTotal.lightsync.llSyncPacketsSkipped );

        llTotals[0] += stats1Sec.lightsync.llLightSyncBytesSent;
        llTotals[1] += stats1Sec.lightsync.llSyncBytesSkipped;
        llTotals[2] += stats1Sec.lightsync.llLightSyncPacketsSent;
        llTotals[3] += stats1Sec.lightsync.llSyncPacketsSkipped;

        llTotals[4] += m_StatsTotal.lightsync.llLightSyncBytesSent;
        llTotals[5] += m_StatsTotal.lightsync.llSyncBytesSkipped;
        llTotals[6] += m_StatsTotal.lightsync.llLightSyncPacketsSent;
        llTotals[7] += m_StatsTotal.lightsync.llSyncPacketsSkipped;
    }

    // Add total
    {
        pResult->AddRow ();
        pResult->AddRow ();
        SString* row = pResult->AddRow ();

        int c = 0;
        row[c++] = "Total";
        row[c++] = CPerfStatManager::GetScaledByteString ( llTotals[0] );
        row[c++] = CPerfStatManager::GetScaledByteString ( llTotals[1] );
        row[c++] = SString ( "%lld", llTotals[2] );
        row[c++] = SString ( "%lld", llTotals[3] );

        row[c++] = CPerfStatManager::GetScaledByteString ( llTotals[4] );
        row[c++] = CPerfStatManager::GetScaledByteString ( llTotals[5] );
        row[c++] = SString ( "%lld", llTotals[6] );
        row[c++] = SString ( "%lld", llTotals[7] );
    }

    // Add reduction
    {
        pResult->AddRow ();
        SString* row = pResult->AddRow ();

        double dBytesSent5Sec      = static_cast < double > ( llTotals[0] );
        double dBytesSkipped5Sec   = static_cast < double > ( llTotals[1] );
        double dPacketsSent5Sec    = static_cast < double > ( llTotals[2] );
        double dPacketsSkipped5Sec = static_cast < double > ( llTotals[3] );

        double dBytesSentAll       = static_cast < double > ( llTotals[4] );
        double dBytesSkippedAll    = static_cast < double > ( llTotals[5] );
        double dPacketsSentAll     = static_cast < double > ( llTotals[6] );
        double dPacketsSkippedAll  = static_cast < double > ( llTotals[7] );

        double dBytesPercent5Sec   = 100 * dBytesSkipped5Sec / Max ( 1.0, dBytesSent5Sec + dBytesSkipped5Sec );
        double dPacketsPercent5Sec = 100 * dPacketsSkipped5Sec / Max ( 1.0, dPacketsSent5Sec + dPacketsSkipped5Sec );

        double dBytesPercentAll    = 100 * dBytesSkippedAll / Max ( 1.0, dBytesSentAll + dBytesSkippedAll );
        double dPacketsPercentAll  = 100 * dPacketsSkippedAll / Max ( 1.0, dPacketsSentAll + dPacketsSkippedAll );

        int c = 0;
        row[c++] = "Reduction percent";
        row[c++] = SString ( "%0.0f%%", -dBytesPercent5Sec );
        row[c++] = "";
        row[c++] = SString ( "%0.0f%%", -dPacketsPercent5Sec );
        row[c++] = "";
        row[c++] = SString ( "%0.0f%%", -dBytesPercentAll );
        row[c++] = "";
        row[c++] = SString ( "%0.0f%%", -dPacketsPercentAll );
        row[c++] = "";

        pResult->AddRow ();
        pResult->AddRow ();
    }
}
///////////////////////////////////////////////////////////////
//
// CPerfStatServerInfoImpl::GetStats
//
//
//
///////////////////////////////////////////////////////////////
void CPerfStatServerInfoImpl::GetStats ( CPerfStatResult* pResult, const std::map < SString, int >& strOptionMap, const SString& strFilter )
{
    //
    // Set option flags
    //
    bool bHelp = MapContains ( strOptionMap, "h" );
    bool bIncludeDebugInfo = MapContains ( strOptionMap, "d" );

    //
    // Process help
    //
    if ( bHelp )
    {
        pResult->AddColumn ( "Server info help" );
        pResult->AddRow ()[0] ="Option h - This help";
        pResult->AddRow ()[0] ="Option d - Include debug info";
        return;
    }

    // Calculate current rates
    long long llIncomingBytesPS = CPerfStatManager::GetPerSecond ( m_llDeltaGameBytesRecv, m_DeltaTickCount.ToLongLong () );
    long long llIncomingBytesPSBlocked = CPerfStatManager::GetPerSecond ( m_llDeltaGameBytesRecvBlocked, m_DeltaTickCount.ToLongLong () );
    long long llOutgoingBytesPS = CPerfStatManager::GetPerSecond ( m_llDeltaGameBytesSent, m_DeltaTickCount.ToLongLong () );
    long long llOutgoingBytesResentPS = CPerfStatManager::GetPerSecond ( m_llDeltaGameBytesResent, m_DeltaTickCount.ToLongLong () );
    SString strIncomingPacketsPS = CPerfStatManager::GetPerSecondString ( m_llDeltaGamePacketsRecv, m_DeltaTickCount.ToDouble () );
    SString strIncomingPacketsPSBlocked = CPerfStatManager::GetPerSecondString ( m_llDeltaGamePacketsRecvBlocked, m_DeltaTickCount.ToDouble () );
    SString strOutgoingPacketsPS = CPerfStatManager::GetPerSecondString ( m_llDeltaGamePacketsSent, m_DeltaTickCount.ToDouble () );
    SString strOutgoingMessagesResentPS = CPerfStatManager::GetPerSecondString ( m_llDeltaGameMessagesResent, m_DeltaTickCount.ToDouble () );

    // Estimate total network usage
    long long llIncomingPacketsPS = CPerfStatManager::GetPerSecond ( m_llDeltaGamePacketsRecv, m_DeltaTickCount.ToLongLong () );
    long long llIncomingPacketsPSBlocked = CPerfStatManager::GetPerSecond ( m_llDeltaGamePacketsRecvBlocked, m_DeltaTickCount.ToLongLong () );
    long long llOutgoingPacketsPS = CPerfStatManager::GetPerSecond ( m_llDeltaGamePacketsSent, m_DeltaTickCount.ToLongLong () );
    long long llNetworkUsageBytesPS = ( llIncomingPacketsPS + llOutgoingPacketsPS ) * UDP_PACKET_OVERHEAD + llIncomingBytesPS + llOutgoingBytesPS;
    long long llNetworkUsageBytesPSInclBlocked = ( llIncomingPacketsPS + llIncomingPacketsPSBlocked + llOutgoingPacketsPS ) * UDP_PACKET_OVERHEAD + llIncomingBytesPS + llIncomingBytesPSBlocked + llOutgoingBytesPS;

    // Calculate uptime
    time_t tUptime = time ( NULL ) - m_tStartTime;
    time_t tDays = tUptime / ( 60 * 60 * 24 );
    tUptime = tUptime % ( 60 * 60 * 24 );
    time_t tHours = tUptime / ( 60 * 60 );
    tUptime = tUptime % ( 60 * 60 );
    time_t tMinutes = tUptime / ( 60 );

    SString strNone;
    CMainConfig* pConfig = g_pGame->GetConfig ();

    m_InfoList.clear ();
    m_StatusList.clear ();
    m_OptionsList.clear ();

    // Fill info lists
    m_InfoList.push_back ( StringPair ( "Platform",                     CStaticFunctionDefinitions::GetOperatingSystemName () ) );
    m_InfoList.push_back ( StringPair ( "Version",                      CStaticFunctionDefinitions::GetVersionSortable () ) );
    m_InfoList.push_back ( StringPair ( "Date",                         GetLocalTimeString ( true ) ) );
    m_InfoList.push_back ( StringPair ( "Uptime",                       SString ( "%d Days %d Hours %02d Mins", (int)tDays, (int)tHours, (int)tMinutes ) ) );
    m_InfoList.push_back ( StringPair ( "Memory",                       GetProcessMemoryUsage() ) );

    if ( !pConfig->GetThreadNetEnabled () )
        m_StatusList.push_back ( StringPair ( "Server FPS",                 SString ( "%d", g_pGame->GetServerFPS () ) ) );
    else
        m_StatusList.push_back ( StringPair ( "Server FPS sync (logic)",    SString ( "%3d (%d)", g_pGame->GetSyncFPS (), g_pGame->GetServerFPS () ) ) );
    m_StatusList.push_back ( StringPair ( "Players",                    SString ( "%d / %d", g_pGame->GetPlayerManager ()->Count (), pConfig->GetMaxPlayers () ) ) );
    m_StatusList.push_back ( StringPair ( "Bytes/sec incoming",         CPerfStatManager::GetScaledByteString ( llIncomingBytesPS ) ) );
    m_StatusList.push_back ( StringPair ( "Bytes/sec outgoing",         CPerfStatManager::GetScaledByteString ( llOutgoingBytesPS ) ) );
    m_StatusList.push_back ( StringPair ( "Packets/sec incoming",       strIncomingPacketsPS ) );
    m_StatusList.push_back ( StringPair ( "Packets/sec outgoing",       strOutgoingPacketsPS ) );
    m_StatusList.push_back ( StringPair ( "Packet loss outgoing",       CPerfStatManager::GetPercentString ( llOutgoingBytesResentPS, llOutgoingBytesPS ) ) );
    m_StatusList.push_back ( StringPair ( "Approx network usage",       CPerfStatManager::GetScaledBitString ( llNetworkUsageBytesPS * 8LL ) + "/s" ) );
    if ( pConfig->GetThreadNetEnabled () )
    {
        m_StatusList.push_back ( StringPair ( "Msg queue incoming",       SString ( "%d", CNetBufferWatchDog::ms_uiInResultQueueSize ) ) );
        if ( bIncludeDebugInfo )
            m_StatusList.push_back ( StringPair ( "       finished incoming",       SString ( "%d", CNetBufferWatchDog::ms_uiFinishedListSize ) ) );
        m_StatusList.push_back ( StringPair ( "Msg queue outgoing",       SString ( "%d", CNetBufferWatchDog::ms_uiOutCommandQueueSize ) ) );
        if ( bIncludeDebugInfo )
            m_StatusList.push_back ( StringPair ( "       finished outgoing",       SString ( "%d", CNetBufferWatchDog::ms_uiOutResultQueueSize ) ) );
    }
    if ( ASE* pAse = ASE::GetInstance() )
        m_StatusList.push_back ( StringPair ( "ASE queries",            SString ( "%d (%d/min)", pAse->GetTotalQueryCount (), pAse->GetQueriesPerMinute () ) ) );

    m_OptionsList.push_back ( StringPair ( "MinClientVersion",          g_pGame->CalculateMinClientRequirement () ) );
    m_OptionsList.push_back ( StringPair ( "RecommendedClientVersion",  pConfig->GetRecommendedClientVersion () ) );
    m_OptionsList.push_back ( StringPair ( "NetworkEncryptionEnabled",  SString ( "%d", pConfig->GetNetworkEncryptionEnabled () ) ) );
    m_OptionsList.push_back ( StringPair ( "VoiceEnabled",              SString ( "%d", pConfig->IsVoiceEnabled () ) ) );
    m_OptionsList.push_back ( StringPair ( "Busy sleep time",           SString ( "%d ms", pConfig->GetPendingWorkToDoSleepTime () ) ) );
    m_OptionsList.push_back ( StringPair ( "Idle sleep time",           SString ( "%d ms", pConfig->GetNoWorkToDoSleepTime () ) ) );
    m_OptionsList.push_back ( StringPair ( "BandwidthReductionMode",    pConfig->GetSetting ( "bandwidth_reduction" ) ) );
    m_OptionsList.push_back ( StringPair ( "LightSyncEnabled",          SString ( "%d", g_pBandwidthSettings->bLightSyncEnabled ) ) );
    m_OptionsList.push_back ( StringPair ( "ThreadNetEnabled",          SString ( "%d", pConfig->GetThreadNetEnabled () ) ) );

    const static CTickRateSettings defaultRates;
    if ( defaultRates.iPureSync != g_TickRateSettings.iPureSync )
        m_OptionsList.push_back ( StringPair ( "Player sync interval",      SString ( "%d", g_TickRateSettings.iPureSync ) ) );
    if ( defaultRates.iLightSync != g_TickRateSettings.iLightSync )
        m_OptionsList.push_back ( StringPair ( "Lightweight sync interval", SString ( "%d", g_TickRateSettings.iLightSync ) ) );
    if ( defaultRates.iCamSync != g_TickRateSettings.iCamSync )
        m_OptionsList.push_back ( StringPair ( "Camera sync interval",      SString ( "%d", g_TickRateSettings.iCamSync ) ) );
    if ( defaultRates.iPedSync != g_TickRateSettings.iPedSync )
        m_OptionsList.push_back ( StringPair ( "Ped sync interval",         SString ( "%d", g_TickRateSettings.iPedSync ) ) );
    if ( defaultRates.iUnoccupiedVehicle != g_TickRateSettings.iUnoccupiedVehicle )
        m_OptionsList.push_back ( StringPair ( "Unocc. veh. sync interval",     SString ( "%d", g_TickRateSettings.iUnoccupiedVehicle ) ) );
    if ( defaultRates.iKeySyncRotation != g_TickRateSettings.iKeySyncRotation )
        m_OptionsList.push_back ( StringPair ( "Keysync mouse sync interval",   SString ( "%d", g_TickRateSettings.iKeySyncRotation ) ) );
    if ( defaultRates.iKeySyncAnalogMove != g_TickRateSettings.iKeySyncAnalogMove )
        m_OptionsList.push_back ( StringPair ( "Keysync analog sync interval",  SString ( "%d", g_TickRateSettings.iKeySyncAnalogMove ) ) );
    if ( defaultRates.iKeySyncAnalogMove != g_TickRateSettings.iNearListUpdate )
        m_OptionsList.push_back ( StringPair ( "Update near interval",      SString ( "%d", g_TickRateSettings.iNearListUpdate ) ) );

    if ( bIncludeDebugInfo )
    {
        m_StatusList.push_back ( StringPair ( "Bytes/sec outgoing resent",  CPerfStatManager::GetScaledByteString ( llOutgoingBytesResentPS ) ) );
        m_StatusList.push_back ( StringPair ( "Msgs/sec outgoing resent",   strOutgoingMessagesResentPS ) );
        m_StatusList.push_back ( StringPair ( "Bytes/sec blocked",          CPerfStatManager::GetScaledByteString ( llIncomingBytesPSBlocked ) ) );
        m_StatusList.push_back ( StringPair ( "Packets/sec  blocked",       strIncomingPacketsPSBlocked ) );
        m_StatusList.push_back ( StringPair ( "Usage incl. blocked",        CPerfStatManager::GetScaledBitString ( llNetworkUsageBytesPSInclBlocked * 8LL ) + "/s" ) );

        m_OptionsList.push_back ( StringPair ( "Main (Logic) core #",       SString ( "%d", _GetCurrentProcessorNumber () ) ) );
        m_OptionsList.push_back ( StringPair ( "Threadnet (Sync) core #",   SString ( "%d", g_uiThreadnetProcessorNumber ) ) );
        m_OptionsList.push_back ( StringPair ( "Raknet thread core #",      SString ( "%d", m_PrevLiveStats.uiNetworkUpdateLoopProcessorNumber ) ) );
        m_OptionsList.push_back ( StringPair ( "DB thread core #",          SString ( "%d", g_uiDatabaseThreadProcessorNumber ) ) );

        // Get net performance stats
        if ( m_NetPerformanceStatsUpdateTimer.Get() > 2000 )
        {
            m_NetPerformanceStatsUpdateTimer.Reset();
            g_pNetServer->GetNetPerformanceStatistics ( &m_NetPerformanceStats, true );
        }
        m_OptionsList.push_back ( StringPair ( "Update cycle prep time max",        SString ( "%s ms (Avg %s ms)", *CPerfStatManager::GetScaledFloatString( m_NetPerformanceStats.uiUpdateCyclePrepTimeMaxUs / 1000.f ), *CPerfStatManager::GetScaledFloatString( m_NetPerformanceStats.uiUpdateCyclePrepTimeAvgUs / 1000.f ) ) ) );
        m_OptionsList.push_back ( StringPair ( "Update cycle process time max",     SString ( "%s ms (Avg %s ms)", *CPerfStatManager::GetScaledFloatString( m_NetPerformanceStats.uiUpdateCycleProcessTimeMaxUs / 1000.f ), *CPerfStatManager::GetScaledFloatString( m_NetPerformanceStats.uiUpdateCycleProcessTimeAvgUs / 1000.f ) ) ) );
        m_OptionsList.push_back ( StringPair ( "Update cycle datagrams max",        SString ( "%d (Avg %s)", m_NetPerformanceStats.uiUpdateCycleDatagramsMax, *CPerfStatManager::GetScaledFloatString( m_NetPerformanceStats.fUpdateCycleDatagramsAvg ) ) ) );
        m_OptionsList.push_back ( StringPair ( "Update cycle datagrams limit",      SString ( "%d", m_NetPerformanceStats.uiUpdateCycleDatagramsLimit ) ) );
        m_OptionsList.push_back ( StringPair ( "Update cycle sends limited",        SString ( "%d (%s %%)", m_NetPerformanceStats.uiUpdateCycleSendsLimitedTotal, *CPerfStatManager::GetScaledFloatString( m_NetPerformanceStats.fUpdateCycleSendsLimitedPercent ) ) ) );
    }

    // Add columns
    pResult->AddColumn ( "Info.Name" );
    pResult->AddColumn ( "Info.Value" );
    pResult->AddColumn ( "Status.Name" );
    pResult->AddColumn ( "Status.Value" );
    pResult->AddColumn ( "Settings.Name" );
    pResult->AddColumn ( "Settings.Value" );


    // Output rows
    std::vector < StringPair >* columnList[] = { &m_InfoList, &m_StatusList, &m_OptionsList };

    uint uiMaxRows = Max ( Max ( m_InfoList.size (), m_StatusList.size () ), m_OptionsList.size () );
    for ( uint i = 0 ; i < uiMaxRows ; i++ )
    {
        SString* row = pResult->AddRow ();
        int c = 0;

        for ( uint a = 0 ; a < NUMELMS( columnList ) ; a++ )
        {
            const std::vector < StringPair >& column = *columnList[a];
            if ( i < column.size () )
            {
                row[c++] = column[i].strName;
                row[c++] = column[i].strValue;
            }
            else
            {
                row[c++] = "";
                row[c++] = "";
            }
        }
    }
}
///////////////////////////////////////////////////////////////
//
// CModelCacheManagerImpl::PreLoad
//
// Cache all weapons and upgrades
//
// Peds KB:                64,832 KB         7-312     306  296 valid, 10 not so valid               219   KB/model             4.45/MB
// Weapons KB:             470               321-372   52   39 valid, 3 invalid(329,332,340)         470   KB all weapons
// Upgrades KB:            2,716             1000-1193 194  all valid                              2,716   KB all upgrades
// Vehicles(400-499) KB:   14,622                                                                    140   KB/model             7/MB
// Vehicles(500-599) KB:   14,888
//
///////////////////////////////////////////////////////////////
void CModelCacheManagerImpl::PreLoad ( void )
{
    if ( m_bDonePreLoad )
        return;

    m_bDonePreLoad = true;

    CTickCount startTicks = CTickCount::Now ();
#if 0
    for ( uint i = 321 ; i <= 372 ; i++ )
    {
        if ( CClientPedManager::IsValidWeaponModel ( i ) )
            AddModelRefCount ( i );
    }
#endif
    m_pGame->GetStreaming()->LoadAllRequestedModels ( false );

    // Get current limits
    int bSlowMethod = GetApplicationSettingInt( DIAG_PRELOAD_UPGRADES_SLOW );
    int iLowestUnsafeUpgrade = GetApplicationSettingInt( DIAG_PRELOAD_UPGRADES_LOWEST_UNSAFE );
    SetApplicationSetting( DIAG_CRASH_EXTRA_MSG, "** AUTO FIXING CRASH (Step 1/2) **\n\n** Please continue and connect to a server **" );

    // Crashed during previous PreLoad?
    if ( WatchDogIsSectionOpen( WD_SECTION_PRELOAD_UPGRADES ) )
    {
        AddReportLog( 8545, SString( "PreLoad Upgrades - Crash detect - bSlowMethod:%d  iLowestUnsafeUpgrade:%d", bSlowMethod, iLowestUnsafeUpgrade ) );
        iLowestUnsafeUpgrade = GetApplicationSettingInt( DIAG_PRELOAD_UPGRADE_ATTEMPT_ID );
        bSlowMethod = 1;
        SetApplicationSettingInt( DIAG_PRELOAD_UPGRADES_LOWEST_UNSAFE, iLowestUnsafeUpgrade );
        SetApplicationSettingInt( DIAG_PRELOAD_UPGRADES_SLOW, bSlowMethod );
        SetApplicationSetting( DIAG_CRASH_EXTRA_MSG, "** AUTO FIXING CRASH (Step 2/2) **\n\n** Please continue and connect to a server **" );
    }

    if ( iLowestUnsafeUpgrade == 0 )
        iLowestUnsafeUpgrade = 1194;

    // PreLoad upgrades
    WatchDogBeginSection( WD_SECTION_PRELOAD_UPGRADES );
    {
        for ( int i = 1000 ; i < iLowestUnsafeUpgrade ; i++ )
        {
            if ( bSlowMethod )
                SetApplicationSettingInt( DIAG_PRELOAD_UPGRADE_ATTEMPT_ID, i );
            AddModelRefCount ( i );
            if ( bSlowMethod )
                m_pGame->GetStreaming()->LoadAllRequestedModels ( false );
        }
        m_pGame->GetStreaming()->LoadAllRequestedModels ( false );
    }
    WatchDogCompletedSection( WD_SECTION_PRELOAD_UPGRADES );
    SetApplicationSetting( DIAG_CRASH_EXTRA_MSG, "" );

    // Report if LowestUnsafeUpgrade has fallen
    int iPrevHiScore = GetApplicationSettingInt( DIAG_PRELOAD_UPGRADES_HISCORE );
    SetApplicationSettingInt( DIAG_PRELOAD_UPGRADES_HISCORE, iLowestUnsafeUpgrade );
    if ( iPrevHiScore > iLowestUnsafeUpgrade )
        AddReportLog( 8544, SString( "PreLoad Upgrades - LowestUnsafeUpgrade fallen from %d to %d", iPrevHiScore, iLowestUnsafeUpgrade ) );

    CTickCount deltaTicks = CTickCount::Now () - startTicks;
    OutputDebugLine ( SString ( "CModelCacheManagerImpl::PreLoad completed in %d ms", deltaTicks.ToInt () ) );
}