事件

事件在让外部了解 Dojo 世界中的动态时起着关键作用。每次Component更新时,World 合约都会发出这些事件。更令人兴奋的是,你可以根据特定需求制作自己的自定义事件!此外,由于使用了 Torii,所有这些事件都被无缝地索引起来,确保了轻松高效的查询。

组件事件

请看 Moves 组件的示例:

#[component]
struct Moves {
    #[key]
    player: Address,
    remaining: u32,
}

当该组件更新时,World 合约将发出一个结构如下的事件:

#[derive(Drop, starknet::Event)]
struct StoreSetRecord {
    table: felt252, // Moves
    keys: Span<felt252>, // [player]
    offset: u8, // 0
    value: Span<felt252>, // [remaining]
}

然后,Torii将捕获这些信息,并编制索引以供查询。这样,你就可以重建世界的状态。

同样,当一个组件被删除时,World 合约将发出一个结构如下的事件:

#[derive(Drop, starknet::Event)]
struct StoreDelRecord {
    table: felt252,
    keys: Span<felt252>,
}

世界事件

当初始化以及注册新组件和系统时,World合约也会发出事件。这些事件通过以下结构体发出:

#[derive(Drop, starknet::Event)]
struct WorldSpawned {
    address: ContractAddress,
    caller: ContractAddress
}
#[derive(Drop, starknet::Event)]
struct ComponentRegistered {
    name: felt252,
    class_hash: ClassHash
}
#[derive(Drop, starknet::Event)]
struct SystemRegistered {
    name: felt252,
    class_hash: ClassHash
}

Torii 也会捕获这些事件,并编制索引以供查询。

自定义事件

在您的系统中,发射自定义事件是非常有益的。幸运的是,有一个方便的 emit!宏可以让您直接从您的世界中发射事件。使用方法如下:

emit !(ctx.world, Moved { address: ctx.origin, direction });

在系统中加入此机能后,它将发出一个结构如下的事件:

#[derive(Drop, starknet::Event)]
struct Moved {
    address: felt252,
    direction: felt252,
}

现在是一个使用自定义事件的完整示例:

fn execute(ctx: Context, direction: Direction) {
    let (mut position, mut moves) = get !(ctx.world, ctx.origin, (Position, Moves));
    moves.remaining -= 1;

    let next = next_position(position, direction);
    
    set !(ctx.world, (moves, next));
    emit !(ctx.world, Moved { address: ctx.origin, direction });
    return ();
}

注意:请阅读 命令 中的 get!set! 宏。