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.

490 lines
21 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Container that allows client & server access to data in player inventories & loadouts
  4. //
  5. //=============================================================================
  6. #ifndef ITEM_INVENTORY_H
  7. #define ITEM_INVENTORY_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "igamesystem.h"
  12. #include "econ_entity.h"
  13. #include "econ_item_view.h"
  14. #include "utlsortvector.h"
  15. #if !defined(NO_STEAM)
  16. #include "steam/steam_api.h"
  17. #include "gcsdk/gcclientsdk.h"
  18. #endif // NO_STEAM
  19. class CPlayerInventory;
  20. class CEconItem;
  21. struct baseitemcriteria_t;
  22. // Inventory Less function.
  23. // Used to sort the inventory items into their positions.
  24. class CInventoryListLess
  25. {
  26. public:
  27. bool Less( CEconItemView* const &src1, CEconItemView *const &src2, void *pCtx );
  28. };
  29. // A class that wants notifications when an inventory is updated
  30. class IInventoryUpdateListener : public GCSDK::ISharedObjectListener
  31. {
  32. public:
  33. virtual void InventoryUpdated( CPlayerInventory *pInventory ) = 0;
  34. virtual void SOCreated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
  35. virtual void SOUpdated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
  36. virtual void SODestroyed( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
  37. virtual void SOCacheSubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
  38. virtual void SOCacheUnsubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
  39. };
  40. //-----------------------------------------------------------------------------
  41. // Purpose: A single player's inventory.
  42. // On the client, the inventory manager contains an instance of this for the local player.
  43. // On the server, each player contains an instance of this.
  44. //-----------------------------------------------------------------------------
  45. class CPlayerInventory : public GCSDK::ISharedObjectListener
  46. {
  47. DECLARE_CLASS_NOBASE( CPlayerInventory );
  48. public:
  49. CPlayerInventory();
  50. virtual ~CPlayerInventory();
  51. void Shutdown( void );
  52. // Returns true if this inventory has been filled out by Steam.
  53. bool InventoryRetrievedFromSteamAtLeastOnce( void ) const { return m_bGotItemsFromSteamAtLeastOnce; }
  54. bool InventorySubscribedToSteamCurrently( void ) const { return m_bCurrentlySubscribedToSteam; }
  55. // Inventory access
  56. GCSDK::SOID_t GetOwner( void ) { return m_OwnerID; }
  57. void SetOwner( GCSDK::SOID_t& ownerID ) { m_OwnerID = ownerID; }
  58. int GetItemCount( void ) const { return m_Items.GetItemVector().Count(); }
  59. int GetDefaultEquippedDefinitionItemsCount( void ) const { return m_aDefaultEquippedDefinitionItems.Count(); }
  60. virtual bool CanPurchaseItems( int iItemCount ) const { return GetMaxItemCount() - GetItemCount() >= iItemCount; }
  61. virtual int GetMaxItemCount( void ) const { return DEFAULT_NUM_BACKPACK_SLOTS; }
  62. CEconItemView *GetItem( int i ) { return m_Items.GetItemVector()[i]; }
  63. CEconItemView *GetDefaultEquippedDefinitionItem( int i ) { return m_aDefaultEquippedDefinitionItems[ i ]; }
  64. CEconItemView *FindDefaultEquippedDefinitionItemBySlot( int iClass, int iSlot ) const;
  65. bool GetDefaultEquippedDefinitionItemSlotByDefinitionIndex( item_definition_index_t nDefIndex, int nClass, int &nSlot );
  66. void SetDefaultEquippedDefinitionItemBySlot( int iClass, int iSlot, item_definition_index_t iDefIndex );
  67. void FindItemsByType( EItemType eType, CUtlVector< CEconItemView* >& outVec );
  68. virtual CEconItemView *GetItemInLoadout( int iClass, int iSlot ) const { AssertMsg( 0, "Implement me!" ); return NULL; }
  69. // Get the item object cache data for the specified item
  70. CEconItem *GetSOCDataForItem( itemid_t iItemID );
  71. const CEconItem *GetSOCDataForItem( itemid_t iItemID ) const;
  72. GCSDK::CGCClientSharedObjectCache *GetSOC( void ) { return m_pSOCache; }
  73. // tells the GC systems to forget about this listener
  74. void RemoveListener( GCSDK::ISharedObjectListener *pListener );
  75. // Finds the item in our inventory that matches the specified global index
  76. CEconItemView *GetInventoryItemByItemID( itemid_t iIndex ) const;
  77. // Finds the item in our inventory in the specified position
  78. CEconItemView *GetItemByPosition( int iPosition, int *pIndex = NULL );
  79. // Used to reject items on the backend for inclusion into this inventory.
  80. // Mostly used for division of bags into different in-game inventories.
  81. virtual bool ItemShouldBeIncluded( int iItemPosition ) { return true; }
  82. // Debugging
  83. virtual void DumpInventoryToConsole( bool bRoot );
  84. // Extracts the position that should be used to sort items in the inventory from the backend position.
  85. // Necessary if your inventory packs a bunch of info into the position instead of using it just as a position.
  86. virtual int ExtractInventorySortPosition( uint32 iBackendPosition ) { return iBackendPosition; }
  87. // Recipe access
  88. int GetRecipeCount( void ) const;
  89. const CEconCraftingRecipeDefinition *GetRecipeDef( int iIndex ) const;
  90. const CEconCraftingRecipeDefinition *GetRecipeDefByDefIndex( uint16 iDefIndex ) const;
  91. int GetMaxCraftIngredientsNeeded( const CUtlVector< itemid_t >& vecCraftEconItems ) const;
  92. void GetMarketCraftCompletionLink( const CUtlVector< itemid_t >& vecCraftItems, char *pchLink, int nNumChars ) const;
  93. int GetPossibleCraftResultsCount( const CUtlVector< itemid_t >& vecCraftItems ) const;
  94. int GetPossibleCraftResultsCount( const CUtlVector< CEconItem* >& vecCraftEconItems ) const;
  95. const CEconCraftingRecipeDefinition *GetPossibleCraftResult( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
  96. int GetPossibleCraftResultID( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
  97. const wchar_t* GetPossibleCraftResultName( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
  98. const wchar_t* GetPossibleCraftResultDescription( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
  99. bool CanAddToCraftTarget( const CUtlVector< itemid_t >& vecCraftItems, itemid_t nNewItem ) const;
  100. bool IsCraftReady( const CUtlVector< itemid_t >& vecCraftItems, int16 &nRecipe ) const;
  101. void CraftIngredients( const CUtlVector< itemid_t >& vecCraftItems ) const;
  102. void SetTargetCraftRecipe( int nRecipe ) { m_nTargetRecipe = nRecipe; }
  103. int16 GetTargetCraftRecipe( void ) const { return m_nTargetRecipe; }
  104. // Finds the item in our inventory that matches the specified global index
  105. void ClearItemCustomName( itemid_t iIndex );
  106. void WearItemSticker( itemid_t iIndex, int nSlot, float flStickerWearCurrent );
  107. // Item access
  108. uint32 GetItemCount( uint32 unItemDef );
  109. // Item previews
  110. virtual int GetPreviewItemDef( void ) const { return 0; };
  111. // Access helpers
  112. virtual void SOClear();
  113. virtual void NotifyHasNewItems() {}
  114. bool AddEconItem( CEconItem * pItem, bool bUpdateAckFile, bool bWriteAckFile, bool bCheckForNewItems );
  115. enum EInventoryItemEvent
  116. {
  117. k_EInventoryItemCreated,
  118. k_EInventoryItemUpdated,
  119. k_EInventoryItemDestroyed,
  120. };
  121. // Made public for an inventory helper func
  122. int m_nTargetRecipe;
  123. protected:
  124. // Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
  125. // use the SteamRequestX functions in CInventoryManager.
  126. void RequestInventory( GCSDK::SOID_t ID );
  127. void AddListener( GCSDK::ISharedObjectListener *pListener );
  128. virtual void RemoveItem( itemid_t iItemID );
  129. bool AddEconDefaultEquippedDefinition( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition );
  130. bool FilloutItemFromEconItem( CEconItemView *pScriptItem, CEconItem *pEconItem );
  131. virtual void SendInventoryUpdateEvent();
  132. virtual void OnHasNewItems() {}
  133. virtual void OnItemChangedPosition( CEconItemView *pItem, uint32 iOldPos ) { return; }
  134. virtual void SOCreated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
  135. virtual void SOUpdated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
  136. virtual void SODestroyed( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
  137. virtual void SOCacheSubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
  138. virtual void SOCacheUnsubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
  139. virtual void ValidateInventoryPositions( void );
  140. // Derivable Inventory hooks
  141. virtual void ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile, EInventoryItemEvent eEventType );
  142. virtual void ItemIsBeingRemoved( CEconItemView *pItem ) { return; }
  143. virtual void DefaultEquippedDefinitionHasBeenUpdated( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition );
  144. virtual void MarkSetItemDescriptionsDirty( int nItemSetIndex );
  145. // Get the index for the item in our inventory utlvector
  146. int GetIndexForItem( CEconItemView *pItem );
  147. protected:
  148. // The SharedObject Id of the player who owns this inventory
  149. GCSDK::SOID_t m_OwnerID;
  150. CUtlVector< CEconItemView*> m_aDefaultEquippedDefinitionItems;
  151. typedef CUtlMap< itemid_t, CEconItemView*, int, CDefLess< itemid_t > > ItemIdToItemMap_t;
  152. // Wrap different container types so they all stay in sync with inventory state
  153. class CItemContainers
  154. {
  155. public:
  156. void Add( CEconItemView* pItem );
  157. void Remove( itemid_t ullItemID );
  158. void Purge();
  159. bool DbgValidate() const; // Walk all containers and confirm content matches
  160. const CUtlVector< CEconItemView*>& GetItemVector( void ) const { return m_vecInventoryItems; }
  161. const ItemIdToItemMap_t& GetItemMap( void ) const { return m_mapItemIDToItemView; }
  162. private:
  163. // The items the player has in his inventory, received from steam.
  164. CUtlVector< CEconItemView*> m_vecInventoryItems;
  165. // Copies of pointers in vector for faster lookups
  166. ItemIdToItemMap_t m_mapItemIDToItemView;
  167. };
  168. CItemContainers m_Items;
  169. int m_iPendingRequests;
  170. bool m_bGotItemsFromSteamAtLeastOnce, m_bCurrentlySubscribedToSteam;
  171. GCSDK::CGCClientSharedObjectCache *m_pSOCache;
  172. CUtlVector<GCSDK::ISharedObjectListener *> m_vecListeners;
  173. friend class CInventoryManager;
  174. };
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. //-----------------------------------------------------------------------------
  178. class CInventoryManager : public CAutoGameSystem
  179. {
  180. DECLARE_CLASS_GAMEROOT( CInventoryManager, CAutoGameSystem );
  181. public:
  182. CInventoryManager( void );
  183. virtual ~CInventoryManager() {}
  184. // Adds the inventory to the list of inventories that should be maintained.
  185. // This causes the game to load the items for the SteamID into this inventory.
  186. // NOTE: This fires off a request to Steam. The data will not be filled out immediately.
  187. void SteamRequestInventory( CPlayerInventory *pInventory, CSteamID pSteamID, IInventoryUpdateListener *pListener = NULL );
  188. void RegisterPlayerInventory( CPlayerInventory *pInventory, IInventoryUpdateListener *pListener = NULL, CSteamID* pSteamID = NULL );
  189. void PreInitGC();
  190. void PostInitGC();
  191. #ifdef CLIENT_DLL
  192. void DeleteItem( itemid_t iItemID, bool bRecycle=false );
  193. int DeleteUnknowns( CPlayerInventory *pInventory );
  194. #endif
  195. public:
  196. //-----------------------------------------------------------------------
  197. // IAutoServerSystem
  198. //-----------------------------------------------------------------------
  199. virtual bool Init( void );
  200. virtual void PostInit( void );
  201. virtual void Shutdown();
  202. virtual void LevelInitPreEntity( void );
  203. virtual void LevelShutdownPostEntity( void );
  204. #if defined(CSTRIKE15) && defined(CLIENT_DLL)
  205. virtual void InsertMaterialGenerationJob( CEconItemView *pItemView );
  206. virtual void OnDestroyEconItemView( CEconItemView *pItemView );
  207. #endif
  208. void GameServerSteamAPIActivated();
  209. virtual CPlayerInventory *GetInventoryForAccount( uint32 iAccountID );
  210. // 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.
  211. virtual void AddBaseItemCriteria( baseitemcriteria_t *pCriteria, CItemSelectionCriteria *pSelectionCriteria ) { return; }
  212. #ifdef CLIENT_DLL
  213. // Must be implemented by derived class
  214. virtual bool EquipItemInLoadout( int iClass, int iSlot, itemid_t iItemID, bool bSwap = false ) = 0;
  215. virtual CPlayerInventory *GeneratePlayerInventoryObject() const { return new CPlayerInventory; }
  216. void DestroyPlayerInventoryObject( CPlayerInventory *pPlayerInventory ) const;
  217. //-----------------------------------------------------------------------
  218. // LOCAL INVENTORY
  219. //
  220. // On the client, we have a single inventory for the local player. Stored here, instead of in the
  221. // local player entity, because players need to access it while not being connected to a server.
  222. // Override GetLocalInventory() in your inventory manager and return your custom local inventory.
  223. //-----------------------------------------------------------------------
  224. virtual void UpdateLocalInventory( void );
  225. virtual CPlayerInventory *GetLocalInventory( void ) { return NULL; }
  226. // The local inventory is used to track discards & responses to. We need to
  227. // make a decision about inventory space right after sending a delete request,
  228. // so we predict the request will work.
  229. void OnItemDeleted( CPlayerInventory *pInventory ) { if ( pInventory == GetLocalInventory() ) m_iPredictedDiscards--; }
  230. static void SendGCConnectedEvent( void );
  231. // Returns the item at the specified backpack position
  232. virtual CEconItemView *GetItemByBackpackPosition( int iBackpackPosition );
  233. // Moves the item to the specified backpack position. If there's another item as that spot, it swaps positions with it.
  234. virtual void MoveItemToBackpackPosition( CEconItemView *pItem, int iBackpackPosition );
  235. // Tries to set the item to the specified backpack position. Passing in 0 will find the first empty position.
  236. // FAILS if the backpack is full, or if that spot isn't clear. Returns false in that case.
  237. virtual bool SetItemBackpackPosition( CEconItemView *pItem, uint32 iPosition = 0, bool bForceUnequip = false, bool bAllowOverflow = false );
  238. // Sort the backpack items by the specified type
  239. virtual void SortBackpackBy( uint32 iSortType );
  240. void SortBackpackFinished( void );
  241. bool IsInBackpackSort( void ) { return m_bInBackpackSort; }
  242. void PredictedBackpackPosFilled( int iBackpackPos );
  243. // Tell the backend to move an item to a specified backend position
  244. virtual void UpdateInventoryPosition( CPlayerInventory *pInventory, uint64 ulItemID, uint32 unNewInventoryPos );
  245. virtual void UpdateInventoryEquippedState( CPlayerInventory *pInventory, uint64 ulItemID, equipped_class_t unClass, equipped_slot_t unSlot, bool bSwap = false );
  246. void BeginBackpackPositionTransaction();
  247. void EndBackpackPositionTransaction();
  248. //-----------------------------------------------------------------------
  249. // CLIENT PICKUP UI HANDLING
  250. //-----------------------------------------------------------------------
  251. // Get the number of items picked up
  252. virtual int GetNumItemPickedUpItems( void ) { return 0; }
  253. // Show the player a pickup screen with any items they've collected recently, if any
  254. virtual bool ShowItemsPickedUp( bool bForce = false, bool bReturnToGame = true, bool bNoPanel = false );
  255. // Show the player a pickup screen with the items they've crafted
  256. virtual void ShowItemsCrafted( CUtlVector<itemid_t> *vecCraftedIndices ) { return; }
  257. // Force the player to discard an item to make room for a new item, if they have one.
  258. // Returns true if the discard panel has been brought up, and the player will be forced to discard an item.
  259. virtual bool CheckForRoomAndForceDiscard( void );
  260. //-----------------------------------------------------------------------
  261. // CLIENT ITEM PICKUP ACKNOWLEDGEMENT FILES
  262. //
  263. // This system avoids showing multiple pickups for items that we've found, but haven't been
  264. // able to move out of unack'd position due to the GC being unavailable. We keep a list of
  265. // items we've ack'd in a client file, and don't re-show pickups for them. When a GC item
  266. // update tells us the item has moved out of the unack'd position, we remove it from our file.
  267. //-----------------------------------------------------------------------
  268. bool HasBeenAckedByClient( CEconItemView *pItem ); // Returns true if it's in our client file
  269. void SetAckedByClient( CEconItemView *pItem ); // Adds it to our client file
  270. void SetAckedByGC( CEconItemView *pItem, bool bSave ); // Removes it from our client file
  271. private:
  272. CUtlRBTree< itemid_t, int32, CDefLess< itemid_t > > m_rbItemIdsClientAck;
  273. // As we move items around in batches (on pickups usually) we need to know what slots will be filled
  274. // by items we've moved, and haven't received a response from Steam.
  275. typedef CUtlMap< uint32, uint64, int > tPredictedSlots;
  276. tPredictedSlots m_mapPredictedFilledSlots;
  277. public:
  278. // TODO: Does this belong here?
  279. bool BGetPlayerQuestIdPointsRemaining( uint16 unQuestID, uint32 &numPointsRemaining, uint32 &numPointsUncommitted );
  280. public:
  281. CEconItemView *CreateReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 = 0 );
  282. void RemoveReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 );
  283. CEconItemView *FindReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 );
  284. CEconItemView *FindOrCreateReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 = 0 );
  285. CEconItemView *FindOrCreateReferenceEconItem( itemid_t ullFauxItemId );
  286. CUtlVector< CEconItemView* > m_pTempReferenceItems; // A collection of econitemviews that are created temporarily just to pull inventory data from.
  287. #endif //CLIENT_DLL
  288. public:
  289. virtual int GetBackpackPositionFromBackend( uint32 iBackendPosition ) { return ExtractBackpackPositionFromBackend(iBackendPosition); }
  290. protected:
  291. //-----------------------------------------------------------------------
  292. // Inventory registry
  293. void DeregisterInventory( CPlayerInventory *pInventory );
  294. struct inventories_t
  295. {
  296. CPlayerInventory *pInventory;
  297. IInventoryUpdateListener *pListener;
  298. };
  299. CUtlVector<inventories_t> m_pInventories;
  300. friend class CPlayerInventory;
  301. inline bool IsValidPlayerClass( equipped_class_t unClass );
  302. inline bool IsValidSlot( equipped_slot_t unSlot );
  303. #ifdef CLIENT_DLL
  304. // Keep track of the number of items we've tried to discard, but haven't recieved responses on
  305. int m_iPredictedDiscards;
  306. typedef CUtlMap< uint32, CUtlString, int > tPersonaNamesByAccountID;
  307. tPersonaNamesByAccountID m_mapPersonaNamesCache;
  308. bool m_bInBackpackSort;
  309. // Allows transaction item updating when moving many items
  310. CMsgSetItemPositions m_itemPositions;
  311. bool m_bIsBatchingPositions;
  312. private:
  313. CON_COMMAND_MEMBER_F( CInventoryManager, "econ_clear_inventory_images", ClearLocalInventoryImages, "clear the local inventory images (they will regenerate)", FCVAR_CLIENTDLL );
  314. #endif //CLIENT_DLL
  315. };
  316. //=================================================================================
  317. // Implement these functions in your game code to create custom derived versions
  318. CInventoryManager *InventoryManager( void );
  319. #ifdef CLIENT_DLL
  320. // Inventory Less function.
  321. // Used to sort the inventory items into their positions.
  322. class CManagedItemViewsLess
  323. {
  324. public:
  325. bool Less( CEconItemView * const & src1, CEconItemView * const & src2, void *pCtx )
  326. {
  327. uint64 unIndex1 = src1->GetItemID();
  328. uint64 unIndex2 = src2->GetItemID();
  329. if ( unIndex1 == unIndex2 )
  330. {
  331. return EconRarity_CombinedItemAndPaintRarity( src1->GetStaticData()->GetRarity(), src1->GetCustomPaintKitIndex() ) >
  332. EconRarity_CombinedItemAndPaintRarity( src2->GetStaticData()->GetRarity(), src2->GetCustomPaintKitIndex() );
  333. }
  334. return unIndex1 == 0ull || ( unIndex1 < unIndex2 );
  335. }
  336. };
  337. class CInventoryItemUpdateManager: public CAutoGameSystemPerFrame
  338. {
  339. public:
  340. virtual void Update( float frametime );
  341. void AddItemView( CEconItemView *pItemView )
  342. {
  343. FOR_EACH_VEC( m_ManagedItems, i )
  344. {
  345. if ( m_ManagedItems[i] == pItemView )
  346. return;
  347. }
  348. m_ManagedItems.Insert( pItemView );
  349. }
  350. void RemoveItemView( CEconItemView *pItemView )
  351. {
  352. m_ManagedItems.FindAndRemove( pItemView );
  353. }
  354. void AddItemViewToFixupList( CEconItemView *pItemView )
  355. {
  356. m_fixupListMutex.Lock();
  357. m_fixupList.AddToHead( pItemView );
  358. m_fixupListMutex.Unlock();
  359. }
  360. void RemoveItemViewFromFixupList( CEconItemView *pItemView )
  361. {
  362. m_fixupListMutex.Lock();
  363. m_fixupList.FindAndRemove( pItemView );
  364. m_fixupListMutex.Unlock();
  365. }
  366. private:
  367. CUtlSortVector< CEconItemView*, CManagedItemViewsLess > m_ManagedItems;
  368. CUtlVector< CEconItemView* > m_fixupList;
  369. CThreadFastMutex m_fixupListMutex;
  370. };
  371. extern CInventoryItemUpdateManager g_InventoryItemUpdateManager;
  372. #endif
  373. #endif // ITEM_INVENTORY_H