43 Commits
Author SHA1 Message Date
bulkandClaude Opus 5.5 fab81be9ac Build every workspace crate against one rust-version
Members declared 1.85 to 1.95, or nothing. horizon-mods needs 1.95 and sits
under horizon-client-lib, cargo-horizon-mod and the launcher, so 1.95 is the
version the game really needs; the lower numbers promised builds that could
not happen. Set it once in [workspace.package] and inherit it everywhere.

The separately built workspaces (launcher, telemetry server, mod registry,
third_party) cannot inherit it and keep their own.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-07 01:14:44 +00:00
arismoko 616e855940 Share mod-owned generation and move dispatch tests to its crate
Delegate launcher trait, event and helper generation to horizon-mod-api-gen. Keep the old-source compatibility path, move dispatch fixtures out of xtask into an unpublished workspace member, and select launcher checks when shared generator code changes.
2026-11-03 02:31:27 +00:00
arismoko 9116ac3911 Generate the native mod API into Cargo OUT_DIR
Build every profile from the catalog, fragments and handwritten signatures. Keep xtask for filling handwritten placeholders, and stamping for catalog data. Stage launcher-owned declarations as build input, retaining shared injection validation for older source trees with committed generated traits.
2026-11-03 02:14:54 +00:00
Ludovic MarieandClaude Opus 5.5 35210289dd Merge main into #7584
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 23:25:07 +01:00
[email protected]andOpenAI GPT-6.1 Sol 2bca4a9fc2 test(mods): include category type in API generator fixture
Co-Authored-By: OpenAI GPT-6.1 Sol <[email protected]>
2026-11-02 18:36:38 +01:00
levzzzandClaude Opus 5.5 7b77a5ec98 Merge main into modapi/entity-handles
Took main's generated Host files and regenerated the mod API.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 21:41:52 +05:00
levzzzandClaude Opus 5.5 b21901f676 Native mods: entity and level handles, and an entity's position, type, UUID and level (#7387)
EntityRef (the world's open epoch and an entity id) and LevelRef (a
dimension), made from an event's id by Host::entity and Host::level. A
helper whose catalog entry names a receiver also becomes a method of that
handle, generated beside Host: entity.position(host) calls
host.entity_position(entity). First reads: position, block position,
rotation, type, UUID and level.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 20:50:56 +05:00
[email protected] 1d07a530d2 xtask: the generated-code stub knows FovPlayer 2026-11-02 16:22:37 +01:00
HrafnaValkyrjaandClaude Sonnet 5.5 f96c17a314 xtask: the mod-api placeholder test edits the catalog, not a stamped-away fragment
new_hook_placeholder_is_reported_then_filled read
tools/native-hook-fragments/native_item_damaged.json, which 48c63bc09
stamped into native-hooks.json. It now drops item_damaged's mod_api entry
from the copied catalog and expects the same error.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018zuDTsnyHkP28bzn3u7S3m
2026-11-02 09:36:51 -05:00
Ludovic MarieandClaude Opus 5.5 19419bea3d Merge main into #7227
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 14:37:43 +01:00
levzzz 050529f5c5 Merge remote-tracking branch 'hr/main' into fix6910
# Conflicts:
#	crates/horizon-client/src/game/native_hooks.rs
2026-11-02 18:06:14 +05:00
arismoko e21b51bf94 Merge remote-tracking branch 'upstream/main' into panic-mods
# Conflicts:
#	crates/horizon-client/src/mod_api.rs
2026-11-02 13:04:56 +00:00
arismoko 6fc2bd3256 A panic in a native mod's hook names the mod and the hook
The generated dispatch loops over mod_api::entered, which marks the thread as
inside each mod's hook while it runs; the crash handler adds "in native mod
<id>, hook <hook>" to the panic's message, and the panic goes on unwinding as
before. The launcher's generated executable passes the bundles' ids to
mod_api::name_mods when the revision has it. Dispatch still takes
&[Box<dyn Hooks>].
2026-11-02 12:37:42 +00:00
arismoko 0c9e0a3563 Merge branch 'main' of https://github.com/horizon-rust/horizon into v2/ses_01M6DYMGWF02H5RBZ0RFVQ78M9-test-host
# Conflicts:
#	crates/horizon-client/src/mod_api/generated_host.rs
2026-11-02 11:21:49 +00:00
Ludovic Marie d8a4a24930 Merge pull request #7044 from arismoko/v2/ses_01M6DMWRZSPA9JSD7HP0ZN2DNJ-de547a67e904
🤖 Agent: queued at 292df3c604. Host methods that forward to the existing native_play_sound/native_send_particles/native_on/mod_key/setting helpers, with no new game logic. One API-surface note: mod_api now re-exports crate::particles::{ParticleOptions, ParticleType}, so renaming a particle variant becomes a breaking mod-API change from here on. Merged with main; xtask mod-api --check passes.
2026-11-02 11:53:35 +01:00
Ludovic Marie 6d91fa6946 Merge pull request #6948 from Xmilon/native/item-stack-screen
🤖 Agent: queued at ff5551084a. Checked on a main merge: `mod-api --check` is clean, xtask's 19 tests pass, and `unittest discover -s tests` passes all 611. Taking `helpers` from fragments lets a helper wait for its API number with the rest of its fragment, and the stamper rejects duplicate names. `native_item_stack` passes `Some(String::new())` as the count, so the decorations draw no count, as the doc says. The helper runs only when a mod screen calls it.
2026-11-02 10:25:50 +01:00
[email protected]andCodex gpt-6.1-terra ff5551084a feat(mods): draw item stacks on screens
Co-Authored-By: Codex gpt-6.1-terra <[email protected]>
2026-11-02 10:15:45 +01:00
arismoko 99520e08ff Stub AnvilCraft in the mod API generator's test 2026-11-02 03:12:33 -06:00
breachatoandClaude Opus 5.5 5350241318 new_hook_placeholder_is_reported_then_filled compares with LF line endings
The generator writes native_hooks.rs with LF, so on a Windows checkout
(core.autocrlf) the refilled file never equalled the CRLF original and
the test failed. Compare both with LF.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 09:57:12 +01:00
levzzzandClaude Opus 5.5 60191c6b70 Native trade hook: each trade's own offer snapshot; xtask stub; docs
Event::Traded now carries the offer as notifyTrade left it, so a
shift-click whose trades level the villager up reports each trade's own
prices. xtask's mod API check gets a MerchantOffer stand-in.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 13:37:30 +05:00
arismoko df7afc32e9 xtask: let Host expose receiverless helpers as &self methods 2026-11-02 08:15:11 +00:00
arismoko 7906dcd4f4 Give every mod API Host method a default body that panics with its name 2026-11-02 08:14:30 +00:00
Ludovic MarieandClaude Opus 5.5 5aceab866a Let the mod API name ItemEnergyBuffer
Since #6253 the hook's types appear in the generated mod_api code, which
only sees what mod_api re-exports: the buffer is now public (a mod builds
it) and re-exported there, and xtask's test stubs it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 08:56:13 +01:00
Ludovic MarieandClaude Opus 5.5 6990936686 Name the tab-complete hook's Suggestion through mod_api
Generated mod API code is also compiled by xtask's test, which cannot see
horizon_command; mod_api now re-exports Suggestion and the test stubs it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-02 08:07:15 +01:00
arismoko c73dbb7b7d xtask mod-api fills new hooks' dispatch placeholders
A new `Game` hook can start with the placeholder body
`let _ = (every, parameter);`. Given its mod_api entry,
`cargo run -p xtask -- mod-api` replaces the placeholder with the
`mod_api::dispatch_<hook>` call, laid out as `cargo fmt` would; `--check`
reports it instead. A body that is neither the placeholder nor already
calls the dispatch is an error, named and never changed. Free-function
hooks stay wired by hand. Generated code is formatted for the
workspace's edition.
2026-11-02 04:30:29 +00:00
arismoko 0cc0fd1510 Mod API: client-library hooks through NativeClientHooks
`menu_slot_rules`, `living_breathe` and `ingredient` are free functions in
horizon-client-lib, which can't see the mod list. One `NativeClientHooks`
struct of callbacks, installed once from the executable's entry point as
horizon-world's `NativeLoadHooks` is, carries the three to their dispatch.
The generator resolves `horizon_client_lib::` targets (and the older
`horizon_client::menu` and `breathing` names) to the client source.

With these, every hook has a mod_api entry, and the check now fails
naming any hook without one.
2026-11-02 04:29:44 +00:00
arismoko 8d9a75e8ef Mod API: trait methods for every hook
Every hook in native-hooks.json and the pending fragments gets a mod_api
contract, so trait mods can answer each through `Hooks`. The generator
reads the fragments too, rejects duplicate names once, and the game's
hook bodies call their dispatch in one short form. Event types the
generated trait names are re-exported from `mod_api`, and horizon-world's
`NativeLoadHooks` gains loot functions and conditions.
2026-11-02 04:29:19 +00:00
arismoko 246f47f20d Hooks take one event struct
Each trait hook now takes its host, where it has one, and one
generated #[non_exhaustive] <Hook>Event holding the hook point's
arguments, as NeoForge's events do: a later version can add a field
without breaking any mod. A number or bool a mod may change is a plain
field, written back once every mod has run, even after a cancel; other
mutable arguments stay &mut fields. One event goes through every mod,
so each sees the changes before it. Cancel and replace outputs stay the
return value. Dispatch signatures and the native_* hook points are
unchanged. Trait injections get the same pattern, their bindings
becoming the event's fields.
2026-11-01 23:27:23 +00:00
arismoko d76b622eae The catalog's helper targets name the module that defines them
46 of 78 named native_hooks while the method lives in another game
module; the generator found methods by name anywhere and checked the
target only against two module names. It now records each method's
module and requires the target to match it.
2026-11-01 19:24:29 +00:00
arismoko 14aa71000a Merge upstream main (ff8e46848d)
# Conflicts:
#	crates/horizon-client/src/client_lib.rs
#	crates/horizon-client/src/entry.rs
#	crates/horizon-client/src/lib.rs
2026-11-01 19:17:20 +00:00
Ludovic MarieandClaude Opus 5.5 3dceebf36b Build horizon-ctl and the client examples from horizon-client-lib
old_world_e2e asked horizon-client-lib for the horizon-client binary, which
only horizon-client has; three e2e docstrings, the agent-control guide and
xtask's comment still built horizon-ctl from horizon-client.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 19:06:12 +01:00
arismoko 21a8f529c0 Mod API: renderer hooks and block-entity drawing
world_drawn and render_needs dispatch through an ordered RenderHooks
trait, which a mod returns from Hooks::render. The renderer list is
installed once beside the mod list and called on the render thread
while the frame is built. block_entity_submit and the existing
block-entity drawing helpers come through the generated trait and
Host, so a trait mod can draw its block entities without a mixin.
2026-11-01 17:52:28 +00:00
arismoko eb6b666426 Mod API: a generated Host for documented Game helpers
Trait mods had no way to call the game back. Host is generated from an
explicit `helpers` allowlist in native-hooks.json: each listed public
native_* helper becomes an object-safe method with the helper's
receiver and docs, implemented by forwarding to Game. Helpers whose
signatures use gameplay-private types or generics stay out, and the
docs list them with the reason.
2026-11-01 17:38:20 +00:00
arismoko 93b36334e2 Typed native mod API: a generated Hooks trait linked by the launcher
Native mods could only reach the game through mixins, so every build
patched the game's source. A mod can now implement
horizon_client::mod_api::Hooks instead.

The trait is generated from native-hooks.json. Each catalog hook gets a
mod_api contract (listen, cancel, replace or collect), and
`cargo run -p xtask -- mod-api` writes the trait methods and their
dispatch from the hook functions' own signatures and docs. Hooks keep
their exact receivers. Level hooks get read-only or mutable level hosts,
and library hooks (loot tables, default components) dispatch through a
set-once table that entry::main_with installs. Types that mods need move
out of the game into mod_api, which re-exports library types rather
than copying them.

The launcher links a bundle's [api] crate into a generated executable
that calls entry::main_with with every trait mod, in bundle order. A
build with only trait mods skips horizon-mixins. pr_ready runs
`xtask mod-api --check` when the catalog, the hooks or xtask change.
2026-11-01 17:38:20 +00:00
[email protected]andCodex 42a5981e94 refactor(client): isolate gameplay from the reusable client and probes
Keep native hook targets and source paths stable. Run gameplay tests in the gameplay library, and build ctl/probes from horizon-client-lib without gameplay. Update build/test selection and the fixed mixin-tool pin.

Co-Authored-By: Codex <[email protected]>
2026-11-01 12:05:47 +01:00
Ludovic MarieandClaude Opus 5.5 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 <[email protected]>
2026-10-26 16:43:32 +01:00
rdbtCVSandCodex f45e3f1237 Optimize launcher preparation with precompiled, batched exporters
Compile and validate original exporter bundles during release builds, cache development compilation, and reuse initialized JVMs and collision data during preparation. Keep legacy preparers compatible while current releases need only a Java runtime.

Co-Authored-By: Codex <[email protected]>
2026-10-25 23:11:23 +00:00
Ludovic MarieandClaude Opus 5.5 519ec1217c Server build: the game without sound or controllers, so Linux servers need neither ALSA nor udev
horizon-client's cpal output and its controllers (gilrs, the DualSense's HID output) move behind the
audio and controllers features, on by default, so the game is unchanged. Built with
--no-default-features it links neither libasound.so.2 nor libudev.so.1. release.yml packages that
build as horizon-engine in horizon-server-linux-x86_64.tar.gz (xtask package-server, checked by
check_imports.py --server); install.sh installs it on Linux (and --archive installs a local one);
horizon-server already prefers horizon-engine. The Dockerfile uses it too, and CI lints it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 20:17:21 +02:00
Ludovic MarieandClaude Opus 5.5 ed6af00ff8 horizon-server: install scripts, a Docker image, and boot services
- packaging/server/install.sh (Linux, macOS) and install.ps1 (Windows) install the latest release (or
  --version) from GitHub, check the SHA-256 GitHub publishes for it, and keep releases side by side:
  <dir>/current points at the one in use, so an update or a rollback is one link, and the game files
  prepared from the owner's Minecraft stay in <dir>/game-files across updates.
- packaging/server/Dockerfile builds the server and the engine; the prepared game files are mounted
  read-only, and the first start writes server.toml from HORIZON_EULA, HORIZON_WORLD, HORIZON_SEED,
  HORIZON_PORT, HORIZON_WHITELIST, HORIZON_PLAYERS and HORIZON_OP (`init` reads them too).
- `horizon-server service install|uninstall|print` writes and loads a systemd unit (user, or --system),
  a launchd agent, or a Windows task at logon. It runs the installer's launcher, so updates apply on
  the next restart.
- Releases build horizon-server and ship it beside horizon-ctl and horizon-prepare; PLAY.txt says how
  to run a server.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-16 20:20:09 +02:00
Ludovic MarieandClaude Opus 5.5 8dc2a0e90a Move the Discord brand assets to the kira repo; this repo holds the game, launcher and website
The Discord server banner (page + PNG), the server icon render and Kira's avatar (SVG master +
render) now live in the private kira repo (ludovic111/kira#1). xtask icons no longer renders them;
the brand README points there, and CONTRIBUTING states what belongs in this repository.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 14:23:14 +02:00
Ludovic MarieandClaude Opus 5.5 fcbbff26a7 Give Horizon a mark, and its icon everywhere
The mark is an H whose crossbar is the horizon: a violet line edge to edge, the stems above it
and their reflection below at a third, on whole units of a 16-unit grid so it stays sharp at
16 px. docs/media/brand holds the SVG masters (square icon, macOS tile, avatars, the mark for
light and dark backgrounds), the two alternatives that were shown with it, the GitHub social
preview and the Discord banner, and a README of what goes where and how to upload what only
Ludovic's accounts can.

`cargo run -p xtask -- icons` renders the masters (rsvg-convert) and packs, in plain Rust:
packaging/icons/horizon.ico and horizon.icns, Linux's hicolor icons 16–512 and the scalable
SVG, the game's run-time window icon, the avatars and the website's favicons.
packaging/linux has .desktop entries for the launcher and the game.

On Windows, build.rs embeds the .ico as icon resource 1 in horizon-client (and its tools) and
horizon-launcher (winresource, a Windows-only build dependency); gpui loads that resource as
the launcher's window icon. The game window sets the icon itself (X11, Windows) and names
itself `horizon` on Wayland so the desktop entry matches.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 00:08:40 +02:00
Ludovic MarieandClaude Opus 5.5 1a730659f0 Add a design system: one set of tokens for the launcher, menus and website
docs/design-system.md describes the new design language (after mkdir.directory: type as the
interface, numbered index lists with hairline rules, one violet accent, space instead of
borders, quiet motion, a faint wordmark) and its tokens, components, surfaces and mark.

crates/horizon-theme now holds the whole system: the two palettes (cool neutrals, light and
dark, each text colour checked against WCAG AA on every background by a test), the type scale
with web sizes, spacing, radii, rules, control heights and motion with CSS easing curves.
Instrument Serif is gone; display type is Geist at medium weight.

`cargo run -p xtask -- tokens` writes website/src/tokens.css from the crate, and a test fails
when the file is out of date. The launcher and the game's menus read the new names through
small adapters; the restyles follow in their own changes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 00:08:22 +02:00
Ludovic MarieandClaude Opus 5.5 842d11efc4 xtask package: the release folder in Rust, replacing packaging/package.sh
`cargo run -p xtask -- package BINARY OUTDIR` does what package.sh did:
OUTDIR wiped and recreated, the `git archive HEAD tools
mods/horizon/src/test/java crates/horizon-prepare research-lock.json LICENSE`
tree extracted (the tar read in Rust, executables kept executable), the client,
horizon-ctl and horizon-prepare copied (.exe beside an .exe, the same error when
one is missing) and PLAY.txt. release.yml calls it; package.sh is gone.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 18:16:20 +02:00