Skip to content

Embeddable Game Standard: Implementation

This guide walks through the steps required for a game developer to implement the Embeddable Game Standard and integrate with Budokan tournaments as well as any other meta apps.

1. Add EGS library

Start by adding the EGS library in your Scarb.toml. You will also need to build the external models to be included

tournaments = { git = "https://github.com/Provable-Games/tournaments.git", tag = "v1.5.0" }
build-external-contracts = [
    "tournaments::components::models::game::m_GameMetadata",
    "tournaments::components::models::game::m_TokenMetadata",
    "tournaments::components::models::game::m_GameCounter",
    "tournaments::components::models::game::m_Score",
    "tournaments::components::models::game::m_Settings",
    "tournaments::components::models::game::m_SettingsDetails",
    "tournaments::components::models::game::m_SettingsCounter",
]

2. Import Component

Import and use the game_component module from EGS.

use tournaments::components::game::game_component;
 
#[dojo::contract]
pub mod MyGame {
    component!(path: game_component, storage: game, event: GameEvent);
    #[abi(embed_v0)]
    impl GameComponentImpl = game_component::GameImpl<ContractState>;
    impl GameComponentInternalImpl = game_component::InternalImpl<ContractState>;
    // ... additional game logic ...
}

3. Implement Required Storage and Events

Define the required storage fields and events as specified in the standard.

#[storage]
struct Storage {
    #[substorage(v0)]
    game: game_component::Storage,
    #[substorage(v0)]
    erc721: ERC721Component::Storage,
    #[substorage(v0)]
    src5: SRC5Component::Storage,
}
 
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
    #[flat]
    GameEvent: game_component::Event,
    #[flat]
    ERC721Event: ERC721Component::Event,
    #[flat]
    SRC5Event: SRC5Component::Event,
}

4. Expose Required Interfaces

Ensure your contract exposes the following:

  • ERC721 interface for game tokens
  • Metadata and settings interfaces
  • Functions for minting, metadata retrieval, and event emission

5. Implement Initialization Logic

Implement the initializer function to set up game metadata, settings, and storage configuration.

fn initializer(
    ref self: ComponentState<TContractState>,
    creator_address: ContractAddress,
    name: felt252,
    description: ByteArray,
    developer: felt252,
    publisher: felt252,
    genre: felt252,
    image: ByteArray,
    namespace: ByteArray,
    score_model: ByteArray,
    score_attribute: ByteArray,
    settings_model: ByteArray,
) {
    // ... initialization logic ...
}

6. Add View Functions

Add Contract view function to return the following:

  • The score of a game id
  • Whether a particular settings id exists
use tournaments::components::interfaces::{IGameDetails, ISettings};
 
#[abi(embed_v0)]
impl GameDetailsImpl of IGameDetails<ContractState> {
    fn score(self: @ContractState, game_id: u64) -> u32 {
        let world: WorldStorage = self.world(@DEFAULT_NS());
        let game: Game = world.read_model(game_id);
        game.score.into()
    }
}
 
#[abi(embed_v0)]
impl SettingsImpl of ISettings<ContractState> {
    fn setting_exists(self: @ContractState, settings_id: u32) -> bool {
        let world: WorldStorage = self.world(@DEFAULT_NS());
        let settings: GameSettings = world.read_model(settings_id);
        settings.exists()
    }
}

7. Check Lifecycle

In each game interaction ensure that the following lifecycle check is made

use tournaments::components::libs::lifecycle::{
    LifecycleAssertionsImpl, LifecycleAssertionsTrait
};
 
let token_metadata: TokenMetadata = world.read_model(game_id);
token_metadata.lifecycle.assert_is_playable(game_id, get_block_timestamp());

By following these steps, your game will be fully compatible with Budokan and any other application using the Embeddable Game Standard.