bffb68b0c5
horizon_mods::index (feature index): index.json's types and rules (unique ids, https URLs, plain file names, hex SHA-256, minisign keys and signatures, a modpack's mods present in the index), open-ended kinds (mod, modpack, resourcepack, shader; unknown kinds kept, not offered), revocations, and check_file: size, hash, revocation, signature and the file's own manifest against its entry. horizon_mods::modpack reads .hpack files: horizon-modpack.toml and an allow-list of overrides. docs/api/mod-index.md documents both, with a sample index the tests read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
96 lines
5.3 KiB
Markdown
96 lines
5.3 KiB
Markdown
# The registry index and `.hpack`
|
|
|
|
Horizon's registry lists what is made for Horizon and reviewed: mods (`.hmod`), modpacks (`.hpack`), resource packs
|
|
and, once their format exists, Horizon shader packs. Submissions are pull requests in
|
|
[ludovic111/horizon-mods](https://github.com/ludovic111/horizon-mods); merging one publishes it. The launcher and the
|
|
website read one file, `index.json`, which that repository's CI builds. The Rust types and every check below are
|
|
`horizon_mods::index` and `horizon_mods::modpack` (feature `index`); the sample is
|
|
`crates/horizon-mods/tests/index/index-v1.json`, read by the tests with the files it lists.
|
|
|
|
Level: preview ([stability.md](stability.md)). Schema 1.
|
|
|
|
## `index.json`
|
|
|
|
```json
|
|
{
|
|
"schema": 1,
|
|
"generated": "2026-10-24T18:00:00Z",
|
|
"projects": [{
|
|
"id": "coords_hud", "kind": "mod", "name": "Coordinates HUD", "summary": "One line.",
|
|
"description": "Markdown.", "authors": ["Horizon"], "owners": ["ludovic111"],
|
|
"license": "MIT", "source": "https://github.com/...", "icon": "https://...png", "key": "RWT...",
|
|
"versions": [{
|
|
"version": "0.1.0", "published": "2026-10-24", "changelog": "",
|
|
"api": "0.1", "side": "client", "capabilities": ["game-read", "hud", "chat"], "game": "26.3",
|
|
"file": { "name": "coords_hud-0.1.0.hmod", "url": "https://github.com/ludovic111/horizon-mods/releases/download/...",
|
|
"size": 438, "sha256": "e113...", "signature": "untrusted comment: ...\n...\ntrusted comment: ...\n...\n" }
|
|
}]
|
|
}],
|
|
"revoked": [{ "id": "bad_mod", "sha256": "1111...", "reason": "Sent chat messages it didn't declare.", "date": "2026-10-24" }]
|
|
}
|
|
```
|
|
|
|
| Field | Meaning |
|
|
| --- | --- |
|
|
| `schema` | 1. A reader refuses a higher number with "update Horizon" rather than misread it. |
|
|
| `projects[].id` | `[a-z0-9_]{1,64}`, unique; a mod's is its manifest's `id`. |
|
|
| `kind` | `mod`, `modpack`, `resourcepack`, `shader` (Horizon's own shader packs, not Iris or OptiFine packs). Other kinds (data packs, worlds, themes) may come without a new schema: a reader keeps a kind it doesn't know and doesn't offer it. |
|
|
| `summary`, `description` | One line for lists; Markdown for the project's page. |
|
|
| `owners` | GitHub logins allowed to publish updates. |
|
|
| `license`, `source` | An SPDX expression and an `https://` address of the source code: both required. |
|
|
| `icon` | `https://`, optional. |
|
|
| `key` | The author's [minisign](https://jedisct1.github.io/minisign/) public key. When set, every version must be signed with it; an update signed with another key is refused. Absent: the project is unsigned and the launcher says so. |
|
|
| `versions` | Newest first, at least one. |
|
|
| `api` | A mod's API line (its manifest's `api`); a modpack's manifest format (`1`). |
|
|
| `side`, `capabilities` | A mod's, read from its manifest by CI, never typed by hand. |
|
|
| `game` | The Minecraft version it is for. |
|
|
| `requires` | A modpack's mods: `{ id, version, sha256 }`, each a version in this index with that hash. |
|
|
| `file` | A plain name with the kind's extension (`.hmod`, `.hpack`, `.zip`), an `https://` URL, the size (at most 64 MiB), the lowercase hex SHA-256, and the `.minisig` text when the project has a key. |
|
|
| `revoked` | Files taken down: one file by `sha256`, or every version of `id` without it. The launcher refuses to install them and turns installed copies off with the reason. |
|
|
|
|
Readers ignore fields they don't know, so an optional field can be added to schema 1. Renaming or removing a field, or
|
|
changing what one means, makes schema 2.
|
|
|
|
## Before a file is installed
|
|
|
|
`index::check_file` runs on the downloaded file, before it reaches the game folder:
|
|
|
|
1. Its size and SHA-256 are the ones the entry lists, and it isn't revoked.
|
|
2. With a project key: its signature verifies with that key (minisign's prehashed and legacy signatures both).
|
|
3. What the file says matches the entry: a mod's `horizon-mod.toml` (id, version, API, side, capabilities) and its
|
|
content's fence ([mods.md](../mods.md#content-mods-api-02)); a modpack's manifest (id, version, format, game,
|
|
mods); a resource pack's `pack.mcmeta`.
|
|
4. A kind this build can't install is refused with "this Horizon can't install a … yet".
|
|
|
|
The game still checks a mod's component imports against its capabilities when it starts it, as for any mod.
|
|
|
|
## `.hpack`
|
|
|
|
A zip holding `horizon-modpack.toml` and, optionally, `overrides/`. The mods are not inside: the launcher downloads
|
|
each from the index and checks it as above.
|
|
|
|
```toml
|
|
format = 1
|
|
id = "cozy" # [a-z0-9_]{1,64}: the profile's folder
|
|
name = "Cozy"
|
|
version = "1.0.0"
|
|
description = "Coordinates and a calm render distance."
|
|
authors = ["Horizon"]
|
|
game = "26.3"
|
|
|
|
[[mods]]
|
|
id = "coords_hud"
|
|
version = "0.1.0"
|
|
sha256 = "e1135345692f6dd8fd4c51920151944b82333e17049c9bb7d756f27b8deefc53"
|
|
on = true # optional, default true: turned on in the profile's horizon-mods.txt
|
|
```
|
|
|
|
Unknown keys are refused. `overrides/` may hold only `options.txt`, `horizon-graphics.txt`, `horizon-extras.txt`,
|
|
`resourcepacks/<name>.zip` and `horizon-mods/.horizon-mod-data/<a listed mod>/...` (a mod's own saved settings,
|
|
capability `storage`), each at most 64 MiB and 256 MiB in all; anything else refuses the pack. The launcher copies
|
|
them into the profile's game folder.
|
|
|
|
## Changelog
|
|
|
|
- Schema 1 (2026-10-24): kinds `mod`, `modpack`, `resourcepack`, `shader`; `.hpack` format 1.
|