Events
Events play a pivotal role in decoding the dynamics of a Dojo world. Every time there's an update to a model, the world contract emits events.
What's even more exciting is that you can craft your own custom events to fit specific needs! Moreover, thanks to model's introspection and Torii, all these events are seamlessly indexed, ensuring easy and efficient querying.
Custom Events
Within your game, emitting custom events can be highly beneficial. Fortunately, there's a handy emit!
command that lets you release events directly from your world. These events are indexed by Torii.
There are two kind of Custom Events with different use-cases.
Using dojo::event
These events are acting like 'off-chain' storage and derive Model which allows Torii to easily parse them.
Since it's a Model it must have a least a #[key]
and any type used inside the model must derive Introspect
.
For example we will declare a PlayerStatus
struct to keep track of player mood.
- We don't need this information on-chain.
- We don't want to historize
PlayerStatus
changes, just keep track of the current/latestPlayerStatus
.
#[derive(Copy, Drop, Introspect)]
struct Mood {
Happy,
Angry,
}
#[derive(Copy, Drop, Serde)]
#[dojo::model]
#[dojo::event]
struct PlayerMood {
#[key]
player: ContractAddress,
mood: Mood,
}
Emit the PlayerMood
event:
emit!(world, (PlayerMood { player, mood: Mood::Happy }));
Each time a PlayerMood
event is emitted, the PlayerMood
Model indexed by Torii will reflect the lasted mood.
Using starknet::Event
These events are acting like classic starknet events, allowing historization.
Torii index this events in a raw format (ex : here).
Declare the starknet Event enum for you contract with a Moved
variant:
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Moved: Moved,
}
Declare the Moved
struct (you can have zero, one or more #[key]
):
#[derive(Drop, Serde, starknet::Event)]
struct Moved {
address: felt252,
direction: felt252,
}
Emit the Moved
event:
emit!(world, (Event::Moved( Moved { address, direction } )));
Example
Now a full example using a custom event:
fn move(world: IWorldDispatcher, direction: Direction) {
let player = get_caller_address();
let (mut position, mut moves) = get!(world, player, (Position, Moves));
moves.remaining -= 1;
moves.last_direction = direction;
let next = next_position(position, direction);
set!(world, (moves, next));
emit!(world, (Event::Moved( Moved { player, direction } )));
}