304 lines
12 KiB
C++
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
|