# Inventory

**URL:** https://heroiclabs.com/docs/hiro/concepts/inventory/
**Keywords:** inventory, hiro
**Categories:** hiro, inventory, concepts

---


# Inventory

The Inventory meta-system in Hiro enables players to collect, upgrade, and consume items in your game. These in-game items can be anything from a piece of equipment like a sword or chestplate, to a cosmetic item like a flag or costume, to a power up like a spawner or boost. 

Inventory items can be purchased from the [virtual store](../economy/virtual-store), or earned through gameplay.

<center>
<img src="{{< fingerprint_image "/images/pages/hiro/concepts/inventory/loudouts-firebreak.png" >}}" style="max-width: 75%;">
<figcaption>Inventory & Loadout Systems from Firebreak by Remedy is supported by Hiro</figcaption>
</center>

{{< note "outline" "" hide_icon>}}
Ready to try it yourself? Explore the [Inventory sample project](../../../sample-projects/unity/hiro-inventory/).
{{</ note>}}

## Customization parameters

The following JSON represents the customization parameters you can use to configure the default user experience for the inventory system.

```json
{
  "items": {
    "iron_sword": {
      "name": "Iron Sword",
      "description": "A sharp sword made of iron.",
      "category": "weapons",
      "item_sets": ["common_weapons"],
      "max_count": 99,
      "stackable": false,
      "consumable": false,
      "string_properties": {
        "equipment_slot": "right_hand"
      },
      "numeric_properties": {
        "rank": 1
      },
      "disabled": false
    },
    "health_potion": {
      "name": "Health Potion",
      "description": "A vial of red liquid used for healing.",
      "category": "potions",
      "max_count": 99,
      "stackable": true,
      "consumable": true,
      "keep_zero": true,
      "consume_reward": {
        "guaranteed": {
          "energies": {
            "health": {
              "min": 100
            }
          }
        }
      }
    },
    "small_crafting_bag": {
      "name": "Small Crafting Bag",
      "description": "A small bag of miscellaneous crafting materials.",
      "category": "loot_bags",
      "max_count": 99,
      "stackable": false,
      "consumable": true,
      "consume_reward": {
        "max_rolls": 2,
        "weighted": [
          {
            "items": {
              "leather_scraps": {
                "min": 1,
                "max": 5
              }
            },
            "weight": 50
          },
          {
            "items": {
              "bronze_nails": {
                "min": 5,
                "max": 100,
                "multiple": 5
              }
            },
            "weight": 50
          }
        ]
      }
    }
  },
  "limits": {
    "categories": {
      "armor": 10
    },
    "item_sets": {
      "shield": 5
    }
  }
}
```

The JSON schema defines several objects which define the various items and item sets that will be available in your game. You can configure as few or as many of each as needed for your desired gameplay.

{{< table name="gdk.concepts.inventory.inventory-system" >}}

### Config Limits

`ConfigLimits` can be used to restrict how many items are able to be held at a given time from specified Categories or Item Sets.

In the case that an item is restricted by its Category `AND` its Item Set:
- Assume there is an item with category `armor` from the item set `shield` that is being granted.
- The inventory limits are set to a maximum of 10 `armor` and 5 `shields`. 
- Even if the user has fewer than 10 pieces of `armor`, they won't be able to receive the item if they currently have 5 `shields`.

{{< table name="gdk.concepts.inventory.config-limits" >}}

Each individual item is keyed by id and may define the following:

### Item

{{< table name="gdk.concepts.inventory.item" >}}

<figure class="float-right" style="max-width: 35%; border: 20px solid transparent; text-align: center;">
  <img 
    src="{{< fingerprint_image "/images/pages/hiro/concepts/inventory/collectables-fruitfall.png" >}}" 
    style="width: 100%;"
  >
  <figcaption> Collectable Items / Cards in Fruit Fall by Gram Games uses Hiro Inventory System </figcaption>
</figure>

## Item Definitions

### Item Categories

Every item definition has a `category` property. This is a simple `string` property that defines which broad collection the item belongs to and is useful for listing items. For example, you may wish to separate your items into categories such as `weapons`, `armor`, and `potions`.

### Item Sets

Item definitions can optionally define an array of `item_sets` that they belong to. Item sets differ from categories in that an item can belong to multiple sets at once. These item sets can be used as tags for the items in your game such as `rare` and `sword`.

Item sets are used in the [reward system](../economy/rewards/) to allow users to be rewarded with a random item that belongs to specific sets (see [example](#granting-inventory-items) below).

### Item Rewards

A powerful feature of the Inventory system is the ability for game designers to add consume rewards to item definitions. When a user consumes the item, they will be granted the reward accordingly. Due to the power and flexibility of the Hiro reward system, this allows game designers the opportunity to create all manner of consumables. 

Consider the following scenarios and associated item definitions:

**A potion that restores 50 health**

```json
{
  "health_potion": {
    "name": "Health Potion",
    "description": "A vial of red liquid used for healing.",
    "category": "potions",
    "max_count": 99,
    "stackable": true,
    "consumable": true,
    "consume_reward": {
      "guaranteed": {
        "energies": {
          "health": {
            "min": 100
          }
        }
      }
    }
  }
}
```

**A coin pouch that rewards between 100 and 500 gold coins in multiples of 10**

```json
{
  "coin_pouch": {
    "name": "Coin Pouch",
    "description": "A small pouch of gold coins.",
    "category": "bags",
    "max_count": 99,
    "stackable": true,
    "consumable": true,
    "consume_reward": {
      "guaranteed": {
        "currencies": {
          "coins": {
            "min": 100,
            "max": 500,
            "multiple": 10
          }
        }
      }
    }
  }
}
```

**A loot chest that rewards a sword and a random rare weapon**

```json
{
  "loot_chest": {
    "name": "Loot Chest",
    "description": "A shiny chest full of treasure.",
    "category": "chests",
    "max_count": 99,
    "stackable": false,
    "consumable": true,
    "consume_reward": {
      "guaranteed": {
        "items": {
          "bronze_sword": {
            "min": 1
          }
        },
        "item_sets": [
          {
            "set": ["rare", "weapon"],
            "min": 1
          }
        ]
      }
    }
  }
}
```

**A loot chest that rewards a weighted random currency**

```json
{
  "currency_chest": {
    "name": "Currency Chest",
    "description": "A shiny chest full of unknown currency.",
    "category": "chests",
    "max_count": 99,
    "stackable": false,
    "consumable": true,
    "consume_reward": {
      "max_rolls": 1,
      "weighted": [
        {
          "currencies": {
            "coins": {
              "min": 100
            }
          },
          "weight": 80
        },
        {
          "currencies": {
            "gems": {
              "min": 10,
              "max": 20,
              "multiple": 5
            }
          },
          "weight": 20
        }
      ]
    }
  }
}
```

## Item Instances

When a user is granted an item, whether from a [Store Purchase](../economy/virtual-store/), as a [Reward](../economy/rewards/), or any other means, it is stored as an item instance inside their inventory. The inventory itself is stored inside the [Storage Engine](../../../nakama/concepts/storage/) under a special collection/key for that user.

A user's inventory has the following JSON schema.

```json
{
  "2cb9c733-a2c8-498f-aaed-8ba24a989c45": {
    "item_id": "iron_sword",
    "owned_time": 1674300933,
    "update_time": 1687347732,
    "count": 1,
    "string_properties": {
      "equipment_slot": "right_hand",
      "gem_slot_1": "strength_ruby",
      "gem_slot_2": "dexterity_emerald"
    },
    "numeric_properties": {
      "rank": 3,
      "monsters_defeated": 435
    }
  },
  "e264eaa7-6bc0-4a78-99ed-18fdadf3afea": {
    "item_id": "potion",
    "owned_time": 1654334562,
    "update_time": 1654338987,
    "count": 12,
    "string_properties": {},
    "numeric_properties": {}
  }
}
```

The inventory is a map of item instance IDs and the associated item instance data, where each item instance has the following structure.

{{< table name="gdk.concepts.inventory.item-instances" >}}

### Item Properties

Item instances have their own metadata, stored within the `string_properties` and `numeric_properties` fields. This allows you to build systems where a user can customize, rank up, or modify the items they own. For example, you may have a weapon rank system that allows your players to "level up" their weapons, or a "gem slot" system that allows players to improve the stats of their items by socketing various gems to them, or perhaps you just want to keep track of how many monsters a user has defeated with a particular weapon as shown in the example above.

When retrieving inventory items, properties are merged between the item instance and its config definition. Item instance properties take precedence, so only properties that don't already exist in the item instance are added from the config. See [Property merging behavior](../../server-framework/inventory/#property-merging-behavior) for examples.

{{< note "important" "Default properties" >}}
Item definitions can define `string_properties` and `numeric_properties` which will be copied across to an item instance when it is retrieved. The values specified in the item definition will always override the value in the item instance. This allows you to update things like stats or XP curves for an item globally across all existing item instances.
{{< / note>}}

### Item Stacking

Where an item is granted that is defined as `stackable`, the inventory system will first check to see if the user currently has an item instance for that item ID. If they do, the `count` property of that particular instance will be increased accordingly. If they don't, or if the item is not `stackable`, a new item instance will be generated instead and added to the user's inventory.

## Additional Information

- [Hiro Inventory sample project](../../../sample-projects/unity/hiro-inventory)
- [Mage Mayhem sample project](../../../sample-projects/games/mage-mayhem)
