summaryrefslogtreecommitdiff
path: root/game/shared/econ/econ_item_inventory.h
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/econ/econ_item_inventory.h')
-rw-r--r--game/shared/econ/econ_item_inventory.h472
1 files changed, 472 insertions, 0 deletions
diff --git a/game/shared/econ/econ_item_inventory.h b/game/shared/econ/econ_item_inventory.h
new file mode 100644
index 0000000..fd6e8b8
--- /dev/null
+++ b/game/shared/econ/econ_item_inventory.h
@@ -0,0 +1,472 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Container that allows client & server access to data in player inventories & loadouts
+//
+//=============================================================================
+
+#ifndef ITEM_INVENTORY_H
+#define ITEM_INVENTORY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "igamesystem.h"
+#include "econ_entity.h"
+#include "gamestringpool.h"
+#include "econ_item_view.h"
+#include "UtlSortVector.h"
+#include "econ_gcmessages.h"
+#include "gc_clientsystem.h"
+
+#if !defined(NO_STEAM)
+#include "steam/steam_api.h"
+#include "gcsdk/gcclientsdk.h"
+#endif // NO_STEAM
+
+
+class CPlayerInventory;
+class CEconItem;
+struct baseitemcriteria_t;
+class CEconItemViewHandle;
+#ifdef CLIENT_DLL
+class ITexture;
+#endif
+
+// Inventory Less function.
+// Used to sort the inventory items into their positions.
+class CInventoryListLess
+{
+public:
+ bool Less( const CEconItemView &src1, const CEconItemView &src2, void *pCtx );
+};
+
+// A class that wants notifications when an inventory is updated
+class IInventoryUpdateListener : public GCSDK::ISharedObjectListener
+{
+public:
+ virtual void InventoryUpdated( CPlayerInventory *pInventory ) = 0;
+
+ virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
+ virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
+ virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
+ virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
+ virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
+ virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
+ virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A single player's inventory.
+// On the client, the inventory manager contains an instance of this for the local player.
+// On the server, each player contains an instance of this.
+//-----------------------------------------------------------------------------
+class CPlayerInventory : public GCSDK::ISharedObjectListener
+{
+ DECLARE_CLASS_NOBASE( CPlayerInventory );
+public:
+ CPlayerInventory();
+ virtual ~CPlayerInventory();
+
+ void Clear();
+
+ // Returns true if this inventory has been filled out by Steam.
+ bool RetrievedInventoryFromSteam( void ) { return m_bGotItemsFromSteam; }
+ bool IsWaitingForSteam( void ) { return (m_iPendingRequests > 0); }
+
+ // Inventory access
+ CSteamID &GetOwner( void ) { return m_OwnerID; }
+ int GetItemCount( void ) const { return m_aInventoryItems.Count(); }
+ virtual bool CanPurchaseItems( int iItemCount ) const { return GetMaxItemCount() - GetItemCount() >= iItemCount; }
+ virtual int GetMaxItemCount( void ) const { return DEFAULT_NUM_BACKPACK_SLOTS; }
+ CEconItemView *GetItem( int i ) { return &m_aInventoryItems[i]; }
+
+ virtual CEconItemView *GetItemInLoadout( int iClass, int iSlot ) { AssertMsg( 0, "Implement me!" ); return NULL; }
+
+ // Get the item object cache data for the specified item
+ CEconItem *GetSOCDataForItem( itemid_t iItemID );
+ GCSDK::CGCClientSharedObjectCache *GetSOC( void ) { return m_pSOCache; }
+
+ // tells the GC systems to forget about this listener
+ void RemoveListener( GCSDK::ISharedObjectListener *pListener );
+
+ // Finds the item in our inventory that matches the specified global index
+ CEconItemView *GetInventoryItemByItemID( itemid_t iIndex, int *pIndex = NULL );
+
+ // Finds the item in our inventory that matches the specified global original id
+ CEconItemView *GetInventoryItemByOriginalID( itemid_t iOriginalID, int *pIndex = NULL );
+
+ // Finds the item in our inventory in the specified position
+ CEconItemView *GetItemByPosition( int iPosition, int *pIndex = NULL );
+
+ // Finds the first item in our backpack with match itemdef
+ CEconItemView *FindFirstItembyItemDef( item_definition_index_t iItemDef );
+
+ // Used to reject items on the backend for inclusion into this inventory.
+ // Mostly used for division of bags into different in-game inventories.
+ virtual bool ItemShouldBeIncluded( int iItemPosition ) { return true; }
+
+ // Debugging
+ virtual void DumpInventoryToConsole( bool bRoot );
+
+ // Extracts the position that should be used to sort items in the inventory from the backend position.
+ // Necessary if your inventory packs a bunch of info into the position instead of using it just as a position.
+ virtual int ExtractInventorySortPosition( uint32 iBackendPosition ) { return iBackendPosition; }
+
+ // Recipe access
+ int GetRecipeCount( void ) const;
+ const CEconCraftingRecipeDefinition *GetRecipeDef( int iIndex );
+ const CEconCraftingRecipeDefinition *GetRecipeDefByDefIndex( uint16 iDefIndex );
+
+ // Item previews
+ virtual int GetPreviewItemDef( void ) const { return 0; };
+
+ // Access helpers
+ virtual void SOClear();
+
+ virtual void NotifyHasNewItems() {}
+
+ void AddItemHandle( CEconItemViewHandle* pHandle );
+ void RemoveItemHandle( CEconItemViewHandle* pHandle );
+
+#ifdef CLIENT_DLL
+ virtual ITexture *GetWeaponSkinBaseLowRes( itemid_t nItemId, int iTeam ) const { return NULL; }
+#endif
+
+
+protected:
+ // Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
+ // use the SteamRequestX functions in CInventoryManager.
+ void RequestInventory( CSteamID pSteamID );
+ void AddListener( GCSDK::ISharedObjectListener *pListener );
+ virtual bool AddEconItem( CEconItem * pItem, bool bUpdateAckFile, bool bWriteAckFile, bool bCheckForNewItems );
+ virtual void RemoveItem( itemid_t iItemID );
+ bool FilloutItemFromEconItem( CEconItemView *pScriptItem, CEconItem *pEconItem );
+ void SendInventoryUpdateEvent();
+ virtual void OnHasNewItems() {}
+ virtual void OnItemChangedPosition( CEconItemView *pItem, uint32 iOldPos ) { return; }
+
+ virtual void SOCreated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
+ virtual void PreSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
+ virtual void SOUpdated( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
+ virtual void PostSOUpdate( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { /* do nothing */ }
+ virtual void SODestroyed( const CSteamID & steamIDOwner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
+ virtual void SOCacheSubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
+ virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
+
+ void ResortInventory( void ) { m_aInventoryItems.RedoSort( true ); }
+ virtual void ValidateInventoryPositions( void );
+
+ // Derived inventory hooks
+ virtual void ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile );
+ virtual void ItemIsBeingRemoved( CEconItemView *pItem ) { return; }
+
+ // Get the index for the item in our inventory utlvector
+ int GetIndexForItem( CEconItemView *pItem );
+
+ void DirtyItemHandles();
+
+protected:
+ // The Steam Id of the player who owns this inventory
+ CSteamID m_OwnerID;
+
+ // The items the player has in his inventory, received from steam.
+ CUtlSortVector<CEconItemView,CInventoryListLess> m_aInventoryItems;
+
+ int m_iPendingRequests;
+ bool m_bGotItemsFromSteam;
+
+ GCSDK::CGCClientSharedObjectCache *m_pSOCache;
+
+ CUtlVector<GCSDK::ISharedObjectListener *> m_vecListeners;
+
+ CUtlVector< CEconItemViewHandle* > m_vecItemHandles;
+
+ friend class CInventoryManager;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CInventoryManager : public CAutoGameSystemPerFrame
+{
+ DECLARE_CLASS_GAMEROOT( CInventoryManager, CAutoGameSystem );
+public:
+ CInventoryManager( void );
+
+ // Adds the inventory to the list of inventories that should be maintained.
+ // This causes the game to load the items for the SteamID into this inventory.
+ // NOTE: This fires off a request to Steam. The data will not be filled out immediately.
+ void SteamRequestInventory( CPlayerInventory *pInventory, CSteamID pSteamID, IInventoryUpdateListener *pListener = NULL );
+
+ void PreInitGC();
+ void PostInitGC();
+
+#ifdef CLIENT_DLL
+ void DropItem( itemid_t iItemID );
+ int DeleteUnknowns( CPlayerInventory *pInventory );
+#endif
+
+public:
+ //-----------------------------------------------------------------------
+ // IAutoServerSystem
+ //-----------------------------------------------------------------------
+ virtual bool Init( void ) OVERRIDE;
+ virtual void PostInit( void ) OVERRIDE;
+ virtual void Shutdown() OVERRIDE;
+ virtual void LevelInitPreEntity( void ) OVERRIDE;
+ virtual void LevelShutdownPostEntity( void ) OVERRIDE;
+
+#ifdef CLIENT_DLL
+ // Gets called each frame
+ virtual void Update( float frametime ) OVERRIDE;
+#endif
+
+ void GameServerSteamAPIActivated();
+
+ virtual CPlayerInventory *GetInventoryForAccount( uint32 iAccountID );
+
+ // We're generating a base item. We need to add the game-specific keys to the criteria so that it'll find the right base item.
+ virtual void AddBaseItemCriteria( baseitemcriteria_t *pCriteria, CItemSelectionCriteria *pSelectionCriteria ) { return; }
+
+#ifdef CLIENT_DLL
+ // Must be implemented by derived class
+ virtual bool EquipItemInLoadout( int iClass, int iSlot, itemid_t iItemID ) = 0;
+
+ virtual CPlayerInventory *GeneratePlayerInventoryObject() const { return new CPlayerInventory; }
+
+ //-----------------------------------------------------------------------
+ // ITEM PRESETS
+ //-----------------------------------------------------------------------
+
+ // Is the given preset index valid?
+ bool IsPresetIndexValid( equipped_preset_t unPreset );
+
+ // Equip all items for the given class and preset (all the work is done on the GC -- this just
+ // sends the message up)
+ bool LoadPreset( equipped_class_t unClass, equipped_preset_t unPreset );
+
+ //-----------------------------------------------------------------------
+ // LOCAL INVENTORY
+ //
+ // On the client, we have a single inventory for the local player. Stored here, instead of in the
+ // local player entity, because players need to access it while not being connected to a server.
+ // Override GetLocalInventory() in your inventory manager and return your custom local inventory.
+ //-----------------------------------------------------------------------
+ virtual void UpdateLocalInventory( void );
+ virtual CPlayerInventory *GetLocalInventory( void ) { return NULL; }
+
+ // The local inventory is used to track discards & responses to. We need to
+ // make a decision about inventory space right after sending a delete request,
+ // so we predict the request will work.
+ void OnItemDeleted( CPlayerInventory *pInventory ) { if ( pInventory == GetLocalInventory() ) m_iPredictedDiscards--; }
+
+ virtual void PersonaName_Precache( uint32 unAccountID );
+ virtual const char *PersonaName_Get( uint32 unAccountID );
+ virtual void PersonaName_Store( uint32 unAccountID, const char *pPersonaName );
+
+ static void SendGCConnectedEvent( void );
+
+ // Returns the item at the specified backpack position
+ virtual CEconItemView *GetItemByBackpackPosition( int iBackpackPosition );
+
+ // Moves the item to the specified backpack position. If there's another item as that spot, it swaps positions with it.
+ virtual void MoveItemToBackpackPosition( CEconItemView *pItem, int iBackpackPosition );
+
+ // Tries to set the item to the specified backpack position. Passing in 0 will find the first empty position.
+ // FAILS if the backpack is full, or if that spot isn't clear. Returns false in that case.
+ virtual bool SetItemBackpackPosition( CEconItemView *pItem, uint32 iPosition = 0, bool bForceUnequip = false, bool bAllowOverflow = false );
+
+ // Sort the backpack items by the specified type
+ virtual void SortBackpackBy( uint32 iSortType );
+ void SortBackpackFinished( void );
+ bool IsInBackpackSort( void ) { return m_bInBackpackSort; }
+
+ void PredictedBackpackPosFilled( int iBackpackPos ) { m_PredictedFilledSlots.FindAndRemove( iBackpackPos ); }
+
+ // Tell the backend to move an item to a specified backend position
+ virtual void UpdateInventoryPosition( CPlayerInventory *pInventory, uint64 ulItemID, uint32 unNewInventoryPos );
+
+ virtual void UpdateInventoryEquippedState( CPlayerInventory *pInventory, uint64 ulItemID, equipped_class_t unClass, equipped_slot_t unSlot );
+
+
+ //-----------------------------------------------------------------------
+ // CLIENT PICKUP UI HANDLING
+ //-----------------------------------------------------------------------
+
+ // Get the number of items picked up
+ virtual int GetNumItemPickedUpItems( void ) { return 0; }
+
+ // Show the player a pickup screen with any items they've collected recently, if any
+ virtual bool ShowItemsPickedUp( bool bForce = false, bool bReturnToGame = true, bool bNoPanel = false );
+
+ // Show the player a pickup screen with the items they've crafted
+ virtual void ShowItemsCrafted( CUtlVector<itemid_t> *vecCraftedIndices ) { return; }
+
+ // Force the player to discard an item to make room for a new item, if they have one.
+ // Returns true if the discard panel has been brought up, and the player will be forced to discard an item.
+ virtual bool CheckForRoomAndForceDiscard( void );
+
+ //-----------------------------------------------------------------------
+ // CLIENT ITEM PICKUP ACKNOWLEDGEMENT FILES
+ //
+ // This system avoids showing multiple pickups for items that we've found, but haven't been
+ // able to move out of unack'd position due to the GC being unavailable. We keep a list of
+ // items we've ack'd in a client file, and don't re-show pickups for them. When a GC item
+ // update tells us the item has moved out of the unack'd position, we remove it from our file.
+ //-----------------------------------------------------------------------
+
+ virtual void AcknowledgeItem ( CEconItemView *pItem, bool bMoveToBackpack = true ); // Client Acknowledges an item and moves it in to the backpack
+ bool HasBeenAckedByClient( CEconItemView *pItem ); // Returns true if it's in our client file
+ void SetAckedByClient( CEconItemView *pItem ); // Adds it to our client file
+ void SetAckedByGC( CEconItemView *pItem, bool bSave ); // Removes it from our client file
+ KeyValues *GetAckKeyForItem( CEconItemView *pItem );
+ void CleanAckFile( void );
+ void SaveAckFile( void );
+
+private:
+ void VerifyAckFileLoaded( void );
+ KeyValues *m_pkvItemClientAckFile;
+ bool m_bClientAckDirty;
+
+private:
+ // As we move items around in batches (on pickups usually) we need to know what slots will be filled
+ // by items we've moved, and haven't received a response from Steam.
+ CUtlVector<int> m_PredictedFilledSlots;
+#endif
+
+public:
+ virtual int GetBackpackPositionFromBackend( uint32 iBackendPosition ) { return ExtractBackpackPositionFromBackend(iBackendPosition); }
+
+private:
+ //-----------------------------------------------------------------------
+ // Pending inventory requests
+ struct pendingreq_t
+ {
+ CPlayerInventory *pInventory;
+ CSteamID pID;
+ };
+ CUtlVector<pendingreq_t> m_hPendingInventoryRequests;
+ void RemovePendingRequest( CSteamID *pSteamID );
+
+protected:
+ //-----------------------------------------------------------------------
+ // Inventory registry
+ void DeregisterInventory( CPlayerInventory *pInventory );
+ struct inventories_t
+ {
+ CPlayerInventory *pInventory;
+ IInventoryUpdateListener *pListener;
+ };
+ CUtlVector<inventories_t> m_pInventories;
+
+ friend class CPlayerInventory;
+
+ inline bool IsValidPlayerClass( equipped_class_t unClass );
+
+#ifdef CLIENT_DLL
+ // Keep track of the number of items we've tried to discard, but haven't recieved responses on
+ int m_iPredictedDiscards;
+
+ typedef CUtlMap< uint32, CUtlString, int > tPersonaNamesByAccountID;
+ tPersonaNamesByAccountID m_mapPersonaNamesCache;
+
+ bool m_bInBackpackSort;
+
+ float m_flNextLoadPresetChange;
+
+ CMsgSetItemPositions m_msgPendingSetItemPositions;
+ CMsgLookupMultipleAccountNames m_msgPendingLookupAccountNames;
+
+ void OnPersonaStateChanged( PersonaStateChange_t *info );
+ CCallback< CInventoryManager, PersonaStateChange_t, false > m_sPersonaStateChangedCallback;
+ CUtlMap< uint64, bool > m_personaNameRequests;
+
+#endif
+};
+
+//=================================================================================
+// Implement these functions in your game code to create custom derived versions
+CInventoryManager *InventoryManager( void );
+
+CBasePlayer *GetPlayerBySteamID( const CSteamID &steamID );
+
+//-----------------------------------------------------------------------------
+// Purpose: Maintains a handle to an CEconItemView within an inventory. When
+// the inventory gets updated and shuffles CEconItemViews around, this
+// handle automatically updates its pointer to point to the new
+// CEconItemView that has the same item_id
+//-----------------------------------------------------------------------------
+class CEconItemViewHandle
+{
+public:
+ CEconItemViewHandle()
+ : m_pItem( NULL )
+ , m_pInv( NULL )
+ , m_bPointerDirty( false )
+ {}
+
+ CEconItemViewHandle( CEconItemView* pItem )
+ : m_pItem( pItem )
+ , m_pInv( NULL )
+ , m_bPointerDirty( false )
+ {
+ SetItem( pItem );
+ }
+
+ virtual ~CEconItemViewHandle()
+ {
+ // Unregister us
+ if ( m_pInv )
+ {
+ m_pInv->RemoveItemHandle( this );
+ }
+ }
+
+ void SetItem( CEconItemView* pItem );
+
+ operator CEconItemView *( void ) const
+ {
+ return Get();
+ }
+
+ CEconItemView* operator->( void ) const
+ {
+ return Get();
+ }
+
+ void ItemIsBeingDeleted( const CEconItemView* pItem )
+ {
+ m_bPointerDirty = true;
+
+ // Inventory told us the item is going away
+ if ( m_pItem == pItem )
+ {
+ m_pItem = NULL;
+ }
+ }
+
+ void InventoryIsBeingDeleted()
+ {
+ m_pInv = NULL;
+ m_pItem = NULL;
+ m_bPointerDirty = false; // So we dont keep trying to look up the item
+ }
+
+ void MarkDirty()
+ {
+ m_bPointerDirty = true;
+ }
+
+private:
+
+ CEconItemView* Get() const;
+
+ mutable bool m_bPointerDirty; // Used to mark when m_pItem is no longer valid
+ CPlayerInventory *m_pInv; // Inventory the item belongs to. Used to look up new CEconItemView
+ mutable CEconItemView* m_pItem; // The item.
+ uint64 m_nItemID; // ID of the item
+ CSteamID m_OwnerSteamID; // Steam ID of the item owner
+};
+
+
+#endif // ITEM_INVENTORY_H