Schemas Config & schemagen
Tool
The schemagen
CLI tool generates libraries for Schemas. It makes it much less error-prone than using the Schemas low-level API, and comes with typed Move APIs when setting and retrieving records.
Using schemagen
with the Dubhe framework
If you are using the Dubhe framework and have a dubhe.config.ts
file in your project, you can edit your Schemas config directly in this file!
A Schemas config should be named dubhe.config.ts
, and placed at the root of your project.
This is the minimal config:
import { defineConfig } from '@0xobelisk/sui-common';
export const dubheConfig = defineConfig({
name: 'example',
description: 'example',
enums: {},
components: {},
resources: {},
errors: {}
});
Generating the schemas
To generate the schemas, run pnpm dubhe schemagen
in the same folder as the config file.
If you are developing a game contract, we recommend using the ECS architecture, which can be easily implemented with components and resources. You can use components to define components for any entity. Regardless of what data the component is, an address entity key type will be generated by default in the contract. For example:
import { defineConfig } from '@0xobelisk/sui-common';
export const dubheConfig = defineConfig({
name: 'example',
description: 'example',
enums: {},
components: {
player: {},
level: 'u32',
monster: {
fields: {
attack: 'u32',
hp: 'u32'
}
}
},
resources: {}
});
The player component will generate a global array, where you can add any entity key to determine if this entity can move. The level component will generate a global key-value data type, allowing you to insert level data for each entity. The monster component will generate a key-multiple-value data type, allowing you to insert multiple data for an entity, such as the monster’s attack and health.
palyer::set(dapp_hub, entity_key1);
palyer::set(dapp_hub, entity_key2);
level::set(dapp_hub, entity_key1, 100);
level::set(dapp_hub, entity_key2, 101);
monster::set(dapp_hub, entity_key1, 100, 10000);
monster::set(dapp_hub, entity_key2, 200, 10000);
Combined with the Dubhe client SDK, you can easily query the corresponding data, such as querying all component data for entity_key1, or specific component data for entity_key1.
In addition to component data types, you may also use resources for global data that is not related to a single entity. You can use this to store data such as map data and leaderboard data.
import { defineConfig } from '@0xobelisk/sui-common';
export const dubheConfig = defineConfig({
name: 'example',
description: 'example',
enums: {},
components: {
player: {},
level: "u32",
monster: {
fields: {
attack: 'u32',
hp: 'u32'
}
},
},
resources: {
switch: 'bool'
maps: {
fields: {
map_id: 'u32',
data: 'vector<u8>',
height: 'u32',
width: 'u32'
},
key: ['map_id']
},
}
})
switch::set(true);
maps::set(dapp_hub, map_id, data, height, width);
If you don’t want to store data but just want to implement notifications for game process results, you can use the offchain field. This makes it easy to implement something similar to events in native contracts.
import { defineConfig } from '@0xobelisk/sui-common';
export const dubheConfig = defineConfig({
name: 'example',
description: 'example',
enums: {},
components: {
player: {},
level: "u32",
monster: {
fields: {
attack: 'u32',
hp: 'u32'
}
},
},
resources: {
switch: 'bool'
maps: {
fields: {
map_id: 'u32',
data: 'vector<u8>',
height: 'u32',
width: 'u32'
},
key: ['map_id']
},
capture_results: {
fields: {
monster: 'address',
result: 'bool'
},
offchain: true
}
}
})
capture_results::set(dapp_hub, monster, result)
You can also customize errors. Just make sure the condition is true to pass, otherwise an error will be thrown.
import { defineConfig } from '@0xobelisk/sui-common';
export const dubheConfig = defineConfig({
name: 'example',
description: 'example',
errors: {
monster_not_found: 'Monster not found',
game_not_start: "The game hasn't started yet"
}
});
monster_not_found_error(condition);
game_not_start_error(condition);