Commit Graph

80 Commits

Author SHA1 Message Date
Ludovic Marie 8ec47d6419 Merge remote-tracking branch 'origin/main' into feat/server-mods-world 2026-10-26 19:14:31 +01:00
Ludovic Marie 5f1c25c226 Merge pull request #2171 from ludovic111/feat/mod-run-quiet
🤖 Agent: merged main to resolve a conflict in game/remote.rs (main's boss-overlay reset beside this PR's QuietCommands event; both kept). Clippy with mods on is clean. Requeued at the new head.
2026-10-26 17:11:50 +01:00
Ludovic Marie 8bb27b44ca Merge origin/feat/mod-run-quiet into feat/server-mods-world; world at API level 4
#2171 takes level 3 (command.run-quiet), so the world interface's functions
take level 4. The workspace members keep main's horizon-hdr and this branch's
beacons example.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 16:51:29 +01:00
Ludovic Marie c5f9e3404c Merge remote-tracking branch 'origin/main' into feat/mod-run-quiet
# Conflicts:
#	crates/horizon-client/src/game/remote.rs
2026-10-26 16:49:16 +01:00
Ludovic Marie c3f5e9f79c Merge remote-tracking branch 'origin/feat/mod-run-quiet' into feat/server-mods-world
# Conflicts:
#	crates/horizon-client/src/game/remote.rs
2026-10-26 16:49:04 +01:00
Ludovic Marie 4fe648b674 Move the website to its own repository (ludovic111/horizon-site)
playhorizon.dev now deploys from the private ludovic111/horizon-site, which holds website/'s history. The files
its build still reads from here move out of website/:

- the design tokens to crates/horizon-theme/tokens.css (xtask tokens writes them, tokens_css_is_up_to_date checks them);
- the roadmap's JSON to roadmap/roadmap.json (tools/roadmap.py build);
- the benchmark fixtures to crates/horizon-telemetry-server/tests/fixtures/benchmarks/ (the site keeps a copy);
- the web icons to docs/media/brand/web/ (xtask icons).

pr_ready loses its website area and the tokens special case; rust_changes, the roadmap's links and every doc
that pointed into website/ follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 16:43:32 +01:00
Ludovic Marie aed8b571c4 Merge remote-tracking branch 'origin/main' into feat/server-mods-world 2026-10-26 15:46:47 +01:00
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 8fa967ac07 Merge remote-tracking branch 'origin/main' into feat/server-mods-game 2026-10-26 14:45:29 +01:00
Ludovic Marie 590ca775c2 Mod registry: download counts in the index and the launcher's browser
The registry's publish job (ludovic111/horizon-mods#7) writes each
project's `downloads` into index.json, summed from GitHub's counts of its
release assets every hour. `index::Project` reads it (absent: 0, never
written when 0, so older readers and the schema are unchanged).

The launcher's Horizon results show "12.3k downloads" like Modrinth's, and
list the most downloaded first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:37:12 +01:00
Ludovic Marie fb86430813 mods: command.run-quiet (API level 3), a batch of commands with nothing in the chat
A mod hands `run-quiet` a list of lines (at most 256 a call). In single
player they run as the player typing them would, with the player's source
made silent; on a Horizon server (it announces horizon:quiet_commands) they
go as one payload that the server runs the same way; on any other server
they fall back to chat commands, whose feedback shows. command.run is
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:30:23 +01:00
Ludovic Marie aea0df9770 Merge pull request #2122 from ludovic111/feat/native-material-stage
🤖 Agent: verified: pr_ready --quick green at this head, 33/33 affected harnesses pass locally, CI verify green, A/B shows no frame cost without a pack. A Horizon shader pack's material stage now colours terrain in the game.
2026-10-26 13:38:03 +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 68fa7714bb Merge remote-tracking branch 'origin/main' into feat/native-material-stage
# Conflicts:
#	docs/shaders.md
2026-10-26 12:48:15 +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 b12c89650e Mod API levels: server mods' players functions are level 1; the registry's lockfile
Main gained players.online, tell and broadcast (#1833) after 0.2.69, so
they take level 1 with render.set-minimap. horizon-mod-registry's own
Cargo.lock picks up wasmparser.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 11:46:27 +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 c813261574 Horizon shader packs: the material stage runs in the game
A pack's `fn material(input: MaterialInput) -> Surface` now gives the lit
colour of every terrain surface: sections and distant tiles, solid,
cutout and translucent, in both the instanced and the flat draws. Terrain
keeps Horizon's meshes, culling and draw lists; only its pipelines change.
Their shader is the pack's stage, a prefixed copy of terrain.wgsl's
terrain section, and entries that hand the pack the texture, the vertex
tint, the light levels and the lightmap's colour apart, then apply the
alpha test and fog as `fs_solid` and `fs_translucent` do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 11:35:15 +01:00
Ludovic Marie 6c995bfa15 Merge remote-tracking branch 'origin/main' into feat/mod-api-level
# Conflicts:
#	crates/horizon-mods/Cargo.toml
#	crates/horizon-mods/src/index/tests.rs
#	launcher/Cargo.lock
2026-10-26 11:09:19 +01:00
Ludovic Marie 88b7bfafc0 Merge pull request #1833 from ludovic111/feat/server-mods-0.3
🤖 Agent: merged main (12 files conflicted with ui, render and input). The runtime now keeps the server/client Hooks split beside the ui-events export, and the Snapshot carries both the GUI fields and the server's players. Locally: the horizon-mods sandbox and unit tests, cargo-horizon-mod tests, and clippy on the client with mods all pass. CI verify and parity pass at b90ab85f4. Bottom of the server-mods stack (#1837, #1894, #1895, #1901 follow).
2026-10-26 11:07:35 +01:00
Ludovic Marie 87ff54e702 Merge remote-tracking branch 'origin/main' into feat/launcher-shader-packs
# Conflicts:
#	docs/shaders.md
2026-10-26 10:40:12 +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 852e7cd524 Merge pull request #1855 from ludovic111/feat/native-shaders-registry
🤖 Agent: verified: pr_ready --quick green (launcher and horizon-mods tests), CI verify and check green, merges cleanly with main. The registry takes Horizon shader packs, checked by the game's own shader check.
2026-10-26 10:39:24 +01:00
Ludovic Marie 28ef79ed66 Merge pull request #1863 from ludovic111/feat/native-shaders-sky
🤖 Agent: verified: pr_ready --quick green, 80/80 affected harnesses pass locally, CI verify green, A/B shows no frame cost without a pack. A Horizon shader pack's sky stage now draws in the game.
2026-10-26 10:36:58 +01:00
Ludovic Marie 94d8130193 Merge branch 'feat/server-mods-game' into feat/server-mods-world
# Conflicts:
#	Cargo.toml
#	crates/cargo-horizon-mod/src/check.rs
#	crates/horizon-client/src/game/mods.rs
#	crates/horizon-mods/src/manifest.rs
#	crates/horizon-mods/src/runtime.rs
2026-10-26 10:04:52 +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 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 cad817c82d Horizon shader packs: the sky stage runs in the game
A pack's `sky` function gets vanilla's colour along each view ray and draws
where the vanilla sky dome draws, under the sun, moon, stars and clouds. The
pipeline's shader is the pack's checked stage (`CheckedStage::source`, new)
followed by a copy of terrain.wgsl's sky with every name prefixed
`horizon_sky_`, so none can meet a pack's; terrain.wgsl's `fs_sky` now calls
`sky_along_ray`, the same code as before.

A running pack is one `NativePack`: the frame every stage reads (written once
a frame), its sky and post stages and its pass timer. In a frame F3 times, the
sky draws in a pass of its own so the overlay can show its time; otherwise it
stays in the world's pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 08:42:57 +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 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 108ced5793 launcher: a Shader packs tab that installs Horizon's own shader packs
The Mods page gets a fourth kind, Shader packs, which searches Horizon's
registry and installs a `.hshader` into `shaderpacks/` once
`index::check_file` has run the game's own `horizon_shader_api::check`.
Modrinth and CurseForge answer that tab with a pointer to the registry:
their shader packs are the shaders/ format and are not offered.

The sample index lists a shader pack (`glow`, made with
`horizon-shader new` and `pack`), so the registry build, check_file and
the launcher's install are tested on a real file. A file of the same
name the registry didn't put in place is no longer called a mod.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:41:24 +01:00
Ludovic Marie cbdbf068bf Merge main into feat/native-shaders-registry 2026-10-26 06:59:07 +01:00
Ludovic Marie ee6dfd2b6c Merge pull request #2016 from ludovic111/feat/mod-ui-key
🤖 Agent: Players rebind a mod's keys on its Options > Mods page (the game's own key rows, saved in horizon-mods.txt), with no WIT type change, so the published mods keep loading. Verified with main merged: clippy, the client, mods and SDK tests, and the in-game check in both modes (24/24).
2026-10-26 06:50:11 +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 1aa6f21620 Horizon shader packs: the post stage runs in the game, with hot reload
A native pack named by HORIZON_SHADER_PACK (a folder with horizon-shaders.toml
or a .hshader in shaderpacks/) is checked, then its post passes run over the
world's own target, the one a shaders/ pack reads: no second target and no
extra pass, and without a pack the frame only tests one Option. The pack is
looked at twice a second; a saved file is checked and rebuilt in place, and a
version that fails is refused in the chat while the last good one keeps
drawing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 05:35:00 +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 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 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 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 c28bea8e96 Mod API: input's permission line says it sees keys and clicks
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:06:16 +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