csgo-2018-source/public/gcsdk/gcbase.h
2021-07-24 21:11:47 -07:00

304 lines
12 KiB
C++

//====== Copyright (c), Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#ifndef GCBASE_H
#define GCBASE_H
#ifdef _WIN32
#pragma once
#endif
#include "gamecoordinator/igamecoordinator.h"
#include "gamecoordinator/igamecoordinatorhost.h"
#include "tier1/utlallocation.h"
#include "gcmsg.h"
#include "jobmgr.h"
#include "tier1/thash.h"
#include "tier1/utlsortvector.h"
#include "http.h"
#include "language.h"
#include "accountdetails.h"
class CGCMsgGetSystemStatsResponse;
namespace GCSDK
{
class CGCSession;
class CGCUserSession;
class CGCGSSession;
class CGCSharedObjectCache;
class CSharedObject;
class CAccountDetails;
struct PackageLicense_t
{
uint32 m_unPackageID;
RTime32 m_rtimeCreated;
};
class CGCBase : public IGameCoordinator
{
public:
CGCBase( );
virtual ~CGCBase();
// Hooks to extend the base behaviors of the IGameCoordinator interface
virtual bool OnInit() { return true; }
virtual bool OnMainLoopOncePerFrame( CLimitTimer &limitTimer ) { return false; }
virtual bool OnMainLoopUntilFrameCompletion( CLimitTimer &limitTimer ) { return false; }
virtual void OnUninit() {}
// returns true if this function handled the message
virtual bool OnMessageFromClient( const CSteamID & senderID, uint32 unMsgType, void *pubData, uint32 cubData ) { return false; }
virtual void OnValidate( CValidator &validator, const char *pchName ) {}
virtual const char *LocalizeToken( const char *pchToken, ELanguage eLanguage, bool bReturnTokenIfNotFound = true ) { return ""; }
// Life cycle management functions
// Called to do any yielding initialization work before reporting as fully operational
virtual bool BYieldingFinishStartup() = 0;
// Called to do any yielding work immediately after becoming full operational
virtual bool BYieldingPostStartup() = 0;
// Call to report that we're fully operational
void SetStartupComplete( bool bSuccess );
// Called to do any yielding work before reporting as ready to shutdown
virtual void YieldingGracefulShutdown() = 0;
virtual CGCUserSession *CreateUserSession( const CSteamID & steamID, CGCSharedObjectCache *pSOCache ) const;
virtual CGCGSSession *CreateGSSession( const CSteamID & steamID, CGCSharedObjectCache *pSOCache, uint32 unServerAddr, uint16 usServerPort ) const;
virtual void YieldingSessionStartPlaying( CGCUserSession *pSession ) {}
virtual void YieldingSessionStopPlaying( CGCUserSession *pSession ) {}
virtual void YieldingSessionStartServer( CGCGSSession *pSession ) {}
virtual void YieldingSessionStopServer( CGCGSSession *pSession ) {}
virtual void YieldingSOCacheLoaded( CGCSharedObjectCache *pSOCache );
virtual void YieldingPreTestSetup() {}
// cache management
CGCSharedObjectCache *YieldingGetLockedSOCache( const CSteamID &steamID );
CGCSharedObjectCache *YieldingFindOrLoadSOCache( const CSteamID &steamID );
CGCSharedObjectCache *FindSOCache( const CSteamID & steamID ); // non-yielding, but may return NULL if the cache exists but is not loaded
bool UnloadUnusedCaches( uint32 unMaxCacheCount, CLimitTimer *pLimitTimer = NULL );
void YieldingReloadCache( CGCSharedObjectCache *pSOCache );
virtual CGCSharedObjectCache *CreateSOCache( const CSteamID &steamID );
CGCUserSession *YieldingGetLockedUserSession( const CSteamID & steamID );
CGCUserSession *FindUserSession( const CSteamID & steamID ) const;
CGCGSSession *YieldingGetLockedGSSession( const CSteamID & steamID );
CGCGSSession *YieldingFindOrCreateGSSession( const CSteamID & steamID, uint32 unServerAddr, uint16 usServerPort, const uint8 *pubVarData, uint32 cubVarData );
CGCGSSession *FindGSSession( const CSteamID & steamID ) const;
CGCSession *YieldingRequestSession( const CSteamID & steamID );
bool BYieldingIsOnline( const CSteamID & steamID );
bool BYieldingSendHTTPRequest( CHTTPRequest *pRequest, CHTTPResponse *pResponse );
bool BYieldingSendHTTPRequest( CHTTPRequest *pRequest, KeyValues *pkvResponse );
bool BSendWebApiRegistration();
int GetSOCacheCount() const;
#ifdef DEBUG
bool IsSOCached( CSharedObject *pObj, int nTypeID );
#endif
int GetUserSessionCount() const;
int GetGSSessionCount() const;
void SetIsShuttingDown( bool bIsShuttingDown ) { m_bIsShuttingDown = true; }
bool GetIsShuttingDown() const { return m_bIsShuttingDown; }
// Iterate over sessions
// WARNING: Don't yield between GetFirst*/GetNext*. Use caution when using
// these any time you might have tens of thousands of sessions to iterate through.
CGCUserSession **GetFirstUserSession() { return m_hashUserSessions.PvRecordFirst(); }
CGCUserSession **GetNextUserSession( CGCUserSession **pUserSession ) { return m_hashUserSessions.PvRecordNext( pUserSession ); }
CGCGSSession **GetFirstGSSession() { return m_hashGSSessions.PvRecordFirst(); }
CGCGSSession **GetNextGSSession( CGCGSSession **pGSSession ) { return m_hashGSSessions.PvRecordNext( pGSSession ); }
typedef CUtlSortVector< CGCGSSession *, CUtlSortVectorDefaultLess< CGCGSSession * >, CCopyableUtlVector< CGCGSSession * > > CGCGSSessionSortedVector_t;
CGCGSSessionSortedVector_t const *GetGSSessionVectorByType( int serverType );
// This can cause the server pointer to change between lists, call it here
void SetGSServerType( CGCGSSession *pGSSession, int serverType );
AppId_t GetAppID() const { return m_unAppID; }
bool BIsStartupComplete() const { return m_bStartupComplete; }
CJobMgr &GetJobMgr() { return m_JobMgr; }
CSteamID YieldingGuessSteamIDFromInput( const char *pchInput );
bool BYieldingRecordSupportAction( const CSteamID & actorID, const CSteamID & targetID, const char *pchData, const char *pchNote );
void PostAlert( EAlertType eAlertType, bool bIsCritical, const char *pchAlertText, const CUtlVector< CUtlString > *pvecExtendedInfo = NULL, bool bAlsoSpew = true );
CAccountDetails *YieldingGetAccountDetails( const CSteamID & steamID );
bool BYieldingGetAccountLicenses( const CSteamID & steamID, CUtlVector< PackageLicense_t > & vecPackages );
bool BYieldingLookupAccount( EAccountFindType eFindType, const char *pchInput, CUtlVector< CSteamID > *prSteamIDs );
bool BYieldingAddFreeLicense( const CSteamID & steamID, uint32 unPackageID, uint32 unIPPublic = 0, const char *pchStoreCountryCode = NULL );
bool BSendGCMsgToClient( const CSteamID & steamIDTarget, const CGCMsgBase& msg );
bool BSendGCMsgToClient( const CSteamID & steamIDTarget, const IProtoBufMsg& msg );
bool BSendSystemMessage( const CGCMsgBase& msg );
bool BSendSystemMessage( const IProtoBufMsg& msg );
bool BSendGCInterMessage( AppId_t unAppID, const IProtoBufMsg &msg );
bool BReplyToMessage( CGCMsgBase &msgOut, const CGCMsgBase &msgIn );
bool BReplyToMessage( IProtoBufMsg &msgOut, const IProtoBufMsg &msgIn );
const char *GetPath() const { return m_sPath; }
virtual const char *GetSteamAPIKey();
void QueueStartPlaying( const CSteamID & steamID, const CSteamID & gsSteamID, uint32 unServerAddr, uint16 usServerPort, const uint8 *pubVarData, uint32 cubVarData );
void YieldingExecuteNextStartPlaying();
bool BIsInLogonSurge() const;
void YieldingStopPlaying( const CSteamID & steamID );
void YieldingStartGameserver( const CSteamID & steamID, uint32 unServerAddr, uint16 usServerPort, const uint8 *pubVarData, uint32 cubVarData );
void YieldingStopGameserver( const CSteamID & steamID );
bool BIsSOCacheBeingLoaded( const CSteamID & steamID ) const { return m_rbtreeSOCachesBeingLoaded.Find( steamID ) != m_rbtreeSOCachesBeingLoaded.InvalidIndex(); }
bool BYieldingLockSteamID( const CSteamID &steamID );
bool BYieldingLockSteamIDPair( const CSteamID &steamIDA, const CSteamID &steamIDB );
bool BLockSteamIDImmediate( const CSteamID &steamID );
void UnlockSteamID( const CSteamID &steamID );
bool IsSteamIDLocked( const CSteamID &steamID );
bool IsSteamIDLockedByJob( const CSteamID &steamID, const CJob *pJob );
bool IsSteamIDUnlockedOrLockedByCurJob( const CSteamID &steamID );
CJob *PJobHoldingLock( const CSteamID &steamID );
const CLock *FindLock( const CSteamID &steamID );
void DumpLocks( bool bFull, int nMax = 10 );
void DumpJobs( int nMax ) const;
virtual void Dump() const;
void VerifySOCacheLRU();
void SetProfilingEnabled( bool bEnabled );
void SetDumpVprofImbalances( bool bEnabled );
bool GetVprofImbalances();
bool YieldingWritebackDirtyCaches( uint32 unSecondToDelayWrite );
void AddCacheToWritebackQueue( CGCSharedObjectCache *pSOCache );
bool BYieldingRetrieveCacheVersion( CGCSharedObjectCache *pSOCache );
void AddCacheToVersionChangedList( CGCSharedObjectCache *pSOCache );
const char *GetCDNURL() const;
struct GCMemcachedBuffer_t
{
const void *m_pubData;
int m_cubData;
};
struct GCMemcachedGetResult_t
{
bool m_bKeyFound; // true if the key was found
CUtlAllocation m_bufValue; // the value of the key
};
// Memcached access
bool BMemcachedSet( const char *pKey, const ::google::protobuf::Message &protoBufObj );
bool BMemcachedDelete( const char *pKey );
bool BYieldingMemcachedGet( const char *pKey, ::google::protobuf::Message &protoBufObj );
bool BMemcachedSet( const CUtlString &strKey, const CUtlBuffer &buf );
bool BMemcachedSet( const CUtlVector<CUtlString> &vecKeys, const CUtlVector<GCMemcachedBuffer_t> &vecValues );
bool BMemcachedDelete( const CUtlString &strKey );
bool BMemcachedDelete( const CUtlVector<CUtlString> &vecKeys );
bool BYieldingMemcachedGet( const CUtlString &strKey, GCMemcachedGetResult_t &result );
bool BYieldingMemcachedGet( const CUtlVector<CUtlString> &vecKeys, CUtlVector<GCMemcachedGetResult_t> &vecResults );
// IP location
bool BYieldingGetIPLocations( CUtlVector<uint32> &vecIPs, CUtlVector<CIPLocationInfo> &infos );
// Stats
virtual void SystemStats_Update( CGCMsgGetSystemStatsResponse &msgStats );
protected:
virtual bool BYieldingLoadSOCache( CGCSharedObjectCache *pSOCache );
void RemoveSOCache( const CSteamID & steamID );
void AddCacheToLRU( CGCSharedObjectCache * pSOCache );
void RemoveCacheFromLRU( CGCSharedObjectCache * pSOCache );
void SetStartupComplete() { m_bStartupComplete = true; }
private:
static void AssertCallbackFunc( const char *pchFile, int nLine, const char *pchMessage );
void UpdateSOCacheVersions();
// this is called from ExecuteNextStartPlaying and nowhere else
void YieldingStartPlaying( const CSteamID & steamID, const CSteamID & gsSteamID, uint32 unServerAddr, uint16 usServerPort, CUtlBuffer *pVarData );
// Base behaviors of the IGameCoordinator interface. These are not overridable.
// They each call the On* version below, which is overridable by subclasses
virtual bool BInit( AppId_t unAppID, const char *pchAppPath, IGameCoordinatorHost *pHost );
virtual bool BMainLoopOncePerFrame( uint64 ulLimitMicroseconds );
virtual bool BMainLoopUntilFrameCompletion( uint64 ulLimitMicroseconds );
virtual void Shutdown();
virtual void Uninit();
virtual void MessageFromClient( const CSteamID & senderID, uint32 unMsgType, void *pubData, uint32 cubData );
virtual void Validate( CValidator &validator, const char *pchName );
virtual void SQLResults( GID_t gidContextID );
// profiling
bool m_bStartProfiling;
bool m_bStopProfiling;
bool m_bDumpVprofImbalances;
// local job handling
CJobMgr m_JobMgr;
CGCWGJobMgr m_wgJobMgr;
// session tracking
CTHash<CGCUserSession *, uint64> m_hashUserSessions;
CTHash<CGCGSSession *, uint64> m_hashGSSessions;
typedef CUtlMap< int, CGCGSSessionSortedVector_t > CGCGSSessionServerTypeMap_t;
CGCGSSessionServerTypeMap_t m_GSSessionsByTypeMap;
CUtlMap< uint64, CGCGSSession*, int > m_mapGSSessionsByNetAddress;
// Shared object caches
CUtlMap<CSteamID, CGCSharedObjectCache *, int> m_mapSOCache;
CUtlVector< CGCSharedObjectCache * >m_vecCacheWritebacks;
CUtlLinkedList< CSteamID, uint32> m_listCachesToUnload;
CUtlRBTree<CSteamID, int > m_rbtreeSOCachesBeingLoaded;
CUtlRBTree<CSteamID, int > m_rbtreeSOCachesWithDirtyVersions;
// steamID locks
CTHash<CLock, CSteamID> m_hashSteamIDLocks;
// Account Details
CAccountDetailsManager m_AccountDetailsManager;
// State
AppId_t m_unAppID;
CUtlString m_sPath;
IGameCoordinatorHost *m_pHost;
bool m_bStartupComplete;
bool m_bIsShuttingDown;
struct StartPlayingWork_t
{
CSteamID m_steamID;
CSteamID m_gsSteamID;
uint32 m_unServerAddr;
uint16 m_usServerPort;
CUtlBuffer *m_pVarData;
};
CUtlLinkedList< StartPlayingWork_t, int > m_llStartPlaying;
int m_nStartPlayingJobCount;
// URL to use for our app's CDN'd images
mutable CUtlString m_sCDNURL;
};
extern CGCBase *GGCBase();
EResult YieldingSendWebAPIRequest( CSteamAPIRequest &request, KeyValues *pKVResponse, CUtlString &errMsg, bool b200MeansSuccess );
} // namespace GCSDK
#endif // GCBASE_H