Blocks API
Mods register new block types and read existing ones through the blocks library.
Constants: render mode
Defines a block rendering step.
| Name | Description |
|---|---|
blocks.RENDER_NONE | Block is not rendered (eg. air) |
blocks.RENDER_SOLID | Block is rendered as opaque, cullable geometry |
blocks.RENDER_ALPHA | Block is rendered as translucent geometry |
Constants: block face
Defines a block face used for culling and other grid-aligned operations.
| Name | Description |
|---|---|
blocks.FACE_NORTH | North face |
blocks.FACE_SOUTH | South face |
blocks.FACE_EAST | East face |
blocks.FACE_WEST | West face |
blocks.FACE_TOP | Top or upper face |
blocks.FACE_BOTTOM | Bottom or lower face |
blocks.FACE_UP | Same as blocks.FACE_TOP |
blocks.FACE_DOWN | Same as blocks.FACE_BOTTOM |
Constants: tool conditionals
Defines a tool category used for block interactions.
| Name | Description |
|---|---|
blocks.TOOL_NONE | Bare hands |
blocks.TOOL_BLADE | A bladed tool (eg. sword, knife) |
blocks.TOOL_XBLADE | A multi-bladed tool (eg. scissors) |
blocks.TOOL_AXE | Axe-like tool |
blocks.TOOL_HOE | Hoe-like tool |
blocks.TOOL_SHOVEL | Shovel-like tool |
blocks.TOOL_HAMMER | Hammer-like tool |
blocks.TOOL_PICK | Pickaxe-like tool |
Constants: touch responses
Defines a touch response for a block.
| Name | Description |
|---|---|
blocks.TOUCH_NONE | Block is not collidable |
blocks.TOUCH_SOLID | Movement stops in the touch direction |
blocks.TOUCH_BOUNCE | The block reflects movement with some attenuation. This is reserved for future use (e.g. slime-like blocks). No builtin block uses it yet |
blocks.TOUCH_THROUGH | The block attenuates movement but does not change its direction. This is reserved for future use (e.g. cobweb, liquids). No builtin block uses it yet |
Constants: category bits
Freeform grouping tags checked at runtime with blocks.has_tag. Any block can carry any number of tags via the tags registration field.
| Name | Description |
|---|---|
blocks.TAG_GAS | Non-solid, passable block (eg. air) |
blocks.TAG_ROCK | Stone-family block. Used by tools and worldgen that check for rock |
blocks.TAG_SOIL | Soil-type block. Dirt, mud, and similar blocks go here |
blocks.TAG_TURF | Turf-type block. Grass and similar blocks go here |
blocks.TAG_XFOIL | Non-solid foliage: grass, bushes, and similar |
blocks.TAG_SFOIL | Solid foliage: leaves and similar |
blocks.TAG_WOOD | Wooden blocks |
Constants: schedule source
A scheduled tick is issued non-randomly with a specific timeout. Scheduled ticks can come from different sources.
| Name | Description |
|---|---|
blocks.TICK_RANDOM | Random tick |
blocks.TICK_NEIGHBOUR | Neighbouring block changed |
blocks.TICK_SCRIPTED | Scripted tick |
Constant: null block
blocks.NULL_BLOCK is an empty, undefined, or otherwise invalid block ID. Treat it as a void block for gameplay and gamedev.
Functions
Function: blocks.get(name) -> integer
Retrieves a numeric block stem ID from a namespaced block ID.
Arguments
nameis a namespaced block ID, eg.mymod:coolblockname
Return value
- Numeric block ID on success
blocks.NULL_BLOCKif the block is missing or the namespace ID is malformed
Notes
- If a block defines states and variants, the return value is a stem ID. The engine does not render, collide with, or raycast a stem placed in the world.
Function: blocks.has_tag(id, tag) -> boolean
Checks if a block has a specified tag.
Arguments
idis a numeric block IDtagis a tag constant, eg.blocks.TAG_SOIL
Return value
trueif the block has the specified tag,falseotherwise
Function: blocks.is_replaceable(id) -> boolean
Checks if a block ID can be overwritten without breaking it first (empty cell, or replaceable = true at registration).
Arguments
idis a numeric block ID (stem or variant), orblocks.NULL_BLOCKfor an empty cell
Return value
trueif another block may occupy the cell,falseotherwise
Function: blocks.add(name, def) -> integer
Function: blocks.add(name, prototype, def) -> integer
Registers a new block in the registry.
Arguments
nameis a namespaced block ID, egmymod:coolblocknamedefis a block definition table (see below)prototype(3-argument form) is a base definition shared across a family of blocks (eg. all stone variants).defmerges on top ofprototype. On conflict, fields indefwin.
Return value
Returns the numeric block ID.
Notes
Rename rule: on conflict, the engine adds a ~N suffix to the encroaching name. N is the smallest integer, starting at 1, that gives a free id (e.g. mymod:myblock~1). Loading stays deterministic for the same mod list and order.
Block definition
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
render | integer | yes | N/D | One of blocks.RENDER_XXXX constants |
albedo | table | depends | {} | Albedo textures to attach to the block model |
masks | table | no | {} | Mask textures to attach to the block model |
animated | boolean | no | false | If true, the engine treats textures in textures as animation frames instead of world-position random frames |
model_name | string | depends | N/D | Block model name for this variant |
model_offset | number[3] | depends | {0, 0, 0} | Offset of the resolved block model |
model_facing | integer | no | blocks.FACE_NORTH | One of blocks.FACE_XXXX. Sets where the model's own north face points, and rotates the whole resolved block model |
bcoll_name | string | depends | N/D | Block collision shape for this variant |
bcoll_offset | number[3] | depends | {0, 0, 0} | Block collision offset |
bcoll_facing | integer | no | blocks.FACE_NORTH | One of blocks.FACE_XXXX. Rotates the resolved collision shape the same way model_facing rotates the model. You can set it independently of model_facing. The collision shape does not need to match the visual, though it usually should |
fluid_name | string | no | N/D | Fluid name that shares the grid cell with the block |
fluid_level | integer | no | 0 | Fluid level if fluid_name is set, in 1/16ths of a block |
health | integer | no | 0 | Base hit points needed to break the block. Tool effects can change this |
sound | string | no | N/D | Sound set for this block |
emission | integer | no | 0 | Emission light value |
dissipation | integer | no | 0 | Amount of light the block absorbs as light passes through it |
touch | integer | no | blocks.TOUCH_SOLID | Block touch response |
touch_coeffs | number[3] | no | {1, 1, 1} | Block touch response coefficients |
tags | integer[] | no | {} | Block tags |
replaceable | boolean | no | false | If true, other blocks can be placed into this cell without breaking it first |
states | table | no | {} | Blockstates table |
variants | table[] | no | {} | Variants table |
on_tick | function | no | nil | Scheduled tick handler |
on_place | function | no | nil | Placement handler. Can allow or deny placement |
on_break | function | no | nil | Break handler |
on_interact | function | no | nil | Interaction handler |
Textures
Albedo
Each texture slot is a list of textures. The engine uses them as position-randomized variations, or as animation frames when animated is true.
Masks
Each texture slot can have a mask texture that the engine uses for certain purposes. Each color channel of an RGBA mask texture can drive per-face logic, and more channels will gain this role in the future.
| Channel | Designation | Description |
|---|---|---|
| Red | Tint mask | Actual tint color is multiplied with this value in shaders |
| Green | Unused | N/A |
| Blue | Unused | N/A |
| Alpha | Unused | N/A |
Facing rotation
model_facing and bcoll_facing each define one 90-degree-step rotation of the whole model or collision shape. They set where the north face of the model points. By default, the north face points world north.
Drops table
drops = {
{
when = { effects = { "silk_touch" } },
items = {
{ name = "stone", count = 1 }
}
},
{
-- entries without a `when` always match; put fallback
-- entries last since matching stops at the first hit
items = {
{ name = "cobblestone", count = 1 }
}
}
}
The engine evaluates entries top to bottom. The first entry whose when clause matches (or that has no when) supplies the drops. The engine ignores later entries.
States table
states = {
<state_name> = {
default = "<default_state>",
hint = { "<value_a>", "<value_b>", ... } -- optional
}
}
Blockstate values are hashed strings. You can write any value via world.sset. hint does not restrict this at runtime; hint is only a registration-time cross-check. The engine checks every when clause across the variants of this block against the union of hint lists for the states it references. A value missing from hint produces a console warning at load time (typo protection, e.g. orientation = "bottum"). Blocks that omit hint for a state skip validation for that state.
State object
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
default | string | yes | N/D | Default blockstate value |
hint | string[] | no | {} | Optional list of valid values for registration-time validation |
Variants
variants = {
{
when = { <state_name> = "<state_value>" },
overrides = {
model_name = "slab_top",
bcoll_offset = { 0, 8, 0 },
health = 2,
replaceable = true,
drops = { ... }
}
}
}
overrides is a table of registration fields (same shape as the top-level definition). It merges on top of the base definition of the block when when matches the current blockstate values.
Target table
Some callbacks pass a target table for the block the initiator looked at (the raycast hit). In on_place, this is the block adjacent to the placement cell.
| Field | Type | Description |
|---|---|---|
stem | integer | Numeric block stem ID of the hit block |
face | integer | Hit surface direction |
ni | number | Surface normal X/I component |
nj | number | Surface normal Y/J component |
nk | number | Surface normal Z/K component |
lx | number | Hit point X component |
ly | number | Hit point Y component |
lz | number | Hit point Z component |
bx | integer | Hit block position X component |
by | integer | Hit block position Y component |
bz | integer | Hit block position Z component |
rx | number | Block-local hit position X component |
ry | number | Block-local hit position Y component |
rz | number | Block-local hit position Z component |
Occupant table
The on_place handler receives an occupant table for the block currently in the placement cell.
| Field | Type | Description |
|---|---|---|
id | integer | Numeric block ID in the placement cell. blocks.NULL_BLOCK when empty |
replaceable | boolean | Whether the placement cell can be occupied: true when empty or when the existing block was registered with replaceable. false otherwise |
on_place handler
on_place = function(bx, by, bz, target, occupant, actor)
if not occupant.replaceable then
return nil -- cell is occupied by a non-replaceable block
end
-- permits placement with these initial states
return { <state_name> = "<state_value>", ... }
end
Returning nil blocks placement. Returning a table (empty or not) permits it. Table entries become initial blockstate values for states not covered by their default.
When placement is permitted, the new block overwrites whatever was in the cell. The engine does not break replaceable occupants, and they do not drop items.
on_break handler
on_interact handler
on_interact = function(bx, by, bz, target, actor)
-- Actions to do when someone interacts with the block
end





