Systems
TL;DRSystems = Functions in a Dojo contract
- Systems are Dojo contract functions.
- Systems can access to the world using the
self.world(<NAMESPACE>)
function. - Systems engage the world contract to alter models' state.
- Systems ought to be concise and specific.
- In most scenarios, systems are stateless.
What are systems?
Within Dojo we define systems as functions within a Dojo contract that act on the world.
Systems play a pivotal role in your world's logic, directly mutating its component states. It's important to understand that to enact these mutations, a system needs explicit permission from the models
owner.
Permissions
In order to write data to the world, a system needs explicit permission from the models
owner.
A simple way to think about system design for permissions:
Dojo interface
In a Dojo contract, you must first define a Dojo interface to declare the systems that your contract will expose.
#[starknet::interface]
trait IActions<T> {
fn spawn(ref self: T);
fn move(ref self: T, direction: Direction);
}
System implementation
To implement the code related to the system, you must be placed inside a #[dojo::contract]
and implement the interface you've defined.
#[dojo::contract]
mod actions {
use super::IActions;
use dojo::model::{ModelStorage, ModelValueStorage};
#[abi(embed_v0)]
impl ActionsImpl of IActions<ContractState> {
fn spawn(ref self: ContractState) {
// Get the default world.
let mut world = self.world(@"dojo_starter");
// 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 mut position: Position = world.read_model(player);
// Update the world state with the new data.
// 1. Move the player's position 10 units in both
// the x and y direction.
let new_position = Position {
player,
vec: Vec2 {
x: position.vec.x + 10,
y: position.vec.y + 10
}
};
// Write the new position to the world.
world.write_model(@new_position);
// 2. Set the player's remaining moves to 100.
let moves = Moves {
player, remaining: 100,
last_direction: Direction::None, can_move: true
};
// Write the new moves to the world.
world.write_model(@moves);
}
fn move(ref self: ContractState, direction: Direction) {
// Get the default world.
let mut world = self.world(@"dojo_starter");
// 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: Position = world.read_model(player);
let mut moves: Moves = world.read_model(player);
// 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);
// Write the new position to the world.
world.write_model(@next);
// Write the new moves to the world.
world.write_model(@moves);
// Emit an event to the world to notify about
// the player's move.
world.emit_event(@Moved { player, direction });
}
}
}
Inside the system's implementation, you can use the Dojo api to easily interact with the world.