diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/econ/econ_item_inventory.h | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/econ/econ_item_inventory.h')
| -rw-r--r-- | game/shared/econ/econ_item_inventory.h | 472 |
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 |