Two globals hold everything live in the game:
| Global | Is |
|---|---|
player |
Your player as an entity handle, or nil outside a world |
world |
The loaded world handle, or nil outside a world |
Both re-resolve on every access, so a respawn or dimension change already shows in the next
read. Guard for nil on the title screen:
module:event("tick", function()
if not player then return end
if player:health() < 8 then
hud.notify("Low HP", ("%.1f left"):format(player:health()), "error")
end
end)Handles are live: every colon-call re-reads the game, so one kept from last tick answers with this tick’s state. The exception is text, which always comes as a snapshot.
| Handle | Comes from |
|---|---|
| Entity | player, world:players(), world:entities(), world:entity(id) |
| Item | e:held_item(), e:equipped(slot), inventory.item, game.item |
| Block state | world:block_state(pos), a block hit’s state |
| Raycast hit | world:raycast(...), world:raycast_entity(...), player:raycast() |
Positions are vec3 everywhere. Data that never changes at runtime (items,
translations) lives on game.
Entities
| Method | Returns |
|---|---|
world:players() |
Every player as an entity handle, yourself included |
world:player(name) |
One player by name, case-insensitive, or nil |
world:entities(type?) |
Every entity, optionally filtered by exact type id ("minecraft:item") |
world:entity(id) |
Entity by numeric id, or nil |
for _, p in ipairs(world:players()) do
if not p:is_self() and p:distance() < 8 then
print(p:name() .. " is close")
end
endBlocks
| Method | Returns |
|---|---|
world:block(pos) |
Block id at a vec3, e.g. "minecraft:air" |
world:block_state(pos) |
Full block state handle |
world:find_blocks(ids, center, radius) |
Positions of matching blocks in a cube around center |
world:sign_text(pos) |
A sign’s four front lines, four back lines and waxed flag, or nil |
world:top_y(x, z[, heightmap]) |
Surface y of a column |
Heightmaps: "motion_blocking" (default) · "motion_blocking_no_leaves" · "world_surface"
· "ocean_floor".
find_blocks takes one block id or a list, scans radius blocks out along each axis
(capped at 64) and returns the matches as vec3 block positions:
local chests = world:find_blocks({ "minecraft:chest", "minecraft:trapped_chest" },
player:position(), 6)
print(#chests .. " chests nearby")Raycasts
| Method | Returns |
|---|---|
world:raycast(from, to[, fluids[, shape]]) |
First block hit between two points, or nil |
world:raycast_entity(from, to) |
Closest entity hit, or nil. Skips spectators and yourself |
fluids = true also hits fluids. shape picks the collision shape to test: "outline"
(default, what the crosshair uses) · "collider" (physics shape) · "visual".
Both need a local player and return nil without one. For the crosshair ray use
player:raycast(max_distance?), which tests blocks and entities at once.
Environment
| Method | Returns |
|---|---|
world:time() |
Time of day in ticks |
world:dimension() |
Dimension id, e.g. "minecraft:overworld" |
world:raining(), world:thundering() |
Weather flags |
world:rain_gradient(), world:thunder_gradient() |
Weather strength, 0..1 |
world:biome(pos) |
Biome id, e.g. "minecraft:plains" |
world:light(pos) |
Block light and sky light, 0–15, as two returns |
local pos = player:position()
print(world:biome(pos), world:light(pos))
if world:raining() then
print("rain strength", world:rain_gradient())
end