Gessa Docs
Recipes

Recipe

Event wiring one trigger emits another responder reacts

A pressure plate over here should open a door over there; a switch should light a lamp across the room; stepping into a zone should start a sequence somewhere else. The sensor and the responder are DIFFERENT entities, so wire them with a named custom event rather than having the trigger reach into the other entity's components blindly.
engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, mutation.v1, hierarchy.v1Copy for LLM

Use this for

making one entity react when a DIFFERENT entity is triggered; a pressure plate that opens a distant door, a switch that lights a far lamp, a trigger that starts a sequence elsewhere; decoupling the sensor from the responder with a custom event

Not for

a trigger that acts on the SAME object it lives on (see doors-buttons-and-interactions); launching the entering player (see jump-pads-and-launchers); scoreboard or match events (see match-flow-and-scoreboards)

Pairs with: Doors buttons levers and press-to-interact, Moving platforms, elevators, rotating hazards, and objects on a patrol path, Timers countdowns cooldowns and enemy waves, Manager scripts driving many objects from one system

The recipe

Author both scripts with project_apply_script_semantic_patch using the ai_safe op pack.

  1. Sensor side: give the trigger object a trigger ColliderComponent (collision:"trigger") via project_add_component, then addTriggerHandler ({ "handlerKey":"onSignal" }). In the whole-body GessaScript (replaceScriptFromGessaScript) emit the event: ctx.events.emit("door_opened", { open: true }). The emitCustomEvent op is the declarative equivalent when you want the event declared in the script's event set.
  2. Responder side: on the door (or lamp, or gate) entity declare the matching handler with createCustomEventHandler ({ "eventKey":"door_opened" }), which creates a guarded onCustomEvent handler for that semantic key. patchComponent acts on the entity the handler lives on, so its body does the reaction directly, e.g. ctx.entity.patchComponent("TransformComponent", { position: {...open} }).
  3. Idempotency: guard the responder with setBooleanState ({ "field":"opened", "value": true }) and check it first, so a second emit does not re-run the open.
  4. Payload: pass ids or values in the emit payload ({ source, amount }) and read them in the handler; do not encode data in the event NAME.
  5. Fan-out is free: any number of responders that declare the same onCustomEvent key all react to one emit. Use distinct event names per wire (gate_north_open, lamp_hall_on) so unrelated responders stay silent.

Pitfalls

  • ctx.events.emit is ROOM-scoped (audience room), so EVERY subscriber of that name reacts. Name events per wire, not generically, or a far responder fires unexpectedly.
  • Do not make the trigger reach across and mutate the other entity directly by guessing its id; the event wire is what keeps the sensor and responder decoupled and reorderable.
  • The responder needs its OWN script carrying the onCustomEvent handler; an emit with no declared subscriber is silently dropped.
  • An event is ephemeral: a responder spawned AFTER the emit never sees it. Drive persistent open/closed truth through setBooleanState, and read that on spawn.

Verify

  • simulation_run (qa.run.start) tripping the sensor trigger and asserting the remote responder reached its reacted state.
  • project_get_graph_snapshot to confirm the trigger handler on the sensor and the onCustomEvent handler on the responder both landed.
Was this helpful?Report an issueContact support

On this page