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
376 lines
14 KiB
//====== Copyright ©, Valve Corporation, All rights reserved. =======
|
|
//
|
|
// Purpose: Additional shared object cache functionality for the GC
|
|
//
|
|
//=============================================================================
|
|
|
|
#ifndef GC_SHAREDOBJECTCACHE_H
|
|
#define GC_SHAREDOBJECTCACHE_H
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "sharedobjectcache.h"
|
|
|
|
class CMsgSOCacheSubscribed_SubscribedType;
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
namespace GCSDK
|
|
{
|
|
|
|
class CCachedSubscriptionMessage;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: The part of a shared object cache that handles all objects of a
|
|
// single type.
|
|
//----------------------------------------------------------------------------
|
|
class CSharedObjectContext
|
|
{
|
|
public:
|
|
CSharedObjectContext( const CSteamID & steamIDOwner );
|
|
|
|
bool BAddSubscriber( const CSteamID & steamID );
|
|
bool BRemoveSubscriber( const CSteamID & steamID );
|
|
void RemoveAllSubscribers();
|
|
bool BIsSubscribed( const CSteamID & steamID ) { return m_vecSubscribers.Find( steamID ) != m_vecSubscribers.InvalidIndex(); }
|
|
|
|
const CUtlVector< CSteamID > & GetSubscribers() const { return m_vecSubscribers; }
|
|
const CSteamID & GetOwner() const { return m_steamIDOwner; }
|
|
private:
|
|
CUtlVector<CSteamID> m_vecSubscribers;
|
|
CUtlVector<int> m_vecSubRefCount;
|
|
CSteamID m_steamIDOwner;
|
|
};
|
|
|
|
class CGCSharedObjectTypeCache;
|
|
|
|
enum ESOTypeFlags
|
|
{
|
|
k_SOFlag_SendToNobody = 0,
|
|
k_ESOFlag_SendToOwningUser = 1 << 0, // will go only to the owner of the cache (if that owner is a user)
|
|
k_ESOFlag_SendToOtherUsers = 1 << 1, // will go only to users who are not the owner of the cache
|
|
k_SOFlag_SendToGameservers = 1 << 2, // will go only to gameservers, regardless of whether they're the owner
|
|
k_SOFlag_LastFlag = k_SOFlag_SendToGameservers,
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Filter object used to determine whether a type cache's objects should
|
|
// should be sent to subscribers and whether each object should be sent
|
|
//----------------------------------------------------------------------------
|
|
class CISubscriberMessageFilter
|
|
{
|
|
public:
|
|
virtual bool BShouldSendAnyObjectsInCache( CGCSharedObjectTypeCache *pTypeCache, uint32 unFlags ) const = 0;
|
|
virtual bool BShouldSendObject( CSharedObject *pSharedObject, uint32 unFlags ) const = 0;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: The part of a shared object cache that handles all objects of a
|
|
// single type.
|
|
//----------------------------------------------------------------------------
|
|
class CGCSharedObjectTypeCache : public CSharedObjectTypeCache
|
|
{
|
|
public:
|
|
|
|
typedef CSharedObjectTypeCache Base;
|
|
|
|
CGCSharedObjectTypeCache( int nTypeID, const CSharedObjectContext & context );
|
|
virtual ~CGCSharedObjectTypeCache();
|
|
|
|
virtual bool AddObject( CSharedObject *pObject );
|
|
virtual CSharedObject *RemoveObject( const CSharedObject & soIndex );
|
|
|
|
void BuildCacheSubscribedMsg( CMsgSOCacheSubscribed_SubscribedType *pMsgType, uint32 unFlags, const CISubscriberMessageFilter &filter );
|
|
virtual void EnsureCapacity( uint32 nItems );
|
|
|
|
static int GetCachedObjectCount( int nTypeID );
|
|
|
|
#ifdef DBGFLAG_VALIDATE
|
|
virtual void Validate( CValidator &validator, const char *pchName );
|
|
#endif
|
|
|
|
private:
|
|
static int UpdateCachedObjectCount( int nTypeID, int nDelta );
|
|
|
|
const CSharedObjectContext & m_context;
|
|
|
|
static CUtlMap<int, int> sm_mapCachedObjectCounts;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: A cache of a bunch of shared objects of different types. This class
|
|
// is shared between clients, gameservers, and the GC and is
|
|
// responsible for sending messages from the GC to cause object
|
|
// creation/destruction/updating on the clients/gameservers.
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CGCSharedObjectCache : public CSharedObjectCache
|
|
{
|
|
public:
|
|
CGCSharedObjectCache( const CSteamID & steamIDOwner = CSteamID() );
|
|
virtual ~CGCSharedObjectCache();
|
|
|
|
const CSteamID & GetOwner() const { return m_context.GetOwner(); }
|
|
const CUtlVector< CSteamID > & GetSubscribers() const { return m_context.GetSubscribers(); }
|
|
|
|
CGCSharedObjectTypeCache *GetTypeCache( int nClassID, bool bCreateIfMissing = false ) { return (CGCSharedObjectTypeCache *)GetBaseTypeCache( nClassID, bCreateIfMissing ); }
|
|
CGCSharedObjectTypeCache *GetTypeCache( int nClassID ) const { return (CGCSharedObjectTypeCache *)const_cast<CGCSharedObjectCache*>(this)->GetBaseTypeCache( nClassID, false ); }
|
|
virtual CSharedObjectTypeCache *CreateTypeCache( int nClassID ) const { return new CGCSharedObjectTypeCache( nClassID, m_context ); }
|
|
|
|
// returns various singleton objects
|
|
template< typename SOClass_t >
|
|
SOClass_t *GetSingleton() const
|
|
{
|
|
GCSDK::CGCSharedObjectTypeCache *pTypeCache = GetTypeCache( SOClass_t::k_nTypeID );
|
|
if ( pTypeCache && pTypeCache->GetCount() == 1 )
|
|
{
|
|
return (SOClass_t *)pTypeCache->GetObject( 0 );
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
virtual uint32 CalcSendFlags( const CSteamID &steamID ) const;
|
|
virtual const CISubscriberMessageFilter &GetSubscriberMessageFilter();
|
|
virtual void AddObject( CSharedObject *pSharedObject );
|
|
bool BDestroyObject( const CSharedObject & soIndex, bool bRemoveFromDatabase );
|
|
virtual CSharedObject *RemoveObject( const CSharedObject & soIndex );
|
|
|
|
template< typename SOClass_t >
|
|
bool BYieldingLoadSchObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & schDefaults );
|
|
|
|
template< typename SOClass_t >
|
|
bool BYieldingLoadSchSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & schDefaults );
|
|
|
|
template< typename SOClass_t, typename SchClass_t >
|
|
bool BYieldingLoadProtoBufObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead );
|
|
|
|
template< typename SOClass_t, typename SchClass_t >
|
|
bool BYieldingLoadProtoBufSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SchClass_t & schDefaults );
|
|
|
|
// @todo temporary for trading and item subscriptions (to be removed once we get cross-game trading)
|
|
virtual void SetTradingPartner( const CSteamID &steamID );
|
|
const CSteamID &GetTradingPartner() const { return m_steamIDTradingPartner; }
|
|
|
|
void AddSubscriber( const CSteamID & steamID );
|
|
void RemoveSubscriber( const CSteamID & steamID );
|
|
void RemoveAllSubscribers();
|
|
void SendSubscriberMessage( const CSteamID & steamID );
|
|
bool BIsSubscribed( const CSteamID & steamID ) { return m_context.BIsSubscribed( steamID ); }
|
|
void ClearCachedSubscriptionMessage();
|
|
|
|
bool BIsDatabaseDirty() const { return m_databaseDirtyList.NumDirtyObjects() > 0; }
|
|
|
|
// This will mark the field as dirty for both network and database
|
|
void DirtyObjectField( CSharedObject *pObj, int nFieldIndex );
|
|
|
|
// Marks only dirty for network
|
|
void DirtyNetworkObjectField( CSharedObject *pObj, int nFieldIndex );
|
|
|
|
// Mark dirty for database
|
|
void DirtyDatabaseObjectField( CSharedObject *pObj, int nFieldIndex );
|
|
|
|
void SendNetworkUpdates( CSharedObject *pObj );
|
|
bool BYieldingAddWriteToTransaction( CSharedObject *pObj, CSQLAccess & sqlAccess );
|
|
void SendAllNetworkUpdates();
|
|
void YieldingWriteToDatabase( CSharedObject *pObj );
|
|
uint32 AddAllWritesToTransaction( CSQLAccess & sqlAccess );
|
|
void CleanAllWrites( );
|
|
|
|
void SetInWriteback( bool bInWriteback );
|
|
bool GetInWriteback() const { return m_bInWriteback; }
|
|
RTime32 GetWritebackTime() const { return m_unWritebackTime; }
|
|
|
|
void SetLRUHandle( uint32 unLRUHandle ) { m_unLRUHandle = unLRUHandle; }
|
|
uint32 GetLRUHandle() const { return m_unLRUHandle; }
|
|
|
|
void Dump() const;
|
|
void DumpDirtyObjects() const;
|
|
#ifdef DBGFLAG_VALIDATE
|
|
virtual void Validate( CValidator &validator, const char *pchName );
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
bool IsObjectCached( CSharedObject *pObj, int nTypeID );
|
|
bool IsObjectDirty( CSharedObject *pObj );
|
|
#endif
|
|
|
|
protected:
|
|
virtual void MarkDirty();
|
|
virtual bool BShouldSendToAnyClients( uint32 unFlags ) const;
|
|
CCachedSubscriptionMessage *BuildSubscriberMessage( uint32 unFlags );
|
|
|
|
CSteamID m_steamIDTradingPartner;
|
|
|
|
protected:
|
|
void SendNetworkUpdateInternal( CSharedObject * pObj, const CUtlVector< int > &dirtyFields );
|
|
void SendUnsubscribeMessage( const CSteamID & steamID );
|
|
|
|
CSharedObjectContext m_context;
|
|
CSharedObjectDirtyList m_networkDirtyList;
|
|
CSharedObjectDirtyList m_databaseDirtyList;
|
|
bool m_bInWriteback;
|
|
RTime32 m_unWritebackTime;
|
|
uint32 m_unLRUHandle;
|
|
const IProtoBufMsg *m_pCacheToUsersSubscriptionMsg;
|
|
uint32 m_unCachedSubscriptionMsgFlags;
|
|
CCachedSubscriptionMessage *m_pCachedSubscriptionMsg;
|
|
};
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Loads a list of CSchemaSharedObjects from a result list from a
|
|
// query.
|
|
// Inputs: pResultSet - The result set from the SQL query
|
|
// schDefaults - A schema object that defines the values to set in
|
|
// the new objects for fields that were not read in the query.
|
|
// Typically this will be whatever fields were in the WHERE
|
|
// clause of the query.
|
|
// csRead - A columnSet defining the fields that were read in the query.
|
|
//----------------------------------------------------------------------------
|
|
template< typename SOClass_t >
|
|
bool CGCSharedObjectCache::BYieldingLoadSchObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & objDefaults )
|
|
{
|
|
if ( NULL == pResultSet )
|
|
return false;
|
|
|
|
CGCSharedObjectTypeCache *pTypeCache = GetTypeCache( SOClass_t::k_nTypeID, true );
|
|
pTypeCache->EnsureCapacity( pResultSet->GetRowCount() );
|
|
for( CSQLRecord record( 0, pResultSet ); record.IsValid(); record.NextRow() )
|
|
{
|
|
SOClass_t *pObj = new SOClass_t();
|
|
pObj->Obj() = objDefaults.Obj();
|
|
record.BWriteToRecord( &pObj->Obj(), csRead );
|
|
pTypeCache->AddObject( pObj );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Loads a single object of a type. If the object is not available,
|
|
// a new object will be created at default values
|
|
// Inputs: pResultSet - The result set from the SQL query
|
|
// schDefaults - A schema object that defines the values to set in
|
|
// the new objects for fields that were not read in the query.
|
|
// Typically this will be whatever fields were in the WHERE
|
|
// clause of the query.
|
|
// csRead - A columnSet defining the fields that were read in the query.
|
|
//----------------------------------------------------------------------------
|
|
template< typename SOClass_t >
|
|
bool CGCSharedObjectCache::BYieldingLoadSchSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SOClass_t & objDefaults )
|
|
{
|
|
if ( NULL == pResultSet )
|
|
return false;
|
|
|
|
if ( pResultSet->GetRowCount() > 1 )
|
|
{
|
|
EmitError( SPEW_SHAREDOBJ, "Multiple rows passed to BYieldingLoadSchSingleton() on type %d\n", objDefaults.GetTypeID() );
|
|
return false;
|
|
}
|
|
else if ( pResultSet->GetRowCount() == 1 )
|
|
{
|
|
return BYieldingLoadSchObjects<SOClass_t>( pResultSet, csRead, objDefaults );
|
|
}
|
|
else
|
|
{
|
|
// Create it if there wasn't one
|
|
SOClass_t *pSchObj = new SOClass_t();
|
|
pSchObj->Obj() = objDefaults.Obj();
|
|
if( !pSchObj->BYieldingAddToDatabase() )
|
|
{
|
|
EmitError( SPEW_SHAREDOBJ, "Unable to add singleton type %d for %s\n", pSchObj->GetTypeID(), GetOwner().Render() );
|
|
return false;
|
|
}
|
|
AddObject( pSchObj );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Loads a list of CProtoBufSharedObjects from a result list from a
|
|
// query.
|
|
// Inputs: pResultSet - The result set from the SQL query
|
|
// schDefaults - A schema object that defines the values to set in
|
|
// the new objects for fields that were not read in the query.
|
|
// Typically this will be whatever fields were in the WHERE
|
|
// clause of the query.
|
|
// csRead - A columnSet defining the fields that were read in the query.
|
|
//----------------------------------------------------------------------------
|
|
template< typename SOClass_t, typename SchClass_t >
|
|
bool CGCSharedObjectCache::BYieldingLoadProtoBufObjects( IGCSQLResultSet *pResultSet, const CColumnSet & csRead )
|
|
{
|
|
if ( NULL == pResultSet )
|
|
return false;
|
|
|
|
CGCSharedObjectTypeCache *pTypeCache = GetTypeCache( SOClass_t::k_nTypeID, true );
|
|
pTypeCache->EnsureCapacity( pResultSet->GetRowCount() );
|
|
for( CSQLRecord record( 0, pResultSet ); record.IsValid(); record.NextRow() )
|
|
{
|
|
SchClass_t schRecord;
|
|
record.BWriteToRecord( &schRecord, csRead );
|
|
|
|
SOClass_t *pObj = new SOClass_t();
|
|
pObj->ReadFromRecord( schRecord );
|
|
pTypeCache->AddObject( pObj );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: Loads a single object of a type. If the object is not available,
|
|
// a new object will be created at default values
|
|
// Inputs: pResultSet - The result set from the SQL query
|
|
// schDefaults - A schema object that defines the values to set in
|
|
// the new objects for fields that were not read in the query.
|
|
// Typically this will be whatever fields were in the WHERE
|
|
// clause of the query.
|
|
// csRead - A columnSet defining the fields that were read in the query.
|
|
//----------------------------------------------------------------------------
|
|
template< typename SOClass_t, typename SchClass_t >
|
|
bool CGCSharedObjectCache::BYieldingLoadProtoBufSingleton( IGCSQLResultSet *pResultSet, const CColumnSet & csRead, const SchClass_t & schDefaults )
|
|
{
|
|
if ( NULL == pResultSet )
|
|
return false;
|
|
|
|
if ( pResultSet->GetRowCount() > 1 )
|
|
{
|
|
EmitError( SPEW_SHAREDOBJ, "Multiple rows passed to BYieldingLoadProtoBufSingleton() on type %d\n", SOClass_t::k_nTypeID );
|
|
return false;
|
|
}
|
|
|
|
// load the duel summary
|
|
SchClass_t schRead;
|
|
CSQLRecord record( 0, pResultSet );
|
|
if( record.IsValid() )
|
|
{
|
|
record.BWriteToRecord( &schRead, csRead );
|
|
}
|
|
else
|
|
{
|
|
CSQLAccess sqlAccess;
|
|
if( !sqlAccess.BYieldingInsertRecord( const_cast<SchClass_t *>( &schDefaults ) ) )
|
|
return false;
|
|
schRead = schDefaults;
|
|
}
|
|
|
|
SOClass_t *pSharedObject = new SOClass_t();
|
|
pSharedObject->ReadFromRecord( schRead );
|
|
AddObject( pSharedObject );
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
} // namespace GCSDK
|
|
|
|
#include "tier0/memdbgoff.h"
|
|
|
|
#endif //GC_SHAREDOBJECTCACHE_H
|