-
Notifications
You must be signed in to change notification settings - Fork 176
/
actions.cairo
150 lines (124 loc) · 4.79 KB
/
actions.cairo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use dojo_examples::models::{Direction, Position, Vec2};
#[dojo::interface]
trait IActions {
fn spawn(ref world: IWorldDispatcher);
fn move(ref world: IWorldDispatcher, direction: Direction);
fn set_player_config(ref world: IWorldDispatcher, name: ByteArray);
fn get_player_position(world: @IWorldDispatcher) -> Position;
}
#[dojo::interface]
trait IActionsComputed {
fn tile_terrain(vec: Vec2) -> felt252;
fn quadrant(pos: Position) -> u8;
}
#[dojo::contract]
mod actions {
use super::IActions;
use super::IActionsComputed;
use starknet::{ContractAddress, get_caller_address};
use dojo_examples::models::{Position, Moves, Direction, Vec2, PlayerConfig, PlayerItem};
use dojo_examples::utils::next_position;
#[derive(Copy, Drop, Serde)]
#[dojo::event]
#[dojo::model]
struct Moved {
#[key]
player: ContractAddress,
direction: Direction,
}
#[abi(embed_v0)]
impl ActionsComputedImpl of IActionsComputed<ContractState> {
#[computed]
fn tile_terrain(vec: Vec2) -> felt252 {
'land'
}
#[computed(Position)]
fn quadrant(pos: Position) -> u8 {
// 10 is zero
if pos.vec.x < 10 {
if pos.vec.y < 10 {
3 // Quadrant - -
} else {
4 // Quadrant - +
}
} else {
if pos.vec.y < 10 {
2 // Quadrant + -
} else {
1 // Quadrant + +
}
}
}
}
// impl: implement functions specified in trait
#[abi(embed_v0)]
impl ActionsImpl of IActions<ContractState> {
// ContractState is defined by system decorator expansion
fn spawn(ref world: IWorldDispatcher) {
let player = get_caller_address();
let position = get!(world, player, (Position));
set!(
world,
(
Moves { player, remaining: 99, last_direction: Direction::None(()) },
Position {
player, vec: Vec2 { x: position.vec.x + 10, y: position.vec.y + 10 }
},
)
);
}
fn move(ref 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, (Moved { player, direction }));
}
fn set_player_config(ref world: IWorldDispatcher, name: ByteArray) {
let player = get_caller_address();
let items = array![
PlayerItem { item_id: 1, quantity: 100 }, PlayerItem { item_id: 2, quantity: 50 }
];
let config = PlayerConfig { player, name, items, favorite_item: Option::Some(1), };
set!(world, (config));
}
fn get_player_position(world: @IWorldDispatcher) -> Position {
let player = get_caller_address();
get!(world, player, (Position))
}
}
}
#[cfg(test)]
mod tests {
use starknet::class_hash::Felt252TryIntoClassHash;
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};
use dojo::test_utils::{spawn_test_world, deploy_contract};
use super::{actions, IActionsDispatcher, IActionsDispatcherTrait};
use dojo_examples::models::{Position, position, Moves, moves, Direction, Vec2};
#[test]
#[available_gas(30000000)]
fn test_move() {
let caller = starknet::contract_address_const::<0x0>();
// models
let mut models = array![position::TEST_CLASS_HASH, moves::TEST_CLASS_HASH,];
// deploy world with models
let world = spawn_test_world(models);
// deploy systems contract
let contract_address = world
.deploy_contract('salt', actions::TEST_CLASS_HASH.try_into().unwrap(), array![].span());
let actions_system = IActionsDispatcher { contract_address };
// System calls
actions_system.spawn();
let initial_moves = get!(world, caller, Moves);
actions_system.move(Direction::Right(()));
let moves = get!(world, caller, Moves);
let right_dir_felt: felt252 = Direction::Right(()).into();
assert(moves.remaining == initial_moves.remaining - 1, 'moves is wrong');
assert(moves.last_direction.into() == right_dir_felt, 'last direction is wrong');
let new_position = get!(world, caller, Position);
assert(new_position.vec.x == 11, 'position x is wrong');
assert(new_position.vec.y == 10, 'position y is wrong');
}
}