Skip to content

Commit

Permalink
feat: init with dojo starter
Browse files Browse the repository at this point in the history
  • Loading branch information
noyyyy committed Nov 22, 2023
1 parent dada8bb commit c1be055
Show file tree
Hide file tree
Showing 13 changed files with 398 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .github/mark-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions .github/mark-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: CI

on:
push:
pull_request:

jobs:
sozo-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: curl -L https://install.dojoengine.org | bash
- run: /home/runner/.config/.dojo/bin/dojoup -v v0.3.2
- run: |
/home/runner/.config/.dojo/bin/sozo build
/home/runner/.config/.dojo/bin/sozo test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cairo1.languageServerPath": "$HOME/.dojo/bin/dojo-language-server",
"cairo1.enableLanguageServer": true,
"cairo1.enableScarb": true
}
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<picture>
<source media="(prefers-color-scheme: dark)" srcset=".github/mark-dark.svg">
<img alt="Dojo logo" align="right" width="120" src=".github/mark-light.svg">
</picture>

<a href="https://twitter.com/dojostarknet">
<img src="https://img.shields.io/twitter/follow/dojostarknet?style=social"/>
</a>
<a href="https://github.com/dojoengine/dojo">
<img src="https://img.shields.io/github/stars/dojoengine/dojo?style=social"/>
</a>

[![discord](https://img.shields.io/badge/join-dojo-green?logo=discord&logoColor=white)](https://discord.gg/PwDa2mKhR4)
[![Telegram Chat][tg-badge]][tg-url]

[tg-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fdojoengine
[tg-url]: https://t.me/dojoengine

# Dojo Starter: Official Guide

The official Dojo Starter guide, the quickest and most streamlined way to get your Dojo Autonomous World up and running. This guide will assist you with the initial setup, from cloning the repository to deploying your world.

Read the full tutorial [here](https://book.dojoengine.org/cairo/hello-dojo.html)

---

## Contribution

This starter project is a constant work in progress and contributions are greatly appreciated!

1. **Report a Bug**

- If you think you have encountered a bug, and we should know about it, feel free to report it [here](https://github.com/dojoengine/dojo-starter/issues) and we will take care of it.

2. **Request a Feature**

- You can also request for a feature [here](https://github.com/dojoengine/dojo-starter/issues), and if it's viable, it will be picked for development.

3. **Create a Pull Request**
- It can't get better then this, your pull request will be appreciated by the community.

For any other questions, feel free to reach out to us [here](https://dojoengine.org/contact).

Happy coding!
22 changes: 22 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "dojo"
version = "0.3.12"
source = "git+https://github.com/dojoengine/dojo#b3f49977fe921564725c30b912126aea57859bbd"
dependencies = [
"dojo_plugin",
]

[[package]]
name = "dojo_examples"
version = "0.3.12"
dependencies = [
"dojo",
]

[[package]]
name = "dojo_plugin"
version = "0.3.12"
source = "git+https://github.com/dojoengine/dojo?tag=v0.3.12#12d58f29ec53454317f1f6d265007a053d279288"
21 changes: 21 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
cairo-version = "2.3.0"
name = "dojo_examples"
version = "0.3.12"

[cairo]
sierra-replace-ids = true

[dependencies]
dojo = { git = "https://github.com/dojoengine/dojo", version = "0.3.12" }

[[target.dojo]]

[tool.dojo]
initializer_class_hash = "0xbeef"

[tool.dojo.env]
rpc_url = "http://localhost:5050/"
# Default account for katana with seed = 0
account_address = "0x517ececd29116499f4a1b64b094da79ba08dfd54a3edaa316134c41f8160973"
private_key = "0x1800000000300000180000000000030000000000003006001800006600"
24 changes: 24 additions & 0 deletions scripts/default_auth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash
set -euo pipefail
pushd $(dirname "$0")/..

export RPC_URL="http://localhost:5050";

export WORLD_ADDRESS=$(cat ./target/dev/manifest.json | jq -r '.world.address')

export ACTIONS_ADDRESS=$(cat ./target/dev/manifest.json | jq -r '.contracts[] | select(.name == "actions" ).address')

echo "---------------------------------------------------------------------------"
echo world : $WORLD_ADDRESS
echo " "
echo actions : $ACTIONS_ADDRESS
echo "---------------------------------------------------------------------------"

# enable system -> component authorizations
COMPONENTS=("Position" "Moves" )

for component in ${COMPONENTS[@]}; do
sozo auth writer $component $ACTIONS_ADDRESS --world $WORLD_ADDRESS --rpc-url $RPC_URL
done

echo "Default authorizations have been successfully set."
151 changes: 151 additions & 0 deletions src/actions.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use dojo_examples::models::{Direction};

// define the interface
#[starknet::interface]
trait IActions<TContractState> {
fn spawn(self: @TContractState);
fn move(self: @TContractState, direction: Direction);
}

// dojo decorator
#[dojo::contract]
mod actions {
use starknet::{ContractAddress, get_caller_address};
use dojo_examples::models::{Position, Moves, Direction, Vec2};
use dojo_examples::utils::next_position;
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,
direction: Direction
}

// impl: implement functions specified in trait
#[external(v0)]
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. Set players moves to 10
// 2. Move the player's position 100 units in both the x and y direction.
set!(
world,
(
Moves { player, remaining: 100, last_direction: Direction::None(()) },
Position { player, vec: Vec2 { x: 10, 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 });
}
}
}

#[cfg(test)]
mod tests {
use starknet::class_hash::Felt252TryIntoClassHash;

// import world dispatcher
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

// import test utils
use dojo::test_utils::{spawn_test_world, deploy_contract};

// import models
use dojo_examples::models::{position, moves};
use dojo_examples::models::{Position, Moves, Direction, Vec2};

// import actions
use super::{actions, IActionsDispatcher, IActionsDispatcherTrait};

#[test]
#[available_gas(30000000)]
fn test_move() {
// caller
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());
let actions_system = IActionsDispatcher { contract_address };

// call spawn()
actions_system.spawn();

// call move with direction right
actions_system.move(Direction::Right(()));

// Check world state
let moves = get!(world, caller, Moves);

// casting right direction
let right_dir_felt: felt252 = Direction::Right(()).into();

// check moves
assert(moves.remaining == 99, 'moves is wrong');

// check last direction
assert(moves.last_direction.into() == right_dir_felt, 'last direction is wrong');

// get new_position
let new_position = get!(world, caller, Position);

// check new position x
assert(new_position.vec.x == 11, 'position x is wrong');

// check new position y
assert(new_position.vec.y == 10, 'position y is wrong');
}
}
4 changes: 4 additions & 0 deletions src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod actions;
mod models;
mod utils;

79 changes: 79 additions & 0 deletions src/models.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use starknet::ContractAddress;

#[derive(Serde, Copy, Drop, Introspect)]
enum Direction {
None: (),
Left: (),
Right: (),
Up: (),
Down: (),
}

impl DirectionIntoFelt252 of Into<Direction, felt252> {
fn into(self: Direction) -> felt252 {
match self {
Direction::None(()) => 0,
Direction::Left(()) => 1,
Direction::Right(()) => 2,
Direction::Up(()) => 3,
Direction::Down(()) => 4,
}
}
}

#[derive(Model, Drop, Serde)]
struct Moves {
#[key]
player: ContractAddress,
remaining: u8,
last_direction: Direction
}

#[derive(Copy, Drop, Serde, Introspect)]
struct Vec2 {
x: u32,
y: u32
}

#[derive(Model, Copy, Drop, Serde)]
struct Position {
#[key]
player: ContractAddress,
vec: Vec2,
}

trait Vec2Trait {
fn is_zero(self: Vec2) -> bool;
fn is_equal(self: Vec2, b: Vec2) -> bool;
}

impl Vec2Impl of Vec2Trait {
fn is_zero(self: Vec2) -> bool {
if self.x - self.y == 0 {
return true;
}
false
}

fn is_equal(self: Vec2, b: Vec2) -> bool {
self.x == b.x && self.y == b.y
}
}

#[cfg(test)]
mod tests {
use super::{Position, Vec2, Vec2Trait};

#[test]
#[available_gas(100000)]
fn test_vec_is_zero() {
assert(Vec2Trait::is_zero(Vec2 { x: 0, y: 0 }), 'not zero');
}

#[test]
#[available_gas(100000)]
fn test_vec_is_equal() {
let position = Vec2 { x: 420, y: 0 };
assert(position.is_equal(Vec2 { x: 420, y: 0 }), 'not equal');
}
}
Loading

0 comments on commit c1be055

Please sign in to comment.