Inventory.Client
Available in the Steamworks Complete asset.

Introduction

1
using InvClient = HeathenEngineering.SteamworksIntegration.API.Inventory.Client;
Copied!
1
public static class Inventory.Client
Copied!
To work with inventory from the point of view of a server you should use the Steam Web API for inventory.
IInventoryService Interface (Steamworks Documentation)
This is a Service interface, methods in this interface should be called with the input_json parameter.
For more info on how to use the Steamworks Web API please see the Web API Overview.

What can it do?

The Steam Inventory Service is a set of features that allow a game to enable persistent player inventories without having to run special servers to manage users or items.
The following is from the Steam Documentation for the Inventory feature.
The Inventory Service can be used in two ways - either server-less or with the addition of a trusted server that knows game state. Without a game server, the game client can communicate directly to the steam service to retrieve users inventory contents, consume and exchange items, and receive new items granted as an effect of playtime. Users can also purchase items directly from the Item Store, or trade and exchange markets in the Steam community. However because the client can't be trusted (and the keys in a client can always be captured by an attacker) you can't give users specific items in this scheme. Rather you select certain items that can be dropped, and configure a drop frequency. At appropriate times, the game client invokes Trigger Item Drop. Steam servers manage the playtime and drop frequency per-player. These APIs are called using an internal "Client API Key" that is assumed to be untrusted. If you have a participating trusted server then you can use a privileged Steam API key on the server and grant explicit items for appropriate situations. It is still important to keep in mind that you can't trust your own clients so you can only do this when the server is the master of the state of the game. Finally in conjunction with the Inventory Service you can sell an individual item or a cart of items, in-game or through a web-based storefront. Check out this presentation from Steam Dev Days 2016 for an implementation overview, details on the specific problems that the Inventory Service solves for developers.
See Steam Inventory Service for more information.
https://kb.heathenengineering.com/assets/steamworks/objects/inventory-item
kb.heathenengineering.com
https://kb.heathenengineering.com/assets/steamworks/objects/inventory-settings
kb.heathenengineering.com
Inventory Result
Heathen KB
Item Detail
Heathen KB
Item Definition
Heathen KB
https://kb.heathenengineering.com/assets/steamworks/objects/item-property
kb.heathenengineering.com
https://kb.heathenengineering.com/assets/steamworks/objects/item-tag
kb.heathenengineering.com

Understanding Callbacks

A callback is a delegate similar to a UnityEvent, that is its a pointer to a method that will be called at some later point ... in the case of Steam methods it gets called when the process completes.
To learn more please read the article on Callbacks and on Lambda Expressions.

Events

EventSteamInventoryDefinitionUpdate

Triggered whenever item definitions have been updated, which could be in response to LoadItemDefinitions or any time new item definitions are available (eg, from the dynamic addition of new item types while players are still in-game).
You would add a listener on this event such as:
Assuming a handler in the form of
1
private void HandleEvent()
2
{
3
}
Copied!
Then you would register the event such as:
1
API.Inventory.Client.EventSteamInventoryDefinitionUpdate.AddListener(HandleEvent);
Copied!
When you no longer need this handler you should remove it for example when the behavior using it is destroyed
1
void OnDestroy()
2
{
3
API.Inventory.Client.EventSteamInventoryDefinitionUpdate.RemoveListener(HandleEvent);
4
}
Copied!

EventSteamInventoryResultReady

This is fired whenever an inventory result transitions from k_EResultPending to any other completed state, see GetResultStatus for the complete list of states. There will always be exactly one callback per handle.
You would add a listener on this event such as:
Assuming a handler in the form of
1
private void HandleEvent(InventoryResult result)
2
{
3
}
Copied!
Then you would register the event such as:
1
API.Inventory.Client.EventSteamInventoryResultReady.AddListener(HandleEvent);
Copied!
When you no longer need this handler you should remove it for example when the behavior using it is destroyed
1
void OnDestroy()
2
{
3
API.Inventory.Client.EventSteamInventoryResultReady.RemoveListener(HandleEvent);
4
}
Copied!

Methods

AddPromoItem

Grant a specific one-time promotional item to the current user.
This can be safely called from the client because the items it can grant can be locked down via policies in the itemdefs. One of the primary scenarios for this call is to grant an item to users who also own a specific other game. This can be useful if your game has custom UI for showing a specific promo item to the user otherwise if you want to grant multiple promotional items then use AddPromoItems or GrantPromoItems.
Any items that can be granted MUST have a "promo" attribute in their itemdef. That promo item list a set of APPIDs that the user must own to be granted this given item. This version will grant all items that have promo attributes specified for them in the configured item definitions. This allows adding additional promotional items without having to update the game client. For example the following will allow the item to be granted if the user owns either TF2 or SpaceWar.
1
public static bool AddPromoItem(SteamItemDef_t itemDef,
2
Action<InventoryResult> callback)
Copied!

AddPromoItems

Grant a specific one-time promotional item to the current user.
This can be safely called from the client because the items it can grant can be locked down via policies in the itemdefs. One of the primary scenarios for this call is to grant an item to users who also own a specific other game. If you want to grant a single promotional item then use AddPromoItem. If you want to grant all possible promo items then use GrantPromoItems.
Any items that can be granted MUST have a "promo" attribute in their itemdef. That promo item list a set of APPIDs that the user must own to be granted this given item. This version will grant all items that have promo attributes specified for them in the configured item definitions. This allows adding additional promotional items without having to update the game client. For example the following will allow the item to be granted if the user owns either TF2 or SpaceWar.
1
public static bool AddPromoItems(ItemDefinition item,
2
Action<InventoryResult> callback)
Copied!
1
public static bool AddPromoItems(SteamItemDef_t[] itemDefs,
2
Action<InventoryResult> callback)
Copied!
1
public static bool AddPromoItems(ItemDefinition[] items,
2
Action<InventoryResult> callback)
Copied!
1
public static bool AddPromoItems(IEnumerable<SteamItemDef_t> itemDefs,
2
Action<InventoryResult> callback)
Copied!

CheckResultSteamID

Checks whether an inventory result handle belongs to the specified Steam ID.
This is important when using Deserialize Results, to verify that a remote player is not pretending to have a different user's inventory.
1
public static bool CheckResultSteamID(SteamInventoryResult_t resultHandle,
2
CSteamID steamIDExpected)
Copied!

Consume Item

Consumes items from a user's inventory. If the quantity of the given item goes to zero, it is permanently removed.
Once an item is removed it cannot be recovered.
This is not for the faint of heart - if your game implements item removal at all, a high-friction UI confirmation process is highly recommended.
1
public static void ConsumeItem(SteamItemInstanceID_t itemConsume,
2
uint quantity,
3
Action<InventoryResult> callback)
Copied!

Deserialize Results

Deserializes a result set and verifies the signature bytes. This call has a potential soft-failure mode where the handle status is set to k_EResultExpired. Get Result Items will still succeed in this mode. The "expired" result could indicate that the data may be out of date - not just due to timed expiration (one hour), but also because one of the items in the result set may have been traded or consumed since the result set was generated. You could compare the timestamp from Get Result Timestamp to ISteamUtils::GetServerRealTime to determine how old the data is. You could simply ignore the "expired" result code and continue as normal, or you could request the player with expired data to send an updated result set. You should call Check Result Steam ID on the result handle when it completes to verify that a remote player is not pretending to have a different user's inventory.
1
public static void DeserializeResult(byte[] buffer,
2
Action<InventoryResult> callback)
Copied!

DestroyResult

Destroys a result handle and frees all associated memory.
This only needs to be called if you are manually handling results ... which should not be happening if your using Heathen's Steamworks.
This is only provided for completness of the API to enable deep customization for those who wish to do so.
1
public static void DestroyResult(SteamInventoryResult_t resultHandle)
Copied!

ExchangeItems

Grant one item in exchange for a set of other items.
This can be used to implement crafting recipes or transmutations, or items which unpack themselves into other items (e.g., a chest).
The caller of this API passes in the requested item and an array of existing items and quantities to exchange for it. The API currently takes an array of items to generate but at this time the size of that array must be 1 and the quantity of the new item must be 1.
Any items that can be granted MUST have an exchange attribute in their itemdef. The exchange attribute specifies a set of recipes that are valid exchanges for this item. Exchange recipes are evaluated atomically by the Inventory Service; if the supplied components do not match the recipe, or do not contain sufficient quantity, the exchange will fail.
It is much simpler to handle this feature through the Item Defenition object.
This is included in the API for completness sake
1
public static void ExchangeItems(SteamItemDef_t generate,
2
SteamItemInstanceID_t[] destroy,
3
uint[] destroyQuantity,
4
Action<InventoryResult> callback)
Copied!

GenerateItems

For developer use only, this will only work if the authenticated Steam user is a member of the development team for this app.
Grants specific items to the current user, for developers only.
This API is only intended for prototyping - it is only usable by Steam accounts that belong to the publisher group for your game.
1
public static void GenerateItems(SteamItemDef_t[] itemDefs,
2
uint[] quantity,
3
Action<InventoryResult> callback)
Copied!

GetAllItems

Start retrieving all items in the current users inventory.
Calls to this function are subject to rate limits and may return cached results if called too frequently. It is suggested that you call this function only when you are about to display the user's full inventory, or if you expect that the inventory may have changed.
1
public static void GetAllItems(Action<InventoryResult> callback = null)
Copied!

GetEligiblePromoItemIDs

Request the list of "eligible" promo items that can be manually granted to the given user.
These are promo items of type "manual" that won't be granted automatically. An example usage of this is an item that becomes available every week.
1
public static void GetEligiblePromoItemDefinitionIDs(CSteamID userId,
2
Action<SteamItemDef_t[], bool> callback)
Copied!

GetItemDefiinitionIDs

Returns the set of all item definition IDs which are defined in the App Admin panel of the Steamworks website. These item definitions may not necessarily be contiguous integers. This should be called in response to a SteamInventoryDefinitionUpdate_t callback. There is no reason to call this function if your game hardcodes the numeric definition IDs (eg, purple face mask = 20, blue weapon mod = 55) and does not allow for adding new item types without a client patch.
1
public static bool GetItemDefinitionIDs(out SteamItemDef_t[] results)
Copied!

GetItemDefinitionProperty

Gets a property value for a specific item definition.
Note that some properties (for example, "name") may be localized and will depend on the current Steam language settings (see ISteamApps::GetCurrentGameLanguage). Property names are always ASCII alphanumeric and underscores.
1
public static string GetItemDefinitionProperty(SteamItemDef_t item,
2
string propertyName)
Copied!

GetItemDefinitionProperties

Returns a list of the avilable properties on a given item
1
public static string[] GetItemDefinitionProperties(SteamItemDef_t item)
Copied!

GetItemsByID

Gets the state of a subset of the current user's inventory.
1
public static void GetItemsByID(SteamItemInstanceID_t[] instanceIds,
2
Action<InventoryResult> callback = null)
Copied!

GetItemPrice

After a successful call to RequestPrices, you can call this method to get the pricing for a specific item definition.
1
public static bool GetItemPrice(SteamItemDef_t item,
2
out ulong currentPrice,
3
out ulong basePrice)
Copied!

GetItemsWithPrices

After a successful call to RequestPrices, you can call this method to get all the pricing for applicable item definitions.
1
public static bool GetItemsWithPrices(out SteamItemDef_t[] items,
2
out ulong[] currentPrices,
3
out ulong[] basePrices)
Copied!

GetResultItemProperty

Gets the dynamic properties from an item in an inventory result set.
1
public static bool GetResultItemProperty(SteamInventoryResult_t resultHandle,
2
uint itemIndex,
3
string propertyName,
4
out string valueBuffer,
5
ref uint bufferSize)
Copied!

GetResultItems

Get the items associated with an inventory result handle.
1
public static bool GetResultItems(SteamInventoryResult_t resultHandle,
2
SteamItemDetails_t[] items,
3
ref uint count)
Copied!

GetResultTimestamp

Gets the server time at which the result was generated.
1
public static DateTime GetResultTimestamp(SteamInventoryResult_t resultHandle)
Copied!

GrantPromoItems

Grant all potential one-time promotional items to the current user.
1
public static bool GrantPromoItems(Action<InventoryResult> callback = null)
Copied!

LoadItemDefinitions

Triggers an asynchronous load and refresh of item definitions.
1
public static bool LoadItemDefinitions()
Copied!

RequestPrices

Request prices for all item definitions that can be purchased in the user's local currency. A SteamInventoryRequestPricesResult_t call result will be returned with the user's local currency code. After that, you can call GetNumItemsWithPrices and GetItemsWithPrices to get prices for all the known item definitions, or GetItemPrice for a specific item definition.
1
public static void RequestPrices(
2
Action<SteamInventoryRequestPricesResult_t, bool> callback)
Copied!

SerializeItemResultsByID

Gets the state of a subset of the current user's inventory and serializes the data.
1
public static void SerializeItemResultsByID(SteamItemInstanceID_t[] instanceIds,
2
Action<byte[]> callback)
Copied!

SerializeAllItemResults

Start retrieving all items in the current users inventory and serializes the data.
1
public static void SerializeAllItemResults(Action<byte[]> callback)
Copied!

StartPurchase

Starts the purchase process for the user, given a "shopping cart" of item definitions that the user would like to buy. The user will be prompted in the Steam Overlay to complete the purchase in their local currency, funding their Steam Wallet if necessary, etc.
1
public static void StartPurchase(SteamItemDef_t[] items,
2
uint[] quantities,
3
Action<SteamInventoryStartPurchaseResult_t, bool> callback)
Copied!

TransferItemQuantity

Transfer items between stacks within a user's inventory.
1
public static void TransferItemQuantity(SteamItemInstanceID_t source,
2
uint quantity,
3
SteamItemInstanceID_t destination,
4
Action<InventoryResult> callback)
Copied!

TriggerItemDrop

Trigger an item drop if the user has played a long enough period of time.
1
public static void TriggerItemDrop(SteamItemDef_t item,
2
Action<InventoryResult> callback)
Copied!

StartUpdateProperties

Starts a transaction request to update dynamic properties on items for the current user. This call is rate-limited by user, so property modifications should be batched as much as possible (e.g. at the end of a map or game session). After calling SetProperty or RemoveProperty for all the items that you want to modify, you will need to call SubmitUpdateProperties to send the request to the Steam servers. A SteamInventoryResultReady_t callback will be fired with the results of the operation.
1
public static SteamInventoryUpdateHandle_t StartUpdateProperties()
Copied!

SubmitUpdateProperties

Submits the transaction request to modify dynamic properties on items for the current user. See StartUpdateProperties.
1
public static void SubmitUpdateProperties(SteamInventoryUpdateHandle_t handle,
2
Action<InventoryResult> callback)
Copied!

RemoveProperty

Removes a dynamic property for the given item.
1
public static void RemoveProperty(SteamInventoryUpdateHandle_t handle,
2
SteamItemInstanceID_t item,
3
string propertyName)
Copied!

SetProperty

Sets a dynamic property for the given item. Supported value types are strings, boolean, 64 bit integers, and 32 bit floats.
1
public static void SetProperty(SteamInventoryUpdateHandle_t handle,
2
SteamItemInstanceID_t item,
3
string propertyName,
4
string data)
Copied!
1
public static void SetProperty(SteamInventoryUpdateHandle_t handle,
2
SteamItemInstanceID_t item,
3
string propertyName,
4
bool data)
Copied!
1
public static void SetProperty(SteamInventoryUpdateHandle_t handle,
2
SteamItemInstanceID_t item,
3
string propertyName,
4
long data)
Copied!
1
public static void SetProperty(SteamInventoryUpdateHandle_t handle,
2
SteamItemInstanceID_t item,
3
string propertyName,
4
float data)
Copied!

GetExtendedItemDetail

Constructs an ItemDetail object based on a native SteamItemDetails_t object and its source result list
1
public static ItemDetail GetExtendedItemDetail(SteamInventoryResult_t result,
2
uint index,
3
SteamItemDetails_t detail)
Copied!

How To

Methods that impact a user's inventory will typically have a callback that returns a type of Inventory Result. In addition the Item Definitions stored in the active Steam Settings will be updated with the resulting Item Details which be used as a real time view of the current state of the user's inventory.
The Item Definitions object contains shortcut methods to many of the features found in the API.Inventory interface.
For example it is possible to consume quantity, add promo items and exchange items directly from the item its self. Please review the Item Definition object closely to understand all the options available to you.

Add Promo Item

Grant a specific one-time promotional item to the current user. This can be safely called from the client because the items it can grant can be locked down via policies in the itemdefs. One of the primary scenarios for this call is to grant an item to users who also own a specific other game. This can be useful if your game has custom UI for showing a specific promo item to the user otherwise if you want to grant multiple promotional items then use Add Promo Items or Grant Prmo Items. Any items that can be granted MUST have a "promo" attribute in their itemdef. That promo item list a set of APPIDs that the user must own to be granted this given item. This version will grant all items that have promo attributes specified for them in the configured item definitions. This allows adding additional promotional items without having to update the game client. For example the following will allow the item to be granted if the user owns either TF2 or SpaceWar.
1
API.Inventory.Client.AddPromoItem(item, callback);
Copied!

Add Promo Items

Grant a specific one-time promotional item to the current user. This can be safely called from the client because the items it can grant can be locked down via policies in the itemdefs. One of the primary scenarios for this call is to grant an item to users who also own a specific other game. If you want to grant a single promotional item then use Add Promo Item. If you want to grant all possible promo items then use Grant Promo Items. Any items that can be granted MUST have a "promo" attribute in their itemdef. That promo item list a set of APPIDs that the user must own to be granted this given item. This version will grant all items that have promo attributes specified for them in the configured item definitions. This allows adding additional promotional items without having to update the game client. For example the following will allow the item to be granted if the user owns either TF2 or SpaceWar.
1
API.Inventory.Client.AddPromoItems(items, callback);
Copied!

Check Result Steam ID

Checks whether an inventory result handle belongs to the specified Steam ID.
This is important when using Deserialize Results, to verify that a remote player is not pretending to have a different user's inventory.
1
if(API.Inventory.Client.CheckResultSteamID(resultHandle, expectedId))
2
Debug.Log("Yes");
3
else
4
Debug.Log("No");
Copied!

Consume Item

Consumes items from a user's inventory. If the quantity of the given item goes to zero, it is permanently removed.
Once an item is removed it cannot be recovered.
This is not for the faint of heart - if your game implements item removal at all, a high-friction UI confirmation process is highly recommended.
1
API.Inventory.Client.ConsumeItem(item, quantity, callback);
Copied!

Deserialize Results

Deserializes a result set and verifies the signature bytes. This call has a potential soft-failure mode where the handle status is set to k_EResultExpired. Get Result Items will still succeed in this mode. The "expired" result could indicate that the data may be out of date - not just due to timed expiration (one hour), but also because one of the items in the result set may have been traded or consumed since the result set was generated. You could compare the timestamp from Get Result Timestamp to ISteamUtils::GetServerRealTime to determine how old the data is. You could simply ignore the "expired" result code and continue as normal, or you could request the player with expired data to send an updated result set. You should call Check Result Steam ID on the result handle when it completes to verify that a remote player is not pretending to have a different user's inventory.
1
API.Inventory.Client.DeserializeResult(buffer, callback);
Copied!

Destroy Result

Destroys a result handle and frees all associated memory.
This only needs to be called if you are manually handling results ... which should not be happening if your using Heathen's Steamworks.
This is only provided for completeness of the API to enable deep customization for those who wish to do so.
1
API.Inventory.Client.DestroyResult(resultHandle);
Copied!

Exchange Items

Grant one item in exchange for a set of other items.
This can be used to implement crafting recipes or transmutations, or items which unpack themselves into other items (e.g., a chest).
The caller of this API passes in the requested item and an array of existing items and quantities to exchange for it. The API currently takes an array of items to generate but at this time the size of that array must be 1 and the quantity of the new item must be 1.
Any items that can be granted MUST have an exchange attribute in their itemdef. The exchange attribute specifies a set of recipes that are valid exchanges for this item. Exchange recipes are evaluated atomically by the Inventory Service; if the supplied components do not match the recipe, or do not contain sufficient quantity, the exchange will fail.
It is much simpler to handle this feature through the Item Definition object.
This is included in the API for completeness sake
1
API.Inventory.Client.ExchangeItems(itemsToGenerate,
2
quantitiesToGenerate,
3
instanceToDestroy,
4
callback);
Copied!

Generate Items

For developer use only, this will only work if the authenticated Steam user is a member of the development team for this app.
Grants specific items to the current user, for developers only.
This API is only intended for prototyping - it is only usable by Steam accounts that belong to the publisher group for your game.
1
API.Inventory.Client.GenerateItems(items, quantity, callback);
Copied!

Get All Items

Start retrieving all items in the current users inventory.
Calls to this function are subject to rate limits and may return cached results if called too frequently. It is suggested that you call this function only when you are about to display the user's full inventory, or if you expect that the inventory may have changed.
1
API.Inventory.Client.GetAllItems(callback);
Copied!

Get Eligible Promo Item IDs

Request the list of "eligible" promo items that can be manually granted to the given user.
These are promo items of type "manual" that won't be granted automatically. An example usage of this is an item that becomes available every week.
1
API.Inventory.Client.GetEligiblePromoItemDefinitionIDs(user, callback);
Copied!

Get Item Defiinition IDs

Returns the set of all item definition IDs which are defined in the App Admin panel of the Steamworks website. These item definitions may not necessarily be contiguous integers. This should be called in response to a SteamInventoryDefinitionUpdate_t callback. There is no reason to call this function if your game hardcodes the numeric definition IDs (eg, purple face mask = 20, blue weapon mod = 55) and does not allow for adding new item types without a client patch.
1
API.Inventory.Client.GetItemDefinitionIDs(out SteamItemDef_t[] results);
Copied!

Get Result Items

Get the items associated with an inventory result handle.
You should never need to call this method if your using Heathen's Steamworks
This method is included for completeness of the interface.
1
API.Inventory.Client.GetResultItems(resultHandle, items, ref count);
Copied!

Get Result Timestamp

Gets the server time at which the result was generated.
This should never need to be called if your Heathen's Steamworks.
This method is included for completeness of the interface.

Grant Promo Items

Grant all potential one-time promotional items to the current user. This can be safely called from the client because the items it can grant can be locked down via policies in the itemdefs. One of the primary scenarios for this call is to grant an item to users who also own a specific other game. If you want to grant specific promotional items rather than all of them see: Add Promo Item and Add Promo Items. Any items that can be granted MUST have a "promo" attribute in their itemdef. That promo item list a set of APPIDs that the user must own to be granted this given item. This version will grant all items that have promo attributes specified for them in the configured item definitions. This allows adding additional promotional items without having to update the game client. For example the following will allow the item to be granted if the user owns either TF2 or SpaceWar.
1
API.Inventory.Client.GrantPromoItems(callback);
Copied!

Trigger Item Drop

Trigger an item drop if the user has played a long enough period of time. This period can be customized in two places:
  • At the application level within Inventory Service: Playtime Item Grants. This will automatically apply to all "playtimegenerator" items that do not specify any overrides.
  • In an individual "playtimegenerator" item definition. The settings would take precedence over any application-level settings.
Only item definitions which are marked as "playtime item generators" can be spawned. Typically this function should be called at the end of a game or level or match or any point of significance in the game in which an item drop could occur. The granularity of the playtime generator settings is in minutes, so calling it more frequently than minutes is not useful and will be rate limited in the Steam client. The Steam servers will perform playtime accounting to prevent too-frequent drops. The servers will also manage adding the item to the players inventory.
1
API.Inventory.Client.TriggerItemDrop(item, callback);
Copied!