Skip to content
ct

Item Vault v1.0

Item Data and Stack Metadata

Place item ids, tags, stack overrides, and world pickup metadata in the right layer.

Status
Current
Version
v1.0
Updated
2026-07-31

ItemVault uses one shared item model across inventory, drops, pickups, and saves:

  • ItemDefinition: item-type data.
  • ItemStack: one concrete stack boundary and its retained item data.
  • 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

ItemDefinition.id is the authoritative identity key. Two distinct ItemDefinition resource instances that share an id are the same item for stacking, slot acceptance, count(id), remove(id, ...), save/load, and the Rust backend's string-id comparison — resource reference identity is not authoritative, only the stable id is. When an ItemStack enters an Inventory that has an ItemDatabase configured, the inventory resolves the stack's id to the database's canonical ItemDefinition instance so every stored stack shares one authoritative definition per id. If an incoming definition disagrees with the canonical one on max_stack, weight, or category, the canonical definition wins and the conflict is logged; per-stack overrides (instance_id, max_override, weight_override) are preserved.

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.stack_id= &"backpack_boundary_07"
	stack.max_override= 20
stack.weight_override= 0.3

Good ItemStack fields:

  • quantity: units in the stack
  • instance_id: optional identity for one retained item instance
  • stack_id: optional identity for the concrete stack boundary; it is distinct from instance_id and is preserved by copies, transfers, and saves
  • max_override: optional max-stack override
  • weight_override: optional weight override
  • resources: optional numeric retained values such as charges or durability

Use instance_id when the game needs to associate external state with one retained item instance. Use stack_id when storage topology itself matters, such as audit trails, slot placement, or preserving a concrete stack boundary. Keep larger game-specific state in game data, keyed by the appropriate identity.

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: Pass a Stack to a Game-Owned World System

If another part of your game keeps its own world state, keep ItemVault as the item/drop/pickup source and adapt at the stack boundary.

var stack:= WorldItemStackMeta.read(spawned_node)
if stack!= null:
	world_items.restore_stack(stack.to_dict())
	WorldItemStackMeta.clear(spawned_node)

ItemVault does not need to own your world object. It provides the resolved ItemVault stack payload cleanly. An ECS can map the same dictionary into its own components through a small project script.

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