diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /gcsdk/accountdetails.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'gcsdk/accountdetails.cpp')
| -rw-r--r-- | gcsdk/accountdetails.cpp | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/gcsdk/accountdetails.cpp b/gcsdk/accountdetails.cpp new file mode 100644 index 0000000..507b9d1 --- /dev/null +++ b/gcsdk/accountdetails.cpp @@ -0,0 +1,721 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Holds the CAccountDetails class. +// +//============================================================================= + +#include "stdafx.h" +#include "accountdetails.h" +#include "rtime.h" +#include "gcsdk_gcmessages.pb.h" + +#include "memdbgon.h" // needs to be the last include in the file + +namespace GCSDK +{ +GCConVar cv_account_details_cache_time( "account_details_cache_time", "600" ); +GCConVar cv_account_details_failure_cache_time( "account_details_failure_cache_time", "10" ); +GCConVar account_details_timeout( "account_details_timeout", "10" ); +GCConVar cv_persona_name_cache_time( "persona_name_cache_time", "60" ); +GCConVar cv_persona_name_failure_cache_time( "persona_name_failure_cache_time", "10" ); +GCConVar cv_persona_name_batch_size( "persona_name_batch_size", "100" ); +GCConVar persona_name_timeout( "persona_name_timeout", "10" ); + +const char *kszAccountDetailsKey = "AccountDetails-v001"; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CAccountDetails::CAccountDetails() +: m_rtimeCached( CRTime::RTime32TimeCur() ), + m_bValid( false ), + m_bPublicProfile( false ), + m_bVacBanned( false ), + m_bCyberCafe( false ), + m_bSchoolAccount( false ), + m_bFreeTrialAccount( false ), + m_bSubscribed( false ), + m_bLowViolence( false ), + m_bLimited( false ), + m_bAccountLocked( false ), + m_bCommunityBanned( false ), + m_bTradeBanned( false ), + m_bIsSteamGuardEnabled( false ), + m_bIsPhoneVerified( false ), + m_bIsTwoFactorAuthEnabled( false ), + m_bIsPhoneIdentifying( false ), + m_unPackage( 0 ), + m_rtimeVACBanEnd( 0 ), + m_unSteamLevel( 0 ), + m_unFriendCount( 0 ), + m_rtimeAccountCreated( 0 ), + m_rtimeTwoFactorEnabled( 0 ), + m_rtimePhoneVerified( 0 ), + m_unPhoneID( 0 ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize a fresh CAccountDetails with data from Steam +//----------------------------------------------------------------------------- +void CAccountDetails::Init( CGCSystemMsg_GetAccountDetails_Response &msgResponse ) +{ + m_bValid = true; + m_sAccountName = msgResponse.account_name().c_str(); + m_bPublicProfile = msgResponse.is_profile_public(); + m_bPublicInventory = msgResponse.is_inventory_public(); + m_bVacBanned = msgResponse.is_vac_banned(); + m_bCyberCafe = msgResponse.is_cyber_cafe(); + m_bSchoolAccount = msgResponse.is_school_account(); + m_bFreeTrialAccount = msgResponse.is_free_trial_account(); + m_bSubscribed = msgResponse.is_subscribed(); + m_bLowViolence = msgResponse.is_low_violence(); + m_bLimited = msgResponse.is_limited(); + m_bAccountLocked = msgResponse.is_account_locked_down(); + m_bCommunityBanned = msgResponse.is_community_banned(); + m_bTradeBanned = msgResponse.is_trade_banned(); + m_unPackage = msgResponse.package(); + m_rtimeVACBanEnd = msgResponse.suspension_end_time(); + m_sCurrency = msgResponse.currency().c_str(); + m_unSteamLevel = msgResponse.steam_level(); + m_unFriendCount = msgResponse.friend_count(); + m_rtimeAccountCreated = msgResponse.account_creation_time(); + m_bIsSteamGuardEnabled = msgResponse.is_steamguard_enabled(); + m_bIsPhoneVerified = msgResponse.is_phone_verified(); + m_bIsTwoFactorAuthEnabled = msgResponse.is_two_factor_auth_enabled(); + m_bIsPhoneIdentifying = msgResponse.is_phone_identifying(); + m_rtimeTwoFactorEnabled = msgResponse.two_factor_enabled_time(); + m_rtimePhoneVerified = msgResponse.phone_verification_time(); + m_unPhoneID = msgResponse.phone_id(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if it's time to remove this entry from the cache +//----------------------------------------------------------------------------- +bool CAccountDetails::BIsExpired() const +{ + int nCacheSeconds = BIsValid() ? cv_account_details_cache_time.GetInt() : cv_account_details_failure_cache_time.GetInt(); + + return m_rtimeCached + nCacheSeconds < CRTime::RTime32TimeCur(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reverts this to an invalid record +//----------------------------------------------------------------------------- +void CAccountDetails::Reset() +{ + m_bValid = false; + m_rtimeCached = CRTime::RTime32TimeCur(); +} + + +#ifdef DBGFLAG_VALIDATE +//----------------------------------------------------------------------------- +// Purpose: Claims all the memory for the AccountDetails object +//----------------------------------------------------------------------------- +void CAccountDetails::Validate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + ValidateObj( m_sAccountName ); +} +#endif // DBGFLAG_VALIDATE + + +//----------------------------------------------------------------------------- +// Purpose: Sends a message to Steam to get a CAccountDetails object +//----------------------------------------------------------------------------- +class CGCJobSendGetAccountDetailsRequest : public CGCJob +{ + CAccountDetailsManager *m_pManager; + CSteamID m_SteamID; + +public: + CGCJobSendGetAccountDetailsRequest( CGCBase *pGC, CAccountDetailsManager *pManager, const CSteamID &steamID ) + : CGCJob( pGC ), m_pManager( pManager ), m_SteamID( steamID ) {} + virtual bool BYieldingRunGCJob() + { + // Yield immediately to be sure that the calling job gets in the wakeup list + BYield(); + + // These requests should come back very quickly, so if they don't we shouldn't wait very long + // jamming up the system + SetJobTimeout( account_details_timeout.GetInt() ); + + // Get an empty account details object + CAccountDetails *pAccount = m_pManager->m_hashAccountDetailsCache.PvRecordFind( m_SteamID.GetAccountID() ); + if ( NULL == pAccount ) + { + pAccount = m_pManager->m_hashAccountDetailsCache.PvRecordInsert( m_SteamID.GetAccountID() ); + } + else + { + // If the record isn't expired, why is it there? + Assert( pAccount->BIsExpired() ); + pAccount->Reset(); + } + + CProtoBufMsg< CGCSystemMsg_GetAccountDetails > msgReqeust( k_EGCMsgGetAccountDetails ); + CProtoBufMsg< CGCSystemMsg_GetAccountDetails_Response > msgReply; + msgReqeust.Body().set_steamid( m_SteamID.ConvertToUint64() ); + msgReqeust.Body().set_appid( GGCBase()->GetAppID() ); + msgReqeust.ExpectingReply( GJobCur().GetJobID() ); + + // try to get the account details at most 2 times + const int kMaxTries = 2; + for ( int iTries = 0; iTries < kMaxTries; iTries++ ) + { + if( !m_pGC->BSendSystemMessage( msgReqeust ) ) + { + EmitWarning( SPEW_GC, 2, "Unable to send GetAccountDetails system message\n" ); + continue; + } + + // All of our request messages are identical, so if we get our replies + // mixed up, it's OK. Bypass the system used to protect us against + // mismatched replies. + ClearFailedToReceivedMsgType( k_EGCMsgGetAccountDetailsResponse ); + + // Wait for the reply + if( !BYieldingWaitForMsg( &msgReply, k_EGCMsgGetAccountDetailsResponse ) ) + { + EmitWarning( SPEW_GC, 2, "Timeout waiting for GetAccountDetails reply for SteamID %s\n", m_SteamID.Render() ); + continue; + } + + if ( k_EResultOK != msgReply.GetEResult() ) + { + EmitInfo( SPEW_GC, 4, 4, "GetAccountDetails request failed with result %d for SteamID %s\n", msgReply.GetEResult(), m_SteamID.Render() ); + break; + } + + Assert( msgReply.Body().eresult_deprecated() == k_EResultOK ); + + // Sanity check the response + if ( msgReply.Body().has_accountid() && msgReply.Body().accountid() != m_SteamID.GetAccountID() ) + { + static bool bHasAlerted = false; + if ( !bHasAlerted ) + { + GGCBase()->PostAlert( k_EAlertTypeInfo, true, CFmtStr( "GetAccountDetails got a response for account %d, but we were expecting a response for account %s\n", msgReply.Body().accountid(), m_SteamID.Render() ) ); + bHasAlerted = true; + } + + EmitError( SPEW_GC, "GetAccountDetails got a response for account %d, but we were expecting a response for account %s\n", msgReply.Body().accountid(), m_SteamID.Render() ); + break; + } + + // All responses should have this + if ( !msgReply.Body().has_account_name() ) + { + EmitError( SPEW_GC, "GetAccountDetails got a response with missing fields for SteamID %s\n", m_SteamID.Render() ); + break; + } + + pAccount->Init( msgReply.Body() ); + m_pManager->CachePersonaName( CSteamID( m_SteamID ), msgReply.Body().persona_name().c_str() ); + + // We got a response, so we shouldn't try again + break; + } + + m_pManager->WakeWaitingAccountDetailsJobs( m_SteamID ); + return true; + } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CCachedPersonaName::CCachedPersonaName() + : m_rtimeCached( 0 ) // This initialization value is important because it makes it expired on creation, + // and the rest of the code will only ask Steam for a name if the cached entry is expired + , m_nLoading( 0 ) + , m_bPreloading( false ) +{ +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CCachedPersonaName::~CCachedPersonaName() +{ + Assert( !BIsLoading() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the newly retrieved persona name +//----------------------------------------------------------------------------- +void CCachedPersonaName::Init( const char *pchPersonaName ) +{ + m_sPersonaName = pchPersonaName; + m_rtimeCached = CRTime::RTime32TimeCur(); + m_bPreloading = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if it's time to remove this entry from the cache +//----------------------------------------------------------------------------- +bool CCachedPersonaName::BIsExpired() const +{ + int nCacheSeconds = BIsValid() ? cv_persona_name_cache_time.GetInt() : cv_persona_name_failure_cache_time.GetInt(); + + return m_rtimeCached + nCacheSeconds < CRTime::RTime32TimeCur(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns true if there is an actual cached name +//----------------------------------------------------------------------------- +bool CCachedPersonaName::BIsValid() const +{ + return !m_sPersonaName.IsEmpty(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reverts this to an invalid record +//----------------------------------------------------------------------------- +void CCachedPersonaName::Reset() +{ + m_sPersonaName.Clear(); + m_rtimeCached = CRTime::RTime32TimeCur(); + m_bPreloading = false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the cached string +//----------------------------------------------------------------------------- +const char *CCachedPersonaName::GetPersonaName() const +{ + return BIsValid() ? m_sPersonaName.Get() : "[unknown]"; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns if this name is loading +//----------------------------------------------------------------------------- +bool CCachedPersonaName::BIsLoading() const +{ + return m_nLoading > 0 || m_bPreloading; +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets that this name has been preloaded +//----------------------------------------------------------------------------- +void CCachedPersonaName::SetPreloading() +{ + m_bPreloading = true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets that a job is waiting for this name to be loaded +//----------------------------------------------------------------------------- +void CCachedPersonaName::AddLoadingRef() +{ + m_nLoading++; +} + + +//----------------------------------------------------------------------------- +// Purpose: Releases the loading ref +//----------------------------------------------------------------------------- +void CCachedPersonaName::ReleaseLoadingRef() +{ + DbgVerify( --m_nLoading >= 0 ); +} + + +#ifdef DBGFLAG_VALIDATE +//----------------------------------------------------------------------------- +// Purpose: Claims all the memory for the CCachedPersonaName object +//----------------------------------------------------------------------------- +void CCachedPersonaName::Validate( CValidator &validator, const char *pchName ) +{ + VALIDATE_SCOPE(); + ValidateObj( m_sPersonaName ); +} +#endif // DBGFLAG_VALIDATE + + +//----------------------------------------------------------------------------- +// Purpose: Sends a message to Steam to get a CAccountDetails object +//----------------------------------------------------------------------------- +class CGCJobSendGetPersonaNamesRequest : public CGCJob +{ + CAccountDetailsManager *m_pManager; + CUtlVector<CSteamID> m_vecSteamIDs; + +public: + CGCJobSendGetPersonaNamesRequest( CGCBase *pGC, CAccountDetailsManager *pManager, CUtlVector<CSteamID> &vecSteamIDs ) + : CGCJob( pGC ), m_pManager( pManager ) + { + m_vecSteamIDs.Swap( vecSteamIDs ); + } + + virtual bool BYieldingRunGCJob() + { + // Yield immediately to be sure that the calling job gets in the wakeup list + BYield(); + + // These requests should come back very quickly, so if they don't we shouldn't wait very long + // jamming up the system + SetJobTimeout( persona_name_timeout.GetInt() ); + + CProtoBufMsg< CMsgGCGetPersonaNames > msgReqeust( k_EGCMsgGetPersonaNames ); + msgReqeust.ExpectingReply( GJobCur().GetJobID() ); + + FOR_EACH_VEC( m_vecSteamIDs, i ) + { + msgReqeust.Body().add_steamids( m_vecSteamIDs[i].ConvertToUint64() ); + } + + CProtoBufMsg< CMsgGCGetPersonaNames_Response > msgReply; + if( !m_pGC->BSendSystemMessage( msgReqeust ) || + !BYieldingWaitForMsg( &msgReply, k_EGCMsgGetPersonaNamesResponse ) ) + { + FOR_EACH_VEC( m_vecSteamIDs, i ) + { + m_pManager->CachePersonaNameFailure( m_vecSteamIDs[i] ); + } + + //if we are shutting down, don't bother reporting this issue, we know we won't be able to get persona names + if( !GGCBase()->GetIsShuttingDown() ) + { + EmitWarning( SPEW_GC, 2, "GetPersonaNames request failed for %d IDs:", m_vecSteamIDs.Count() ); + FOR_EACH_VEC( m_vecSteamIDs, nID ) + { + EmitWarning( SPEW_GC, 2, " %s", m_vecSteamIDs[ nID ].Render() ); + } + EmitWarning( SPEW_GC, 2, "\n" ); + } + } + else + { + for ( int i = 0; i < msgReply.Body().succeeded_lookups_size(); i++ ) + { + const CMsgGCGetPersonaNames_Response_PersonaName &result = msgReply.Body().succeeded_lookups( i ); + m_pManager->CachePersonaName( CSteamID( result.steamid() ), result.persona_name().c_str() ); + } + for ( int i = 0; i < msgReply.Body().failed_lookup_steamids_size(); i++ ) + { + m_pManager->CachePersonaNameFailure( CSteamID( msgReply.Body().failed_lookup_steamids( i ) ) ); + } + } + + FOR_EACH_VEC( m_vecSteamIDs, i ) + { + m_pManager->WakeWaitingPersonaNameJobs( m_vecSteamIDs[i] ); + } + return true; + } +}; + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CAccountDetailsManager::CAccountDetailsManager() + : m_hashAccountDetailsCache( k_nAccountDetailsRunInterval / k_cMicroSecPerShellFrame ) + , m_hashPersonaNameCache( k_nAccountDetailsRunInterval / k_cMicroSecPerShellFrame ) +{ + m_hashAccountDetailsCache.Init( k_cAccountDetailsInit, k_cBucketAccountDetails ); + m_hashPersonaNameCache.Init( k_cAccountDetailsInit, k_cBucketAccountDetails ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Work to be done once per frame +//----------------------------------------------------------------------------- +void CAccountDetailsManager::MarkFrame() +{ + m_hashAccountDetailsCache.StartFrameSchedule( true ); + m_hashPersonaNameCache.StartFrameSchedule( true ); + SendBatchedPersonaNamesRequest(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets a CAccountDetails object +//----------------------------------------------------------------------------- +CAccountDetails *CAccountDetailsManager::YieldingGetAccountDetails( const CSteamID &steamID, bool bForceReload ) +{ + AssertRunningJob(); + if( !steamID.IsValid() || !steamID.BIndividualAccount() ) + return NULL; + + // Check the local cache + CAccountDetails *pAccountDetails = NULL; + if ( BFindAccountDetailsInLocalCache( steamID, &pAccountDetails ) ) + { + if ( pAccountDetails && bForceReload ) + { + // Clear it, continue with fresh load + m_hashAccountDetailsCache.Remove( pAccountDetails ); + } + else + { + return pAccountDetails; + } + } + + // Not in the local cache, ask Steam + int iMapIndex = m_mapQueuedAccountDetailsRequests.Find( steamID ); + if ( !m_mapQueuedAccountDetailsRequests.IsValidIndex( iMapIndex ) ) + { + iMapIndex = m_mapQueuedAccountDetailsRequests.Insert( steamID ); + CGCJobSendGetAccountDetailsRequest *pJob = new CGCJobSendGetAccountDetailsRequest( GGCBase(), this, steamID ); + pJob->StartJob( NULL ); + } + + m_mapQueuedAccountDetailsRequests[iMapIndex].AddToTail( GJobCur().GetJobID() ); + GJobCur().BYieldingWaitForWorkItem(); + + // Check again, if it's not there then it's not there + BFindAccountDetailsInLocalCache( steamID, &pAccountDetails ); + return pAccountDetails; +} + + +//----------------------------------------------------------------------------- +// Purpose: Finds an AccountDetails object in the local cache. Returns true +// if it was found, false if it should be checked remotely +//----------------------------------------------------------------------------- +bool CAccountDetailsManager::BFindAccountDetailsInLocalCache( const CSteamID &steamID, CAccountDetails **ppAccount ) +{ + CAccountDetails *pAccountLocal = m_hashAccountDetailsCache.PvRecordFind( steamID.GetAccountID() ); + if( NULL == pAccountLocal || pAccountLocal->BIsExpired() ) + return false; + + *ppAccount = pAccountLocal->BIsValid() ? pAccountLocal : NULL; + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Wakes any jobs waiting on this result +//----------------------------------------------------------------------------- +void CAccountDetailsManager::WakeWaitingAccountDetailsJobs( const CSteamID &steamID ) +{ + int iMapIndex = m_mapQueuedAccountDetailsRequests.Find( steamID ); + if ( !m_mapQueuedAccountDetailsRequests.IsValidIndex( iMapIndex ) ) + return; + + CCopyableUtlVector<JobID_t> &vecJobsWaiting = m_mapQueuedAccountDetailsRequests[iMapIndex]; + FOR_EACH_VEC( vecJobsWaiting, i ) + { + GGCBase()->GetJobMgr().BRouteWorkItemCompletedDelayed( vecJobsWaiting[i], false ); + } + m_mapQueuedAccountDetailsRequests.RemoveAt( iMapIndex ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets a persona name for a user +//----------------------------------------------------------------------------- +const char *CAccountDetailsManager::YieldingGetPersonaName( const CSteamID &steamID ) +{ + VPROF_BUDGET( "CAccountDetailsManager::YieldingGetPersonaName", VPROF_BUDGETGROUP_STEAM ); + + AssertRunningJob(); + + if( !steamID.IsValid() || !steamID.BIndividualAccount() ) + return "[unknown]"; + + // Check the local cache + CCachedPersonaName *pPersonaName = FindOrCreateCachedPersonaName( steamID ); + if ( !pPersonaName->BIsExpired() ) + return pPersonaName->GetPersonaName(); + + // Not in the local cache, ask Steam + pPersonaName->AddLoadingRef(); + + // Queue the request and start a lookup job if we have enough pending + int iMapIndex = m_mapQueuedPersonaNameRequests.Find( steamID ); + if ( !m_mapQueuedPersonaNameRequests.IsValidIndex( iMapIndex ) ) + { + iMapIndex = m_mapQueuedPersonaNameRequests.Insert( steamID ); + m_vecPendingPersonaNameLookups.AddToTail( steamID ); + if ( m_vecPendingPersonaNameLookups.Count() >= cv_persona_name_batch_size.GetInt() ) + { + SendBatchedPersonaNamesRequest(); + } + } + + m_mapQueuedPersonaNameRequests[iMapIndex].AddToTail( GJobCur().GetJobID() ); + GJobCur().BYieldingWaitForWorkItem(); + + // At this point we'll either have a persona name or we won't + pPersonaName->ReleaseLoadingRef(); + return pPersonaName->GetPersonaName(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Let's the system know that we should load the persona name for this +// user, but does not block on it +//----------------------------------------------------------------------------- +void CAccountDetailsManager::PreloadPersonaName( const CSteamID &steamID ) +{ + if( !steamID.IsValid() || !steamID.BIndividualAccount() ) + return; + + // See if we already have it + CCachedPersonaName *pCachedName = FindOrCreateCachedPersonaName( steamID ); + if ( !pCachedName->BIsExpired() || pCachedName->BIsLoading() ) + return; + + // Queue the request and start a lookup job if we have enough pending + pCachedName->SetPreloading(); + m_mapQueuedPersonaNameRequests.Insert( steamID ); + m_vecPendingPersonaNameLookups.AddToTail( steamID ); + if ( m_vecPendingPersonaNameLookups.Count() >= cv_persona_name_batch_size.GetInt() ) + { + SendBatchedPersonaNamesRequest(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sends a batch of persona name requests +//----------------------------------------------------------------------------- +void CAccountDetailsManager::SendBatchedPersonaNamesRequest() +{ + if ( 0 == m_vecPendingPersonaNameLookups.Count() ) + return; + + // Start the job. This swaps out our buffer with an empty one + CGCJobSendGetPersonaNamesRequest *pJob = new CGCJobSendGetPersonaNamesRequest( GGCBase(), this, m_vecPendingPersonaNameLookups ); + pJob->StartJob( NULL ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Caches a persona name +//----------------------------------------------------------------------------- +void CAccountDetailsManager::CachePersonaName( const CSteamID &steamID, const char *pchPersonaName ) +{ + CCachedPersonaName *pCachedPersonaName = FindOrCreateCachedPersonaName( steamID ); + pCachedPersonaName->Init( pchPersonaName ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Remembers that we failed to cache a persona name +//----------------------------------------------------------------------------- +void CAccountDetailsManager::CachePersonaNameFailure( const CSteamID &steamID ) +{ + CCachedPersonaName *pCachedPersonaName = FindOrCreateCachedPersonaName( steamID ); + pCachedPersonaName->Reset(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Purges a specific persona name from the cache +//----------------------------------------------------------------------------- +void CAccountDetailsManager::ClearCachedPersonaName( const CSteamID &steamID ) +{ + CCachedPersonaName *pPersonaNameLocal = m_hashPersonaNameCache.PvRecordFind( steamID.GetAccountID() ); + if( NULL != pPersonaNameLocal && !pPersonaNameLocal->BIsLoading() ) + { + m_hashPersonaNameCache.Remove( pPersonaNameLocal ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets a CCachedPersonaName record +//----------------------------------------------------------------------------- +CCachedPersonaName *CAccountDetailsManager::FindOrCreateCachedPersonaName( const CSteamID &steamID ) +{ + CCachedPersonaName *pPersonaName = m_hashPersonaNameCache.PvRecordFind( steamID.GetAccountID() ); + if ( NULL != pPersonaName ) + return pPersonaName; + else + return m_hashPersonaNameCache.PvRecordInsert( steamID.GetAccountID() ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Wakes any jobs waiting on this result +//----------------------------------------------------------------------------- +void CAccountDetailsManager::WakeWaitingPersonaNameJobs( const CSteamID &steamID ) +{ + int iMapIndex = m_mapQueuedPersonaNameRequests.Find( steamID ); + if ( !m_mapQueuedPersonaNameRequests.IsValidIndex( iMapIndex ) ) + return; + + CCopyableUtlVector<JobID_t> &vecJobsWaiting = m_mapQueuedPersonaNameRequests[iMapIndex]; + FOR_EACH_VEC( vecJobsWaiting, i ) + { + GGCBase()->GetJobMgr().BRouteWorkItemCompletedDelayed( vecJobsWaiting[i], false ); + } + m_mapQueuedPersonaNameRequests.RemoveAt( iMapIndex ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Purges old data from the cache. Returns true if there is more +// work to do +//----------------------------------------------------------------------------- +bool CAccountDetailsManager::BExpireRecords( CLimitTimer &limitTimer ) +{ + VPROF_BUDGET( "Expire account details", VPROF_BUDGETGROUP_STEAM ); + + for ( CAccountDetails *pDetails = m_hashAccountDetailsCache.PvRecordRun(); NULL != pDetails; pDetails = m_hashAccountDetailsCache.PvRecordRun() ) + { + if ( pDetails->BIsExpired() ) + { + m_hashAccountDetailsCache.Remove( pDetails ); + } + + if ( limitTimer.BLimitReached() ) + return true; + } + + for ( CCachedPersonaName *pPersonaName = m_hashPersonaNameCache.PvRecordRun(); NULL != pPersonaName; pPersonaName = m_hashPersonaNameCache.PvRecordRun() ) + { + if ( pPersonaName->BIsExpired() && !pPersonaName->BIsLoading() ) + { + m_hashPersonaNameCache.Remove( pPersonaName ); + } + + if ( limitTimer.BLimitReached() ) + return true; + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Prints status +//----------------------------------------------------------------------------- +void CAccountDetailsManager::Dump() const +{ + int nJobsWaiting = 0; + FOR_EACH_MAP_FAST( m_mapQueuedAccountDetailsRequests, iMap ) + { + nJobsWaiting += m_mapQueuedAccountDetailsRequests[iMap].Count(); + } + + EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\tAccount Details: %d cached, %d lookups in flight, %d jobs waiting\n", m_hashAccountDetailsCache.Count(), m_mapQueuedAccountDetailsRequests.Count(), nJobsWaiting ); + + nJobsWaiting = 0; + FOR_EACH_MAP_FAST( m_mapQueuedPersonaNameRequests, iMap ) + { + nJobsWaiting += m_mapQueuedPersonaNameRequests[iMap].Count(); + } + + EmitInfo( SPEW_CONSOLE, SPEW_ALWAYS, LOG_ALWAYS, "\tPersona Names: %d cached, %d lookups in flight, %d jobs waiting\n", m_hashPersonaNameCache.Count(), m_mapQueuedPersonaNameRequests.Count(), nJobsWaiting ); +} + +} // namespace GCSDK |