Curitor
Gameplay Systems · Topic Guide

Inventory & Equipment

Carried stacks in a hotbar and bag, gear worn in five slots that both shows on the character and boosts their stats — with mouse drag-and-drop and full gamepad support. You author items as assets; nothing in the UI, the network layer or the save system needs to learn about a new one.

Items are assets

An ItemDefinition asset carries both representations of an item at once: a sprite for UI slots and a world model for dropped items and worn gear. Sprite is UI, model is world — an item with no model still works, and falls back to a generic placeholder crate when it lands on the ground.

Create one with Create → Party Core Kit → Inventory → Item Definition. Everything downstream — hotbar tiles, pickup prompts, drops, loot tables, the network layer, save files — reads the asset. Adding an item is authoring an asset, not editing code.

FieldTypeDefaultWhat it does
idstringUnique machine-readable key, e.g. 'stone'. This is what travels over the network and into save files, so it is the one field you should not change after players have saves.
displayNamestringShown in the hotbar and in pickup prompts.
iconSpriteHotbar tile icon. Optional — the tile falls back to the display name.
descriptionstringBody text in the inventory window's details pane.
worldModelGameObject3D model shown when the item lies in the world, and — for equipment — worn on the character. Null gives a generic placeholder crate.
worldModelDropScalefloat1Scale applied to the world model when the item is lying on the ground, so a wearable-sized mesh can read correctly as a pickup.
maxStackint1How many fit in one slot. 1 means every copy takes its own slot.
pickupActivationInteractionActivationPressHow pickups of this item activate: Press, Hold or a repeated press. Authored pickups and runtime drops both default to this, so a dropped item keeps behaving the way that item's pickups behave.
pickupHoldSecondsfloat1Hold duration, when the activation is Hold.
pickupPressCountint3How many presses, when the activation is a repeated press.

Carrying: the hotbar and the bag

CharacterInventory is one flat array of slots split into two visible regions: the leading slots are the hotbar, the rest are the bag. Selection cycles the hotbar; the bag is what the inventory window shows.

FieldTypeDefaultWhat it does
hotbarSlotsint6Quick-access slots shown on the hotbar. Selection cycles these.
bagSlotsint12Additional slots shown in the inventory panel, opened with the Inventory action (keyboard I, gamepad Select by default).
knownItemsItemDefinition[]Every item that may appear in this inventory. Replicated item ids resolve back to assets through this list, exactly as CharacterStats resolves effects through knownEffects.
allowItemDroppingbooltrueAllow dropping items into the world by dragging a slot out of the window or right-clicking it. Off means items can only be moved between slots.

Wearing: five slots, and why bonuses live in stats

CharacterEquipment holds one EquipmentDefinition per slot — Head, Body, Legs, LeftHand, RightHand — and requires a CharacterInventory on the same object, because gear is moved in and out of the bag rather than existing separately from it.

An EquipmentDefinition is an ItemDefinition — it inherits every field above and adds the wearing ones. That inheritance is also the whole eligibility rule: the item type is the category. A piece fits a slot when it is equipment and its slot matches. There is no separate tag list to keep in sync.

// The entire eligibility check, from CharacterEquipment:
public static bool CanEquip(ItemDefinition item, EquipmentSlot slot)
{
    return item is EquipmentDefinition equipment && equipment.slot == slot;
}
FieldTypeDefaultWhat it does
slotEquipmentSlotWhich of the five slots this piece fits: Head, Body, Legs, LeftHand or RightHand.
modifiersStatModifier[]Stat improvements while equipped. Each names a StatDefinition and a flat bonus added to that stat's MAXIMUM — for example +25 max health.
equipPositionVector3(0, 0, 0)Local position offset on the target bone. Tune per item and per rig.
equipRotationVector3(0, 0, 0)Local rotation, in euler angles, on the target bone.
equipScalefloat1Uniform scale for the worn visual.

Worn visuals attach to the rig's Humanoid bones — head to Head, body to Chest, legs to Hips, hands to LeftHand and RightHand — so any Humanoid character wears the same gear without per-character setup.

Dropping and picking up

Dragging a slot out of the inventory window — or right-clicking it — drops the stack into the world as a physical pickup wearing the item's worldModel. The drop is a real object — a trigger sphere for range, a collider and a rigidbody so it falls and rests, and an InteractableBehaviourthat shows a prompt once you are close. Activating that prompt — press, hold, or repeated press, whichever the item's pickupActivation says — puts the stack back in your bag.

Dropped items belong to the world, not to whoever dropped them: every player can see and take one, and they survive a save. That last part takes a little machinery, because a runtime-spawned object cannot be "remembered" the way a scene object can — there is nothing in the loaded scene to restore onto. The save holds a recipe instead (which item, how many, where it came to rest) and rebuilds the drop. See Saving & Loading for the three shapes persistence uses.

Set allowItemDropping to false on CharacterInventory for a game where items should never reach the floor.

Giving a player something

  1. Author the item

    Create → Party Core Kit → Inventory → Item Definition. Set an id, a displayName, an icon, and a maxStack above 1 if it should pile up.
  2. Add it to knownItems

    On the player's CharacterInventory, append the asset to knownItems. Skipping this works offline and fails online, which is the worst way for it to fail.
  3. Hand it over

    Either place a pickup in the scene, add the item to a container's loot, or call AddItem from a rule or a script.
  4. Press play

    The tile appears in the hotbar, the details pane reads the description, and dropping it puts the world model on the floor.

The API, if you want it

The surface is deliberately small, and every mutating call returns bool so a refusal is something you can branch on rather than something you discover later.

using Curitor.PartyCoreKit.Inventory;
using UnityEngine;

public class StarterKit : MonoBehaviour
{
    [SerializeField] private CharacterInventory inventory;
    [SerializeField] private CharacterEquipment equipment;
    [SerializeField] private ItemDefinition stone;
    [SerializeField] private EquipmentDefinition helmet;

    private void Start()
    {
        // false when there is no room -- the item is NOT silently eaten.
        if (!inventory.AddItem(stone, 10))
            Debug.Log("Bag is full.");

        // Equip from whichever slot the helmet landed in; whatever was
        // worn goes back to the bag.
        if (inventory.AddItem(helmet))
        {
            for (int i = 0; i < inventory.SlotCount; i++)
            {
                if (inventory.GetSlot(i)?.item != helmet) continue;
                equipment.EquipFromInventory(i, EquipmentSlot.Head);
                break;
            }
        }
    }

    private void OnEnable()
    {
        inventory.OnSlotChanged += HandleSlotChanged;
        inventory.OnSelectionChanged += HandleSelectionChanged;
        equipment.OnEquipmentChanged += HandleEquipmentChanged;
    }

    private void OnDisable()
    {
        inventory.OnSlotChanged -= HandleSlotChanged;
        inventory.OnSelectionChanged -= HandleSelectionChanged;
        equipment.OnEquipmentChanged -= HandleEquipmentChanged;
    }

    private void HandleSlotChanged(int index) { }
    private void HandleSelectionChanged(int previous, int current) { }
    private void HandleEquipmentChanged(EquipmentSlot slot) { }
}

The rest of the surface: GetSlot, FindItem (id to asset, through knownItems), MoveSlot, DropFromSlot, RemoveFromSlot, RemoveFromSelected, SelectSlot and CycleSelection; on equipment, GetEquipped, CanEquip, EquipFromInventory, UnequipToInventory and DropEquipped.

The windows

The inventory window supports mouse drag-and-drop and a gamepad-native select-to-move flow; container windows use hover-for-details, click-to-take. All of it is built from the toolkit's themed widget kit, so restyling your game restyles these screens too.

The window is opened by the Inventory input action — I on keyboard, Select on a gamepad by default — routed through a HotkeyBehaviour and a Toggle Object instruction rather than hard-wired. Rebinding it is editing the input asset; re-pointing it at a different panel is editing one instruction, no code either way.

Multiplayer