text: ﻿//========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: Additional shared object cache functionality for the GC
  //
  //=============================================================================
  
  #ifndef GCCLIENT_SHAREDOBJECTCACHE_H
  #define GCCLIENT_SHAREDOBJECTCACHE_H
  #ifdef _WIN32
  #pragma once
  #endif
  
  #include "sharedobjectcache.h"
  
  class CMsgSOCacheSubscribed;
  
  class CMsgSOCacheSubscribed_SubscribedType;
  
  namespace GCSDK {
  
  /// Enumerate different events that might trigger a callback to an ISharedObjectListener
      enum ESOCacheEvent {
  
          /// Dummy sentinel value
          eSOCacheEvent_None = 0,
  
          /// We received a our first update from the GC and are subscribed
          eSOCacheEvent_Subscribed = 1,
  
          /// We lost connection to GC or GC notified us that we are no longer subscribed.
          /// Objects stay in the cache, but we no longer receive updates
          eSOCacheEvent_Unsubscribed = 2,
  
          /// We received a full update from the GC on a cache for which we were already subscribed.
          /// This can happen if connectivity is lost, and then restored before we realized it was lost.
          eSOCacheEvent_Resubscribed = 3,
  
          /// We received an incremental update from the GC about specific object(s) being
          /// added, updated, or removed from the cache
          eSOCacheEvent_Incremental = 4,
  
          /// A lister was added to the cache
          /// @see CGCClientSharedObjectCache::AddListener
          eSOCacheEvent_ListenerAdded = 5,
  
          /// A lister was removed from the cache
          /// @see CGCClientSharedObjectCache::RemoveListener
          eSOCacheEvent_ListenerRemoved = 6,
      };
  
  //----------------------------------------------------------------------------
  // Purpose: Allow game components to register themselves to hear about inventory
  //			changes when they are received from the server
  //----------------------------------------------------------------------------
      class ISharedObjectListener {
      public:
  
          /// Called when a new object is created in a cache we are currently subscribed to, or when we are added
          /// as a listener to a cache which already has objects in it
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Subscribed
          /// - eSOCacheEvent_Resubscribed
          /// - eSOCacheEvent_Incremental
          /// - eSOCacheEvent_ListenerAdded
          virtual void SOCreated(const CSteamID &steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent) = 0;
  
          /// Called when we are about to update objects in our cache but haven't done any of the work yet.
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Resubscribed
          /// - eSOCacheEvent_Incremental
          virtual void PreSOUpdate(const CSteamID &steamIDOwner, ESOCacheEvent eEvent) = 0;
  
          /// Called when an object is updated in a cache we are currently subscribed to.
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Resubscribed
          /// - eSOCacheEvent_Incremental
          virtual void SOUpdated(const CSteamID &steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent) = 0;
  
          /// Called when we're finished updating objects in our cache for this batch.
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Resubscribed
          /// - eSOCacheEvent_Incremental
          virtual void PostSOUpdate(const CSteamID &steamIDOwner, ESOCacheEvent eEvent) = 0;
  
          /// Called when an object is about to be deleted in a cache we are currently subscribed to.
          /// The object will have already been removed from the cache, but is still valid.
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Incremental
          /// - eSOCacheEvent_Resubscribed
          virtual void SODestroyed(const CSteamID &steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent) = 0;
  
          /// Called to notify a listener that he is subscribed to the cache.
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Subscribed
          /// - eSOCacheEvent_Resubscribed
          /// - eSOCacheEvent_ListenerAdded
          ///
          /// A listener is guaranteed that it will not receive incremental updates (SOCreated,
          /// SOUpdated, SODestroyed) while not subscribed.  (Before the SOCacheSubscribed or
          /// after SOCacheUnsubscribed.)  However, note that it may be possible to receive
          /// an SOCacheSubscribed message while already subscribed.  This can happen if the
          /// GC loses and restores connection, or otherwise decides that a full update is
          /// necessary.
          virtual void SOCacheSubscribed(const CSteamID &steamIDOwner, ESOCacheEvent eEvent) = 0;
  
          /// Called to notify a listener that he is no longer subscribed to the cache.
          /// if he is being removed as a listener, then he will no longer receive
          /// updates.  Otherwise, he might receive another SOCacheSubscribed
          /// message, followed by further update notifications.
          ///
          /// eEvent will be one of:
          /// - eSOCacheEvent_Unsubscribed
          /// - eSOCacheEvent_ListenerRemoved
          virtual void SOCacheUnsubscribed(const CSteamID &steamIDOwner, ESOCacheEvent eEvent) = 0;
      };
  
  
  //----------------------------------------------------------------------------
  // Purpose: The part of a shared object cache that handles all objects of a 
  //			single type.
  //----------------------------------------------------------------------------
      class CGCClientSharedObjectContext {
      public:
          CGCClientSharedObjectContext(const CSteamID &steamIDOwner);
  
          bool BAddListener(ISharedObjectListener *pListener);
  
          bool BRemoveListener(ISharedObjectListener *pListener);
  
          void SOCreated(const CSharedObject *pObject, ESOCacheEvent eEvent) const;
  
          void PreSOUpdate(GCSDK::ESOCacheEvent eEvent) const;
  
          void SOUpdated(const CSharedObject *pObject, ESOCacheEvent eEvent) const;
  
          void PostSOUpdate(GCSDK::ESOCacheEvent eEvent) const;
  
          void SODestroyed(const CSharedObject *pObject, ESOCacheEvent eEvent) const;
  
          void SOCacheSubscribed(const CSteamID &steamIDOwner, ESOCacheEvent eEvent) const;
  
          void SOCacheUnsubscribed(const CSteamID &steamIDOwner, ESOCacheEvent eEvent) const;
  
          const CSteamID &GetOwner() const { return m_steamIDOwner; }
  
          const CUtlVector<ISharedObjectListener *> &GetListeners() const { return m_vecListeners; }
  
      private:
          CSteamID m_steamIDOwner;
          CUtlVector<ISharedObjectListener *> m_vecListeners;
      };
  
  
  //----------------------------------------------------------------------------
  // Purpose: The part of a shared object cache that handles all objects of a 
  //			single type.
  //----------------------------------------------------------------------------
      class CGCClientSharedObjectTypeCache : public CSharedObjectTypeCache {
      public:
          CGCClientSharedObjectTypeCache(int nTypeID, const CGCClientSharedObjectContext &context);
  
          virtual ~CGCClientSharedObjectTypeCache();
  
          bool BParseCacheSubscribedMsg(const CMsgSOCacheSubscribed_SubscribedType &msg,
                                        CUtlVector<CSharedObject *> &vecCreatedObjects,
                                        CUtlVector<CSharedObject *> &vecUpdatedObjects,
                                        CUtlVector<CSharedObject *> &vecObjectsToDestroy);
  
          CSharedObject *BCreateFromMsg(const void *pvData, uint32 unSize, bool *bUpdatedExisting);
  
          bool BDestroyFromMsg(const void *pvData, uint32 unSize);
  
          bool BUpdateFromMsg(const void *pvData, uint32 unSize);
  
          void RemoveAllObjects(CUtlVector<CSharedObject *> &vecObjects);
  
      private:
          const CGCClientSharedObjectContext &m_context;
      };
  
  
  //----------------------------------------------------------------------------
  // 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 CGCClientSharedObjectCache : public CSharedObjectCache {
          friend class CGCSOUpdateMultipleJob;
  
      public:
          CGCClientSharedObjectCache(const CSteamID &steamIDOwner = CSteamID());
  
          virtual ~CGCClientSharedObjectCache();
  
          /// Have we received at least one update from the GC?
          bool BIsInitialized() const { return m_bInitialized; }
  
          /// Are we currently subscribed to updates from the GC?
          bool BIsSubscribed() const { return m_bSubscribed; }
  
          /// Who owns this cache?
          virtual const CSteamID &GetOwner() const { return m_context.GetOwner(); }
  
          /// Adds a listener interface to the object.  A call to re-add
          /// a listener that's already listening is harmlessly ignored.
          ///
          /// If the cache is currently subscribed, then the listener will
          /// immediately receive a SOCacheSubscribed call.
          void AddListener(ISharedObjectListener *pListener);
  
          /// Removes a listener interface on the object.  Returns true
          /// if we were listening and removed OK, false if we were not
          /// previously listening and the call was ignored
          ///
          /// If the cache is currently subscribed and we were listening,
          /// then the listener will immediately receive a SOCacheUnsubscribed
          /// call.
          bool RemoveListener(ISharedObjectListener *pListener);
  
          CGCClientSharedObjectTypeCache *
          FindTypeCache(int nClassID) { return (CGCClientSharedObjectTypeCache *) FindBaseTypeCache(nClassID); }
  
          CGCClientSharedObjectTypeCache *
          CreateTypeCache(int nClassID) { return (CGCClientSharedObjectTypeCache *) CreateBaseTypeCache(nClassID); }
  
          bool BParseCacheSubscribedMsg(const CMsgSOCacheSubscribed &msg);
  
          void NotifyUnsubscribe();
  
          void NotifyResubscribedUpToDate();
  
          bool BCreateFromMsg(int nTypeID, const void *pvData, uint32 unSize);
  
          bool BDestroyFromMsg(int nTypeID, const void *pvData, uint32 unSize);
  
          bool BUpdateFromMsg(int nTypeID, const void *pvData, uint32 unSize);
  
  #ifdef DBGFLAG_VALIDATE
          virtual void Validate( CValidator &validator, const char *pchName );
  #endif
  
      protected:
      private:
          virtual CSharedObjectTypeCache *AllocateTypeCache(int nClassID) const OVERRIDE {
              return new CGCClientSharedObjectTypeCache(nClassID, m_context);
          }
  
          CGCClientSharedObjectTypeCache *GetTypeCacheByIndex(int nIndex) {
              return (CGCClientSharedObjectTypeCache *) CSharedObjectCache::GetTypeCacheByIndex(nIndex);
          }
  
          CGCClientSharedObjectContext m_context;
          bool m_bInitialized;
          bool m_bSubscribed;
      };
  
  
  } // namespace GCSDK
  
  
  #endif //GCCLIENT_SHAREDOBJECTCACHE_H
  