Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
14 KiB

  1. //====== Copyright �, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Additional shared object cache functionality for the GC
  4. //
  5. //=============================================================================
  6. #ifndef GC_SHAREDOBJECTCACHE_H
  7. #define GC_SHAREDOBJECTCACHE_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "sharedobjectcache.h"
  12. class CMsgSOCacheSubscribed_SubscribedType;
  13. #include "tier0/memdbgon.h"
  14. namespace GCSDK
  15. {
  16. class CCachedSubscriptionMessage;
  17. //----------------------------------------------------------------------------
  18. // Purpose: The part of a shared object cache that handles all objects of a
  19. // single type.
  20. //----------------------------------------------------------------------------
  21. class CSharedObjectContext
  22. {
  23. public:
  24. CSharedObjectContext( const CSteamID & steamIDOwner );
  25. bool BAddSubscriber( const CSteamID & steamID );
  26. bool BRemoveSubscriber( const CSteamID & steamID );
  27. void RemoveAllSubscribers();
  28. bool BIsSubscribed( const CSteamID & steamID ) { return m_vecSubscribers.Find( steamID ) != m_vecSubscribers.InvalidIndex(); }
  29. const CUtlVector< CSteamID > & GetSubscribers() const { return m_vecSubscribers; }
  30. const CSteamID & GetOwner() const { return m_steamIDOwner; }
  31. private:
  32. CUtlVector<CSteamID> m_vecSubscribers;
  33. CUtlVector<int> m_vecSubRefCount;
  34. CSteamID m_steamIDOwner;
  35. };
  36. class CGCSharedObjectTypeCache;
  37. enum ESOTypeFlags
  38. {
  39. k_SOFlag_SendToNobody = 0,
  40. k_ESOFlag_SendToOwningUser = 1 << 0, // will go only to the owner of the cache (if that owner is a user)
  41. k_ESOFlag_SendToOtherUsers = 1 << 1, // will go only to users who are not the owner of the cache
  42. k_SOFlag_SendToGameservers = 1 << 2, // will go only to gameservers, regardless of whether they're the owner
  43. k_SOFlag_LastFlag = k_SOFlag_SendToGameservers,
  44. };
  45. //----------------------------------------------------------------------------
  46. // Purpose: Filter object used to determine whether a type cache's objects should
  47. // should be sent to subscribers and whether each object should be sent
  48. //----------------------------------------------------------------------------
  49. class CISubscriberMessageFilter
  50. {
  51. public:
  52. virtual bool BShouldSendAnyObjectsInCache( CGCSharedObjectTypeCache *pTypeCache, uint32 unFlags ) const = 0;
  53. virtual bool BShouldSendObject( CSharedObject *pSharedObject, uint32 unFlags ) const = 0;
  54. };
  55. //----------------------------------------------------------------------------
  56. // Purpose: The part of a shared object cache that handles all objects of a
  57. // single type.
  58. //----------------------------------------------------------------------------
  59. class CGCSharedObjectTypeCache : public CSharedObjectTypeCache
  60. {
  61. public:
  62. typedef CSharedObjectTypeCache Base;
  63. CGCSharedObjectTypeCache( int nTypeID, const CSharedObjectContext & context );
  64. virtual ~CGCSharedObjectTypeCache();
  65. virtual bool AddObject( CSharedObject *pObject );
  66. virtual CSharedObject *RemoveObject( const CSharedObject & soIndex );
  67. void BuildCacheSubscribedMsg( CMsgSOCacheSubscribed_SubscribedType *pMsgType, uint32 unFlags, const CISubscriberMessageFilter &filter );
  68. virtual void EnsureCapacity( uint32 nItems );
  69. static int GetCachedObjectCount( int nTypeID );
  70. #ifdef DBGFLAG_VALIDATE
  71. virtual void Validate( CValidator &validator, const char *pchName );
  72. #endif
  73. private:
  74. static int UpdateCachedObjectCount( int nTypeID, int nDelta );
  75. const CSharedObjectContext & m_context;
  76. static CUtlMap<int, int> sm_mapCachedObjectCounts;
  77. };
  78. //----------------------------------------------------------------------------
  79. // Purpose: A cache of a bunch of shared objects of different types. This class
  80. // is shared between clients, gameservers, and the GC and is
  81. // responsible for sending messages from the GC to cause object
  82. // creation/destruction/updating on the clients/gameservers.
  83. //----------------------------------------------------------------------------
  84. class CGCSharedObjectCache : public CSharedObjectCache
  85. {
  86. public:
  87. CGCSharedObjectCache( const CSteamID & steamIDOwner = CSteamID() );
  88. virtual ~CGCSharedObjectCache();
  89. const CSteamID & GetOwner() const { return m_context.GetOwner(); }
  90. const CUtlVector< CSteamID > & GetSubscribers() const { return m_context.GetSubscribers(); }
  91. CGCSharedObjectTypeCache *GetTypeCache( int nClassID, bool bCreateIfMissing = false ) { return (CGCSharedObjectTypeCache *)GetBaseTypeCache( nClassID, bCreateIfMissing ); }
  92. CGCSharedObjectTypeCache *GetTypeCache( int nClassID ) const { return (CGCSharedObjectTypeCache *)const_cast<CGCSharedObjectCache*>(this)->GetBaseTypeCache( nClassID, false ); }
  93. virtual CSharedObjectTypeCache *CreateTypeCache( int nClassID ) const { return new CGCSharedObjectTypeCache( nClassID, m_context ); }
  94. // returns various singleton objects
  95. template< typename SOClass_t >
  96. SOClass_t *GetSingleton() const
  97. {
  98. GCSDK::CGCSharedObjectTypeCache *pTypeCache = GetTypeCache( SOClass_t::k_nTypeID );
  99. if ( pTypeCache && pTypeCache->GetCount() == 1 )
  100. {
  101. return (SOClass_t *)pTypeCache->GetObject( 0 );
  102. }
  103. return NULL;
  104. }
  105. virtual uint32 CalcSendFlags( const CSteamID &steamID ) const;
  106. virtual const CISubscriberMessageFilter &GetSubscriberMessageFilter();
  107. virtual void AddObject( CSharedObject *pSharedObject );
  108. bool BDestroyObject( const CSharedObject & soIndex, bool bRemoveFromDatabase );
  109. virtual CSharedObject *RemoveObject( const CSharedObject & soIndex );
  110. template< typename SOClass_t >
  111. bool BYieldingLoadSchObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & schDefaults );
  112. template< typename SOClass_t >
  113. bool BYieldingLoadSchSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & schDefaults );
  114. template< typename SOClass_t, typename SchClass_t >
  115. bool BYieldingLoadProtoBufObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead );
  116. template< typename SOClass_t, typename SchClass_t >
  117. bool BYieldingLoadProtoBufSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SchClass_t & schDefaults );
  118. // @todo temporary for trading and item subscriptions (to be removed once we get cross-game trading)
  119. virtual void SetTradingPartner( const CSteamID &steamID );
  120. const CSteamID &GetTradingPartner() const { return m_steamIDTradingPartner; }
  121. void AddSubscriber( const CSteamID & steamID );
  122. void RemoveSubscriber( const CSteamID & steamID );
  123. void RemoveAllSubscribers();
  124. void SendSubscriberMessage( const CSteamID & steamID );
  125. bool BIsSubscribed( const CSteamID & steamID ) { return m_context.BIsSubscribed( steamID ); }
  126. void ClearCachedSubscriptionMessage();
  127. bool BIsDatabaseDirty() const { return m_databaseDirtyList.NumDirtyObjects() > 0; }
  128. // This will mark the field as dirty for both network and database
  129. void DirtyObjectField( CSharedObject *pObj, int nFieldIndex );
  130. // Marks only dirty for network
  131. void DirtyNetworkObjectField( CSharedObject *pObj, int nFieldIndex );
  132. // Mark dirty for database
  133. void DirtyDatabaseObjectField( CSharedObject *pObj, int nFieldIndex );
  134. void SendNetworkUpdates( CSharedObject *pObj );
  135. bool BYieldingAddWriteToTransaction( CSharedObject *pObj, CSQLAccess & sqlAccess );
  136. void SendAllNetworkUpdates();
  137. void YieldingWriteToDatabase( CSharedObject *pObj );
  138. uint32 AddAllWritesToTransaction( CSQLAccess & sqlAccess );
  139. void CleanAllWrites( );
  140. void SetInWriteback( bool bInWriteback );
  141. bool GetInWriteback() const { return m_bInWriteback; }
  142. RTime32 GetWritebackTime() const { return m_unWritebackTime; }
  143. void SetLRUHandle( uint32 unLRUHandle ) { m_unLRUHandle = unLRUHandle; }
  144. uint32 GetLRUHandle() const { return m_unLRUHandle; }
  145. void Dump() const;
  146. void DumpDirtyObjects() const;
  147. #ifdef DBGFLAG_VALIDATE
  148. virtual void Validate( CValidator &validator, const char *pchName );
  149. #endif
  150. #ifdef DEBUG
  151. bool IsObjectCached( CSharedObject *pObj, int nTypeID );
  152. bool IsObjectDirty( CSharedObject *pObj );
  153. #endif
  154. protected:
  155. virtual void MarkDirty();
  156. virtual bool BShouldSendToAnyClients( uint32 unFlags ) const;
  157. CCachedSubscriptionMessage *BuildSubscriberMessage( uint32 unFlags );
  158. CSteamID m_steamIDTradingPartner;
  159. protected:
  160. void SendNetworkUpdateInternal( CSharedObject * pObj, const CUtlVector< int > &dirtyFields );
  161. void SendUnsubscribeMessage( const CSteamID & steamID );
  162. CSharedObjectContext m_context;
  163. CSharedObjectDirtyList m_networkDirtyList;
  164. CSharedObjectDirtyList m_databaseDirtyList;
  165. bool m_bInWriteback;
  166. RTime32 m_unWritebackTime;
  167. uint32 m_unLRUHandle;
  168. const IProtoBufMsg *m_pCacheToUsersSubscriptionMsg;
  169. uint32 m_unCachedSubscriptionMsgFlags;
  170. CCachedSubscriptionMessage *m_pCachedSubscriptionMsg;
  171. };
  172. //----------------------------------------------------------------------------
  173. // Purpose: Loads a list of CSchemaSharedObjects from a result list from a
  174. // query.
  175. // Inputs: pResultSet - The result set from the SQL query
  176. // schDefaults - A schema object that defines the values to set in
  177. // the new objects for fields that were not read in the query.
  178. // Typically this will be whatever fields were in the WHERE
  179. // clause of the query.
  180. // csRead - A columnSet defining the fields that were read in the query.
  181. //----------------------------------------------------------------------------
  182. template< typename SOClass_t >
  183. bool CGCSharedObjectCache::BYieldingLoadSchObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & objDefaults )
  184. {
  185. if ( NULL == pResultSet )
  186. return false;
  187. CGCSharedObjectTypeCache *pTypeCache = GetTypeCache( SOClass_t::k_nTypeID, true );
  188. pTypeCache->EnsureCapacity( pResultSet->GetRowCount() );
  189. for( CSQLRecord record( 0, pResultSet ); record.IsValid(); record.NextRow() )
  190. {
  191. SOClass_t *pObj = new SOClass_t();
  192. pObj->Obj() = objDefaults.Obj();
  193. record.BWriteToRecord( &pObj->Obj(), csRead );
  194. pTypeCache->AddObject( pObj );
  195. }
  196. return true;
  197. }
  198. //----------------------------------------------------------------------------
  199. // Purpose: Loads a single object of a type. If the object is not available,
  200. // a new object will be created at default values
  201. // Inputs: pResultSet - The result set from the SQL query
  202. // schDefaults - A schema object that defines the values to set in
  203. // the new objects for fields that were not read in the query.
  204. // Typically this will be whatever fields were in the WHERE
  205. // clause of the query.
  206. // csRead - A columnSet defining the fields that were read in the query.
  207. //----------------------------------------------------------------------------
  208. template< typename SOClass_t >
  209. bool CGCSharedObjectCache::BYieldingLoadSchSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & objDefaults )
  210. {
  211. if ( NULL == pResultSet )
  212. return false;
  213. if ( pResultSet->GetRowCount() > 1 )
  214. {
  215. EmitError( SPEW_SHAREDOBJ, "Multiple rows passed to BYieldingLoadSchSingleton() on type %d\n", objDefaults.GetTypeID() );
  216. return false;
  217. }
  218. else if ( pResultSet->GetRowCount() == 1 )
  219. {
  220. return BYieldingLoadSchObjects<SOClass_t>( pResultSet, csRead, objDefaults );
  221. }
  222. else
  223. {
  224. // Create it if there wasn't one
  225. SOClass_t *pSchObj = new SOClass_t();
  226. pSchObj->Obj() = objDefaults.Obj();
  227. if( !pSchObj->BYieldingAddToDatabase() )
  228. {
  229. EmitError( SPEW_SHAREDOBJ, "Unable to add singleton type %d for %s\n", pSchObj->GetTypeID(), GetOwner().Render() );
  230. return false;
  231. }
  232. AddObject( pSchObj );
  233. return true;
  234. }
  235. }
  236. //----------------------------------------------------------------------------
  237. // Purpose: Loads a list of CProtoBufSharedObjects from a result list from a
  238. // query.
  239. // Inputs: pResultSet - The result set from the SQL query
  240. // schDefaults - A schema object that defines the values to set in
  241. // the new objects for fields that were not read in the query.
  242. // Typically this will be whatever fields were in the WHERE
  243. // clause of the query.
  244. // csRead - A columnSet defining the fields that were read in the query.
  245. //----------------------------------------------------------------------------
  246. template< typename SOClass_t, typename SchClass_t >
  247. bool CGCSharedObjectCache::BYieldingLoadProtoBufObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead )
  248. {
  249. if ( NULL == pResultSet )
  250. return false;
  251. CGCSharedObjectTypeCache *pTypeCache = GetTypeCache( SOClass_t::k_nTypeID, true );
  252. pTypeCache->EnsureCapacity( pResultSet->GetRowCount() );
  253. for( CSQLRecord record( 0, pResultSet ); record.IsValid(); record.NextRow() )
  254. {
  255. SchClass_t schRecord;
  256. record.BWriteToRecord( &schRecord, csRead );
  257. SOClass_t *pObj = new SOClass_t();
  258. pObj->ReadFromRecord( schRecord );
  259. pTypeCache->AddObject( pObj );
  260. }
  261. return true;
  262. }
  263. //----------------------------------------------------------------------------
  264. // Purpose: Loads a single object of a type. If the object is not available,
  265. // a new object will be created at default values
  266. // Inputs: pResultSet - The result set from the SQL query
  267. // schDefaults - A schema object that defines the values to set in
  268. // the new objects for fields that were not read in the query.
  269. // Typically this will be whatever fields were in the WHERE
  270. // clause of the query.
  271. // csRead - A columnSet defining the fields that were read in the query.
  272. //----------------------------------------------------------------------------
  273. template< typename SOClass_t, typename SchClass_t >
  274. bool CGCSharedObjectCache::BYieldingLoadProtoBufSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SchClass_t & schDefaults )
  275. {
  276. if ( NULL == pResultSet )
  277. return false;
  278. if ( pResultSet->GetRowCount() > 1 )
  279. {
  280. EmitError( SPEW_SHAREDOBJ, "Multiple rows passed to BYieldingLoadProtoBufSingleton() on type %d\n", SOClass_t::k_nTypeID );
  281. return false;
  282. }
  283. // load the duel summary
  284. SchClass_t schRead;
  285. CSQLRecord record( 0, pResultSet );
  286. if( record.IsValid() )
  287. {
  288. record.BWriteToRecord( &schRead, csRead );
  289. }
  290. else
  291. {
  292. CSQLAccess sqlAccess;
  293. if( !sqlAccess.BYieldingInsertRecord( const_cast<SchClass_t *>( &schDefaults ) ) )
  294. return false;
  295. schRead = schDefaults;
  296. }
  297. SOClass_t *pSharedObject = new SOClass_t();
  298. pSharedObject->ReadFromRecord( schRead );
  299. AddObject( pSharedObject );
  300. return true;
  301. }
  302. } // namespace GCSDK
  303. #include "tier0/memdbgoff.h"
  304. #endif //GC_SHAREDOBJECTCACHE_H