Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Events

Events are for many-to-many, poll-when-convenient communication — damage dealt, an item picked up, anything a handful of unrelated systems might want to react to without tight coupling. If you instead want guaranteed same-tick reactions, see Observers.

Register the event type on the app:

app.add_event::<Damage>()

This is idempotent — safe to call from two different plugins that both want Damage.

Sending and reading

struct Damage(u32);

fn deal_damage(mut writer: EventWriter<Damage>) {
    writer.send(Damage(10));
}

fn log_damage(mut reader: EventReader<Damage>) {
    for event in reader.iter() {
        println!("took {} damage", event.0);
    }
}

Events<T> is double-buffered: an event sent during tick N is visible to readers for the rest of N and all of N + 1, then dropped. Each EventReader keeps its own read cursor (like Local), so a reader sees every event exactly once no matter when it runs relative to the writer, and multiple readers of the same type don’t interfere with each other.

For a resource/event type that might not be registered — e.g. an optional plugin’s event — take Option<EventReader<T>>/Option<EventWriter<T>> instead.

Signaling that an async result is ready

A particularly useful case: a system polling a Promise<T> (a GPU readback, say) and another system that needs to react once the result lands. Sending an event when the Promise resolves is usually a better fit than publishing the result as a resource — see Promise: handing the result to a dependent system via an Event for the full walkthrough, including why send beats Commands::insert_resource for same-tick delivery.