c5bb51bb05
A server mod's registration now lists each command's arguments: a name, a kind (word, text, integer with bounds, number, boolean, player, block-pos) and whether it is optional. The server adds them to the command tree every player receives, after vanilla's commands, so a player's chat box completes and colours them as vanilla's. When a player sends one, the server parses the line as vanilla's parsers do (horizon-mods' commands.rs: ~ coordinates from the player, @s/@p, integer bounds) and calls the mod's command hook with the values by name, or answers with vanilla's error without calling the mod. The hub keeps the server mods' commands as a root in the commands report's format and resends players' trees when they change (CommandTree:: packet_with); the game sets it when its mods start, stop or reload, or a hub opens. In-frame, the window's own chat box lists them by name. SDK: Registration::command_with(name, [Argument::...]), Argument builders, Args (text(), integer(), player(), block_pos() ...); command(name) is free text, an optional text argument. Examples: welcome's /mined [player], beacons' /beacon [height] and /ground [pos], with scripts for values and errors. Docs: docs/mods.md (typed commands, kinds table), docs/api/mods.md and the regenerated reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
290 lines
12 KiB
Markdown
290 lines
12 KiB
Markdown
<!-- Generated from crates/horizon-mod-sdk/wit/horizon.wit and the manifest's capabilities by crates/horizon-mods/tests/api_reference.rs; a test fails when this file is out of date. Update it with: HORIZON_WRITE_DOCS=1 cargo test -p horizon-mods --features pack --test api_reference -->
|
|
# 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](../mods.md); stability and versions: [stability.md](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`](#game) | see your position, health and the time |
|
|
| `chat` | [`chat`](#chat) | show you chat messages |
|
|
| `hud` | [`hud`](#hud) | draw text on your screen |
|
|
| `storage` | [`storage`](#storage) | save its own settings to disk |
|
|
| `registries` | data files (`assets/`, `data/`), no interface | add blocks and items to your worlds |
|
|
| `players` | [`players`](#players) | see who is on the server and message them |
|
|
| `world` | [`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 `block-pos`
|
|
|
|
| Field | Type | |
|
|
| --- | --- | --- |
|
|
| `x` | `s32` | |
|
|
| `y` | `s32` | |
|
|
| `z` | `s32` | |
|
|
|
|
### variant `argument-kind`
|
|
|
|
What an argument of a command takes. The server sends each command and its arguments to players' games, whose chat box completes and colours them as vanilla's; the server parses them before the mod's `command` hook gets their values.
|
|
|
|
| Case | Payload | |
|
|
| --- | --- | --- |
|
|
| `word` | | One word: letters, digits and `_ - . +`. |
|
|
| `text` | | The rest of the line, spaces included: only last. |
|
|
| `integer` | `tuple<option<s32>, option<s32>>` | A whole number, within the bounds given. |
|
|
| `number` | | A number with or without decimals. |
|
|
| `boolean` | | `true` or `false`. |
|
|
| `player` | | One online player: a name, or `@s` or `@p` (whoever typed it, as vanilla picks for a player). |
|
|
| `block-pos` | | A block position: three whole numbers, each one also `~` or `~n`, relative to whoever typed it. |
|
|
|
|
### record `argument`
|
|
|
|
| Field | Type | |
|
|
| --- | --- | --- |
|
|
| `name` | `string` | Shown in the chat box's hint (`<height>`) and the key of its value. |
|
|
| `kind` | `argument-kind` | |
|
|
| `optional` | `bool` | Optional arguments come after every required one. |
|
|
|
|
### record `server-command`
|
|
|
|
| Field | Type | |
|
|
| --- | --- | --- |
|
|
| `name` | `string` | Without the slash. A name vanilla already uses is refused (vanilla's command runs). |
|
|
| `arguments` | `list<argument>` | In order; none: the command takes nothing after its name. Free text is one optional `text` argument. |
|
|
|
|
### variant `argument-value`
|
|
|
|
An argument's value, parsed as its kind says.
|
|
|
|
| Case | Payload | |
|
|
| --- | --- | --- |
|
|
| `word` | `string` | |
|
|
| `text` | `string` | |
|
|
| `integer` | `s32` | |
|
|
| `number` | `f64` | |
|
|
| `boolean` | `bool` | |
|
|
| `player` | `player` | |
|
|
| `block-pos` | `block-pos` | |
|
|
|
|
### record `registration`
|
|
|
|
| Field | Type | |
|
|
| --- | --- | --- |
|
|
| `commands` | `list<server-command>` | Commands players may type. |
|
|
| `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`. |
|
|
|
|
| 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, values: list<tuple<string, argument-value>>) -> result<option<string>, string>` | `/name args` typed by `player`: ok(some(text)) is their feedback, err(text) their error in red. `values` holds each argument given, by name, in order (an optional one left out isn't there); a line that doesn't parse never reaches the mod: the player gets vanilla's error. |
|
|
| `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. |
|