diff options
Diffstat (limited to 'public/gcsdk/sharedobject.h')
| -rw-r--r-- | public/gcsdk/sharedobject.h | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/public/gcsdk/sharedobject.h b/public/gcsdk/sharedobject.h new file mode 100644 index 0000000..d1bfdd3 --- /dev/null +++ b/public/gcsdk/sharedobject.h @@ -0,0 +1,305 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Base class for objects that are kept in synch between client and server +// +//============================================================================= + +#ifndef SHAREDOBJECT_H +#define SHAREDOBJECT_H +#ifdef _WIN32 +#pragma once +#endif + +// ENABLE_SO_OVERWRITE_PARANOIA can be set to either 0 or 1. If enabled, it will add +// extra fields to every CSharedObject instance to try and detect overwrites at the +// cost of additional runtime memory. +#define ENABLE_SO_OVERWRITE_PARANOIA 0 + +// ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA can be set to either 0 or 1. If enabled, it +// will add extra fields to every CSharedObject instance to try and detect issues with +// constructions/destruction (ie., double-deletes, etc.), including reference counting. +#define ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA (defined( STAGING_ONLY )) + +#include "tier0/memdbgon.h" + +namespace GCSDK +{ + +class CSQLAccess; +class CSharedObject; +typedef CSharedObject *(*SOCreationFunc_t)( ); +class CSharedObjectCache; + + + +//---------------------------------------------------------------------------- +// Purpose: Abstract base class for objects that are shared between the GC and +// a gameserver/client. These can also be stored in the database. +//---------------------------------------------------------------------------- +class CSharedObject +{ + friend class CGCSharedObjectCache; + friend class CSharedObjectCache; +public: + +#ifdef GC + virtual ~CSharedObject() + { +#if ENABLE_SO_OVERWRITE_PARANOIA + m_pThis = NULL; +#endif // ENABLE_SO_OVERWRITE_PARANOIA + +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + AssertMsg2( m_nRefCount == 0, "Deleting shared object type %d with refcount %d", m_nSOTypeID, m_nRefCount ); + + m_nSOTypeID = -1; + m_nRefCount = -1; +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + } + +#if ENABLE_SO_OVERWRITE_PARANOIA + CSharedObject *m_pThis; +#endif // ENABLE_SO_OVERWRITE_PARANOIA + +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + int m_nRefCount; + mutable int m_nSOTypeID; +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + + void Check() const + { +#if ENABLE_SO_OVERWRITE_PARANOIA + Assert( m_pThis == this ); +#endif // ENABLE_SO_OVERWRITE_PARANOIA + +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + Assert( m_nRefCount >= 0 ); + + if ( m_nSOTypeID == kSharedObject_UnassignedType ) + { + m_nSOTypeID = GetTypeID(); + } + + Assert( m_nSOTypeID >= 0 ); +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + } +#else + virtual ~CSharedObject() {} +#endif + + virtual int GetTypeID() const = 0; + virtual bool BParseFromMessage( const CUtlBuffer & buffer ) = 0; + virtual bool BParseFromMessage( const std::string &buffer ) = 0; + virtual bool BUpdateFromNetwork( const CSharedObject & objUpdate ) = 0; + virtual bool BIsKeyLess( const CSharedObject & soRHS ) const = 0; + virtual void Copy( const CSharedObject & soRHS ) = 0; + virtual void Dump() const = 0; + virtual bool BShouldDeleteByCache() const { return true; } + virtual CUtlString GetDebugString() const { return PchClassName( GetTypeID() ); }; + + bool BIsKeyEqual( const CSharedObject & soRHS ) const; + + static void RegisterFactory( int nTypeID, SOCreationFunc_t fnFactory, uint32 unFlags, const char *pchClassName ); + static CSharedObject *Create( int nTypeID ); + static uint32 GetTypeFlags( int nTypeID ); + static const char *PchClassName( int nTypeID ); + static const char *PchClassBuildCacheNodeName( int nTypeID ); + static const char *PchClassCreateNodeName( int nTypeID ); + static const char *PchClassUpdateNodeName( int nTypeID ); + +#ifdef GC + virtual bool BIsNetworked() const { return true; } + virtual bool BIsDatabaseBacked() const { return true; } + virtual bool BYieldingAddToDatabase(); + virtual bool BYieldingWriteToDatabase( const CUtlVector< int > &fields ); + virtual bool BYieldingRemoveFromDatabase(); + + virtual bool BYieldingAddInsertToTransaction( CSQLAccess & sqlAccess ) { return false; } + virtual bool BYieldingAddWriteToTransaction( CSQLAccess & sqlAccess, const CUtlVector< int > &fields ) { return false; } + virtual bool BYieldingAddRemoveToTransaction( CSQLAccess & sqlAccess ) { return false; } + + virtual bool BAddToMessage( CUtlBuffer & bufOutput ) const = 0; + virtual bool BAddToMessage( std::string *pBuffer ) const = 0; + virtual bool BAddDestroyToMessage( CUtlBuffer & bufDestroy ) const = 0; + virtual bool BAddDestroyToMessage( std::string *pBuffer ) const = 0; + + virtual bool BParseFromMemcached( CUtlBuffer & buffer ) { return false; } + virtual bool BAddToMemcached( CUtlBuffer & bufOutput ) const { return false; } + + bool BSendCreateToSteamID( const CSteamID & steamID, const CSteamID & ownerID, uint64 ulVersion ) const; + bool BSendDestroyToSteamID( const CSteamID & steamID, const CSteamID & ownerID, uint64 ulVersion ) const; + +#ifdef DBGFLAG_VALIDATE + virtual void Validate( CValidator &validator, const char *pchName ); + static void ValidateStatics( CValidator & validator ); +#endif + +protected: +/* + // Dirty bit modification. Do not call these directly on SharedObjects. Call them + // on the cache that owns the object so they can be added/removed from the right lists. + virtual void DirtyField( int nField ) = 0; + virtual void MakeDatabaseClean() = 0; + virtual void MakeNetworkClean() = 0; +*/ +#endif // GC + +#ifdef GC + CSharedObject() + { +#if ENABLE_SO_OVERWRITE_PARANOIA + m_pThis = this; +#endif // ENABLE_SO_OVERWRITE_PARANOIA + +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + m_nRefCount = 0; + m_nSOTypeID = kSharedObject_UnassignedType; +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + } +#endif + +private: +#if ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + enum { kSharedObject_UnassignedType = -999 }; +#endif // ENABLE_SO_CONSTRUCT_DESTRUCT_PARANOIA + + struct SharedObjectInfo_t + { + SOCreationFunc_t m_pFactoryFunction; + uint32 m_unFlags; + const char *m_pchClassName; + CUtlString m_sBuildCacheSubNodeName; + CUtlString m_sUpdateNodeName; + CUtlString m_sCreateNodeName; + }; + static CUtlMap<int, SharedObjectInfo_t> sm_mapFactories; + +public: + static const CUtlMap<int, SharedObjectInfo_t> & GetFactories() { return sm_mapFactories; } +}; + +typedef CUtlVectorFixedGrowable<CSharedObject *, 1> CSharedObjectVec; + +#ifdef GC + +//this class manages the stats for the shared objects, such as how many exist, how many have been sent, how many have been created, how many destroyed +class CSharedObjectStats +{ +public: + + CSharedObjectStats(); + + //called to register a shared object class given a type ID and name. This will return false if + //a type of this ID is already registered + void RegisterSharedObjectType( int nTypeID, const char* pszTypeName ); + + //called to track when a shared object is created/destroyed to update the running total + void TrackSharedObjectLifetime( int nTypeID, int32 nCount ); + + //called when a shared object is created to track its creation + void TrackSharedObjectSendCreate( int nTypeID, uint32 nCount ); + //called when a shared object is destroyed to track counts + void TrackSharedObjectSendDestroy( int nTypeID, uint32 nCount ); + + //tracks a new subscription + void TrackSubscription( int nTypeID, uint32 nFlags, uint32 nNumSubscriptions ); + + //called when a shared object is sent + void TrackSharedObjectSend( int nTypeID, uint32 nNumClients, uint32 nMsgSize ); + + //reset the stats for all the caches + void ResetStats(); + + //called to start/stop collecting stats + void StartCollectingStats(); + void StopCollectingStats(); + bool IsCollectingStats() const { return m_bCollectingStats; } + + //called to report the currently collected stats + void ReportCollectedStats() const; + +private: + + struct SOStats_t + { + SOStats_t(); + void ResetStats(); + + //the text name of this cache + CUtlString m_sName; + //the number of outstanding SO cache objects of this type. This is not cleared + uint32 m_nNumActive; + //the type ID of this stat + int m_nTypeID; + + //the total number that have been created/destroyed. Active is difference between these + uint32 m_nNumCreated; + uint32 m_nNumDestroyed; + //how many bytes we have sent (raw, and multiplexed to multiple subscribers) + uint64 m_nRawBytesSent; + uint64 m_nMultiplexedBytesSent; + //the number of sends since our last clear + uint32 m_nNumSends; + //how many subscriptions we have gotten by various subscription types + uint32 m_nNumSubOwner; + uint32 m_nNumSubOtherUsers; + uint32 m_nNumSubGameServer; + }; + + //sort function that controls the order that the SO stats are presented in the report + static bool SortSOStatsSent( const SOStats_t* pLhs, const SOStats_t* pRhs ); + static bool SortSOStatsSubscribe( const SOStats_t* pLhs, const SOStats_t* pRhs ); + + //to compact the memory space for wide ranging type IDs, the list of stats has two components, an array that can be looked up + //via the type ID which maps to a stat index (or invalid index if no mapping is registered) + static const uint16 knInvalidIndex = ( uint16 )-1; + CUtlVector< uint16 > m_vTypeToIndex; + CUtlVector< SOStats_t > m_Stats; + + //are we currently collecting stats or not? + bool m_bCollectingStats; + //the time that we've been collecting + CJobTime m_CollectTime; + uint64 m_nMicroSElapsed; +}; + +//global stat tracker +extern CSharedObjectStats g_SharedObjectStats; + +#endif + + +//---------------------------------------------------------------------------- +// Purpose: Templatized function to use as a factory method for +// CSharedObject subclasses +//---------------------------------------------------------------------------- +template<typename SharedObjectSubclass_t> +CSharedObject *CreateSharedObjectSubclass() +{ + return new SharedObjectSubclass_t(); +} + +// Version that always asserts and returns NULL, for SOs that should not be auto-created this way +template<int nSharedObjectType> +CSharedObject *CreateSharedObjectSubclassProhibited() +{ + AssertMsg( false, "Attempting to auto-create object of type %d which does not allow SO-based creation", nSharedObjectType ); + return NULL; +} + +#ifdef GC +#define REG_SHARED_OBJECT_SUBCLASS( derivedClass, flags ) GCSDK::CSharedObject::RegisterFactory( derivedClass::k_nTypeID, GCSDK::CreateSharedObjectSubclass<derivedClass>, (flags), #derivedClass ) +// GC only -- sharedobjects that cannot be auto-created by the SO code, and might not have a specific derived class that +// publicly implements the interface +#define REG_SHARED_OBJECT_SUBCLASS_BY_ID_NOCREATE( strName, nTypeID, flags ) \ + GCSDK::CSharedObject::RegisterFactory( nTypeID, CreateSharedObjectSubclassProhibited<nTypeID>, (flags), strName ) +#else +#define REG_SHARED_OBJECT_SUBCLASS( derivedClass ) GCSDK::CSharedObject::RegisterFactory( derivedClass::k_nTypeID, GCSDK::CreateSharedObjectSubclass<derivedClass>, 0, #derivedClass ) +#endif + +} // namespace GCSDK + + +#include "tier0/memdbgoff.h" + +#endif //SHAREDOBJECT_H |