Server World API

Reading and placing blocks from server-side Lua, and the per-block interact and update hooks.

Weather hooks and block hooks receive a world object representing the world they run in. It lets scripts inspect and change blocks; every change is saved and broadcast to clients automatically.

All coordinates are block coordinates (integers). layer selects the block layer: 0 = background walls, 1 = foreground (the colliding layer), 2+ = overlay (fluids, effects).


Fields

FieldTypeDescription
world_namestringThe world’s name (read-only).

Reading Blocks

get_block_at(x, y, layer)

Returns a block table describing the block at that position, or an empty table if there is no block there — check for id before using the result:

local block = world:get_block_at(x, y, 1)
if block.id ~= nil then
    log_info("found " .. block.name)
end

Block table keys:

KeyTypeDescription
namestringThe block’s registered name.
idnumberThe block’s numeric ID.
facingstring"Up", "Down", "Left", or "Right".
statenumberThe block’s state value (drives state-based block textures).
biome_idnumberID of the biome this block belongs to.
block_light_levelnumberLight emitted/held from block light sources (0–255).
sky_light_levelnumberLight from the sky (0–255).
fluid_levelnumberFluid fill amount for fluid blocks.
is_surface_blockbooleanWhether this is the top-of-world surface block in its column.
block_matter_typestringThe block’s matter type (solid, liquid, …).
block_shapetable{ type = "Full" }, or { type = "Slab", divisions = n, side = "...", count = n } for partial blocks.

Placing Blocks

set_block_at_from_name(x, y, block_name)

Places a fresh block by name (e.g. "STONE"). This is the simplest and usually best way to place blocks. The layer is determined by the block type itself; the biome is inherited from the block previously at that position. Raises an error if the name is unknown.

set_block_at_from_block_id(x, y, block_id)

Same as above, but takes a numeric block ID — useful together with get_block_variation (see lua-server-globals.md).

set_block_at(x, y, block_table)

Places a fully specified block. Use this only when you need control over facing, state, fluid level, or shape — otherwise prefer the two functions above.

Required keys: id, facing, biome_id, block_light_level, sky_light_level, fluid_level, state, collidable (boolean), and block_shape.

Note: a table returned by get_block_at cannot be passed straight back into set_block_at — it lacks the required collidable key. Copy the fields you want and add collidable yourself:

local old = world:get_block_at(x, y, 1)
if old.id ~= nil then
    world:set_block_at(x, y, {
        id = old.id,
        facing = "Left",                 -- the change we wanted
        biome_id = old.biome_id,
        block_light_level = old.block_light_level,
        sky_light_level = old.sky_light_level,
        fluid_level = old.fluid_level,
        state = old.state,
        collidable = true,
        block_shape = old.block_shape,
    })
end

Block Hooks

Blocks can run server-side Lua of their own. Both hooks are declared per block entry in your block-config.md file and receive the world object as their first argument.

blocks:
  - name: ritual_stone
    # ...
    scripts:
      server-on-interact: /blocks/ritual_stone_interact.lua
      server-update: /blocks/ritual_stone_update.lua
    interact-cooldown-ms: 500            # optional, default 0

Each value is a bare path to a .lua file that returns its handler function.

scripts: keyWhen CalledSignature
server-on-interactA player interacts with a block of this typefunction(world, x, y, layer, player_entity_id)
server-updateEvery server tick, for each placed block of this typefunction(world, x, y, layer, delta_ns)
  • interact-cooldown-ms sets the minimum time between interactions on a single block cell (0 = no cooldown).
  • Update hooks only run for blocks of types that declare one, so ordinary blocks cost nothing. A block type with an update hook ticks for every placed block of that type in loaded chunks — keep the handler light, and use block state plus early returns to skip idle blocks.
  • delta_ns is the tick delta in nanoseconds (delta_ns * 1e-9 = seconds).
-- Turns the block into stone when a player interacts with it.
return function(world, x, y, layer, player_entity_id)
    world:set_block_at_from_name(x, y, "STONE")
end

See Also