Contracts
Rules of thumb
- Note that every field you add in a model will raise the storage cost of each transaction that modifies the model.
- Try to make models as small as possible, and re-use existing models as much as possible, every model and system that you add raises the size of the CASM, and there is a limit to the size of a declared contract on Starknet.
- Keep systems stateless. Store your game state in models.
- When implementing a new game logic, you will need to keep in mind that the game already has physics implemented, such as weight, position, movement, speed, etc. If creating something that needs to have any of this logic, re-use components so everything stays logical.
Models
Keys
Use the ID
type alias for keys that require a unique identifier.
Model design
entity_id: u32
Implementations
Where possible make traits for the models so they are stateless for unit testing.
Always use generate trait where possible to minimise code.
#[generate_trait]
Adding a model
#[derive(Copy, Drop, Serde)]
#[dojo::model]
pub struct Structure {
#[key]
entity_id: ID,
category: StructureCategory,
created_at: u64
}
To test this model, you need to add it to the contracts/src/utils/testing/world.cairo
file so it can be instantiated
in the tests.
Event models
If you need some data to be available in the client, but it doesn't need to be stored onchain, you can use an event model.
#[derive(Introspect, Copy, Drop, Serde)]
#[dojo::event]
#[dojo::model]
pub struct ExampleEvent {
#[key]
id: ID,
#[key]
event_id: EventType,
my_data_field: u8
}
Adding a system
Design systems like this in the directory
- SystemName
- system_name.cairo
- tests.cairo
system.cairo
should include the implementation of the system like this.
Things to note:
- Interface at top of File
- use of
super::IBuildingContract
to minimise imports and make it clear where the interface is defined.
#[dojo::interface]
trait IBuildingContract<TContractState> {
fn create(
entity_id: ID,
building_coord: s0_eternum::models::position::Coord,
building_category: s0_eternum::models::buildings::BuildingCategory,
produce_resource_type: Option<u8>
);
}
#[dojo::contract]
mod building_systems {
use s0_eternum::alias::ID;
use s0_eternum::models::{
resources::{Resource, ResourceCost}, owner::Owner, hyperstructure::HyperStructure,
order::Orders, position::{Coord, Position, PositionTrait, Direction},
buildings::{BuildingCategory, Building, BuildingImpl},
production::{Production, ProductionRateTrait}, realm::{Realm, RealmImpl}
};
#[abi(embed_v0)]
impl BuildingContractImpl of super::IBuildingContract<ContractState> {
fn create(
world: IWorldDispatcher,
entity_id: ID,
building_coord: Coord,
building_category: BuildingCategory,
produce_resource_type: Option<u8>,
) {
}
}
}
To test this system, you need to add it to the contracts/src/utils/testing/world.cairo
file so it can be instantiated
in the tests.