87 Commits
Author SHA1 Message Date
rdbt c96af77eb6 Merge pull request #11144 from xxaxio/fix/11082-linux-audio-buffer
audio: support HORIZON_AUDIO_BUFFER override for Linux buffer underruns
2026-11-06 21:17:13 +00:00
rdbtCVSandClaude Opus 5.5 cd99e67d1c Native client doc: macOS is a target too
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-06 20:35:11 +00:00
AxxioandAntigravity bfdff7afb6 docs/native-client: update stale platform scope note
macOS and Windows are supported platforms with dedicated documentation under docs/platform/. Replace the stale 'macOS and Windows are out of scope' sentence with a reference to docs/platform/.

Fixes #11145.

Co-Authored-By: Antigravity <[email protected]>
2026-11-06 14:36:19 +01:00
AxxioandAntigravity 89dc5664de audio: support HORIZON_AUDIO_BUFFER override for Linux buffer underruns
On Linux, Horizon asks ALSA for a 1024-frame fixed buffer to keep sound effects low-latency. When PipeWire is configured with min-quantum >= 1024 (common for Bluetooth audio or in VMs), the 1024-frame buffer repeatedly underruns with POLLERR and produces no sound.

Allow setting HORIZON_AUDIO_BUFFER=default or HORIZON_AUDIO_BUFFER=<frames> (e.g. 2048) to override the fixed buffer request and use a larger or system-default buffer. Document the environment variable in native-client.md.

Fixes #11082.

Co-Authored-By: Antigravity <[email protected]>
2026-11-06 14:21:51 +01:00
GabrielNichols 1a6a403884 fix(windows): avoid repeated firewall prompts in fixtures and launcher updates
Keep same-machine test sockets on loopback and stage launcher-managed games
at a stable executable path per game home. Preserve runtime dependencies and
protect running installed/native versions from replacement and cleanup.

Refs #9685.
2026-11-05 04:42:32 -03:00
ElyTheCat 76e92e12de Merge branch 'main' into perf/entity-occlusion-culling-pipeline 2026-11-05 08:05:40 +03:30
utophii a0cf173b1f fix(ci): address musl release review feedback 2026-11-04 22:41:13 +03:00
ElyTheCat 3ec390a6b8 Merge branch 'main' into perf/entity-occlusion-culling-pipeline 2026-11-04 21:14:37 +03:30
rdbtCVSandOpenAI Codex c25f708490 Merge main and remove remaining RAM limit features
Remove the hard allocation ceiling and glass launcher slider added since the original revert. Keep read-only memory diagnostics and unrelated upstream changes.

Co-Authored-By: OpenAI Codex <[email protected]>
2026-11-04 10:18:52 +00:00
ElyTheCat 946bfb559c Merge origin/main into entity occlusion culling pipeline
Keep the latest main particle culling and graphics settings alongside the shared synchronous and asynchronous entity occlusion path.\n\nCo-Authored-By: OpenAI Codex <[email protected]>
2026-11-04 04:41:47 +03:30
Ludovic Marie 1564656e02 Merge pull request #8548 from horizon-rust/fix/ramlimit-windows-no-paging
🤖 Agent: queued, verify and launcher green on 3f941752. CI never builds Windows, so the Windows-only code was checked separately: clippy -D warnings for x86_64-pc-windows-gnu is clean on horizon-threads (all targets) and horizon-client (with and without default features), with the C build scripts (mimalloc, ring) stubbed.
2026-11-03 21:28:52 +01:00
Ludovic MarieandClaude Opus 5.5 3f9417521f RAM limit: step down before the limit on Windows too, never page the game out
On Windows a RAM limit was a hard working set limit (SetProcessWorkingSetSizeEx
with QUOTA_LIMITS_HARDWS_MAX_ENABLE): Windows kept the game under it by moving
what it used least to the page file, and the game only stepped down once it
was already slow and faulting hard. Players saw a low limit make the game slow
instead of making it hold less (#6651, #6652).

Windows now does what Linux and macOS do: once a second the game compares its
working set with the limit and, past nine tenths of it, turns far terrain off
and lowers the render distance in use until it fits. The system cap, the page
fault pressure, the frozen-game check and the frame clock that fed it are
gone. The limit stays opt-in (no launcher value, no limit), and
HORIZON_MEMORY_HARD_MB is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-03 19:14:29 +01:00
gorkandClaude Code c85c4baf4a docs: tidy formatting in native-client
Co-Authored-By: Claude Code <[email protected]>
2026-11-03 18:29:07 +01:00
Ludovic MarieandClaude Opus 5.5 7a4507893d docs: what the hard memory limit counts on each system
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-03 02:47:10 +01:00
ElyTheCatandOpenAI Codex 37380065b7 Optimize async entity occlusion hot paths
Co-Authored-By: OpenAI Codex <[email protected]>
2026-11-02 22:34:15 +03:30
CocofireHD caa34071cd memory: a RAM limit that holds the process, not one that pages
HORIZON_MEMORY_LIMIT_MB caps the working set, and Windows meets it by moving pages out: at 512 MB the game still committed 2.2 GB here. HORIZON_MEMORY_HARD_MB (and /ramlimit hard) is a budget of the process's commit instead. The governor sheds far terrain and render distance against it, the allocator refuses what would pass it, and a game that cannot fit ends with a crash report or a message naming the limit rather than living in the page file.
2026-11-02 18:47:40 +01:00
ElyTheCatandOpenAI Codex a9a08ef1a6 Separate async entity occlusion rewrite
Isolate the entity occlusion cache and worker from particle visibility. Keep entity modes in the existing settings, submit inflated entity AABBs before model generation, and refine visible entities with their emitted bounds. Preserve fail-open handling and add async culling telemetry.

Co-Authored-By: OpenAI Codex <[email protected]>
2026-11-02 18:47:26 +03:30
CocofireHDandHermes Agent e589de1c48 F3 + S: dump the texture atlas to screenshots/debug
Vanilla's `KeyboardHandler` branch for `key.debug.dumpDynamicTextures` takes
`TextureUtil.getDebugTexturePath(gameDirectory)` (`screenshots/debug`), calls
`TextureManager.dumpAllSheets` and shows `debug.dump_dynamic_textures` with the
folder as a clickable link. Horizon bound the key and its action was a no-op.

`hud::dump_atlas` writes the atlas as `name.png` beside `name.txt`, as
`TextureAtlas.dumpContents` does: the PNG of the pixels and one line per
sprite, sorted by name, `%s\tx=%d\ty=%d\tw=%d\th=%d%n` in texels
(`dumpSpriteNames`). The file is `minecraft_textures_atlas_gui`, vanilla's
debug name for `minecraft:textures/atlas/gui.png` (`Identifier.toDebugFileName`
replaces `/` and `:` with `_`); Horizon packs the GUI, font, particle, map and
skin sprites into that one atlas, so it stands in for the atlases vanilla dumps
apart.

Fixes #7042.

Co-Authored-By: Hermes Agent (deepseek-v4.1-flash) <[email protected]>
2026-11-02 11:37:54 +01:00
ElyTheCatandOpenAI Codex 9c10104446 Optimize asynchronous entity and particle culling
Replace the collision-prone four-way visibility cache with a bounded sorted cache and validate repeated occlusion proofs through frame-local ordered lookup. Keep entity visibility conservative and off block entities, and add batched particle culling modes sharing the occlusion worker.

Add a reproducible benchmark note and screenshots for Sync and Async modes.

Fixes #6684

Co-Authored-By: OpenAI Codex <[email protected]>
2026-11-02 11:40:02 +03:30
rdbtCVSandClaude Sonnet 5.5 e7bdd16474 Remove the RAM limit
A soft limit that lowers render distance and then crashes the game is not
a cap, and only Windows could hold the game under a number at all. Takes out
the launcher's Maximum memory row, HORIZON_MEMORY_LIMIT_MB, /ramlimit, the
governor and the watcher thread (reverts #5800 and #5801). A Java instance's
-Xmx stays settable from the launcher CLI.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-11-02 00:48:32 +00:00
Ludovic MarieandClaude Opus 5.5 dea8e3b54c Merge main into the client library split
Ports main's lib.rs (block_edit, cit, lod_net, ram_limit, social_screen) into
client_lib.rs, main.rs's --player-dir logging and ram_limit into entry.rs, and
the horizon-optifine dependency into horizon-client-lib.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 19:02:57 +01: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
simonandClaude Opus 5.5 048a9276d8 The game can keep under a RAM limit
HORIZON_MEMORY_LIMIT_MB and /ramlimit cap the RAM the game holds. On
Windows a hard working set limit enforces it, so a low limit costs speed
instead of crashing. Elsewhere, and when the game is slow and faulting
hard, far terrain and the render distance in use step down and come back.
The game crashes with a report only if it can't run under the limit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-01 19:05:48 +10:00
Ludovic Marie 5595b0225f Merge branch 'pr3574' into pr3580 2026-10-31 17:51:32 +01:00
Ludovic Marie 7fcec44100 Merge remote-tracking branch 'origin/main' into pr3574 2026-10-31 17:51:31 +01:00
GIGABAIT93andClaude Opus 5.5 78db89ba16 horizon-prepare: --java-home, log the jar read, document named inputs (#3545)
- Merges #3574 (and with it #3567 and #3551) for docs/api/launch.md.
- --java-home names a Java the launcher manages (Options::java_home was
  there for horizon-launcher only).
- The import logs the client jar it read, which --client-jar may have
  named outside the Minecraft folder.
- named_asset_store_serves_the_asset_commands: with an empty Minecraft
  folder, an asset command fails without --assets-dir and copies from
  the store it names.
- docs/api/launch.md and native-client.md: the named inputs, that an
  earlier verified import is reused instead, the server jar rule (Horizon
  never downloads it; a launcher only for an owner), --java-home.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 15:31:26 +02:00
GIGABAIT93andClaude Opus 5.5 8311857928 docs: put --complete and --progress json back in native-client.md
The merge of #3567 into this branch dropped them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 15:29:19 +02:00
GIGABAIT93 8dbde815ba Merge branch 'feat/launch-api-client' into feat/launch-api-prepare-complete 2026-10-30 15:26:30 +02:00
GIGABAIT93andClaude Opus 5.5 6f0f282cf1 horizon-prepare: lock a folder while preparing, unstamp before writing (#3545)
- A preparation removes the stamp before it writes anything and stamps
  again at the end, so --check calls a folder being prepared, or whose
  preparation stopped, not current.
- Each preparation holds .horizon-prepare.lock in the resources and in
  root's .local (add_assets in the resources); a second one says it is
  waiting and waits. tools/prepare_output.py leaves the lock out of the
  digest.
- missing_extras is the one completeness check: --check and the
  launcher's COMPLETIONS both use it.
- The Java exporters and the worker run in root's .local, so vanilla's
  logs/ stays in the scratch, not where the preparer was started.
- --check's help and docs/native-client.md say what it doesn't test
  (contents) and that exit 1 is either gaps or "can't check".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 15:26:08 +02:00
Сидоренко Егор АлекчеевичandCodex 93f42ead5b Add independent opt-in Windows allocator build features
Expose Segment Heap manifest integration and mimalloc separately, with unchanged defaults and reproduction/PE validation instructions.

Fixes #4042

Co-Authored-By: Codex (GPT-6) <[email protected]>
2026-10-30 02:02:22 +03:00
Ludovic MarieandClaude Opus 5.5 4623d2e59f Merge main into this branch
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:18:33 +01:00
GIGABAIT93andClaude Opus 5.5 7f8c190b29 horizon-prepare: name the game files one by one (#3545)
--version-json, --client-jar, --libraries-dir and --assets-dir name
the files a launcher keeps in a layout of its own (instance folders,
shared libraries and assets), each replacing only what --minecraft-dir
would give; every file is still checked against research-lock.json's
pins. GameFiles gains the libraries and asset store folders, and
Options the Inputs (Default in the launcher, so it is unchanged).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:47:51 +02:00
GIGABAIT93andClaude Opus 5.5 82cf8916e2 horizon-prepare: --complete and --progress json (#3545)
--complete prepares, copies the sounds, then fails unless --check would
pass: one command for resources with nothing missing (without the sounds
step the game is silent, which is easy to miss).

--progress json prints one JSON object a line: {"message": ...} for each
log line, {"fraction": F} as each of the preparation's 18 stages begins
and at the end, {"error": ...} on failure. prepare_with_progress takes
the fraction; prepare keeps its signature, and a test keeps STAGES equal
to the stages steps() opens.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:39:47 +02:00
GIGABAIT93andClaude Opus 5.5 da7aa1f73b horizon-prepare: --output and --check (#3545)
--output DIR puts the prepared resources elsewhere than
<root>/.local/horizon-client/<version>, for preparing and for the asset
commands (sounds, panorama, fonts, packs, languages, now one add_assets
behind them); the exporters' scratch files stay in <root>/.local.

--check exits 0 when the resources are complete and current for this
preparer and 1 otherwise, printing each gap with the command that fills
it: the manifest's schema and Minecraft version, the OUTPUT_VERSION that
made them, and the extras the launcher completes (packs, panorama,
Unifont, languages, sounds). A preparation now stamps its resources with
its OUTPUT_VERSION (horizon-prepare.json), which the output digest
leaves out, so the stamp needs no new OUTPUT_VERSION.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:28:44 +02:00
Ludovic MarieandClaude Opus 5.5 dc943f95e8 Launcher: Play downloads and prepares Minecraft for an owner
An owner with no Minecraft on the computer no longer needs to find
"Download and prepare": Play on a version not prepared yet prepares it
(from the player's install when there is one, else downloaded from
Mojang for the signed-in owner, Java included) and then starts the game,
as the official launcher does. Without an owner Play stays off.

With no install found, the Resources row offers the download alone and
the Minecraft folder row says none is needed. The CLI's not-prepared
error and the READMEs stop asking for a local install and Java.

The download path itself (download_for_owner, mojang.rs) is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 20:51:58 +01:00
Kacpherek e0a48b3f66 Document the 2..128 render distance range 2026-10-28 05:56:49 +01:00
Ludovic MarieandClaude Opus 5.5 3063d87199 docs: Discord Rich Presence is live with the Horizon application
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 11:49:53 +01:00
Ludovic MarieandClaude Opus 5.5 15e46114a6 Discord Rich Presence: show what the player does, with a switch in Horizon Settings
Each frame the game hands the presence thread its status (menus; single
player, multiplayer or hosting a world with its party size; the
dimension; the game mode), and only a change wakes it. The switch
"Discord Rich Presence" (on by default, discordPresence in
horizon-extras.txt) sits beside Controller Settings. Dedicated servers
never start it. tools/discord_presence_e2e.py runs real games against a
fake Discord: title, world, Nether and quit on the server thread and
in-frame, a LAN host (both paths) and guest, the switch, and a Discord
started after the game.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 11:49:44 +01:00
Ludovic MarieandClaude Opus 5.5 042adc674a One menu style, vanilla's: Horizon's settings join vanilla's Options
Drop the Horizon menu style (options_horizon.rs, front.rs, the live title
backdrop and its post grade, the launcher's menu-style setting, CLI and MCP
tool). Every screen is vanilla's. Horizon's own settings hang off vanilla's
Options the way mods add theirs: Horizon Settings... and Mods... take the
Telemetry/Credits slots, and Horizon Settings opens Graphics, Advanced
Graphics, Shader Packs, Controller Settings, Extras and Mods, each a vanilla
options list with tooltips. Play with friends moves behind vanilla's Friends
buttons: the pause menu's opens Play with Friends (share, copy, stop), the
title screen's opens Join a Friend, and Direct Connection takes a full code.

Old files load as before: horizon.txt's menuStyle line and
horizon-graphics.txt's level line are ignored.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 21:06:51 +02:00
Ludovic MarieandClaude Opus 5.5 817a71ffa5 Clients keep the light the server sends; the server sends light updates
A remote client (a LAN guest, or the game on its server thread) threw away
the light in each LevelChunkWithLight and relit the column and its
neighbours itself. It now applies the sky and block layers as
ClientPacketListener.applyLightData does, and relights only block changes,
as vanilla's client does.

The hub now sends ClientboundLightUpdatePacket for the light sections that
changed in a column to the players for whom it is on the tracked border
(ChunkHolder.broadcastChanges), so light from blocks a guest doesn't track
reaches it.

horizon-ctl gains 'light X1 Y1 Z1 X2 Y2 Z2', and lan_e2e a 'light' check
comparing the guest's light with the host's.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-18 09:39:50 +02:00
Ludovic MarieandClaude Opus 5.5 0892f944c0 Agent control: wait for a state, and the log of what happened
wait-for screen NAME|widget ID|loaded|chat TEXT|event KIND replies once
the game gets there (--timeout, default 30 s, ends in an error of kind
timeout; --since SEQ counts chat and events from an earlier point), so
scripts and agents stop polling. events [--since SEQ] lists what
happened, oldest first, numbered: screens, chat lines, deaths, respawns,
items gained or lost, dimensions, worlds opened and closed. The state is
compared once per event loop turn and only under --control, so watching
never changes the game. respawn now says when the death screen's button
is not active yet instead of clicking it to no effect.

horizon-ctl and its MCP gain both; tools/agent_control_e2e.py gains an
events scenario.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 14:51:30 +02:00
Ludovic MarieandClaude Opus 5.5 1a067b3d9e Agent control: read and set every option by key
options-get [KEY...] gives every options.txt option by its vanilla key
with its value and what it accepts (type, range, step or choices; enums
by name, key bindings as key.keyboard.w). options-set KEY VALUE sets one,
applies it at once and saves options.txt as the options screen does
(language and resource packs reload too); a value the option refuses is
an error naming what it accepts, and the option keeps its value. After a
set, ui reads the redrawn screen.

horizon-ctl and its MCP gain both; tools/agent_control_e2e.py gains an
options scenario.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 14:38:20 +02:00
Ludovic MarieandClaude Opus 5.5 8c5d1ed86b Agent control: the widget tree of every screen, click and set by id
`ui` lists every widget the last frame drew (title menus, pause, options
in both menu styles, inventories and menus) with an id, its kind, label,
bounds and value; `click ID` clicks one through the same window events
as the mouse, `set ID VALUE` moves a slider along its track. Ids come
from labels (FOV: 70 is fov), world/server/language rows carry their
names, Horizon switches, sliders and segments their row's caption, and
inventory slots are slot-ID with their stacks. After a click, the next
widget command waits for a redrawn frame.

horizon-ctl and its MCP gain ui, click and set, and launch --offscreen.
tools/agent_control_e2e.py gains a ui scenario and runs offscreen on
macOS; both scenarios now handle Singleplayer opening Create New World
when there are no worlds.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 14:08:15 +02:00
rdbtCVS aab88753b6 Keep title panorama optional during full resource preparation 2026-10-14 19:15:16 +01:00
rdbtCVS eebf5621bf Fix classic menu panorama resource preparation 2026-10-14 18:54:51 +01:00
Ludovic MarieandClaude Opus 5.5 8355a6ff14 horizon-prepare sounds: the sound copy in Rust, run by the launcher
tools/fetch_sounds.py (and the lab.py functions it used) becomes
`horizon-prepare sounds` (horizon_prepare::sounds): the pinned asset index,
sounds.json and every .ogg from the player's own launcher install, each SHA-1
checked, into .local/horizon-client/<version>. The launcher runs it as part of
Prepare (in-process, the version's own binary when its sources differ and it
knows the subcommand, in-process for older versions), and a launcher install
without the assets only logs that the game will be silent. Player docs no
longer mention Python for sound.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 18:10:34 +02:00
Ludovic MarieandClaude Opus 5.5 66c6bd6b13 F3 + C writes a crash report
The debug crash from #90 printed a stand-in report; it now ends the game
with a DebugCrash error that main reports as "Manually triggered debug
crash" with the stack where it was raised. The game keeps the error that
ends it as an error, not a string, so main can tell. Leading std backtrace
frames are dropped (macOS keeps them).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 17:15:20 +02:00
Ludovic MarieandClaude Opus 5.5 1569572ba0 Game logs and crash reports; launcher crash notice; logs in the CLIs and MCP
The game writes logs/latest.log in its home like vanilla's log4j config
(client-1.21.2.xml): [HH:mm:ss] [thread/LEVEL]: message, rolled at start and
at midnight to logs/<date>-<n>.log.gz, seven a day. Messages go through the
log facade and still print their old text on stderr.

A main-thread panic or a fatal error writes
crash-reports/crash-<date>_<time>-client.txt (error, stack, Horizon and
Minecraft versions, OS, CPU, memory, GPU adapter, render settings, resource
packs, world, last 50 log lines). Development builds crash on purpose with
HORIZON_DEBUG_CRASH.

The launcher shows "Horizon crashed" when the game it started ends badly,
with Open report, Copy report, Open logs folder and Report on Discord;
Settings gets a Logs row. horizon-launcher logs and horizon-ctl logs
(--lines N, --crash) print the log's end or the newest report, and both MCP
servers have a logs tool.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 16:58:35 +02:00
Ludovic MarieandClaude Opus 5.5 a995fd3b46 Prepare with horizon-prepare: launcher, release folders, messages and docs
The launcher prepares a version in-process when it ships the preparer sources
the launcher was built with, with the version's own horizon-prepare when they
differ, and with the Python script only for versions made before it. Release
folders ship horizon-prepare and its sources; resources are reused between
versions with the same preparer. The game's messages, PLAY.txt, the docs and
release builds name horizon-prepare, and tools/prepare_native_client.py is a
wrapper of it for the development tools.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 16:29:33 +02:00
Ludovic MarieandClaude Opus 5.5 6716b0d953 Docs: agent control with horizon-ctl and its MCP server
README gets an Agent control section (out of the roadmap: it's done), the
native client guide describes every command group, the blocking semantics,
exit codes, launch discovery, MCP and the two transports, and PLAY.txt tells
release players about horizon-ctl.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 21:59:35 +02:00