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

//====== Copyright © 1996-2005, 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 "econ_item_view.h"
#include "utlsortvector.h"
#if !defined(NO_STEAM)
#include "steam/steam_api.h"
#include "gcsdk/gcclientsdk.h"
#endif // NO_STEAM
class CPlayerInventory;
class CEconItem;
struct baseitemcriteria_t;
// Inventory Less function.
// Used to sort the inventory items into their positions.
class CInventoryListLess
{
public:
bool Less( CEconItemView* const &src1, CEconItemView *const &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( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SOUpdated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SODestroyed( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SOCacheSubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE { InventoryUpdated( NULL ); }
virtual void SOCacheUnsubscribed( GCSDK::SOID_t owner, 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 Shutdown( void );
// Returns true if this inventory has been filled out by Steam.
bool InventoryRetrievedFromSteamAtLeastOnce( void ) const { return m_bGotItemsFromSteamAtLeastOnce; }
bool InventorySubscribedToSteamCurrently( void ) const { return m_bCurrentlySubscribedToSteam; }
// Inventory access
GCSDK::SOID_t GetOwner( void ) { return m_OwnerID; }
void SetOwner( GCSDK::SOID_t& ownerID ) { m_OwnerID = ownerID; }
int GetItemCount( void ) const { return m_Items.GetItemVector().Count(); }
int GetDefaultEquippedDefinitionItemsCount( void ) const { return m_aDefaultEquippedDefinitionItems.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_Items.GetItemVector()[i]; }
CEconItemView *GetDefaultEquippedDefinitionItem( int i ) { return m_aDefaultEquippedDefinitionItems[ i ]; }
CEconItemView *FindDefaultEquippedDefinitionItemBySlot( int iClass, int iSlot ) const;
bool GetDefaultEquippedDefinitionItemSlotByDefinitionIndex( item_definition_index_t nDefIndex, int nClass, int &nSlot );
void SetDefaultEquippedDefinitionItemBySlot( int iClass, int iSlot, item_definition_index_t iDefIndex );
void FindItemsByType( EItemType eType, CUtlVector< CEconItemView* >& outVec );
virtual CEconItemView *GetItemInLoadout( int iClass, int iSlot ) const { AssertMsg( 0, "Implement me!" ); return NULL; }
// Get the item object cache data for the specified item
CEconItem *GetSOCDataForItem( itemid_t iItemID );
const CEconItem *GetSOCDataForItem( itemid_t iItemID ) const;
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 ) const;
// Finds the item in our inventory in the specified position
CEconItemView *GetItemByPosition( int iPosition, int *pIndex = NULL );
// 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;
const CEconCraftingRecipeDefinition *GetRecipeDefByDefIndex( uint16 iDefIndex ) const;
int GetMaxCraftIngredientsNeeded( const CUtlVector< itemid_t >& vecCraftEconItems ) const;
void GetMarketCraftCompletionLink( const CUtlVector< itemid_t >& vecCraftItems, char *pchLink, int nNumChars ) const;
int GetPossibleCraftResultsCount( const CUtlVector< itemid_t >& vecCraftItems ) const;
int GetPossibleCraftResultsCount( const CUtlVector< CEconItem* >& vecCraftEconItems ) const;
const CEconCraftingRecipeDefinition *GetPossibleCraftResult( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
int GetPossibleCraftResultID( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
const wchar_t* GetPossibleCraftResultName( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
const wchar_t* GetPossibleCraftResultDescription( const CUtlVector< itemid_t >& vecCraftItems, int nIndex ) const;
bool CanAddToCraftTarget( const CUtlVector< itemid_t >& vecCraftItems, itemid_t nNewItem ) const;
bool IsCraftReady( const CUtlVector< itemid_t >& vecCraftItems, int16 &nRecipe ) const;
void CraftIngredients( const CUtlVector< itemid_t >& vecCraftItems ) const;
void SetTargetCraftRecipe( int nRecipe ) { m_nTargetRecipe = nRecipe; }
int16 GetTargetCraftRecipe( void ) const { return m_nTargetRecipe; }
// Finds the item in our inventory that matches the specified global index
void ClearItemCustomName( itemid_t iIndex );
void WearItemSticker( itemid_t iIndex, int nSlot, float flStickerWearCurrent );
// Item access
uint32 GetItemCount( uint32 unItemDef );
// Item previews
virtual int GetPreviewItemDef( void ) const { return 0; };
// Access helpers
virtual void SOClear();
virtual void NotifyHasNewItems() {}
bool AddEconItem( CEconItem * pItem, bool bUpdateAckFile, bool bWriteAckFile, bool bCheckForNewItems );
enum EInventoryItemEvent
{
k_EInventoryItemCreated,
k_EInventoryItemUpdated,
k_EInventoryItemDestroyed,
};
// Made public for an inventory helper func
int m_nTargetRecipe;
protected:
// Inventory updating, called by the Inventory Manager only. If you want an inventory updated,
// use the SteamRequestX functions in CInventoryManager.
void RequestInventory( GCSDK::SOID_t ID );
void AddListener( GCSDK::ISharedObjectListener *pListener );
virtual void RemoveItem( itemid_t iItemID );
bool AddEconDefaultEquippedDefinition( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition );
bool FilloutItemFromEconItem( CEconItemView *pScriptItem, CEconItem *pEconItem );
virtual void SendInventoryUpdateEvent();
virtual void OnHasNewItems() {}
virtual void OnItemChangedPosition( CEconItemView *pItem, uint32 iOldPos ) { return; }
virtual void SOCreated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOUpdated( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SODestroyed( GCSDK::SOID_t owner, const GCSDK::CSharedObject *pObject, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOCacheSubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void SOCacheUnsubscribed( GCSDK::SOID_t owner, GCSDK::ESOCacheEvent eEvent ) OVERRIDE;
virtual void ValidateInventoryPositions( void );
// Derivable Inventory hooks
virtual void ItemHasBeenUpdated( CEconItemView *pItem, bool bUpdateAckFile, bool bWriteAckFile, EInventoryItemEvent eEventType );
virtual void ItemIsBeingRemoved( CEconItemView *pItem ) { return; }
virtual void DefaultEquippedDefinitionHasBeenUpdated( CEconDefaultEquippedDefinitionInstanceClient *pDefaultEquippedDefinition );
virtual void MarkSetItemDescriptionsDirty( int nItemSetIndex );
// Get the index for the item in our inventory utlvector
int GetIndexForItem( CEconItemView *pItem );
protected:
// The SharedObject Id of the player who owns this inventory
GCSDK::SOID_t m_OwnerID;
CUtlVector< CEconItemView*> m_aDefaultEquippedDefinitionItems;
typedef CUtlMap< itemid_t, CEconItemView*, int, CDefLess< itemid_t > > ItemIdToItemMap_t;
// Wrap different container types so they all stay in sync with inventory state
class CItemContainers
{
public:
void Add( CEconItemView* pItem );
void Remove( itemid_t ullItemID );
void Purge();
bool DbgValidate() const; // Walk all containers and confirm content matches
const CUtlVector< CEconItemView*>& GetItemVector( void ) const { return m_vecInventoryItems; }
const ItemIdToItemMap_t& GetItemMap( void ) const { return m_mapItemIDToItemView; }
private:
// The items the player has in his inventory, received from steam.
CUtlVector< CEconItemView*> m_vecInventoryItems;
// Copies of pointers in vector for faster lookups
ItemIdToItemMap_t m_mapItemIDToItemView;
};
CItemContainers m_Items;
int m_iPendingRequests;
bool m_bGotItemsFromSteamAtLeastOnce, m_bCurrentlySubscribedToSteam;
GCSDK::CGCClientSharedObjectCache *m_pSOCache;
CUtlVector<GCSDK::ISharedObjectListener *> m_vecListeners;
friend class CInventoryManager;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CInventoryManager : public CAutoGameSystem
{
DECLARE_CLASS_GAMEROOT( CInventoryManager, CAutoGameSystem );
public:
CInventoryManager( void );
virtual ~CInventoryManager() {}
// 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 RegisterPlayerInventory( CPlayerInventory *pInventory, IInventoryUpdateListener *pListener = NULL, CSteamID* pSteamID = NULL );
void PreInitGC();
void PostInitGC();
#ifdef CLIENT_DLL
void DeleteItem( itemid_t iItemID, bool bRecycle=false );
int DeleteUnknowns( CPlayerInventory *pInventory );
#endif
public:
//-----------------------------------------------------------------------
// IAutoServerSystem
//-----------------------------------------------------------------------
virtual bool Init( void );
virtual void PostInit( void );
virtual void Shutdown();
virtual void LevelInitPreEntity( void );
virtual void LevelShutdownPostEntity( void );
#if defined(CSTRIKE15) && defined(CLIENT_DLL)
virtual void InsertMaterialGenerationJob( CEconItemView *pItemView );
virtual void OnDestroyEconItemView( CEconItemView *pItemView );
#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, bool bSwap = false ) = 0;
virtual CPlayerInventory *GeneratePlayerInventoryObject() const { return new CPlayerInventory; }
void DestroyPlayerInventoryObject( CPlayerInventory *pPlayerInventory ) const;
//-----------------------------------------------------------------------
// 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--; }
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 );
// 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, bool bSwap = false );
void BeginBackpackPositionTransaction();
void EndBackpackPositionTransaction();
//-----------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------
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
private:
CUtlRBTree< itemid_t, int32, CDefLess< itemid_t > > m_rbItemIdsClientAck;
// 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.
typedef CUtlMap< uint32, uint64, int > tPredictedSlots;
tPredictedSlots m_mapPredictedFilledSlots;
public:
// TODO: Does this belong here?
bool BGetPlayerQuestIdPointsRemaining( uint16 unQuestID, uint32 &numPointsRemaining, uint32 &numPointsUncommitted );
public:
CEconItemView *CreateReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 = 0 );
void RemoveReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 );
CEconItemView *FindReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 );
CEconItemView *FindOrCreateReferenceEconItem( item_definition_index_t iDefIndex, int iPaintIndex, uint8 ub1 = 0 );
CEconItemView *FindOrCreateReferenceEconItem( itemid_t ullFauxItemId );
CUtlVector< CEconItemView* > m_pTempReferenceItems; // A collection of econitemviews that are created temporarily just to pull inventory data from.
#endif //CLIENT_DLL
public:
virtual int GetBackpackPositionFromBackend( uint32 iBackendPosition ) { return ExtractBackpackPositionFromBackend(iBackendPosition); }
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 );
inline bool IsValidSlot( equipped_slot_t unSlot );
#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;
// Allows transaction item updating when moving many items
CMsgSetItemPositions m_itemPositions;
bool m_bIsBatchingPositions;
private:
CON_COMMAND_MEMBER_F( CInventoryManager, "econ_clear_inventory_images", ClearLocalInventoryImages, "clear the local inventory images (they will regenerate)", FCVAR_CLIENTDLL );
#endif //CLIENT_DLL
};
//=================================================================================
// Implement these functions in your game code to create custom derived versions
CInventoryManager *InventoryManager( void );
#ifdef CLIENT_DLL
// Inventory Less function.
// Used to sort the inventory items into their positions.
class CManagedItemViewsLess
{
public:
bool Less( CEconItemView * const & src1, CEconItemView * const & src2, void *pCtx )
{
uint64 unIndex1 = src1->GetItemID();
uint64 unIndex2 = src2->GetItemID();
if ( unIndex1 == unIndex2 )
{
return EconRarity_CombinedItemAndPaintRarity( src1->GetStaticData()->GetRarity(), src1->GetCustomPaintKitIndex() ) >
EconRarity_CombinedItemAndPaintRarity( src2->GetStaticData()->GetRarity(), src2->GetCustomPaintKitIndex() );
}
return unIndex1 == 0ull || ( unIndex1 < unIndex2 );
}
};
class CInventoryItemUpdateManager: public CAutoGameSystemPerFrame
{
public:
virtual void Update( float frametime );
void AddItemView( CEconItemView *pItemView )
{
FOR_EACH_VEC( m_ManagedItems, i )
{
if ( m_ManagedItems[i] == pItemView )
return;
}
m_ManagedItems.Insert( pItemView );
}
void RemoveItemView( CEconItemView *pItemView )
{
m_ManagedItems.FindAndRemove( pItemView );
}
void AddItemViewToFixupList( CEconItemView *pItemView )
{
m_fixupListMutex.Lock();
m_fixupList.AddToHead( pItemView );
m_fixupListMutex.Unlock();
}
void RemoveItemViewFromFixupList( CEconItemView *pItemView )
{
m_fixupListMutex.Lock();
m_fixupList.FindAndRemove( pItemView );
m_fixupListMutex.Unlock();
}
private:
CUtlSortVector< CEconItemView*, CManagedItemViewsLess > m_ManagedItems;
CUtlVector< CEconItemView* > m_fixupList;
CThreadFastMutex m_fixupListMutex;
};
extern CInventoryItemUpdateManager g_InventoryItemUpdateManager;
#endif
#endif // ITEM_INVENTORY_H