World access
Status: Partly implemented (API 1.11). Get and set blocks (mod blocks included), the dimension name, game and day time, the server overworld and the client level; since API 1.11 ray casts (collision, outline and visual shapes, fluids, entities), bulk reads and snapshots, block state properties, block facts, light, sky access and heightmaps, containers and block entity data, and
level.block_changed. Other levels by name, weather, game rules, explosions, scheduled ticks and chunk data are Planned.
Function table: level, registry. Guide: World Access.
Functions
cl_result cl_level_get_block(cl_level level, cl_block_pos pos, cl_block_state* out); // TICK
cl_result cl_level_set_block(cl_level level, cl_block_pos pos, cl_block_state state,
cl_set_block_flags flags); // server, TICK
cl_result cl_level_dimension(cl_level level, char* buf, size_t cap, size_t* out_len); // "minecraft:overworld"
int64_t cl_level_game_time(cl_level level);
int64_t cl_level_day_time(cl_level level);
bool cl_level_is_client(cl_level level);
cl_level cl_server_overworld(void); // the running server's overworld (null if none)
cl_level cl_client_level(void); // the client's level (null when not in a world)
// API 1.11
cl_result cl_level_raycast(cl_level, cl_vec3 from, cl_vec3 to, const cl_raycast_opts*, cl_raycast_hit* out); // both sides
cl_result cl_level_get_blocks(cl_level, cl_block_pos min, cl_block_pos max, cl_block_state* out, size_t cap, size_t* n);
cl_snapshot cl_level_snapshot(cl_level, cl_block_pos min, cl_block_pos max); // owned; read from any thread
cl_result cl_level_light(cl_level, cl_block_pos, cl_light_info* out);
bool cl_level_can_see_sky(cl_level, cl_block_pos);
cl_result cl_level_heightmap(cl_level, int32_t x, int32_t z, cl_heightmap kind, int32_t* out);
cl_result cl_level_set_block_property(cl_level, cl_block_pos, cl_str name, cl_str value, cl_set_block_flags); // server
cl_result cl_level_container_size(cl_level, cl_block_pos, int32_t* out); // server
cl_item_stack cl_level_container_get(cl_level, cl_block_pos, int32_t slot); // server, owned
cl_result cl_level_container_set(cl_level, cl_block_pos, int32_t slot, cl_item_stack); // server
cl_result cl_level_block_entity_type(cl_level, cl_block_pos, char* buf, size_t cap, size_t* n); // server
cl_result cl_level_block_entity_get(cl_level, cl_block_pos, char* buf, size_t cap, size_t* n); // server, SNBT
cl_result cl_level_block_entity_merge(cl_level, cl_block_pos, cl_str snbt); // server
flags: CL_SET_UPDATE_NEIGHBORS (1), CL_SET_UPDATE_CLIENTS (2), CL_SET_ALL (both; vanilla’s setBlock(pos, state, 3)). The other levels (Nether, End) come from events (event.level) and from cl_entity_level(player).
Ray casts
cl_raycast_opts: blocks (CL_RAY_BLOCKS_COLLIDER, OUTLINE, VISUAL, NONE), fluids (CL_RAY_FLUIDS_NONE, SOURCE, ANY, WATER), entities, entity_margin, ignore, source. cl_raycast_hit: type (CL_HIT_MISS, BLOCK, ENTITY), pos, face, block_pos, state, entity, inside, distance. VISUAL is BlockBehaviour#getVisualShape: glass, stained and tinted glass, copper grates, bars, panes and powder snow are empty; mud and soul sand are full blocks; fences and snow layers use their outline. The line is at most 1024 blocks.
Bulk reads and snapshots
The box order is x fastest, then z, then y; at most 2,097,152 blocks (128³). Unloaded positions read CL_BLOCK_UNLOADED. A buffer smaller than the box gets nothing (the count tells the size); WASM reads up to 262,144 states per call. Snapshots: cl_snapshot_get_info, cl_snapshot_get(s, pos), cl_snapshot_copy(s, offset, out, cap, &n), cl_snapshot_retain / cl_snapshot_release.
Light and heightmaps
cl_light_info: block, sky, combined (max(block, sky - sky_darken), Level#getMaxLocalRawBrightness), sky_darken. Heightmaps: CL_HEIGHTMAP_WORLD_SURFACE, OCEAN_FLOOR, MOTION_BLOCKING, MOTION_BLOCKING_NO_LEAVES (Level#getHeight; clients have WORLD_SURFACE and MOTION_BLOCKING).
Containers and block entities
A container is any block container vanilla’s hoppers see (a double chest is 54 slots). container_get returns a copy with every data component; container_set works like Container#setItem. Block entity data is SNBT as /data get block shows it; merge works like /data merge block and sends the update.
Block state properties and block facts (registry, any thread)
cl_result cl_block_state_property(cl_block_state, cl_str name, char* buf, size_t cap, size_t* n); // "true", "north", "3"
cl_result cl_block_state_with(cl_block_state, cl_str name, cl_str value, cl_block_state* out);
cl_result cl_block_state_properties(cl_block_state, char* buf, size_t cap, size_t* n); // "facing,half,..."
cl_result cl_block_state_property_values(cl_block_state, cl_str name, char* buf, size_t cap, size_t* n);
cl_result cl_block_state_to_string(cl_block_state, char* buf, size_t cap, size_t* n); // /setblock syntax
cl_result cl_block_state_parse(cl_str text, cl_block_state* out);
cl_result cl_block_get_info(cl_block_state, cl_block_info* out);
cl_result cl_block_sound_type(cl_block_state, char* buf, size_t cap, size_t* n); // "stone", "wood", ...
cl_result cl_block_sound_event(cl_block_state, cl_block_sound kind, char* buf, size_t cap, size_t* n);
cl_block_info: is_air, is_liquid, solid, occludes, solid_render, collision_full, has_collision, replaceable, requires_tool, has_block_entity, random_ticks, hardness, friction, speed_factor, jump_factor, light_emission, light_dampening, map_color, map_color_rgb, sound_volume, sound_pitch.
Events
| Event | Side | Fields | Filter |
|---|---|---|---|
level.block_changed |
both | level, pos, old_state, new_state, client |
the new state’s block |
On the server it fires at the end of the level’s tick for every change of the tick, in order; on a client right after the client’s copy changed. World generation and chunk loading do not fire it.
Bindings
| C | C++ (clight::Level) |
Lua |
|---|---|---|
cl_level_get_block(l, pos, &s) |
l.get_block(pos) → Expected<cl_block_state> |
l:get_block(pos) |
cl_level_set_block(l, pos, s, CL_SET_ALL) |
l.set_block(pos, state) (flags default to CL_SET_ALL), l.set_block(pos, "minecraft:stone") |
l:set_block(pos, "minecraft:stone"), l:set_block(pos, "minecraft:oak_stairs[facing=east]") (flags default to "all") |
cl_easy_set_block(l, pos, "minecraft:stone") (C, clight_easy.h) |
||
cl_level_dimension(l, ...) |
l.dimension() → Expected<std::string> |
l:dimension() |
cl_level_game_time(l) |
l.game_time() |
l:game_time() |
cl_server_overworld() |
clight::level::server_overworld() |
cl.level.server_overworld() |
cl_level_raycast(l, a, b, &o, &hit) |
l.raycast(a, b, &o) → Expected<cl_raycast_hit> |
l:raycast(a, b, { blocks = "visual", entities = true }) → { type, pos, ... } |
cl_level_get_blocks(l, lo, hi, buf, cap, &n) |
l.get_blocks(lo, hi) → Expected<std::vector<cl_block_state>> |
l:get_blocks(lo, hi) → a list |
cl_level_snapshot(l, lo, hi) |
l.snapshot(lo, hi) → clight::Snapshot (RAII) |
l:snapshot(lo, hi) → s:get(pos), s:info(), s:copy(offset) |
cl_level_light(l, pos, &li) |
l.light(pos) |
l:light(pos) |
cl_level_heightmap(l, x, z, kind, &y) |
l.heightmap(x, z, kind) |
l:heightmap(x, z, kind?) ("motion_blocking"; nil when not loaded) |
cl_level_set_block_property(l, pos, n, v, f) |
l.set_block_property(pos, n, v, f) |
l:set_block_property(pos, "open", true), l:get_block_property(pos, "open") |
cl_level_container_* |
l.container_size(pos) / container_get / container_set |
l:container(pos) → { size, get(slot), set(slot, stack), items() } or nil |
cl_level_block_entity_* |
l.block_entity_get(pos) / block_entity_merge |
l:block_entity(pos) (nil without), l:block_entity_type(pos), l:block_entity_merge(pos, snbt) |
cl_block_state_property(s, n, ...) |
cl.registry.state_property(s, "open") → true / false / number / string / nil |
|
cl_block_state_with(s, n, v, &o) |
cl.registry.state_with(s, "age", 7) |
|
cl_block_get_info(s, &i) + cl_block_sound_type |
cl.registry.block_info(s) (with sound_type) |
Example
-- a pillar of gold where a player breaks a diamond ore
cl.on("block.break", function(event)
if event.block ~= "minecraft:diamond_ore" then return end
for i = 1, 3 do
event.world:set_block(event.pos:above(i), "minecraft:gold_block")
end
end)
-- footsteps by material
local hit = world:raycast(player.pos, player.pos + cl.vec(0, -1.5, 0))
if hit.type == "block" and cl.registry.block_info(hit.state).sound_type == "wood" then play_creak() end
Planned
Levels by dimension id and the level list, world height and seed, weather and time changes, game rules, difficulty, block destruction with drops, scheduled block ticks, explosions, chunk access and per-chunk data.