ItemVault uses one shared item model across inventory, drops, pickups, and saves:
ItemDefinition: item-type data.ItemStack: one stack instance.WorldItemStackMeta: the implementation helper ItemVault uses to attach a stack to a spawned pickup/world node until pickup/drop events consume it.
Three Layers
| Layer | Use it for | Example |
|---|---|---|
ItemDefinition |
Data shared by every copy of an item type | iron_ore, display name, icon, category, tags |
ItemStack |
One stack instance quantity | 12 iron ore, one sword instance id |
WorldItemStackMeta |
Temporary ItemVault stack handoff on a spawned world node | Attach a stack to a pickup scene node |
WorldItemStackMeta stores one resolved ItemStack under ItemVault's shared
item_stack node metadata key on the spawned world node. ItemVault spawners,
pickups, and adapter code can then recover the same stack without duplicating
metadata parsing.
Put Game Terms on ItemDefinition
Use ItemDefinition for stable facts about an item type.
var ore := ItemDefinition.new()
ore.id = &"iron_ore"
ore.display_name = "Iron Ore"
ore.category = &"material"
ore.tags = [&"ore", &"smithing"]
ore.max_stack = 99
ore.weight = 0.25
Good ItemDefinition fields:
- Stable ids:
iron_ore,health_potion,moonleaf - UI labels and icons
- Inventory categories:
material,consumable,quest,currency - Tags for game queries:
ore,smithing,healing,rare - Default max stack and weight
- World scene used when the item is dropped
Use ids, categories, and tags for game-specific vocabulary. A farming game can
use category = &"crop" with tags like &"spring" or &"seed". A dungeon
game can use category = &"relic" with tags like &"cursed" or &"fire".
Put Per-Stack Data on ItemStack
Use ItemStack for a specific stack in inventory or in the world.
var stack := ItemStack.new(ore, 12)
stack.instance_id = &"mine_drop_042"
stack.max_override = 20
stack.weight_override = 0.3
Good ItemStack fields:
quantity: units in the stackinstance_id: optional identity for one specific stackmax_override: optional max-stack overrideweight_override: optional weight override
Use instance_id when the game needs to associate external state with one
specific stack: durability, rolled affixes, quest ownership, crafted-by value,
or GECS component state. Keep larger game-specific state in game data, keyed by
instance_id.
Use WorldItemStackMeta for Spawned World Nodes
When a drop spawns a pickup scene, ItemVault needs the world node to carry the resolved stack until pickup events or adapter code read it back.
var pickup: Node = pickup_scene.instantiate()
var stack := ItemStack.new(ore, 12)
WorldItemStackMeta.write(pickup, stack)
Later, ItemVault can read the same stack:
var stack: ItemStack = WorldItemStackMeta.read(pickup)
if stack != null:
print("Picked up %s x%s" % [stack.item.id, stack.quantity])
Use WorldItemStackMeta only for the ItemVault world-node stack handoff. Put
durability, biome source, quest flags, flavor text, or other game state on
ItemDefinition, ItemStack, or a game-owned system.
Pickup Node Lifetime
WorldItemStackMeta does not use a global registry. The ItemStack is stored
on the pickup node's Godot metadata. ItemVault pickups clear that metadata
after emitting PickupEvent, so listeners receive the stack but a consumed
pickup does not keep a stale handoff.
That means:
- If the pickup node is freed, the node metadata is freed with it.
- If the world unloads, unsaved pickup-node metadata is gone.
- No global registry cleanup is required.
- Adapter code can call
WorldItemStackMeta.clear(node)after consuming a stack into another world/entity system. - Persistent dropped-world-items are a game save concern.
If a game needs dropped pickups to survive world unload, read the stack before freeing or unloading the node and save the stack dictionary:
var stack := WorldItemStackMeta.read(pickup)
if stack != null:
save_world_drop(pickup.global_position, stack.to_dict())
When the world loads again, recreate the pickup node and write the restored
ItemStack back with WorldItemStackMeta.write(pickup, stack).
Example: ItemVault Pickup Route
The default flow is ItemVault-owned and inventory-oriented:
ItemVault drop -> spawned pickup node -> PickupEvent -> Inventory or Wallet
If the pickup is handled by ItemVault's spawner pickup route, SpawnEvent.stack
and PickupEvent.stack contain the same ItemStack.
Example: GECS or Custom World Adapter
If your game consumes ECS-compatible world entities downstream, keep ItemVault as the item/drop/pickup source and adapt at the stack boundary.
var stack := WorldItemStackMeta.read(spawned_node)
if stack != null:
gecs_world.spawn_item_entity(stack.to_dict())
WorldItemStackMeta.clear(spawned_node)
ItemVault does not need to own your ECS entity. It provides the resolved ItemVault stack payload cleanly.
Example: Keep Rare Roll Data in Your Game
For rare, rolled, or crafted items, keep heavy game data outside
WorldItemStackMeta and link it with instance_id.
var sword_stack := ItemStack.new(sword_definition, 1)
sword_stack.instance_id = &"sword_roll_1007"
rare_item_rolls[sword_stack.instance_id] = {
"rarity": &"legendary",
"damage_bonus": 7,
"crafted_by": "Ari",
}
The stack remains small and save-friendly. The game owns detailed rolled data and can save it in its own system.
What's Next
- Read
json-catalogs-and-saves.mdfor JSON catalog and save examples. - Read
../save-schema.mdfor save/load reference. - Read
dimension-neutral-handling.mdfor shared 2D/3D item-event handling.
Source
addons/item_vault/guides/item-data-and-stack-metadata.md
Plugin docs root:gdscript/plugins/item_vault_dev/addons/item_vault/guides