Server mods get interface world: get-block(dimension, x, y, z) reads a
loaded chunk's block state as "minecraft:oak_log[axis=y]", get-biome its
biome ("minecraft:plains"), and
set-blocks(dimension, changes) sets up to 4096 blocks per call, checked at
once, made as /setblock makes them (place_state: neighbours, light, block
entities, every client told through the block log) after the call, before
that dimension's next tick.
Reads cost no copy: for a mod call the game lends Mods the levels' chunk
maps (moved out with mem::take and put back after), only while a running
mod has world. Writes for a level that isn't ticking (another dimension,
in-frame) wait for it, up to 65,536.
Test scripts get blocks (setup) and expect.blocks; cargo horizon-mod check
reports a trial run's block writes. Example beacons: /beacon builds a
glowstone pillar beside the player, /ground reads the block underfoot and the biome.
parse_state is now a free function so the mod path shares it.
Docs: docs/mods.md (the capability, script keys), docs/api/mods.md and the
regenerated reference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
10 KiB
Mod API reference
The contract between Horizon and its mods: the WIT package horizon:mods@0.1.0, every interface, type, function and hook in it, and the capabilities a manifest may list. The guide is mods.md; stability and versions: stability.md. Manifest api lines this game serves: 0.1, 0.2, 0.3.
Capabilities
In capabilities |
Grants | The player reads "May …" |
|---|---|---|
game-read |
game |
see your position, health and the time |
chat |
chat |
show you chat messages |
hud |
hud |
draw text on your screen |
storage |
storage |
save its own settings to disk |
registries |
data files (assets/, data/), no interface |
add blocks and items to your worlds |
players |
players |
see who is on the server and message them |
world |
world |
read and change the world's blocks |
World horizon-mod
A client mod: runs in the player's game.
- Imports (what the game offers):
log,game,chat,hud,storage - Exports (what the mod provides):
events
World horizon-server-mod
A server mod (manifest side = "server", api = "0.3", experimental): runs where the world is simulated, on the dedicated server, a LAN host and single player's own server.
- Imports (what the game offers):
log,storage,players,world - Exports (what the mod provides):
server-events
log
Access: always granted.
The mod's log, in the game's log under the mod's id. Always granted.
enum level
| Case | |
|---|---|
debug |
|
info |
|
warn |
|
error |
| Function | Signature | What it does |
|---|---|---|
write |
func(level: level, message: string) |
One line in the game's log as [mod <id>] message, at that level. |
game
Access: capability game-read.
Capability game-read: the local player and the world clock.
record player
| Field | Type | |
|---|---|---|
x |
f64 |
Feet position, in blocks. |
y |
f64 |
|
z |
f64 |
|
yaw |
f32 |
Degrees, as F3 shows them. |
pitch |
f32 |
Degrees: -90 looks straight up, 90 straight down. |
health |
f32 |
Hit points as vanilla counts them: 20 is full health without effects. |
food |
u32 |
0 to 20, as the hunger bar. |
dimension |
string |
minecraft:overworld, minecraft:the_nether, ... |
record clock
| Field | Type | |
|---|---|---|
game-time |
u64 |
Ticks since the world was created. |
day-time |
u64 |
24000 ticks per day; 0 is 6:00 on the first day. |
| Function | Signature | What it does |
|---|---|---|
get-player |
func() -> option<player> |
None on the title screen. |
get-clock |
func() -> option<clock> |
None on the title screen. |
chat
Access: capability chat.
Capability chat: messages only the local player sees.
| Function | Signature | What it does |
|---|---|---|
show |
func(text: string) |
Shown in chat after the mod's name, like a system message. |
hud
Access: capability hud.
Capability hud: one panel of text lines per mod, drawn by the game every frame until the mod changes or clears it (no call per frame).
enum corner
| Case | |
|---|---|
top-left |
|
top-right |
|
bottom-left |
|
bottom-right |
record line
| Field | Type | |
|---|---|---|
text |
string |
Plain text, up to 256 characters. |
color |
u32 |
0xRRGGBB. |
| Function | Signature | What it does |
|---|---|---|
set-panel |
func(corner: corner, lines: list<line>) |
Replaces the mod's panel: up to 16 lines in that corner of the screen. |
clear |
func() |
Removes the mod's panel. |
storage
Access: capability storage.
Capability storage: a per-mod folder of small key/value files, quota'd (docs/mods.md). Keys are [a-z0-9_.-]{1,64}, one path segment.
| Function | Signature | What it does |
|---|---|---|
get |
func(key: string) -> option<list<u8>> |
None if key has never been set, or the key is not well-formed. |
set |
func(key: string, value: list<u8>) -> result<_, string> |
Errs on a malformed key or over quota (bytes for the whole mod). |
delete |
func(key: string) |
No error if key was already absent. |
events
Access: exported by the mod: the game calls it.
What the game calls. Only the hooks init asks for are ever called.
record registration
| Field | Type | |
|---|---|---|
commands |
list<string> |
Chat commands, without the slash. A name vanilla already uses is refused (vanilla's command runs). |
tick |
bool |
Call tick every game tick (20 per second while playing). |
frame |
bool |
Call frame every rendered frame. Budget: 0.1 ms. |
chat |
bool |
Call chat for each chat line the player receives. |
| Function | Signature | What it does |
|---|---|---|
init |
func() -> result<registration, string> |
Once, after loading. An error keeps the mod off and is shown. |
tick |
func(tick: u64) |
Each game tick while in a world, with the game's tick counter. |
frame |
func(seconds: f32) |
Each rendered frame, with the seconds since the last one. |
command |
func(name: string, args: string) -> result<option<string>, string> |
/name args: ok(some(text)) is shown as feedback, err(text) in red. |
chat |
func(text: string) |
Each chat line the player receives, as plain text. |
players
Access: capability players.
Capability players, server mods only (manifest api = "0.3", experimental): the players on the server, and messages to them.
enum game-mode
| Case | |
|---|---|
survival |
|
creative |
|
adventure |
|
spectator |
record player
| Field | Type | |
|---|---|---|
id |
string |
The player's UUID, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. |
name |
string |
|
x |
f64 |
Feet position, in blocks. |
y |
f64 |
|
z |
f64 |
|
dimension |
string |
minecraft:overworld, minecraft:the_nether, ... |
game-mode |
game-mode |
|
health |
f32 |
Hit points as vanilla counts them: 20 is full health without effects. |
| Function | Signature | What it does |
|---|---|---|
online |
func() -> list<player> |
The players online, in the order they joined. |
tell |
func(player: string, text: string) -> bool |
A system message to one player, after the mod's name; false when no player with that id is online. Up to 8 messages per call. |
broadcast |
func(text: string) |
A system message to every player and the server's log, after the mod's name. Counts toward the same 8 per call. |
world
Access: capability world.
Capability world, server mods only (manifest api = "0.3", experimental): the blocks of the server's loaded chunks, and changes to them through the server's own block updates.
record block-change
| Field | Type | |
|---|---|---|
x |
s32 |
|
y |
s32 |
|
z |
s32 |
|
state |
string |
minecraft:oak_log[axis=y]; properties left out take the block's defaults, minecraft:stone alone is the default state. |
| Function | Signature | What it does |
|---|---|---|
get-block |
func(dimension: string, x: s32, y: s32, z: s32) -> option<string> |
The block state at a position in a dimension (minecraft:overworld, ...), as minecraft:oak_log[axis=y], as of this call: none where the server has no chunk loaded there. |
get-biome |
func(dimension: string, x: s32, y: s32, z: s32) -> option<string> |
The biome at a position (minecraft:plains, ...), as the server stores it (one per 4 x 4 x 4 cell): none where no chunk is loaded. |
set-blocks |
func(dimension: string, blocks: list<block-change>) -> result<_, string> |
Sets blocks as /setblock does: the old block entity removed, neighbours and shapes updated, light, and every player told. Every state is checked now (an error queues nothing); the changes are made in order after this call returns, before that dimension's next tick; one in a chunk not loaded then is skipped. At most 4096 per call. |
server-events
Access: exported by the mod: the game calls it.
What the server calls in a server mod (manifest api = "0.3", experimental). Only the hooks init asks for are ever called. The player in each event is as the server saw them when it happened.
type player
type player = player
record registration
| Field | Type | |
|---|---|---|
commands |
list<string> |
Commands players may type, without the slash. A name vanilla already uses is refused (vanilla's command runs). |
tick |
bool |
Call tick every server tick (20 per second). |
joins |
bool |
Call player-joined and player-left. |
chat |
bool |
Call chat for each chat message a player sends. |
blocks |
bool |
Call block-broken and block-placed. |
record block-pos
| Field | Type | |
|---|---|---|
x |
s32 |
|
y |
s32 |
|
z |
s32 |
| Function | Signature | What it does |
|---|---|---|
init |
func() -> result<registration, string> |
Once, after loading. An error keeps the mod off and is logged. |
tick |
func(tick: u64) |
Each server tick, with the server's tick counter. |
player-joined |
func(player: player) |
A player joined the server; they are in players.online already. |
player-left |
func(player: player) |
A player left the server; they are no longer in players.online. |
chat |
func(player: player, text: string) |
A chat message a player sent, as plain text. |
command |
func(player: player, name: string, args: string) -> result<option<string>, string> |
/name args typed by player: ok(some(text)) is their feedback, err(text) their error in red. |
block-broken |
func(player: player, pos: block-pos, state: string) |
A player broke the block at pos in their dimension: state is what was there, as minecraft:oak_log[axis=y]. |
block-placed |
func(player: player, pos: block-pos, state: string) |
A player placed state at pos in their dimension. |