Typed events
Declare a gameplay fact as an immutable record and publish it from the component that owns the event:
record ChestOpened { int Coins; }
class Chest : Component {
[EventId("opened")] public event ChestOpened Opened;
[Property] int CoinsTaken;
public void Open() {
CoinsTaken += 3;
Opened.Emit(new ChestOpened(3));
}
}Another component observes future notifications with a named synchronous void handler, or awaits the next notification:
class ChestPresenter : Component {
Subscription observation;
void Start() {
var chest = Scene.FindByName("Chest").GetComponent<Chest>();
if (chest != null) observation = chest.Opened.Subscribe(OnOpened);
}
void OnOpened(ChestOpened result) { Transform.Move(result.Coins, 0); }
public async Task<int> WaitForOpen(Chest chest) {
var result = await chest.Opened.Next();
return result.Coins;
}
}Subscriptions
Subscription.Cancel() unregisters the handler. Id, IsActive, and Reason are read-only. Subscriptions cannot be [Property] values or record members.
Retirement of either component removes the subscription. Registration inside a task also ties it to that task. Disabled listeners skip events without buffering them. A listener’s presentation tasks belong to its registration task, or its component when registered outside a task.
See Subscription.
Next()
Next() returns Task<Payload> and unregisters on completion, cancellation, failure, or either component’s retirement. The continuation runs on a later frame. Combine with Task.Race for an owned timeout.
Emit rules
- Only the declaring component can
Emitits own event. - Payloads must be immutable records. Nested records, enums, options, vectors, and typed assets keep their types.
- Delivery is synchronous FIFO. An event emitted by a handler waits until the current event finishes.
- One failing handler is reported without stopping other listeners.
- Emit describes state you already committed — it does not make surrounding statements transactional.
- Events are not replayed to later subscribers.
- Pure functions and
finallycannot emit, subscribe, or callNext, including through helpers. Cleanup may cancel an existing subscription.
Flow
The event appears under its component, with an aggregate Payload pin and typed member pins (for example Coins). Optional values expose presence separately; reading an absent value reports a binding error.
[EventId("opened")] keeps the Flow key stable. Source Rename inserts it automatically when needed. Script Studio shows event waits and live subscriptions with their source identities.
See Scripts and Flow.