Hello Dojo
本节假定您已安装 Dojo 工具链并熟悉 Cairo。如果没有,请参阅 快速入门部分。
十五分钟进道场(dojo)
你可以将 Dojo 视为 Cairo 的抽象,类似于 React 对 JavaScript 的抽象。它能让您编写速记命令,并在编译时扩展为复杂的查询。Dojo 基于著名的实体组件系统(Entity Component System,ECS)架构。
在 Dojo 中,您可以使用系统和组件来设计您的世界。系统概括了世界的逻辑,而组件则表示状态。这种强大的模式允许你以高度模块化的方式构建逻辑。如果你还不明白,不要着急,我们将在下文中详细介绍。
首先,让我们建立一个在本地运行的项目。在一个空目录下执行:
sozo init
恭喜您您现在有了一个本地 Dojo 项目。该命令会在您的当前目录下创建一个 dojo-starter
项目。它是新项目的理想起点,为您提供了开始项目所需的一切。
Dojo项目剖析
检查 dojo-starter
项目的内容,你会发现其结构如下(不包括非Cairo代码文件):
src
- components.cairo
- systems.cairo
- lib.cairo
Scarb.toml
Dojo 项目在很大程度上类似于标准的 Cairo 项目,区别在于创建 组件
和 系统
时使用的一些特殊属性标记。让我们接下来探讨一下。
打开src/components.cairo
文件以继续。
#[derive(Component, Copy, Drop, Serde, SerdeLen)]
struct Moves {
#[key]
player: ContractAddress,
remaining: u8,
}
#[derive(Component, Copy, Drop, Serde, SerdeLen)]
struct Position {
#[key]
player: ContractAddress,
x: u32,
y: u32
}
...rest of code
请注意 #[derive(Component, Copy, Drop, Serde, SerdeLen)]
属性。要识别组件,我们必须包含 Component
。这将向 Dojo 编译器发出信号,表明此结构体应被视为组件。
我们的 Moves
组件在其状态中包含一个 remaining
值。#[key]
属性告知 Dojo,该组件是由 player
字段索引的。如果你对这一点不熟悉,我们将在本章后面的内容中说明它的重要性。从本质上讲,它意味着您可以使用 player
字段来查询此组件。
同样,我们还拥有一个保存 x
和 y
值的 Position
组件。同样,该组件由 player
字段索引。
现在,让我们检查一下src/systems.cairo
文件:
#[system]
mod spawn {
use array::ArrayTrait;
use box::BoxTrait;
use traits::Into;
use dojo::world::Context;
use dojo_examples::components::Position;
use dojo_examples::components::Moves;
fn execute(ctx: Context) {
let position = get!(ctx.world, ctx.origin, (Position));
set!(
ctx.world,
(
Moves {
player: ctx.origin, remaining: 10
},
Position {
player: ctx.origin, x: position.x + 10, y: position.y + 10
},
)
);
return ();
}
}
让我们来分析一下:
#[system]
正如我们使用的 #[derive(Component)]
属性一样,#[system]
属性通知 Dojo 编译器此结构是一个系统,并指示它进行相应的编译。
fn execute(ctx: Context)
您会发现该系统有一个 execute
函数。需要注意的是,所有 Dojo 系统都需要一个 execute
函数。该函数接受一个 Context
作为参数。Context
(上下文) 是一个独特的结构,它提供了关于世界和调用者的信息。
值得一提的是,一个系统可以不仅仅包含 execute
函数。您可以根据需要自由添加多个函数。不过,execute
函数是必须的,因为系统执行时会调用它。
现在让我们看看下一行:
let position = get!(ctx.world, ctx.origin, (Position));
在这里,我们使用 get!
命令 来获取 ctx.origin
实体的 Position
组件。ctx.origin
是调用者的地址。第一次调用时,它将返回:
Position {
player: 0x0, // zero address
x: 0,
y: 0
}
现在是下一行:
set!(
ctx.world,
(
Moves {
player: ctx.origin, remaining: 10
}, Position {
player: ctx.origin, x: position.x + 10, y: position.y + 10
},
)
);
这里我们使用 set!
命令 为 ctx.origin
实体设置Moves
和Position
组件。
在很短的时间内,我们在这里做了很多事情。让我们来回顾一下:
- 解释了 Dojo 项目的解剖结构
- 解释
#[derive(Component)]
和#[system]
属性的含义 - 解释了
execute
函数 - 解释了
Context
结构 - 介绍了
get!
和set!
命令
在本地运行!
既然我们已经掌握了一些理论知识,那就来构建 Dojo 项目吧!
sozo build
这就把组件和系统编译成了一个可以部署的工件!就这么简单!
现在,让我们将其部署到 Katana 中!首先,我们需要让 Katana 运行:
katana --disable-fee
成功!现在,Katana应已在本地计算机上运行。现在开始部署!
sozo migrate --name test
这将把工件部署到 Katana 中。你应该会看到类似下面的终端输出:
Migration account: 0x33c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c
[1] 🌎 Building World state....
> No remote World found
[2] 🧰 Evaluating Worlds diff....
> Total diffs found: 7
[3] 📦 Preparing for migration....
> Total items to be migrated (7): New 7 Update 0
# Executor
> Contract address: 0x1a8cc7a653543337be184d21ceeb5cfc7e97af5ab7da5e4be77f373124d7e48
# World
> Contract address: 0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16
# Components (2)
Moves
> class hash: 0x3240ca67c41c5ae5557f87f44cca2b590f40407082dd390d893a514cfb2b8cd
Position
> class hash: 0x4caa1806451739b6fb470652b8066a11f80e847d49003b43cca75a2fd7647b6
# Systems (3)
spawn
> class hash: 0x1b949b00d5776c8ba13c2fdada38d4b196f3717c93c5c254c4909ed0eb249f7
move
> class hash: 0x2534c514efeab524f24cd4b03add904eb540391e9966ebc96f8ce98453a4e1e
library_call
> class hash: 0xabfd55d9bb6552aac17d78b33a6e18b06b1b95d4f684637e661dd83053fd45
🎉 Successfully migrated World on block #4 at address 0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16
Your 🌎 is now deployed at 0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16
!
让我们讨论一下项目中的 Scarb.toml
文件。该文件包含环境变量,可使在项目中运行 CLI 命令变得轻而易举。(点击此处了解更多信息)。
在文件底部添加世界地址:
world_address = "0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16"
这样就为项目建立了世界地址。然后就可以运行以下命令:
sozo execute spawn
这样就激活了产卵系统。现在你有了一个可以互动的本地世界。
索引
设置好本地世界后,让我们来深入研究索引。你可以用这个简单的命令为整个世界建立索引:
torii
执行上述操作可激活本地 torii 服务器,使用 SQLite 作为其数据库,数据库地址为 http://0.0.0.0:8080
。它会自动将你的世界索引到表中,允许你使用 GraphQL 查询。
我们已经讲了很多!下面我们来回顾一下:
- 构建一个 Dojo 世界
- 将项目部署到 Katana
- 在本地运行生成系统
- 用 Torii 索引世界
接下来的步骤
本概述仅仅提供了一个对 Dojo 端到端的快速了解。然而,这些世界的潜力是巨大的!Dojo 被设计为用于管理数百个系统和组件,可发挥无限的创造力。那么,您下一步将制作什么呢?