Skip to content

Commit

Permalink
Merge pull request #85 from gianalarcon/hello-dojo-v0.3.0
Browse files Browse the repository at this point in the history
Update hello-dojo tutorial
  • Loading branch information
gianalarcon authored Oct 18, 2023
2 parents 078161b + cff5984 commit 5d9e832
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 73 deletions.
2 changes: 0 additions & 2 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
- [0.2.0 -> 0.3.0](./cairo/migration/0.3.0.md)
- [ECS in 15 minutes](./cairo/hello-dojo.md)

- [Components](./cairo/components.md)

- [Entities](./cairo/entities.md)
- [Testing](./cairo/testing.md)

Expand Down
1 change: 0 additions & 1 deletion src/cairo/components.md

This file was deleted.

172 changes: 103 additions & 69 deletions src/cairo/hello-dojo.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ Inspect the contents of the `dojo-starter` project, and you'll notice the follow

```bash
src
systems
- raw_contract.cairo
- with_decorator.cairo
- actions.cairo
- lib.cairo
- models.cairo
- utils.cairo
Expand Down Expand Up @@ -66,28 +64,25 @@ Our `Moves` model houses a `player` field. At the same tine, we have the `#[key]

In a similar vein, we have a `Position` component that have a Vec2 data structure. Vec holds `x` and `y` values. Once again, this component is indexed by the `player` field.

Now, let's examine the `src/systems/raw_contract.cairo` file:
Now, let's examine the `src/actions.cairo` file:

```rust,ignore
#[starknet::contract]
mod player_actions_external {
// dojo decorator
#[dojo::contract]
mod actions {
use starknet::{ContractAddress, get_caller_address};
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};
use dojo_examples::models::{Position, Moves, Direction, Vec2};
use dojo_examples::utils::next_position;
use super::IPlayerActions;
#[storage]
struct Storage {
world_dispatcher: IWorldDispatcher,
}
use super::IActions;
// declaring custom event struct
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Moved: Moved,
}
// declaring custom event struct
#[derive(Drop, starknet::Event)]
struct Moved {
player: ContractAddress,
Expand All @@ -96,30 +91,62 @@ mod player_actions_external {
// impl: implement functions specified in trait
#[external(v0)]
impl PlayerActionsImpl of IPlayerActions<ContractState> {
impl ActionsImpl of IActions<ContractState> {
// ContractState is defined by system decorator expansion
fn spawn(self: @ContractState) {
// Access the world dispatcher for reading.
let world = self.world_dispatcher.read();
// Get the address of the current caller, possibly the player's address.
let player = get_caller_address();
// Retrieve the player's current position from the world.
let position = get!(world, player, (Position));
// Retrieve the player's move data, e.g., how many moves they have left.
let moves = get!(world, player, (Moves));
// Update the world state with the new data.
// 1. Increase the player's remaining moves by 10.
// 2. Move the player's position 10 units in both the x and y direction.
set!(
world,
(
Moves { player, remaining: 10, last_direction: Direction::None(()) },
Position { player, vec: Vec2 { x: 10, y: 10 } },
Moves {
player, remaining: moves.remaining + 10, last_direction: Direction::None(())
},
Position {
player, vec: Vec2 { x: position.vec.x + 10, y: position.vec.y + 10 }
},
)
);
}
// Implementation of the move function for the ContractState struct.
fn move(self: @ContractState, direction: Direction) {
// Access the world dispatcher for reading.
let world = self.world_dispatcher.read();
// Get the address of the current caller, possibly the player's address.
let player = get_caller_address();
// Retrieve the player's current position and moves data from the world.
let (mut position, mut moves) = get!(world, player, (Position, Moves));
// Deduct one from the player's remaining moves.
moves.remaining -= 1;
// Update the last direction the player moved in.
moves.last_direction = direction;
// Calculate the player's next position based on the provided direction.
let next = next_position(position, direction);
// Update the world state with the new moves data and position.
set!(world, (moves, next));
// Emit an event to the world to notify about the player's move.
emit!(world, Moved { player, direction });
return ();
}
}
}
Expand All @@ -129,22 +156,33 @@ mod player_actions_external {

#### System is a contract

As you can see a `System` is like a regular Starknet contract. It imports the Models we defined earlier and exposes two functions `spawn` and `move`. These functions are called when a player spawns into the world and when they move respectively.
As you can see a `System` is like a dojo(starknet) contract. It imports the Models we defined earlier and exposes two functions `spawn` and `move`. These functions are called when a player spawns into the world and when they move respectively.

```rust,ignore
// Retrieve the player's current position from the world.
let position = get!(world, player, (Position));
// Retrieve the player's move data, e.g., how many moves they have left.
let moves = get!(world, player, (Moves));
```

Here we use `get!` [command](./commands.md) to retrieve the `Position` model for the `player` entity, which is the address of the caller.
Here we use `get!` [command](./commands.md) to retrieve the `Position` and `Moves` model for the `player` entity, which is the address of the caller.

Now the next line:

```rust,ignore
// Update the world state with the new data.
// 1. Increase the player's remaining moves by 10.
// 2. Move the player's position 10 units in both the x and y direction.
set!(
world,
(
Moves { player, remaining: 10, last_direction: Direction::None(()) },
Position { player, vec: Vec2 { x: 10, y: 10 } },
Moves {
player, remaining: moves.remaining + 10, last_direction: Direction::None(())
},
Position {
player, vec: Vec2 { x: position.vec.x + 10, y: position.vec.y + 10}
},
)
);
```
Expand Down Expand Up @@ -191,40 +229,44 @@ World name: test
[1] 🌎 Building World state....
> No remote World found
[2] 🧰 Evaluating Worlds diff....
> Total diffs found: 6
> Total diffs found: 5
[3] 📦 Preparing for migration....
> Total items to be migrated (6): New 6 Update 0
> Total items to be migrated (5): New 5 Update 0

# Executor
> Contract address: 0x5c3494b21bc92d40abdc40cdc54af66f22fb92bf876665d982c765a2cc0e06a
# Base Contract
> Class Hash: 0x7aec2b7d7064c1294a339cd90060331ff704ab573e4ee9a1b699be2215c11c9
# World
> Contract address: 0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16
> Contract address: 0x1af130f7b9027f3748c1e3b10ca4a82ac836a30ac4f2f84025e83a99a922a0c
# Models (2)
Moves
> Class hash: 0xb37482a660983dfbf65968caa26eab260d3e1077986454b52ac06e58ae20c4
Position
> Class hash: 0x6ffc643cbc4b2fb9c424242b18175a5e142269b45f4463d1cd4dddb7a2e5095
> Registered at: 0x36eedf55545c4e770da905325bb00f853864a15d1fbf4fbfb54f668f074d553
# Contracts (2)
player_actions
> Contract address: 0x2e4ff2961ac4f49e1e3c2b55c5090cc80ca61c38fdcabc7acabbf81e28a4abe
player_actions_external
> Contract address: 0x7cb0ac6dd2cd2a38bd27ce47ba429a1f31bf69055040342253f972e0b0473ce
> Registered at: 0x3e74b09d320ceb5d4401842bec805489019c04202bc23bc67a385f6e537dce0
# Contracts (1)
actions
> Contract address: 0x69a474a39b11d05c07bb9090fd1961b8e1c87aa5643e7b97087cb0c7620356a

🎉 Successfully migrated World at address 0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16
🎉 Successfully migrated World at address 0x1af130f7b9027f3748c1e3b10ca4a82ac836a30ac4f2f84025e83a99a922a0c

✨ Updating manifest.json...

✨ Done.

```

Your 🌎 is now deployed at `0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16`!

This establishes the world address for your project.

Let's discuss the `Scarb.toml` file in the project. This file contains environment variables that make running CLI commands in your project a breeze. (Read more about it [here](./config.md)). Make sure your file specifies the version of Dojo you have installed!
Let's discuss the `Scarb.toml` file in the project. This file contains environment variables that make running CLI commands in your project a breeze. (Read more about it [here](./config.md)). Make sure your file specifies the version of Dojo you have installed!. In this case version `v0.3.0`

```toml
[dependencies]
dojo = { git = "https://github.com/dojoengine/dojo", rev = "v0.3.0" }
```

### Indexing

Expand All @@ -237,24 +279,23 @@ torii --world 0x71b95a2c000545624c51813444b57dbcdcc153dfc79b6b0e3a9a536168d1e16
Running the command mentioned above starts a Torii server on your local machine. This server uses SQLite as its database and is accessible at http://0.0.0.0:8080/graphql. Torii will automatically organize your data into tables, making it easy for you to perform queries using GraphQL. When you run the command, you'll see terminal output that looks something like this:

```bash
2023-10-13T10:14:10.903554Z INFO torii::server: 🚀 Torii listening at http://0.0.0.0:8080
2023-10-13T10:14:10.903568Z INFO torii::server: Graphql playground: http://0.0.0.0:8080/graphql

2023-10-13T10:14:10.904767Z INFO torii_core::engine: processed block: 0
2023-10-13T10:14:10.905334Z INFO torii_core::engine: processed block: 1
2023-10-13T10:14:10.905949Z INFO torii_core::engine: processed block: 2
2023-10-13T10:14:10.906422Z INFO torii_core::engine: processed block: 3
2023-10-13T10:14:10.907088Z INFO torii_core::engine: processed block: 4
2023-10-13T10:14:10.907951Z INFO torii_core::engine: processed block: 5
2023-10-13T10:14:10.908566Z INFO torii_core::engine: processed block: 6
2023-10-13T10:14:10.909239Z INFO torii_core::engine: processed block: 7
2023-10-13T10:14:10.920225Z INFO torii_core::processors::register_model: Registered model: Moves
2023-10-13T10:14:10.928852Z INFO torii_core::processors::register_model: Registered model: Position
2023-10-13T10:14:10.929576Z INFO torii_core::engine: processed block: 8
2023-10-13T10:14:10.930337Z INFO torii_core::engine: processed block: 9
2023-10-13T10:14:10.930982Z INFO torii_core::engine: processed block: 10
2023-10-13T10:14:10.931467Z INFO torii_core::engine: processed block: 11
2023-10-13T10:14:10.931964Z INFO torii_core::engine: processed block: 12
2023-10-18T06:49:48.184233Z INFO torii::server: 🚀 Torii listening at http://0.0.0.0:8080
2023-10-18T06:49:48.184244Z INFO torii::server: Graphql playground: http://0.0.0.0:8080/graphql

2023-10-18T06:49:48.185648Z INFO torii_core::engine: processed block: 0
2023-10-18T06:49:48.186129Z INFO torii_core::engine: processed block: 1
2023-10-18T06:49:48.186720Z INFO torii_core::engine: processed block: 2
2023-10-18T06:49:48.187202Z INFO torii_core::engine: processed block: 3
2023-10-18T06:49:48.187674Z INFO torii_core::engine: processed block: 4
2023-10-18T06:49:48.188215Z INFO torii_core::engine: processed block: 5
2023-10-18T06:49:48.188611Z INFO torii_core::engine: processed block: 6
2023-10-18T06:49:48.188985Z INFO torii_core::engine: processed block: 7
2023-10-18T06:49:48.199592Z INFO torii_core::processors::register_model: Registered model: Moves
2023-10-18T06:49:48.210032Z INFO torii_core::processors::register_model: Registered model: Position
2023-10-18T06:49:48.210571Z INFO torii_core::engine: processed block: 8
2023-10-18T06:49:48.211678Z INFO torii_core::engine: processed block: 9
2023-10-18T06:49:48.212335Z INFO torii_core::engine: processed block: 10

```

You can observe that our `Moves` and `Position` models have been successfully registered.
Expand Down Expand Up @@ -282,7 +323,7 @@ After you run the query, you will receive an output like this:
"name": "Moves",
"class_hash": "0xb37482a660983dfbf65968caa26eab260d3e1077986454b52ac06e58ae20c4",
"transaction_hash": "",
"created_at": "2023-10-13 14:55:47"
"created_at": "2023-10-18 06:49:48"
}
}
}
Expand All @@ -308,22 +349,15 @@ Once you execute the subscription, you will receive notifications whenever new e
To accomplish this, we have to go back to our primary terminal and check the contracts section.

```bash
# Contracts (2)
player_actions
> Contract address: 0x2e4ff2961ac4f49e1e3c2b55c5090cc80ca61c38fdcabc7acabbf81e28a4abe
player_actions_external
> Contract address: 0x7cb0ac6dd2cd2a38bd27ce47ba429a1f31bf69055040342253f972e0b0473ce
# Contracts (1)
actions
> Contract address: 0x69a474a39b11d05c07bb9090fd1961b8e1c87aa5643e7b97087cb0c7620356a
```

We have `player_actions` contract address and `player_actions_external` contract address.
Since these two contracts have the same functionality, we can choose any of them to start to create entities.

For this example let's choose player_actions contract address: `0x2e4ff2961ac4f49e1e3c2b55c5090cc80ca61c38fdcabc7acabbf81e28a4abe`

In your main local terminal, run the following command:
We have to use `actions` contract address to start to create entities. In your main local terminal, run the following command:

```bash
sozo execute 0x2e4ff2961ac4f49e1e3c2b55c5090cc80ca61c38fdcabc7acabbf81e28a4abe spawn
sozo execute 0x69a474a39b11d05c07bb9090fd1961b8e1c87aa5643e7b97087cb0c7620356a spawn
```

By running this command, you've activated the spawn system, resulting in the creation of a new entity. This action establishes a local world that you can interact with.
Expand All @@ -339,9 +373,9 @@ Now, go back to your GraphiQL IDE, and you will notice that you have received th
"0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
],
"model_names": "Moves",
"event_id": "0x000000000000000000000000000000000000000000000000000000000000000d:0x0000:0x0000",
"created_at": "2023-10-13 15:08:53",
"updated_at": "2023-10-13 15:08:53"
"event_id": "0x000000000000000000000000000000000000000000000000000000000000000b:0x0000:0x0000",
"created_at": "2023-10-18 06:53:12",
"updated_at": "2023-10-18 06:53:12"
}
}
}
Expand All @@ -354,9 +388,9 @@ Now, go back to your GraphiQL IDE, and you will notice that you have received th
"0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
],
"model_names": "Moves,Position",
"event_id": "0x000000000000000000000000000000000000000000000000000000000000000d:0x0000:0x0001",
"created_at": "2023-10-13 15:08:53",
"updated_at": "2023-10-13 15:08:53"
"event_id": "0x000000000000000000000000000000000000000000000000000000000000000b:0x0000:0x0001",
"created_at": "2023-10-18 06:53:12",
"updated_at": "2023-10-18 06:53:12"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/toolchain/torii/graphql.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ subscription modelRegistered {

Graphql also supports subscription to a targeted entity or model, for this we have to pass its id as an argument

In this example, our serve provides a `entityUpdated` subscription, which should notify clients whenever an entity with id `0x28cd7ee02d7f6ec9810e75b930e8e607793b302445abbdee0ac88143f18da20` is updated. On the same subscription we can get the model(components) values of entityUpdated. A client can execute a subscription that looks like this:
In this example, our server provides a `entityUpdated` subscription, which should notify clients whenever an entity with id `0x28cd7ee02d7f6ec9810e75b930e8e607793b302445abbdee0ac88143f18da20` is updated. On the same subscription we can get the model(components) values of the updated entity . A client can execute a subscription that looks like this:

```graphql
subscription {
Expand Down

0 comments on commit 5d9e832

Please sign in to comment.