Skip to main content

World and platform data

A hub or spoke reads and writes the platform's own data through the node API. This covers the world's chunks and voxels, who is standing where, grids and their permissions, and players' tier features, group permissions and app state. Every operation works inside the instance's own app.

Scopes​

A node type asks for what it needs in the manifest. Its instances can use only those scopes.

"arena": {
"kind": "hub",
"parent": "lobby",
"digest": "…",
"scopes": ["world.read", "world.write", "grids.read"]
}
ScopeWhat it allows
players.readA player's identity (players in the app now), tier features, group membership and permissions, and app state; an avatar's app state.
players.writeReplacing a player's app state (players with access to the app).
world.readChunks, the voxels written into them, and the actors in or near a chunk.
world.writeWriting voxels.
grids.readGrids by id or by the chunk they cover, and whether a player holds a grid permission.
permissions.writeGranting and revoking grid permissions.

A type that declares no scopes can use none of them. A deploy naming any other scope is refused. Scope changes take effect as instances start again.

From Rust​

The ckx-sdk crate wraps each operation:

use ckx_sdk::prelude::*;

fn plant(ctx: &Ctx, at: ChunkPos, player: u64) -> Result<()> {
// Only where the player may build: the most specific grid over the chunk decides.
let grid = ctx.grids().at(at, GridPick::Smallest)?.ok_or_else(|| Error::new("no grid here"))?;
if !ctx.grids().check_permission(grid.id, player, "update_voxel_data")? {
return Err(Error::new("not your land"));
}
ctx.world().set_voxels(&[VoxelWrite { chunk: at, voxel: (3, 12, 7), voxel_type: 54, state: None }])?;
Ok(())
}
CallScopeReturns
ctx.world().chunk(at)world.readThe chunk's dense voxel grid and metadata blob, or None.
ctx.world().voxels(at)world.readVoxels written into the chunk, up to 2,048.
ctx.world().set_voxels(&writes)world.writeUp to 16 voxels in one transaction, written as the app and shown to nearby players. Each voxel is 0-15 on each axis of its chunk, each voxel_type 0-255, and each voxel's state at most 1 KiB; a batch with anything else is refused whole.
ctx.world().actors(at)world.readActors in a chunk, from live presence (up to 200).
ctx.world().actors_near(at, xz, y)world.readActors within xz chunks across (at most 3) and y up and down (at most 1), up to 500.
ctx.grids().get(id)grids.readOne of the app's grids, with its low and high chunk; Grid::contains(at) tests a chunk.
ctx.grids().at(at, pick)grids.readThe grid covering a chunk. Where grids nest, Smallest is the most specific one (the smallest box; of equal boxes, the lowest id), the grid that decides voxel writes there; First is the lowest id and Largest the biggest box.
ctx.grids().check_permission(grid, player, key)grids.readWhether the player holds the key on the grid, directly or through a group, unexpired.
ctx.players().get(player)players.readGamertag and disambiguation, for players in the app now.
ctx.players().features(player)players.readThe feature keys the player's access tier grants.
ctx.players().check_permission(player, group, key)players.readMembership of one of the app's groups (teams, channels), or a permission within it.
ctx.players().state(player) / set_state(player, bytes)players.read / players.writeThe player's app state, the same blob game clients read with CrowdyJS client.state (up to 256 KiB).
ctx.players().avatar_state(avatar)players.readAn avatar's app state.
ctx.permissions().grant(grid, player, &keys, ttl)permissions.writeGrants runtime permission keys on one of the app's grids to a player with access to the app, until revoked or for ttl seconds.
ctx.permissions().revoke(grid, player, keys)permissions.writeRevokes the named keys, or all of them.

Permission keys come from the platform's runtime permission catalog, such as update_voxel_data, teleport or access.

Errors and limits​

A refused operation returns a CallError whose status says why:

StatusWhy
DeniedThe type did not declare the scope.
NotFoundNo such player in the app (or none with access, for writes and grants), or no such grid in the app.
AppErrorBad input: an out-of-range coordinate or voxel type, too many writes, an unknown permission key. The message says which.
RateLimitedThe app sent more than the platform allows. Reads and writes are counted separately, and each voxel in a batch counts as one write. Retry with backoff.

ctx.node(op, json) sends an operation with a JSON body directly, for anything the typed calls do not cover.

Coming from the legacy APIs​

Legacyck-exec
Compute chunk_get, voxels_list, voxel_set, actors_list, actors_list_radiusctx.world()
grid_permission_check, and the expression builtins grid_at, grid_contains, grid_min, grid_max, has_grid_permission, has_chunk_permissionctx.grids()
Authority rules tier_feature and group_permissionctx.players().features and check_permission, checked in handler code
Permission effects (grant and revoke as a function side effect)ctx.permissions()
user_state_get / user_state_set, avatar_state_getctx.players().state, set_state and avatar_state
grid_state_get / grid_state_setA hub keyed by the grid holds that state

Next: realtime events.