Commit Graph

79 Commits

Author SHA1 Message Date
Ludovic Marie 9a7f75b75d Merge pull request #1894 from ludovic111/feat/server-mods-game
🤖 Agent: merged main (aec52c85e). pr_ready --quick passes (1308 horizon-client tests, clippy, 507 LOC). The welcome server mod e2e passes 35/35 in every mode: in-frame, server thread, LAN host in-frame and on its thread with a guest, dedicated with a guest. Verify is green; parity now runs on main (parity-scope). Queued.
2026-10-26 15:30:36 +01:00
Ludovic Marie f49d5d91e6 Site: downloads and 1-5 star ratings on /mods
- The list shows each project's rating (stars, mean and count) and its
  downloads ("12.3k downloads"), ordered by downloads by default; an Order
  menu also sorts by rating or name (?sort= too).
- A project's page shows the same, then a rating control: five stars when
  signed in (the account's own rating lit), "Sign in with GitHub to rate"
  (coming back to the page) when not, a note for its owners.
- Ratings come from the registry service's GET /api/mods/ratings; a rating
  is POSTed with the session's CSRF token. Until the service answers, the
  pages show downloads only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:29:31 +01:00
Ludovic Marie a27579dd72 Merge remote-tracking branch 'origin/main' into feat/server-mods-game
# Conflicts:
#	crates/horizon-client/src/game/mods.rs
2026-10-26 13:29:17 +01:00
Ludovic Marie 5a9e07301b Merge pull request #2113 from ludovic111/feat/mod-raycast
🤖 Agent: game.raycast, mod API level 2. CI is green on c23b4e8e4. In game, in-frame and on the server thread, the ui guest's /raycast passes all four checks: glass at 2 blocks, nothing at 1, gold after /setblock, the sky is no hit. The ported Orbital Laser aims with it and fires in both modes. Queued.
2026-10-26 13:13:29 +01:00
Ludovic Marie 4fbb0cde70 Merge pull request #1837 from ludovic111/feat/server-mod-test-scripts
🤖 Agent: The test scripts for server mods. CI is green on d64bd7c52, and the PR is now based on main after #1833 merged. I ran pr_ready --quick on this head merged with main (b8027d4b1): fmt, clippy, the horizon-mods and welcome tests (48) and the launcher tests (132) all pass. The only affected harness is lan_integration, which runs in CI. Queued.
2026-10-26 12:43:44 +01:00
Ludovic Marie c23b4e8e41 Mod API: game.raycast, the block the player looks at (level 2)
`game.raycast(distance)` returns the first block along the player's view
(fluids pass), up to 1024 blocks: through the loaded chunks as the
crosshair's ray goes, then across the distant terrain's ground heights
(`Lod::ground`, from Stink-O's fork). The game casts it only while a running
mod imports the function. It is API level 2, so older Horizons refuse a mod
that calls it with "update Horizon".

Co-authored-by: Stink-O <180130752+Stink-O@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:27:06 +01:00
Ludovic Marie 0a9a7c0d06 Merge remote-tracking branch 'origin/main' into feat/mod-api-level 2026-10-26 11:45:15 +01:00
Ludovic Marie 8cc8c6180d Mod API levels: refuse a mod made for a newer Horizon, list each version's level
Every function the game offers mods has the API level it arrived at
(crates/horizon-mods/src/api_level.rs): level 0 is the contract of
Horizon 0.2.67 and 0.2.68, level 1 adds render.set-minimap. A mod needs
the level of the newest function it imports, read from its component.

- The game refuses a mod that calls a function it doesn't have with
  "made for a newer Horizon (it uses ...): update Horizon to run it"
  instead of wasmtime's linking error.
- The registry index lists each mod version's level (api_level, read
  from the file by CI); check_file compares it when the entry has one,
  and the moved extras' installer takes the newest version this game
  can run.
- cargo horizon-mod check prints the level.
- The api_reference test fails until a new WIT function has a level.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 10:39:47 +01:00
Ludovic Marie 593b99a68b Merge branch 'feat/server-mod-test-scripts' into feat/server-mods-game
# Conflicts:
#	crates/horizon-client/src/game/mods.rs
2026-10-26 10:01:50 +01:00
Ludovic Marie d64bd7c528 Merge branch 'feat/server-mods-0.3' into feat/server-mod-test-scripts
# Conflicts:
#	crates/horizon-mods/src/testing.rs
2026-10-26 09:56:41 +01:00
Ludovic Marie b90ab85f44 Merge remote-tracking branch 'origin/main' into feat/server-mods-0.3
# Conflicts:
#	Cargo.toml
#	crates/cargo-horizon-mod/src/check.rs
#	crates/horizon-client/src/game/mods.rs
#	crates/horizon-mod-sdk/src/lib.rs
#	crates/horizon-mod-sdk/wit/horizon.wit
#	crates/horizon-mods/src/manifest.rs
#	crates/horizon-mods/src/runtime.rs
#	crates/horizon-mods/src/testing.rs
#	crates/horizon-mods/tests/sandbox.rs
#	docs/api/mods-reference.md
#	docs/api/mods.md
#	docs/mods.md
2026-10-26 09:51:00 +01:00
Ludovic Marie 6c3473c6e0 Official mod: Minimap
The minimap extra as a mod (mods/official/minimap): the extra's five
options on its settings page, kept in its storage with the extra's values
(corner, size, shape, zoom, rotate), and the map drawn by the game
through render.set-minimap, so it looks and costs the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 08:40:03 +01:00
Ludovic Marie 24ab642e7b Mod API: render.set-minimap, a map the game keeps in a corner
What the official Minimap mod needs: a mod picks the corner, side, scale,
shape and turning, and the game draws the map as the minimap extra does,
from the same tiles (vanilla's map colours, the floor under roofs) within
its own frame budget. One map at a time, the first loaded mod's. A new
function and type, so mods built before it keep loading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 08:20:30 +01:00
Ludovic Marie 301b006ef4 Merge pull request #1816 from ludovic111/feat/mod-test-runner
🤖 Agent: cargo horizon-mod test runs a mod's test scripts with no game. Main is merged in, and the runner fills the new snapshot fields (input, render, frame stats) with the trial run's screen size. Verified: clippy, the cargo-horizon-mod, coords-hud and horizon-mods tests (57), launcher, and cargo horizon-mod test on coords-hud (2 scripts).
2026-10-26 08:07:39 +01:00
Ludovic Marie f7d7c7c70a Merge main into feat/mod-test-runner
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:47:58 +01:00
Ludovic Marie c8d75a7892 Merge main into feat/official-zoom-mod
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:24:16 +01:00
Ludovic Marie 2f46365df1 Merge remote-tracking branch 'origin/main' into feat/mod-ui-key 2026-10-26 06:15:25 +01:00
Ludovic Marie bea3165267 Merge main into feat/mod-test-runner
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 06:03:11 +01:00
Ludovic Marie 7ecb43ccc8 Merge pull request #1982 from ludovic111/feat/official-hud-mods
🤖 Agent: Horizon's official FPS Counter and Keystrokes as mods in mods/official/, same options and look as the extras (pixel-identical, frame cost within noise). Main merged in (wasmtime 48). Verified: pr_ready, clippy and tests of both mods, horizon-mods tests, both mods' settings pages in game.
2026-10-26 06:02:08 +01:00
Ludovic Marie 82deb28954 Merge main into feat/mod-ui-key
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:54:27 +01:00
Ludovic Marie e372fce7ab Merge branch 'feat/mod-ui-key' into feat/official-zoom-mod 2026-10-26 05:35:16 +01:00
Ludovic Marie 3e3c0cebb5 Mod keys: rows the game adds to the settings page, not a WIT widget
A new case in ui's widget variant stops every ui mod built before it from
loading: the runtime links a component only when each imported
function's types match exactly ("expected variant of 5 cases, found
4"), so the published FPS Counter and Keystrokes would break. Instead,
the game lists a mod's keys first on its page in Options > Mods, as Key
Binds rows, and a mod with keys gets a page even without ui. No WIT
type changes. docs/api/stability.md said a new case the mod sends isn't
breaking; it is, and now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:34:49 +01:00
Ludovic Marie d8aaf367eb Merge pull request #2013 from ludovic111/feat/mod-api-zoom
🤖 Agent: Mod API (experimental): render.set-zoom and input.claim-wheel, held mod keys let go when a screen opens, mod keys on mouse buttons. The consume choice is in stability.md. Verified: pr_ready (1300 tests), sandbox tests, in game 22/22 in-frame and on the server thread.
2026-10-26 05:12:07 +01:00
Ludovic Marie 0cb1d46393 Merge main into feat/official-hud-mods
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:09:45 +01:00
Ludovic Marie 53289d3565 Official mod: Zoom, the zoom extra as a mod
mods/official/zoom: hold the key (Z) to zoom in at the starting zoom,
the wheel changes it while held (x1.25 a step, 1.25 to 10), smooth
easing and slower turning as options. Same settings page as the extra,
with the key widget for the key. Built on render.set-zoom,
input.claim-wheel and ui's key widget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:08:36 +01:00
Ludovic Marie 2e05b11a4d Merge remote-tracking branch 'origin/feat/official-hud-mods' into feat/official-zoom-mod 2026-10-26 04:53:36 +01:00
Ludovic Marie 061ae61465 Merge pull request #1963 from ludovic111/feat/mod-api-extras
🤖 Agent: Mod API calls the official HUD mods use: render corner panels, text width and frame stats; input mappings and clicks per second; a ui button widget. Main merged in (after #1914's widget refactor). Verified: horizon-mods tests, clippy with and without mods, horizon-client tests (1121 lib), Keystrokes' settings page in game.
2026-10-26 04:45:01 +01:00
Ludovic Marie 7e4012c83e Mod API: a key widget, so players bind a mod's keys (ui, input)
A ui page's key widget shows one of the mod's keys as Key Binds does
("Zoom: Z"). A click waits for the next key or mouse button, which
becomes the key; Esc binds none. The game keeps the choice in
horizon-mods.txt (key.<mod>.<name>:key.keyboard.z), applies it when
the mods load and to keys registered later, and lets a held key go when
it is rebound. register-key's key is now the default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 04:41:12 +01:00
Ludovic Marie 2ae2e57c66 Merge pull request #1449 from ludovic111/chore/wasmtime-48
🤖 Agent: main merged into the branch (merge commit); verify passed on this head.
2026-10-26 04:19:14 +01:00
Ludovic Marie 6bbf40e345 Merge pull request #1753 from ludovic111/feat/structure-blocks-harness
🤖 Agent: structures stack brought up to date with main (merge commits), verify and parity passed on this head.
2026-10-26 04:13:52 +01:00
Ludovic Marie 980c619b81 Merge feat/mod-api-extras (with main) into feat/official-hud-mods
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 03:20:09 +01:00
Ludovic Marie 1e317cff5e Merge branch 'feat/mod-api-extras' into feat/mod-api-zoom 2026-10-26 03:19:44 +01:00
Ludovic Marie 50c54098ef Merge feat/mod-input (with main) into feat/mod-api-extras
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 03:13:27 +01:00
Ludovic Marie 48db367d4a Mod API: zoom the camera, take the mouse wheel (render, input)
render.set-zoom divides the field of view by up to 10, eased through the
game's FOV easing or at once, with a turning scale (at least 0.05); only
while playing, and the spyglass's own view wins. The strongest of several
mods' zooms counts, and the built-in zoom keeps working beside it.

input.claim-wheel takes the wheel from the hotbar while playing: its steps
are the mod's wheel events. That is the one input a mod consumes; its keys
never do (docs/api/stability.md). A screen opening now lets the mod's held
keys up, and mod keys bound to mouse buttons (key.mouse.4) are heard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 03:09:29 +01:00
Ludovic Marie b7b7cd6c50 Merge main into feat/mod-input: input beside command and render
Capability::ALL is 9 with Input; the SDK re-exports command and input;
the API reference is regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 03:09:13 +01:00
Ludovic Marie a9b5ca3936 Merge main: test beside main's new templates
The usage line, the docs and the website list `test` with main's
`new --template code|content`; the code template keeps tests/hello.toml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 02:08:41 +01:00
Ludovic Marie 07f1bcff68 Merge main: render beside main's command capability
Both add a Capability variant: the list holds 8 now. The SDK re-exports
both interfaces; the API reference is regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 02:02:00 +01:00
Ludovic Marie 48121cb109 Merge origin/main into chore/wasmtime-48
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 01:59:44 +01:00
Ludovic Marie 35e047fb8e Merge origin/main into feat/yung-port-as-written
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 01:59:00 +01:00
Ludovic Marie eec2e87a15 Merge main: command beside main's ui capability
Conflicts kept both sides: the capability list (now 7), the WIT, the
SDK's re-exports and docs, the mods state's fields, the workspace
members and AGENTS.md's macOS --exclude list. The API reference is
regenerated, and docs/api/stability.md lists `command` with the 0.1
preview interfaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:48:02 +01:00
Ludovic Marie fbd6bee3e3 Official mods: FPS Counter and Keystrokes, the first extras as mods
The FPS counter and keystrokes extras rewritten as mods on the public API
(render, input, ui, storage), in mods/official/, with the extras' options
on their settings pages and the extras' look: the same boxes, colours and
text positions, pixel for pixel. They are workspace members, so clippy and
pr_ready cover them; a maintainer publishes them in horizon-mods. The
built-in extras stay until the removal PR, which installs these for the
players who had them on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:08:55 +01:00
Ludovic Marie e3bd626688 Mod API: what the extras need as mods: corner panels, frame stats, mappings, buttons
The built-in extras become official mods; these are the calls the FPS
counter and keystrokes overlay need to look and behave the same:

- render.set-corner(corner, w, h, shapes): a box the game places with
  its own corner stacking (under the status effects, with the overlays
  and hud panels), clear-corner; text-width(text) in the HUD font
  (advances for U+0000..U+024F, 6 otherwise); frame-stats(): the game's
  FPS counter (fps, min, 1% low).
- input.mapping(name): a movement or click mapping's key label and
  whether it is held; clicks-per-second() for attack and use.
- ui: a button widget (200 x 20, select(id, 0)) for settings pages.
- The game keeps its FPS and click counters running while a mod runs,
  and refreshes the snapshot every frame for mods with a frame hook.
- The ui test guest gains /corner and /readings, with a sandbox test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 23:08:15 +01:00
Ludovic Marie fada660310 Mod API: capability input (experimental): claimed items' use, mod keys
- WIT `input`: claim-items(ids) makes the use button on those items the
  mod's: use-start, then use-stop with the ticks held (button up, item
  out of the hand, or a screen opening); the game does nothing else
  with the click. register-key(name, label, key) for up to 16 keys
  (key.keyboard.r), heard as key-down / key-up while playing; the
  game's own mapping on the key still runs. held(), poll() (256 kept).
- game/mod_input.rs: play_mouse asks mod_use first (local and remote
  windows), the tick ends a use whose item left the hand, the keyboard
  and horizon-ctl's key send the physical key to mod_key.
- No claim and no key, no cost: one check each.
- Experimental: the manifest needs experimental = ["input"].
- The ui test guest gains /input_claim, /input_poll and /input_held,
  with a sandbox test. Docs: mods.md, stability.md, the changelog, the
  regenerated reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:10:44 +01:00
Ludovic Marie 61c44c22ef Mod API: capability render (experimental): HUD shapes and camera shake
Mods draw through the game's own renderer, never their own shaders:

- WIT `render`: set-hud(shapes) with fill, quad (any four corners),
  sprite (the game's GUI sprites), item (scaled) and text shapes, up
  to 1024, kept until replaced; gui-size(); shake(strength, seconds).
- Drawn over the HUD after the extras, under chat and screens, hidden
  with F1 (game/mod_render.rs). Colours are 0xAARRGGBB.
- shake turns the view, not the player: jolts fade out squared, add up
  to 1, at most 3 degrees of yaw and 2 of pitch, scaled by Distortion
  Effects (screenEffectScale; 0 turns it off).
- Experimental: the manifest needs experimental = ["render"].
- No mod drawing, no cost: an empty iterator and an is_empty check.
- cargo horizon-mod check reports shakes and HUD shapes. The ui test
  guest gains /render_hud, /render_clear and /render_shake, with a
  sandbox test; HudBatch gets fill_quad.
- Docs: mods.md, stability.md, the changelog, the regenerated reference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 21:35:12 +01:00
Ludovic Marie 8b4336013a Merge pull request #1864 from socksprox/feat/mod-ui
🤖 Agent: thank you @socksprox! Merged after review (two follow-up commits on your branch: `ui` is opt-in through `experimental = ["ui"]`, and the Settings button now appears when a mod sets its page after loading), tests in game in-frame, on a server-thread window and as a LAN guest, and this head's verify.
2026-10-25 21:07:26 +01:00
Ludovic Marie 05396b4edf ui: experimental, opted into with experimental = ["ui"] in the manifest
docs/api/stability.md: a new API starts experimental, usable only by
opting in with a manifest field naming it. Capability ui now needs
experimental = ["ui"] beside capabilities; without it the manifest is
refused with that line to add. A capability promoted later stays
accepted in the list, so such manifests keep loading.

The ui test guest opts in; stability.md gets ui's row; docs/mods.md
shows the key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 20:57:10 +01:00
Ludovic Marie 3a35e147e5 Server mods run in the game: server thread, in-frame, LAN hosts, dedicated
The game that simulates a world now starts its server mods (API 0.3,
experimental): single player's server thread, single player in-frame
(beside client mods), a LAN host either way, and the dedicated server.
Windows that are clients of a server never run them.

game/server_mods.rs: tick_server_mods at the end of the tick diffs the
players (player_joined, player_left), delivers the tick's chat and block
events in order, then calls tick. Block events come from players' breaking
and placing (the acting player is the guest during as_guest); chat from the
local chat path and the hub's new HostEvent::PlayerChat; a guest's /command
reaches its mod before vanilla's dispatcher. tell and command replies go to
their player (the window's chat or a SystemChat); broadcast goes to every
player and the log.

--dev-mod now works on the server thread, and servers check a dev mod's
file once a second from their tick. Every hook returns at once when no
server mod runs; without the mods feature they are empty stubs.

Docs: docs/mods.md (where server mods run, when hooks run, not yet),
docs/api/mods.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 18:48:13 +01:00
socksprox af7a685b5c Mod API: capability ui — mod-owned screens and settings pages
New WIT interface `ui` (text, item and list widgets; open-screen,
close-screen, set-settings) plus a `ui-events` export (select, closed,
settings-opened), in a second world `horizon-ui-mod` so mods built before
it keep loading. The game lays out and draws the widgets with its own
menus' code: a screen the mod owns (Esc/Done to leave) and a Settings
button on the mod's Options > Mods row that opens its page.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-25 17:09:25 +01:00
Ludovic Marie ba4cf45aac cargo horizon-mod: content mods (new --template content, build packs assets and data, check takes no code)
- `new --template content`: a content mod with one block (Glowing Amethyst,
  copying vanilla's amethyst block) and its block state, model, item model,
  name, loot, recipe and pickaxe tag; `--template code` is the default.
- `build` packs the mod's `assets/` and `data/` (read and checked as the
  game reads them) beside the component; a folder without `Cargo.toml` is a
  content mod and needs no compiler.
- `check` takes a `.hmod` with no `mod.wasm`: "no code: content only,
  nothing to run" instead of the trial run, which refused it, so the
  registry can publish content mods.
- The guide (content mods, make a mod) and docs/mods.md, docs/api/mods.md
  say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 16:35:58 +01:00
Ludovic Marie bcd42f50e9 cargo horizon-mod test: server mods' scripts
A test script drives a server mod as a server would: join = "Alex" brings a
player in (ids stable per name, so a rejoin is the same player), as = "Steve"
picks who acts (the first player on otherwise), and player, chat, command,
break and place are that player's doing; leave = "Alex" lets them go. Server
expectations: told (every players.tell, "Name: text") and broadcast; feedback
and error read the reply to the player who typed the command. Ticks call both
kinds of tick hooks, so one script format serves client and server mods.

The welcome example gets two scripts (greeting, a newcomer announced once
even after a reload, /online across dimensions, /mined per player), run by
the sandbox tests with coords-hud's; docs/mods.md lists the server keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:55:55 +01:00