Skip to content

Tutorial: Per-Instance Pub/Sub with LocalSignalTransmitter

Some signals are global — every system listens to one bus, like the level-up event of an RPG. Other signals are per-instance — every prefab instance has its own routing, and a signal raised on one instance shouldn't fire listeners on another. That's the gap LocalSignalTransmitter fills.

By the end of this tutorial you'll have a prefab where each instance has its own signal bus — one chest opening doesn't fire the listeners on every other chest.

Prerequisites: Basic familiarity with SignalType and Events.


When LocalSignalTransmitter Beats a Shared EventAsset

EventAsset is global: any listener that subscribes to the asset hears every raise. That's exactly what you want for things like "game paused" or "tutorial step complete" — one bus, many listeners.

But consider a treasure chest prefab:

  • Each chest has its own "opened" moment.
  • Each chest has its own UI tooltip and particle effect.
  • When chest A opens, only A's listeners should fire — not B's, not C's.

A shared EventAsset fans the signal to everyone. A direct UnityEvent works but can't be plugged into any IEvent slot. LocalSignalTransmitter gives you the best of both: routing scoped to a single instance, but exposed through the standard IEvent and SignalType surface.


1. Add a LocalSignalTransmitter to the Prefab

Open your Chest prefab. Add the LocalSignalTransmitter component.

Add Component → Jungle → Events → Local Signal Transmitter

The component carries no Inspector fields — it's a pure routing hub. The asset value comes through the SignalType assets you reference into it from elsewhere.


2. Create the Signals

Right-click in the Project → Create → Jungle → Events → Signal Type. Name it ChestOpenedSignal.

This is a shared key — the type of signal. The hub provides the scope: every chest's transmitter knows about ChestOpenedSignal but routes its listeners independently.


3. Raise the Signal on This Chest's Transmitter

When a chest opens, raise the signal on its own transmitter.

In the chest's "Opened" process (a phase process of an AttachableObject, a ProcessComponent, anywhere that runs a process), add a Raise Signal On Owner Transmitter Operation:

Field Value
owner The chest GameObject (often this).
signal ChestOpenedSignal.

The operation finds the LocalSignalTransmitter on the owner GameObject and calls Raise(ChestOpenedSignal) on it. Only listeners that registered on that transmitter fire.

For "raise on a transmitter I'm holding by reference" use Raise Signal On Transmitter Operation instead — it takes a direct hub reference.


4. Listen to the Signal on the Same Chest

Anywhere on the chest prefab that wants to react to its own open signal: drop a Signal Event From Hub into an IEvent slot.

For example, on the same chest, add a ProcessComponent and set its Begin trigger to a SignalEventFromHub:

Field Value
transmitter The chest's LocalSignalTransmitter.
signal ChestOpenedSignal.

When the chest raises ChestOpenedSignal on its transmitter, this ProcessComponent begins — and only this chest's ProcessComponent, not its siblings'.


5. Or Listen via a Reactor

Combine with a Reactor on the chest for typed reactions:

Reactor (on the chest)
└─ Event Target
   ├─ Source: SignalEventFromHub(LocalSignalTransmitter, ChestOpenedSignal)
   └─ Entries
       └─ Body: SpawnParticleCommand, PlayAudioCommand, UpdateUICommand

Same pattern, gives you per-entry overlap and retrigger policies plus the Reactor's lifecycle behaviour.


6. When to Use Reactor.Receive Instead

The Reactor's signal target uses a different mechanism — signals are pushed in via Reactor.Receive(signal). Use it when:

  • The signal arrives from outside the chest (a global event, a manager).
  • You want all signal-receiving targets on the Reactor to share the same routing.

Use LocalSignalTransmitter when the signal is intrinsic to this instance — same prefab, same chest, signal routed locally.

Both can coexist on the same chest — a Reactor for cross-system signals, a LocalSignalTransmitter for instance-local broadcasts.


7. SignalEventFromHub Anywhere

SignalEventFromHub is just an IEvent implementation. That means anywhere an IEvent slot exists — WaitForEventProcess, AttachingAgent grab/drop triggers, Reactor event targets, ProcessComponent begin/end — you can plug a transmitter-scoped signal in. The transmitter-scoped routing applies regardless of where you plugged it.


8. SignalType vs EventAsset Decision Table

Question If yes, pick...
Will many systems share this event globally? EventAsset
Does every prefab instance need its own routing? SignalType + LocalSignalTransmitter
Do you need typed access to a value inside the listener? A Reactor target (Float, Bool, Vector3, ...) — not a signal at all.
Does the routing need to feed multiple reactor entries on one component? Reactor.Receive(signal)

There's no hard wall between the patterns — SignalEventFromHub exposes a transmitter-scoped signal as an IEvent, so it composes everywhere an EventAsset would.


Next Steps