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.