Gessa Docs
Recipes

Recipe

Inventory item pickups keys and equipping

The player collects keys, potions, or ammo, carries them, and spends them later. There is no inventory or StatsComponent (stripped); the inventory is a durable warehouse record and item logic is a script.
engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, persistence.v1, ui.v1, world.v1Copy for LLM

Use this for

picking up keys, potions, ammo, and tools into a held inventory; tracking quantities of items; using, consuming, or equipping an item; a locked door that opens only if the player holds the key

Not for

a pure score counter with no items (see collectibles-and-scoring); durable cross-session profile saves only (see saves-and-persistence); weapon firing behavior (see projectiles-and-ranged-weapons)

Pairs with: Collectibles pickups scoring and win condition, Saves persistence player progress and data stores, UI HUD panels widgets and world nameplates, Doors buttons levers and press-to-interact

The recipe

Author with project_apply_script_semantic_patch using the ai_safe op pack. Held items live in a warehouse store (default storeKey:"inventory", recordKey:"player"), one field per item type.

  1. Make each world pickup an entity tagged by item type with a trigger ColliderComponent (collision:"trigger").
  2. On pickup, addTriggerHandler { "handlerKey":"onPickup" }. Inside it: incrementNumericState { "field":"keys", "by": 1 } to add a counted item, or writeTypedStateValue to set a unique key you either hold or do not; then despawnEntity { "reason":"picked_up" } to remove the world item.
  3. For a list of distinct items, append to an array field with ctx.warehouse.append in a whole-body GessaScript body (replaceScriptFromGessaScript); read the whole record back with ctx.warehouse.get or filter with ctx.warehouse.query.
  4. Gate an action on holding an item: readTypedStateValue the item field, and only open the locked door (see doors-buttons-and-interactions) or fire the weapon when the count is above zero.
  5. Consume or equip: on use, incrementNumericState the field by -1 (consume) or writeTypedStateValue an equipped field to the item id (equip). Project every count to the HUD with wireHudStateBinding or ctx.ui.setWidgetValue.

Pitfalls

  • Keep the inventory in the warehouse, not on a component; a count written only on the entity is lost when the entity despawns or the player reloads.
  • ctx.warehouse.* writes are prefetch-then-drain and authority-gated (persistence.prefetch_only); mutate on the server, and read the field you intend to change in the same handler so the drain is deterministic.
  • Decrement guardedly: check the count is above zero before consuming, or you create negative inventory.
  • For stackable items increment a number; for unique items (a named key) set a boolean or an id, not a counter.

Verify

  • simulation_run (qa.run.start) to prove a pickup raises the count, using an item lowers it, and a gated door opens only while the key is held.
  • project_get_graph_snapshot to confirm the pickup triggers and handlers exist.
Was this helpful?Report an issueContact support

On this page