Documentation
Features
πŸ‘œ Inventory

πŸ‘œ Inventory


What is Inventory

  • Contains all items in the player's possession
  • Inventory is internally an InventorySaveData item, which makes it managed by the SaveData system

Advantages of Inventory

  • Uniform way of accessing and manipulating inventory items
  • Build for maximum expandability
  • Subscribe to changes in inventory
  • Allows stackable and non-stackable items

How to create Inventory items

Managing inventory consists of 2 parts, InventoryAsset and InventoryData. Creating the InventoryAsset is required but the InventoryData is optional.

Use the GameSuite preferences inventory panel to generate the files. Just enter the name of the item in the inventory name field.

  • Inventory name: The format of inventory assets is WeaponInventoryAsset, so just enter Weapon will generate the correct file name
  • Add inventory data: do you want to add additional specific data that should be saved for every item, continue reading to learn more on InventoryData .

Inventory preferences

InventoryAsset

This is the LibraryAsset of the inventory item, which should contain all fixed data about this item that never changes (aside from app updates or AB testing). This data is not stored in the SaveData of the player.
This is the a simple example of a collectable card with an extra model and rarity to define in the inspector.
Inherit from InventoryAsset and define the required specific variables required for this item:

namespace Game
{
	public class CardInventoryAsset : InventoryAsset
	{
		[Resource]
		public Guid Model;
		[Rarity]
		public Guid Rarity;
	}
}

Lets have a look at a more complex example where the game needs to store information per item. When the Inventory system asks for the save data format it returns an implementation of InventoryData named SwordInventoryData.

namespace Game
{
	public class SwordInventoryAsset : InventoryAsset
	{
		[Resource]
		public Guid Model;
		public int StartLevel;
		public int LevelCap;
		public int RuneSlotCount;
		[Rarity]
		public Guid Rarity;
		public bool SingleHanded;
		[BoneAttachment]
		public Guid BoneAttachment;
		
		public override InventoryData GetInventoryData(Type type = null)
		{
            SwordInventoryData sword = base.GetInventoryData(typeof(SwordInventoryData));
			sword.Level = StartLevel;
			// Add any specific initial SwordInventoryData manipulation here.
			return sword;
		}
	}
}

InventoryData

This is the actual data object that gets stored in the SaveData and gets serialized to device. This data is optional.
Add any specific data that should be saved across game sessions here.

The default values in InventoryData is a Guid which points to the InventoryAsset defined above and the Amount of copies the player has in its possession.

This example is connected to the last example SwordInventoryAsset and allows to store a level, durability and which runes have been equipped on every sword instance:

namespace Game
{
	public class SwordInventoryData : InventoryData
	{
		public int Level;
		public int Durability;
		public List<Guid> Runes = new List<Guid>();
	}
}

!!! tip "Optional" InventoryData is optional, when the asset does not have any customizable properties that need to be stored except from the amount the player has, creating an empty SwordInventoryData class is not required.
That being said, if you expect to have customizable properties in the future, it is a wise choice to create an empty SwordInventoryData class.

How to access Inventory items

Get inventory items

Managing the inventory happens through the InventorySaveData, get it from the SaveData by using:

SaveData.Get<InventorySaveData>();

The shortcut for the current player InventorySaveData can be fetched with the shortcut Inventory. Then there are multiple ways to get access to inventory data. In the snippet below you can see which are accessible, when the Guid is named guid it is referring to the internal InventoryData.UID value. assetGuid is referring to the Library InventoryAsset UID, which in most cases is more useful as you want to tie the Inventory library to your SaveData.

public class InventorySaveData : ISaveData
{
	public ObservableCollection<InventoryData> InventoryItems;
 
	public int GetAmount(Guid assetGuid)
 
	public bool TryGet(Guid guid, out InventoryData inventoryData)
	public bool TryGet<T>(Guid guid, out T customInventoryData) where T : InventoryData
	public bool TryGetByAsset(Guid assetGuid, out InventoryData customInventoryData)
	public bool TryGetByAsset<T>(Guid assetGuid, out T customInventoryData) where T : InventoryData
 
	public List<T> GetAll<T>(Guid assetGuid) where T : InventoryData
	public List<InventoryData> GetAll(Guid assetGuid)
	public List<T> GetAll<T>() where T : InventoryData
}

It is possible to just access the InventoryItems list itself and do any checks yourself, but the methods included cover most use cases.
Lets say you want to get all WeaponInventoryData items in the player's inventory:

List<WeaponInventoryData> weapons = SaveData.Get<InventorySaveData>().GetAll<WeaponInventoryData>();

Adding inventory data

Adding items is easy, either add any InventoryData item yourself or let the system handle it for you. These are the build-in methods available:

public class InventorySaveData : ISaveData
{
	public void SetAmount(Guid assetGuid, int amount)
	public void Add(InventoryData inventoryData)
	public void Add(Guid assetGuid, int amount = 1)
	public bool TryAdd(Guid assetGuid, int amount = 1)
}

This example of a build-in action shows perfectly how easy it is to add items to the player's inventory from a library inventory asset.

public class ActionGetInventory : IAction
{
	[Inventory]
	public Guid Item;
	[Tooltip("Use negative amount to subtract items")]
	public int Amount = 1;
 
	public void Execute()
	{
		Inventory.TryAdd(Item, Amount);
	}
}

Remove inventory data

Either remove items directly from the InventoryData.UID or use the InventoryLibrary asset UID:

public class InventorySaveData : ISaveData
{
	public void Remove(Guid assetGuid, int amount = 1)
	public bool TryRemove(Guid assetGuid, int amount = 1)
	public void RemoveAll()
}

Subscribing to changes

When needing to get updates on what gets added or removed from the inventory, the InventorySaveData provides 2 ways of doing so:

public class InventorySaveData : ISaveData
{
	public delegate void InventoryChangeDelegate(Guid assetGuid, int previousAmount, int newAmount);
	public event InventoryChangeDelegate Changed;
 
	public void SubscribeToChange(Guid assetGuid, Action<int, int> callback)
	public void UnsubscribeToChange(Guid assetGuid, Action<int, int> callback)
}

Subscribe to general changes in the inventory using the Changed delegate:

protected void Start()
{
	Inventory.Get<InventorySaveData>().Changed += OnInventoryChanged;
}
 
protected void OnDestroy()
{
	// Be sure to always unsubscribe when the script gets destroyed.
	Inventory.Changed -= OnInventoryChanged;
}
 
private void OnInventoryChanged(Guid assetGuid, int previousAmount, int newAmount)
{
	if (Libraries.Get<InventoryLibrary>().TryGet(assetGuid, InventoryAsset inventoryAsset))
	{
		// Implement logic here and do something with the InventoryAsset.
	}
}

The other way is directly subscribing to a specific inventory asset:

[Inventory]
public Guid Item;
 
protected void Start()
{
	Inventory.SubscribeToChange(Item, OnInventoryChanged);
}
 
protected void OnDestroy()
{
	// Be sure to always unsubscribe when the script gets destroyed.
	Inventory.UnsubscribeToChange(Item, OnInventoryChanged);
}
 
private void OnInventoryChanged(int previousAmount, int newAmount)
{
	// Implement any required logic here.
}

InventoryAsset default values

Can Own Multiple

CanOwnMultiple defines wether the player can have multiple items. An achievement or a player headquarters upgrade are examples of items that the player should only have 1 of.

Stackable vs non-stackable

Stackable

A stackable inventory asset are items which are all the same and should not contain individual customizable properties per item.
Stackable items would be:

  • Coins
  • Gems
  • Potions
  • Apples
  • Arrows
  • Cards in a card battler game

Non-stackable

Non-stackable inventory assets are the opposite, so they are customizable / upgradable per item:

  • Armor pieces with each their own quality level (helmet lvl 1, helmet lvl 5 etc.)
  • Sword with runes that can be equipped
  • Upgradable characters
  • Car with custom body paint and tuning parts assigned

!!! example "Upgradable cards" When having only a single item available in the entire game of that item, such as a card battler, where you would have one character card that can be leveled by gathering copies/xp, it is Stackable item. When the game has multiple characters of the same type that can be separately upgraded or manipulated, use the non-stackable inventory asset.

!!! abstract "Inner workings" Internally, when using stackable, there will be 1 InventoryData element stored which has an int amount inside. Non-stackable will have every item as a separate InventoryData item in the SaveData.

Initial Save

Set the player starting items in the InitialSaveConfig, which is a ConfigLibraryAsset. Remote configs and AB testing can be used to change these initial values so different player can have different balancing experiences.


Inventory initial save

Reference existing items

A character can have items equipped from the inventory itself. Which means the InitialSaveData should be able to link to another item within the InitialSaveData. This can be done by applying the [InventoryData] attribute.
Lets say the game has characters which can be leveled up and should equip weapons and armor which can also be upgraded, then it is always the best option to link to items within the InventorySaveData.

public class CharacterInventoryData : InventoryData
{
	public int Health;
	[InventoryData]
	public List<Guid> EquippedItems = new List<Guid>();
}

Inventory initial save link

Debug Menu

Go to Debug Menu > Cheats > Items > Inventory to give items to the player. They are categorized by asset type, such as WeaponInventoryAsset, so if there are lots of different weapons in the game, they will be categorized under Weapon >.


Inventory debug menu
Inventory debug inventory