🤖 Agent: rebased on main e0798a4224 (main made cosmeticsOthers optional in Extras::serialize; the crosshair keeps main's string and appends the pvp lines). Desktop: clippy -D warnings and rustfmt pass on the stack's top; before this rebase pr_ready passed 3946 tests on this commit (fails: main's 4 gfx:: clear_budget GPU tests on lavapipe, which CI passes, and NixOS's missing uname in a Python install.sh test). CI verify green on this head. Off by default; the crosshair mask is rebuilt only on a settings change.
🤖 Agent: verified b5c41f4 on playhorizon (launcher fmt, clippy -D warnings, 51 native_mods tests; the new test fails before the fix) and CI is green. Only the one-line form of horizon-mixins' diagnostic changes: it leads with mod_id (injection_id) when the tool names one; E_MODULE_CONFLICT carries no mod_id and reads as before.
🤖 Agent: opening a rolled chest now also drops `LootTable`/`LootTableSeed` from its saved source compound, so an emptied chest no longer re-rolls after a reload; `consume_container_loot` touches nothing when the chest had no rolled marker. The 576 harness cases vary seed and table, but the result never depends on either: three modes would cover the same thing. Proven in our union run (client tests, desktop).
🤖 Agent: entries 11 (`DATA_ID_CUSTOM_DISPLAY_BLOCK`, optional block state, 0 = none) and 12 (`DATA_ID_DISPLAY_OFFSET`, default from the kind) now reach clients and are read back, so single player and vanilla servers show a cart's DisplayState. One gap noted in your body and left for later: `default_display_offset` gives 6 for a chest cart where 26.3's `MinecartChest` says 8. Proven in our union run (client tests, desktop).
🤖 Agent: `AdvancementRewards.grant`'s function now runs as the player with suppressed output and GAMEMASTER permission, and restores the outer callback so a reward's `return 9` can't replace the grant command's result. We merged main so your group runs after #9288's bell group in the corpus; verify is green on that merge.
Horizon Settings > PvP & HUD... is a new page of options a PvP player sets, all off by
default (docs/pvp.md). The first is the crosshair: shape (cross, T, X, circle, square,
dot), size, gap, thickness, colour (inverted as vanilla, or solid), outline, centre dot,
and another colour over a living entity (vanilla's crosshairPickEntity). Its first
settings draw vanilla's 15-pixel cross; the attack indicator stays vanilla's.
The pixels are worked out once per settings change (CrosshairCache), so a frame only
adds their quads.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A player's native build on 2026-11-04 failed with "horizon-mixins failed
(exit status: 1)" on Horizon 998b1d8, the commit fast_items 0.1.0 pins.
fast_items applies there; built together with a mod made for an older
Horizon (14 of the 72 registry native mods don't apply at 998b1d8, among
them appleskin, flair, mod_menu and freecam), the other mod's hook target
is gone. The diagnostic named that mod only deep in a file path. It now
leads with the mod and its injection: "appleskin (hud): E_TARGET_NOT_FOUND".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: caps `parse_nodes` recursion at 128 where `execute … run` redirects to the root, so the 400-deep chain from #9252 fails to parse instead of overflowing the server thread; the 400-deep test would abort the binary without it. Chosen over #9320, which capped execution only. Nothing else found.
🤖 Agent: attachment now uses the entity-context collision shape (`entityCanStandOnFace`), so soul sand only takes a shulker under it and scaffolding follows the shulker's height. We pushed a89eb944c, a full-cube fast path, because `canStayAt` runs every tick per shulker. Proven with the client tests on a union with main (desktop).
🤖 Agent: the dismount on teleport matches `Entity.teleport`'s `stopRiding()`. We pushed 23a886d93: a relative yaw is a delta in vanilla's transition, so riders turn by the vehicle's turn either way, and `facing` leaves them unturned. The ignored rider game test passes on a union with main (desktop), with clippy and the client tests.
🤖 Agent: mobs now stop a dragon fireball and take its breath, through the lingering clouds' `cloud_affect` path (undead healed). We pushed 01634eab6 so the per-tick End scans gather mobs only while a fireball or breath cloud exists. Proven with fmt, clippy and the client tests on a union with main (desktop).
🤖 Agent: merging. The row button takes the detail card's own checks (installed, checking, busy, support.installable) and calls the same mods_install with the known project, so native-mod consent still comes first; stop_propagation keeps the click from selecting the row. Proof: union with main, #9198 and #9314: launcher fmt, clippy -D warnings and 492 launcher tests pass.
🤖 Agent: merging with one change. The client tick now emitted the arrow's hit, splash and extinguish sounds and played them, but Entity.playSound passes no player to Level.playSound and ClientLevel.playSeededSound plays only for its own player (26.3 bytecode), so the server's packets already play them: every arrow hit sounded twice. tick_client now drops its Sound events after the tick, so the random draws stay in vanilla's order; the new test fails without it. The rest matches AbstractArrow.tick: the whole startFalling/tickDespawn branch is inside !isClientSide. Proof: union with main, #9198 and #9328: fmt, clippy -D warnings, Python tests and the client and client-lib tests pass; arrows tests pass on this head.
🤖 Agent: merging. Zombie.convertVillagerToZombieVillager and ZombieVillager.finishConversion send level events 1026 and 1027 only when not silent, and handleEntityEvent(16) draws volume before pitch, as here. I merged main and put 1026/1027 into main's new level_event_except (no excluded player, like the other null-player level events), and gave the probe's hand-built MobType main's new item_stack_limits field. Proof: union with main, #9314 and #9328: fmt, clippy -D warnings, Python tests and the client and client-lib tests pass; CI parity runs the new zombie_cure_sound harness.
🤖 Agent: bells now tick on the headless server before the renderer guard, matching `BellBlockEntity.serverTick`/`makeRaidersGlow`. Small cost to know: while any bell is in `be_anims.bells` the raiders tag set is cloned each tick, and server bells stay in the map until their block changes. Proven with the client tests on a union with main (desktop).
🤖 Agent: `summon` now goes through `server.call` + `in_owner_level` like `mobs` already does, so the mob ticks on the server thread and reaches the window through the tracker; the default position is computed from the window's own player first. Nothing else found.
🤖 Agent: `self.dim == Dim::End` is the level being ticked (levels swap per dimension), so a summoned overworld dragon now gives 500 and builds no exit portal, as `EnderDragon.tickDeath` with no `dragonFight` does; the new harness checks it against a vanilla server. Nothing else found.
🤖 Agent: matches `Dolphin.tick` on a client (NoAI return, in water, lengthSqr > 0.03, four particles at ±0.3 of the yaw, one `1.2 - nextFloat()*0.7` draw a tick from the mob's own random). It runs only on the window's copies, so the server's random sequence is untouched. Nothing else found.
🤖 Agent: matches `SpellcasterIllager.customServerAiStep` (Illusioner has no override) and `IllusionerBlindnessSpellGoal.performSpellCasting` blinding any LivingEntity target. One gap left: `EffectMob` carries no source entity where vanilla passes the illusioner; it only matters for effect attribution. Proven with the client tests on a union with main (desktop).
🤖 Agent: `Marks` keys each mark by item id, the catalogue's hash and the window scale, and hands every replaced image to `drop_image` once per frame next to `sky.free_replaced`, so the atlas stops growing on redraws; the tests cover reuse, a scale change and a new file. Nothing else found.
🤖 Agent: Ludovic decided on 11-04 to remove Horizon's RAM limit, so this goes in. A correction: earlier agent comments here said he had decided to keep the opt-in limit. That was wrong; he never decided that. One concrete point, checked: a Java instance's -Xmx stays settable in both layouts. Classic: main.rs:3281 renders memory_row when not glass, and memory_row returns None for non-Java instances (launch_page.rs:250). Glass: the Edit dialog renders glass_memory_row (glass_instance.rs:678), and memory_instance filters to Java instances. java_launch.rs:427 still passes -Xmx{memory_mb}M. Our 13:57Z review was wrong about this. I merged main (d571d80a06) and found no stale HORIZON_MEMORY_*, /ramlimit or lang keys. Proof on playhorizon: fmt; clippy -D warnings on client/client-lib/render/threads (default) and on horizon-client with --no-default-features; the server build with --no-default-features; tests for threads 17, client-lib+render 2693, client 878; the launcher's fmt and clippy, plus 571 launcher tests. Thanks rdbtCVS.
Entity.playSound passes no player to Level.playSound and
ClientLevel.playSeededSound plays only for its own player, so the
client's copy of an arrow plays no hit, splash or extinguish sound;
the server's sound packets carry them. Playing them as well doubled
every arrow hit in single player and on servers.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- game-build.yml and launcher.yml: the windows-arm64 matrix entries are
continue-on-error, so the sign and publish jobs that need them still run.
- nightly-build.yml: horizon-windows-arm64.zip goes into SHA256SUMS and the
Nightly only when it was built; otherwise a ::warning:: says it is left out.
- launcher.yml: the release warns when the ARM64 zip or setup is missing (its
sign and publish steps already take dist/horizon-launcher-* by glob).
- Test: an ARM64 launcher skips a launcher release without its own zip and
never takes the x64 one (launcher_update_from).
- actionlint: windows-11-vs2026-arm is GitHub's image, newer than its label list.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: a player with no cosmetics and no saved choice now sees none on others and the game never asks the service about them; owners see them as before, an explicit choice wins. Proof: a gameplay test against a fake service (non-owner sends no request), 27 cosmetics + 78 render + 9 wardrobe tests and clippy -D warnings green on the desktop.
🤖 Agent: ten merged fragments numbered through API 409 by the repo's own stamper; the workflow now warns instead of failing, because the setting that lets Actions open PRs would also let it approve them.
The native hook stamp workflow has failed since 14:35Z: the repository
doesn't let GitHub Actions open pull requests, so ten merged fragments
stayed unnumbered. This stamps them on current main with
tools/stamp_native_hooks.py, and makes the workflow leave a warning
naming the pushed branch instead of failing, since enabling that
setting would also let Actions approve pull requests.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A player whose account owns no cosmetic now sees a vanilla game by default:
no cosmetics or name tag styles on other players, and the game never asks
the service about them. An owner keeps today's behaviour, and an explicit
choice in the settings or the Wardrobe always wins (CONTRIBUTING.md:
Horizon-only features that change the look are off by default).
- prefs: `cosmeticsOthers` has no line until chosen (`Option<Others>`,
`Others::effective(chose, owns)`); ownership kept per account in
`cosmetics-owned.txt`.
- account::owns: `GET /v1/me` with the same Mojang-join sign-in as
Show my cosmetics.
- game: asks once a run (last run's answer first), retried with the
existing backoff; one sign-in at a time; the button shows the effective
value and pressing it stores a choice.
- launcher: the Wardrobe (visible to everyone, unchanged) shows the
effective value and notes the account's ownership for the game.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: matches Breeze.isInvulnerableTo (source.getEntity() instanceof Breeze, the owner for projectiles); main merged (trident/bee conflicts taken from main plus attacker_species, and main's new damage_type test literal filled in). The older wind-charge special case in game/wind.rs now duplicates breeze::accepts_damage: follow-up. verify green at this head.
canStayAt runs every tick for each shulker; the prepared collision table
gives full cubes the canonical Shapes.block() identity, so skip the face
shape and XOR join for them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
scene.rs keeps Backdrop::new's tint-at-read and the box blur, with upstream's
"no float blur while the blur is 0". launcher/lang/*.json take upstream's
tables and get the two Performance mode strings at the top again.
TeleportCommand passes a relative rotation as a delta, so
calculatePassengerTransition's 'add 0' still turns each rider by that delta
from its own angle: the rider keeps its angle to the vehicle either way.
Without a rotation argument, and with facing, the transition's rotation is
Relative.ROTATION with no delta and the riders do not turn (LookAt turns
the target alone). Replace the per-axis relatives with that one flag, and
turn riders from the angle before the vehicle's pitch clamp.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: a lectern with no book now reads page -1 as vanilla's Mth.clamp(page, 0, pageCount - 1) gives (the PR first had 0); the lectern test passed on playhorizon, and this head only merges main.
tick_end runs these every tick in the End, where hundreds of endermen can
live; with no dragon projectile there is nothing to hit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: added one guard: the open menu's mouse-down-out closes it on the same press, so a right click on the open row reopened it instead of closing it; the handler now skips that press as the ⋮ does (menu_closed_at). Desktop launcher run at this head: fmt, clippy -D warnings, all tests 0.
🤖 Agent: the location pointer now follows a symlinked ~/.config (it used to error on every start for those players); the data roots still refuse links. verify and launcher are green on this head, and launcher fmt/clippy/tests pass on Linux.
launcher/lang/*.json take upstream's tables and get the two Performance mode
strings at the top of each, so later additions at the end of upstream's tables
no longer conflict.
Prefer DirectX 12 for Auto on Windows ARM64 while preserving Vulkan as an option. Keep launcher updates on the process architecture, select game assets for the native machine with an x64 fallback, and preserve x64 native-mod builds under emulation.
🤖 Agent: the Cull wrapper now pads each row by `gap`, so the mods, modpack-report and project-version lists (gap 8, rows without a margin) finally get their spacing, while the release and notes rows drop their own mb so nothing doubles; radius::CONTROL/ROW equal the old 10/12 px literals, so the field corners don't move. Launcher clippy -D warnings and 476 tests green on this head.
🤖 Agent: #[serde(other)] Unknown lets /v1/shop and /v1/me answers with a state a newer service adds still parse, so the Wardrobe's top-bar check (shop::shown, which reads open and the dates, not the state) keeps working; the test covers all three answers and the on-disk round trip.
🤖 Agent: item_cached now refuses an id or hash outside 1-64 of [A-Za-z0-9_] before touching the disk or the service, the rule horizon_cosmetics::fetch already applies, so a catalogue entry like ../x can't read or write outside the cache folder; the traversal test also checks that no request was made.
The open menu's mouse-down-out runs on the same press and closes it first,
so the row's right-click handler saw no menu and reopened it. Skip that
press, as the ⋮ does with closed_by_this_press.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: merging. Horizon-only keys go out with `translate_with_fallback` from en_us, so vanilla clients on a Horizon server still read English instead of a raw key. Proof: on this head (main merged in; the conflict was only both sides adding tests or keys next to each other), rustfmt, Python tests, clippy -D warnings and the horizon-client and horizon-chat-filter lib tests (873 + 17) pass.
🤖 Agent: docs only, follow-up to #9308 (merged at its first head): labels the 2026-11-04 Mac mini reports 'offscreen, not comparable', since Horizon offscreen against a windowed vanilla isn't a fair pair; checks green at 2f8c8ddab.
🤖 Agent: merging. `/loot insert` now asks `canPlaceItem` through the hoppers' `Containers::can_place`, so loot can't land in a furnace's result slot, matching LootCommand.distributeToContainer. Proof: on this head (main merged in: the source check now sits before main's new command_slots, and the corpus keeps this group), rustfmt, Python tests, clippy -D warnings and the horizon-client lib tests (873) pass; CI parity runs the item block containers group.
🤖 Agent: merging with one change, from the 26.3 client's bytecode: AbstractBoat.interact answers SUCCESS (a swing) unless sneaking or out of control, and doesn't check for room on the client (only the server's startRiding does); AbstractChestBoat passes only out of control, not sneaked at, with room. Minecart.interact is the one that answers CONSUME. Paintings and item frames were right. Proof: on this head (main merged in; the conflict was only both sides adding tests or keys next to each other), rustfmt, Python tests, clippy -D warnings and the horizon-client and horizon-chat-filter lib tests (873 + 17) pass.
🤖 Agent: finishes #8632 (GabrielNichols): native build cache strings in all 85 launcher tables (inserted at the top so main's appends don't conflict), a build refused only while the cache is busy, launcher reference regenerated; also native cache locks are now unlocked before closing, since a child spawned meanwhile kept them taken (flaky Busy; new test fails without it). Desktop run at this head: fmt, clippy -D warnings, all launcher tests 0.
🤖 Agent: merging. I moved the plunge off the level random: FishingHook draws it from `syncronizedRandom`, reseeded every tick from the UUID and the game time, and an extra level draw shifts every later one out of vanilla's order. It is also computed in float, as Mth.nextFloat does. rdbtCVS's agent then shared the helper with remote hooks. Proof: on this head (main merged in; the conflict was only both sides adding tests or keys next to each other), rustfmt, Python tests, clippy -D warnings and the horizon-client and horizon-chat-filter lib tests (873 + 17) pass.
🤖 Agent: The padding follows the Mipmap Levels option through `mipmap_option`, which starts at 4 until `set_mipmap_levels` runs. A pack loaded before the option is applied stitches with 4 levels' padding once. Minor. I pushed cddb5526: merged main after #9059 landed (clean). Proof: main + this head + #8433: fmt, clippy -D warnings (render, shaders, client; all targets) clean; `gfx::pack` tests 92 pass, the 4 failures are `clear_budget_tests`, which fail the same way on plain main.
🤖 Agent: Items and primed TNT now end their move with `getBlockSpeedFactor`, through #8096's shared helpers, and a no-physics item skips it as vanilla does. Cost: one extra block-speed lookup per item per tick, a farm's whole item count; vanilla pays the same. I pushed ef4e5c04: merged main and gave the soul sand/honey TNT test main's new `PrimedTnt` fields (`rotation` from #8667, `block_state`), without which it no longer compiled. Proof: main + this head + #9060: fmt, clippy -D warnings (client, client-lib, render, shaders; all targets), horizon-client + client-lib tests 0 failed (1666 + 862).
- Self-update, game installs and native-mod toolchains follow the running
launcher's architecture again (std::env::consts), not IsWow64Process2's native
machine: an x64 launcher on an ARM64 PC stays x64, so an update never swaps a
working emulated setup for an untested ARM64 window. The ARM64 launcher comes
from horizon-launcher-setup-arm64.exe.
- The ARM64 launcher installs the x64 game (under emulation) from a release
without an ARM64 build, and checks that file's signed checksum
(GAME_FALLBACK, asset_installed). Same fallback in horizon-server's updater
and packaging/server/install.ps1, so ARM64 installs keep working before the
first Nightly with an ARM64 archive.
- ci.yml's windows-arm64 job runs by hand only: GitHub's runner queue is full,
and main's checks runs gate the releases. The Nightly and launcher releases
build the ARM64 archives every run.
- launcher.yml: the ARM64 smoke test accepts the x64 fallback's PE machine; the
macOS-only version check keeps python3.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The pointer, its lock and the startup check went through `checked_path`, which
refuses any link on the way. A Linux player whose ~/.config (or home) is a link,
as dotfiles managers and Silverblue make it, got "Could not open the data folder"
at every start without ever moving data, and "Use the default folder" could not
clear it. The pointer is never copied, so its path now follows links
(`pointer_path`); the data roots still refuse them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Horizon ran offscreen (no presenting) while vanilla drew into a window, so the Mac rows are not a fair
comparison; the website keeps the Mac mini's 2026-10-22 runs. The reports stay as a record, labelled.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The lang tables merged by key: main's keys (with #9286's shop changes) and
this branch's 14 data-move strings.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: data only (9 perf_bench reports + a note under benchmarks/perf); checks green at be11ce8db. One point: the Mac rows are offscreen and both machines were loaded, as site-2026-11-04.md says, so don't read them as clean ratios.
🤖 Agent: merging. `shutil.which('keytool')` first, then `$JAVA_HOME/bin`, fixes the harness under the parity shim's stand-in java (the env-only management_protocol failure on playhorizon). Proof: union with main: Python tests pass, including the three new keystore tests.
🤖 Agent: merging. One `ZipArchive` for all declarations turns the check from declarations × central-directory reads into one read; `Source` is cloned only to free the borrow of `self` (a PathBuf). Proof: union with main: fmt, clippy -D warnings and horizon-mods tests pass.
🤖 Agent: merging with changes. Main meanwhile took food and shears on the client in remote_mob_takes, matching the 26.3 bytecode (Animal.mobInteract and Sheep.mobInteract answer CONSUME there; only the server checks canFallInLove and readyForShearing), so I merged main and kept its version. What this PR still adds is the dye rule, now `sheep_takes`: DyeItem.interactLivingEntity takes a living, unsheared sheep of another colour and passes otherwise; the isSheared test is mine. Left for a follow-up: the caller swings for CONSUME answers too, where vanilla swings only on SUCCESS. Proof: on this head, rustfmt, clippy -D warnings on horizon-client and its remote_mob_use tests (5) pass.
🤖 Agent: merging. The guest path (`drop_guest_items`) took no random draws before and now takes vanilla's four per stack from the level random, so later level draws shift as in vanilla. Vanilla draws from the entity's own random; Horizon keeps the level's in all three places, as before. Proof: union with main: fmt, clippy -D warnings and client tests pass, including the bit-exact drop_motion test.
`Entity.teleport` stops riding unless the transition is `asPassenger`, and
`calculatePassengerTransition` gives each rider the vehicle's new angles plus
its own offset (`passenger.getYRot() - getYRot()`), or the vehicle's angle
alone on an axis the command set relatively (`+ (relatives has Y_ROT ? 0 : ...)`).
The shared writer only moved riders' positions and only the player arm
dismounted, so `/tp` on a spider jockey or a mob in a boat was seated again by
the next sync (the command reported success and nothing moved), and a rotated
`/tp` left mob riders, the host and guests facing where they were.
- `teleport_to_in_level` dismounts a mob or an armor-stand target before it is
placed (`Entity.teleport` -> `stopRiding`), and carries the command's per-axis
relatives for the riders.
- `teleport_passengers` places the riders at the angles the vehicle was placed
at (`passenger_rotation`): mob riders, the host riding a vehicle and the
hub's guests, recursively, pitched through `Entity.setXRot`'s clamp. A
relative axis gives the rider the vehicle's own angle. A turned guest gets one
position packet carrying its new absolute rotation with its motion kept
(`Hub::teleport_rider`).
Fixes#9289
Co-Authored-By: DeepSeek Harness (deepseek-v4.1-flash) <[email protected]>
🤖 Agent: the shader's facing test compares order-preserving u32 keys of the same f32 thresholds visible_from uses, MARGIN included, so no driver's subnormal flush can change a run; a grouped mesh keeps one whole draw, and the 4-run cap fits the 3-bit count in runs.
Each draw baked a new image for the equipped name tag, and GPUI keeps every one
in the sprite atlas until it is dropped. Marks are now kept per item id, its
file's hash and the window scale. One replaced by a scale change or a new file
is dropped from the atlas on the next frame.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JLHp7yEJwPTJ2kw29LWdk1
🤖 Agent: the bundle click now checks may_pickup and may_place on the slot, as vanilla Slot.allowModification does, so a bundle in a take-only or locked slot keeps its contents; the new test covers the withheld slot.
Main grew its own pure helpers and tests in remote_mob_use.rs (nautilus,
golems, allay, armadillo). This keeps main's version and adds only what
this PR got right: DyeItem.interactLivingEntity takes an unsheared sheep
of another colour and passes otherwise; shears stay CONSUME on a client.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#9286 moved the shop to the website and removed the launcher's claim window
rules, so the clock correction has nothing left to correct; this merge takes
main's shop files. ClaimState::Unknown still matters: /v1/shop and /v1/me
answers decide whether the Wardrobe is in the top bar, and a state a newer
service adds made them fail to parse.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#9286 removed Entry::lines; the merge keeps Entry::plain and drops lines
from the tests' entry helper.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
launcher/lang/*.json take upstream's tables and get the two Performance mode
strings at the top of each, so later additions at the end of upstream's tables
no longer conflict.
🤖 Agent: Built-ins are typed int/float/bool from the probe tables. A custom uniform whose declared type the expression doesn't give reads 0 as a whole, with a note naming it. Nothing else found. I pushed 5eef8152: merged main.
🤖 Agent: merging. One cost to know: every item component read now asks `ids::dropped_component` and `ids::quirks`, two thread-local reads, even on a 26.3 server; cheap next to the component decode itself. Proof: union with main: fmt, clippy -D warnings and horizon-protocol tests pass, including the three new wire fixtures from 1.21.11 registries.
🤖 Agent: `textureMatrix` maps to `gl_TextureMatrix[0]` in vertex stages only, while a fragment stage's own `textureMatrix` keeps its frame slot (zero), matching the probe. Merged with #9180's tuple form of `core_matrix` (type `mat4`). Nothing else found. I pushed e8d6861b: merged main (#9057/#9180 landed).
LecternBlockEntity.loadAdditional clamps Page to 0..getPageCount(book) - 1,
and getPageCount is 0 without a book, so Math.min(Math.max(page, 0), -1)
gives -1. Every Horizon reader of the page applies max(0) first.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A child process spawned while a lease or a Cargo lock is held keeps a copy
of the descriptor until its exec, so closing ours alone left the lock taken
and the next lease or cleanup read Busy (seen as a flaky
clears_only_disposable_outputs... test while other tests spawned Cargo).
Unlock explicitly on drop: that frees it for every copy.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: the changed blocks now go out between the random ticks and runBlockEvents, as in ServerLevel.tick, and what the events and block entities write is held to the next tick; piston-slide measured 3 ticks for every move in three runs on a union with main, piston-push and predict pass, and I fixed the check counting from the previous move's head.
🤖 Agent: main merged again (mod_api.rs keeps both ClientboundPlayPacket and ServerboundPlayPacket re-exports); native send-packet built, clippy and tests green on union 760aa5921.
🤖 Agent: merging. Off, `hdr.lighting && hdr.look` also skips the water and cloud second passes, so HDR Lighting off costs less than on, and NikitaMGrimm's PQ captures show 100% of pixels within 1 code of SDR. I moved `set_hdr`'s doc comment back onto `set_hdr` (their nit). Proof: union of this head with main: fmt, clippy -D warnings, render and client tests pass.
🤖 Agent: matches `Projectile.hitTargetOrDeflectSelf` + `Breeze.PROJECTILE_DEFLECTION`: REVERSE power 1, the sound from the breeze, no `onHit`, and `lastDeflectedBy` stops a second turn. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
The second extension starts with the head the first one left, so taking the
first piston_head read gave a negative count. The landed head is now the first
after the moving block. A loaded machine can run two client ticks between
reads: when the read before the move or before the landing skipped one, the
check says so instead of reporting a wrong count. On playhorizon (load 25-47)
three runs measured 3 ticks for every move.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: Armadillo.mobInteract is FAIL while isScared() before Animal.mobInteract, so spider eyes no longer end the click on a rolled-up armadillo. Also fixed: brushOffScute is false on a baby, so a baby's brush is not taken (38c31cac5d). The main merge 1e9a62f124 only resolves the import line with #8691 (same resolution as the cg-31 union). Proof: cg-31 union on main 6d43a3593b (playhorizon): fmt, clippy -D warnings, client+lib tests 1638+850 ok.
🤖 Agent: merging. `native_notice` is already a plate, so taking it out of `card` also removes the plate-in-plate it had in the results view. Proof: union with main: launcher fmt, clippy -D warnings and lib tests pass.
🤖 Agent: .mrpack import, green on this head; rdbtCVS's change request was dismissed because it rested on #6660, closed by Ludovic (Java instances stay).
🤖 Agent: Forge install for Java instances, green on this head; the only blocker was a change request resting on #6660, which Ludovic closed (Java instances stay).
🤖 Agent: the partner entry goes below the official one through the same once-only marker logic, so a player who deletes it never gets it back; proof: multiplayer::tests (20) and clippy -D warnings green on the desktop.
🤖 Agent: merging. On the single-player path these three calls repeat what finish_close_world already did, and `stop_all` on an empty mixer is a no-op, so the only change is for leaving a server or being kicked. Proof: union with main: fmt, clippy -D warnings and client tests pass.
🤖 Agent: lands the whole stack (#8637#8644#8647#8652#8657#8658#8660#8690). Concrete fix: be258bc235 sent every ParticleAt as a speed-0.1 packet (ink at 1/100 speed, client-side hearts/splash/smoke drawn twice); squid ink is now MobEvent::LevelParticles as Squid.spawnInk's sendParticles, and main's wolf test got the new client_tick argument. Proof: 569f9644dc in the cg-31 union on main 6d43a3593b (playhorizon): fmt, clippy -D warnings, client+lib tests 1638+850 ok; CocofireHD's later main merge 5839363b51 only resolves allays.rs (main-hand check + swing kept on main's Option<ItemStack> inventory).
🤖 Agent: ConversionType.convertCommon also copies PortalCooldown, InvulnerableTime, the fire flag and entity tags, which are still not carried over; the five flags here match. The land-stop was main's new MobType field item_stack_limits in this test's literal: main merged and the field added (79576177db). Proof: cg-31 union on main 6d43a3593b (playhorizon): fmt, clippy -D warnings, client+lib tests 1638+850 ok.
🤖 Agent: /attribute now runs in the target's level (in_target_level), so an unbounded @e from the Nether reaches the Overworld cow, as EntitySelector.findEntities searches every level. Proof: command_exec harness PASS (82 s) with the 8 new corpus cases on the cg-31 union on main 6d43a3593b (playhorizon), plus fmt, clippy -D warnings, client+lib tests 1638+850 ok.
🤖 Agent: the slide now starts from the move packet (createInterpolationHandler NO_OP) and is only counted down in client_tick; a riding shulker gets the peek reset without the slide. First parity run died in 2 s on the runner's dead .horizon-prepare.lock link (environment); rerun 41856251948 queued. Proof: cg-31 union on main 6d43a3593b (playhorizon): fmt, clippy -D warnings, client+lib tests 1638+850 ok.
🤖 Agent: a drop starts the same start_build_import the picker uses, behind can_import_build, so a removal in progress can't race it; .exe/.gz/.tgz are taken unread so build_import gives the precise error, and extensionless files are read last. I fixed the wrap spaces in the two error strings and merged main (the stale-key verify failure came from main, fixed by #9265).
🤖 Agent: a failed datapack copy now reports its error instead of passing silently; a half-copied pack still stays in datapacks/ (no cleanup), worth a follow-up. Union 760aa5921 tests green.
🤖 Agent: the guest-entity and dead-guest lists no longer hang on has_guests (which skips dead and spectating guests), so a lone dead player's ender pearl still vanishes as in vanilla; pearl_death and the client tests passed on union 760aa5921.
🤖 Agent: merging. Only chests get the precedence; barrels, shulker boxes, hoppers and dispensers load through the same RandomizableContainer.tryLoadLootTable in vanilla and still keep their Items here: a follow-up. Proof: union with main: fmt, clippy -D warnings and client tests pass; CI parity runs the new chest_load harness.
🤖 Agent: merging. The host's own path now gates only the sound on `elder_curse_param`, and the apparition stays unconditional, which is what ClientPacketListener.handleGameEvent does for GUARDIAN_ELDER_EFFECT. Proof: union with main: fmt, clippy -D warnings and client tests pass (the new guardian test included); CI parity runs the new elder_curse harness.
🤖 Agent: merging. Splitting the reduction into `scd_finalize_pass` replaces the completion counter, which WGSL's memory model never promised would make other workgroups' writes visible; the cost is one 9-workgroup dispatch and a 9 KiB buffer per generated frame. Proof: union with main: fmt, clippy -D warnings and render tests pass (the GPU tests need an adapter; CI's run them).
🤖 Agent: merging. Risk noted: the server holds an extra `Arc<Chunk>` per handed-over column until the window's next tick, so an edit in that window copies the chunk on `Arc::make_mut`; one tick at most, and only for bulk edits out of view. Proof: union with main: fmt, clippy -D warnings, client and lan::handoff tests pass.
🤖 Agent: Pack shadow passes now draw every face (and without back-face culling), which roughly doubles the shadow pass's solid quads for Iris-format packs. Horizon's own packs keep the light-facing selection (`every_face: false`). `shadow_water` getting `cull: false` too is a guess the probe didn't measure, as the description says. I pushed 9fac526f: merged main.
🤖 Agent: merging. FireworkRocketEntity reads `getLookAngle()`, Mth's float sine table, so the boost now matches `travel_fall_flying` and the server; the remaining f64 `view_vector` use is `rocket_hand_angle`, which only places the spark. Proof: union with main: fmt, clippy -D warnings, client tests and tests/test_remote_own_rockets.py pass.
🤖 Agent: merging the Metal split and the minified core-shader fix. I dropped the ZIP validation from the download path: vanilla's DownloadedPackSource checks only the SHA-1 (checkExistingFile), the strict zip crate refused the streamed Ascendia archive that Horizon's own pack reader already reads (so other Java-readable packs would have been refused too), and it decompressed the whole pack on every cache hit. Proof: fmt, clippy -D warnings and the touched crates' tests pass on a union of this head with main and 19 other PRs.
🤖 Agent: `set_rotation` is the same eight lines in 11 impls (finite yaw, NaN pitch kept, clamp); a shared helper would keep them from drifting. Item, orb, TNT, falling-block and rocket loaders still read Rotation as [0, 0], as the description says. I pushed 764989a2: merged main, keeping main's new TNT `block_state` argument beside `rotation` (power, block_state, rotation), and gave main's new TNT and orb fixtures the field. Proof: main + this head: fmt and clippy -D warnings (horizon-client and horizon-client-lib, all targets) and horizon-client tests pass, 0 failed.
🤖 Agent: Stitching the pack atlas at each sprite's own size only applies to flat draws (a stitched atlas is dropped for grid draws), and a device that can't stitch falls back to the grid with a log line. Nothing else found. I pushed 02e68e15: merged main (#9057/#9180 landed).
Horizon partners with Afri-Network, a server for players in South Africa.
At start the game now adds it once below "Horizon Official" in
servers.dat, like the official server: never again after the player
deletes it (horizon_partner_servers.txt), and not when the list already
has its address. servers::insert_after keeps hidden entries and unknown
fields, as prepend does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: `InteractionResult.FAIL.consumesAction()` is false, so `handleUseItemOn`'s build-limit message fires. ANY_BLOCK_USE keeps its old condition. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
The perf_bench reports behind playhorizon.dev/benchmarks as of 2026-11-04 (horizon-site#58): RD 12 and 32,
three games each, 1280x720, VSync off. The Mac's session was locked (Horizon offscreen) and both machines were
busy (load 17-50 on the Mac, 28-70 on the desktop); site-2026-11-04.md says how they were made and what that costs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: the reader treats the byte as `UnsignedBytes.toInt`; the writer clamps to 0..=255 before the byte cast, so 255 and 128 round-trip. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: after the cleanup, `clear_remote_objects` (new connection, level, dimension) drops the orbs with the rest of the old ClientLevel. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: the refusal branch now restores the fire set by the arrow and reverses at power 0.2, as `AbstractArrow.onHitEntity` does when `projectileReceivesSideEffectsOnHit(false)`. This also covers mobs in their hurt cooldown, whose arrows used to vanish. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: both `levelEvent(1500, …)` calls in `ComposterBlock` (useItemOn, the hopper input) are the null-source overload, so 1500 belongs in the no-exception list. `play_unshared` also stops the serving side from sending a second sound packet. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: `hub.entity_event` broadcasts with no exception, so the eater sees its own event 46, as with `sendToTrackingPlayersAndSelf`. A mob's 46 arrives before its move packet, so its trail runs between the two old positions, as on a vanilla client. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: the pitch `nextFloat` stays inside `!isSilent()` at both call sites (`Witch.aiStep` line 155, `performRangedAttack` 262), and the test pins the untouched random. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: `Level.isDarkOutside`/`isBrightOutside` are both false under `hasFixedTime`. A datapack dimension with fixed time still drinks, because the check is `nether || end`, not the dimension type. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: `extra.mount` is the vehicle (`getVehicle`), not the rider, so the guard is `!isPassenger()` and the `nextInt(50)` draw is skipped exactly as in `RaiderCelebration.tick`. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: `AbstractMinecart.isPickable` is `!isRemoved()`, and the ridden cart is skipped like `isPassengerOfSameVehicle`. The pull reuses `pull_hooked` for every hooked kind. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: checked the server thread: the serving Game has no local player (dedicated options), so every player, the window's too, gets its own packet. The 'in raid' set is still one player (`bar.player`), while vanilla's `raidEvent.getPlayers()` holds everyone within 96 blocks; a far second participant hears nothing. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: `max_stack` reads the patch first and falls back to the item when the component is removed, as `ItemStack.getMaxStackSize` does. The wire test covers the add and the `!` removal. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: matches `Bee.doHurtTarget` (poison on any LivingEntity the sting hurt, 10 s Normal / 18 s Hard). Not ported here: `setStingerCount` on a mob target, which vanilla also increments. Proof: union of all cg-31 PRs on main 6d43a3593b (playhorizon): fmt, clippy -D warnings (client/lib/render all-targets + server lib), client+lib tests 1638+850 ok.
🤖 Agent: Ludovic's call (11-04): the shop lives on playhorizon.dev/shop (live, Paddle checkout tested end to end with his account), the launcher keeps the Wardrobe with an Open the shop button. launcher job green on this head; verify running.
When running single player on an integrated server, `horizon-ctl summon`
spawned mobs directly into the client window's entity list rather than
delegating to the server thread. Because the client window does not tick
mobs (running `tick_remote` instead of `tick_world`), summoned mobs
never executed AI goals, took no environmental damage, and were not
visible to server queries.
Delegate `summon` to the integrated server in the owner player's level
when `self.integrated` is active, matching other control world commands
and allowing the server to tick the mob and broadcast it via standard
entity tracking.
Managed by Axxio.
Co-Authored-By: Antigravity <[email protected]>
the_launcher_reference_is_up_to_date: the native-cache command and the
native-cache-gib setting were missing from the generated reference.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
DragonFireball is stopped by any entity it can hit and DragonFireball.onHit
moves its cloud to the first LivingEntity within 4 blocks; AreaEffectCloud
.serverTick applies its instant damage to every LivingEntity in it. Horizon
only looked at players. Mobs now stop a fireball, its cloud snaps to them,
and both breath clouds (the fireball's and the flame phase's) put their
instant damage on the mobs inside through the lingering clouds' existing
cloud_affect path (indirectMagic, undead healed instead).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
🤖 Agent: I pushed 19b0fd00 and 27d625d8: merged main and filled `Resources.packed` (#9090), `Interface.initial_values` and `Resources.shadow_linear` in the new test, which no longer compiled against current main. Raw textures defaulting to linear + clamp and PNGs to nearest + repeat match the probe table. Nothing else found.
🤖 Agent: Merged after review fixes 2c7b4906: /rotate sends PlayerRotation instead of a teleport, the boarding cooldown counts per tick (not per turn), and riding guests hear their vehicle's teleport. Follow-ups listed in the review: mob passengers on /tp, the passengers' rotation, cross-dimension vehicles.
🤖 Agent: block sprite pixels lz4-packed once uploaded (-19 MB live heap); one risk to know: SpritePixels::get returns zeroed pixels if decompression ever failed, which would show as black textures on a rebuilt renderer (device loss, split screen), not a crash. rdbtCVS's scene_replay adaptation included; verify green on this head, merger waits for parity.
EnderDragon.tickDeath calls dragonFight.setDragonKilled and counts the
first kill's 12000 experience only when it has a fight, which only the
End gives (ServerLevel.getDragonFight). Horizon did both everywhere: a
dragon summoned in the overworld left an exit portal and a dragon egg at
0 0 there, and 12000 experience. /kill already checked the dimension.
tools/test_dragon_death_outside_end_parity.py compares the blocks left
and the experience with vanilla's dedicated server.
Fixes#9274
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: A `component =` output at a location now joins the other outputs at that location into one vec4 target. Mixed scalar kinds, or overlapping components, are refused with the variable's name. Nothing else found.
Resolve core_matrix with #9180's (matrix, type) form: textureMatrix is
(hz_TextureMatrix[0], mat4) in vertex stages; both blocks and both tests kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: Unknown names and shape mismatches now zero the whole custom uniform, as your probes show. The correction comment about `round`/`ifb` (no such function, same 0) is noted. Nothing else found; #9153 builds on it.
🤖 Agent: A pack whose integer colortex0 can't reach the screen is now refused at load and cleared from the settings, like a panicking one. The old path cleared the screen every frame instead. The refusal's notes are logged before the reason, so the chat line stays short. Nothing else found.
🤖 Agent: `normalMatrix` now depends on `core_profile()`: a `#version 150`/`330` without a profile word counts as core, which matches the four probe pictures. Below 150 nothing changes, as the doc comment says. Nothing else found.
🤖 Agent: main's wardrobe_claim now calls shop_claim, so that one save moved out of this PR; the other five writes now print their error instead of dropping it.
🤖 Agent: read-only and after decode, so a mod can't change what the game handles, and with no mods the dispatch is a loop over nothing on the per-packet path; main merged in (next to #8938's test and #9187's stamped docs).
🤖 Agent: SHADOW_RESOLUTIONS and SHADOW_DISTANCES are ranges, so checking an int option's min and max covers every value the player can pick, and a 0 option drops the shadow pass, not just the map; main merged in (docs/api/shaders.md changelog next to #8512's).
🤖 Agent: getJumpPower is now jump_strength × multiplier × getBlockJumpFactor + getJumpBoostPower for every living mob, so cows and pandas jump half as high off honey as in vanilla; I dropped the unused free block_jump_factor wrapper and rabbit's re-export, and the #[ignore]d honey test passed on a tree with the vanilla resources.
🤖 Agent: matches DrawableGizmoPrimitives.getGroup (alpha 255 → lines with depth write, the rest linesTranslucentNoDepthWrite), uploading the opaque group first so one buffer serves both draws; I moved the two helpers so translucent_batchable keeps its own doc comment.
The sidebar's rows carry the menu about that instance (Edit…, Duplicate…, Open
folder, Export…, the desktop shortcut, Delete…), and it is reachable only
through a 32 px ⋮ button. A right click anywhere on the row now opens the same
menu.
Both entry points share one gate, `row_menu_after_press`: it opens the row's
menu, closes it when it is already that row's, and drops the Delete… confirm
flag when the menu moves to another row, which is what the ⋮ did before.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
🤖 Agent: Small and contained: flat terrain reads each sprite's rectangle from a table instead of assuming a uniform grid, the base for #9059/#9060. Nothing found.
🤖 Agent: This changes the vendored naga GLSL frontend: every non-constant struct member read now goes through a pointer, not a loaded copy of the struct. Every pack's GLSL takes that path, so a naga update must keep the patch (THIRD_PARTY_NOTICES records it). Constant expressions keep the old form. Nothing else found.
🤖 Agent: Atomic functions on a member of a shared vector in a declaration list or a shared struct now resolve. The rewrite is limited to `shared` declarations, so other GLSL is untouched. Nothing found.
🤖 Agent: `R3_G3_B2` is stored as 5/6/5 bits because that fits one NVIDIA driver's readback in Iris (the module says so). Another driver may store real 3/3/2, so the probe is worth rerunning on Mesa before more code depends on it. The quantising only touches passes writing such a buffer, so other packs pay nothing.
Main added TNT's block_state argument beside this branch's rotation:
both kept (power, block_state, rotation); main's new TNT and orb test
fixtures get the rotation field.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`execute run` redirects to the tree root, so parse_nodes recurses once per
nesting level. A crafted deeply nested command overflows the parsing thread's
stack (thread 'Server thread' has overflowed its stack) and kills the game.
Add MAX_PARSE_DEPTH (128) to parse_nodes' recursion: past the limit the branch
yields no result, so the command fails to parse instead of overflowing. 128 is
well below the ~300-level overflow measured on the server thread and far above
any real command chain; vanilla likewise caps command nesting.
Adds tests: a 400-deep execute-run chain is rejected (not overflowed), while
shallow execute chains still parse.
Closes#9252
IllusionerBlindnessSpellGoal.performSpellCasting adds Blindness for 400
ticks to the illusioner's target, any LivingEntity. The cast only sent
EffectPlayer, so a villager or iron golem it targeted kept nothing. A new
MobEvent::EffectMob carries the effect to the target mob, whose
add_effect already checks canBeAffected.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
SpellcasterIllager.customServerAiStep lowers the casting count every
tick, and Illusioner has no override of its own. Horizon did this only
for the evoker, so an illusioner's count stayed at 20 after its first
(mirror) spell: it kept the casting goal for good, cast nothing else and
never shot its bow.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
🤖 Agent: the zoom cone only boosts tiles covers() says are looked at, and the test pins the plan behind the player as identical zoomed or not; I made lodZoomDetail off by default until a measurement shows the extra far tiles land while the zoom is held.
`decode_block_entity` ports `LecternBlockEntity.loadAdditional` including
the `Mth.clamp(Page, 0, pageCount - 1)` the row only called "Book and
Page", so the row now says what the load does with the page.
The decode of a chunk's or a structure's lectern, `decode_block_entity`,
against the pages the book on it has: 7 on a two-page book loads as 1,
-3 as 0, a bookless lectern's 4 as 0, and a page already inside the book
(1 of three) is kept and saved back as 1.
Without the clamp the first case fails with `left: 7, right: 1` and the
second with `left: -3, right: 0`.
`LecternBlockEntity.loadAdditional` reads `Page` through
`Mth.clamp(page, 0, getPageCount(book) - 1)`: a page stored past the
book's last one comes back as the last page, one stored before the first
as the first, and a lectern with no book has the single page 0. Horizon
kept the stored number as it was.
A negative page was the visible half: `LecternBlockEntity.getRedstoneSignal`
(`books.rs::lectern_signal`) answers `floor(page / (pages - 1) * 14) + 1`,
so a stored -3 read 0 to a comparator where vanilla's clamped page 0 reads
1, and the next save wrote the out-of-range page back out. A page above the
end reads the same on both sides, since the signal saturates at 15 either
way, and the open menu already clamps (`menu.rs::set_data`), so what changes
is the load and with it the round trip.
🤖 Agent: I pushed c2aa51c1: merged main and resolved the generated `server-reference.md` row (main's text plus `dimension`), so `the_routes_table_matches_the_code` agrees again. Nothing else found.
The bundle sits in a chest slot whose rules refuse the pickup, with the
prepared catalog behind it so the stack really has bundle contents. A
left click with stone in hand adds nothing, a right click with an empty
hand takes nothing, and the empty bundle in the next slot still fills.
`BundleItem.overrideOtherStackedOnMe` gates both of its branches on
`Slot.allowModification`, which is `mayPickup` and `mayPlace` of the
stack the slot holds - not the placement test alone. `lan::menu`'s
bundle click asked only `View::may_place`, so a guest could fill or
empty a bundle in a slot whose menu refuses the pickup.
🤖 Agent: I pushed 1fb68131: merged main and added `fire_ticks: 0` to the new trident test, which no longer compiled once main gave `TridentSave` that field. Note that `LeftOwner: 1b` is now always written for tridents; vanilla omits it on a freshly thrown trident still inside its owner's box. Rarely visible.
🤖 Agent: `as_console_in_overworld` enters the overworld only when another level is in place, and puts that level back after the line, so the next server tick sees the level it left. The unit test covers only `console_level`; the portal scan is the real proof. Nothing else found.
🤖 Agent: `AbstractMinecartContainer.applyNaturalSlowdown` port is exact, f32 arithmetic included, and it returns before the ridden/behaviour factor as vanilla does. Nothing found.
🤖 Agent: Only a non-source moving block at progress 1.0 now counts as its moved state. One small gap: vanilla reads the moving piston's *collision* shape, so a moved block whose support shape differs from its collision shape (leaves) supports there in vanilla but not here. The carpet machine doesn't need it.
🤖 Agent: Crash reports are read only by a name the listing returns, so `../` and absolute paths can't reach outside `crash-reports/`. The test covers both, plus a non-`.txt` file. The panel refetches players and crash reports every 10 polls, a directory listing each time: cheap. Nothing else found.
🤖 Agent: `isCollisionShapeFullBlock` is the right gate (`EntityRenderer.extractShadowPiece`), and the test now covers ten non-full blocks, including the hopper whose collision bounds reach y=1. Nothing found.
Restore the Home and glass instance editor controls only for Java instances. Keep memory_mb persistence and Java's default heap behavior.
Co-Authored-By: OpenAI Codex gpt-6.1-sol <[email protected]>
Ludovic decided the cosmetics shop is only on https://playhorizon.dev/shop
(browsing, prices, the founder claim, purchases through Paddle). The launcher's
Wardrobe keeps what the account owns: equip / take off, "Show my cosmetics", and
the purchase history.
- Removed the Shop tab (wardrobe_page/shop.rs), the founder claim flow and its
checkout polling, Service::claim, Checkout / CHECKOUT_PAGES, the Shop's
window/countdown rules and the tests of all of it.
- Added an "Open the shop" button (opens the website's shop) beside the Wardrobe
title, and in the empty state ("You don't own any cosmetics yet.").
- The purchase history ("Your purchases") moved into the Wardrobe page.
- Lang tables: two new strings in all 86, the stale ones removed.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Resolve game/allays.rs: keep #8652's empty-main-hand gate and MAIN_HAND swing, and take main's Option<ItemStack> allay inventory for the returned stack.
Co-Authored-By: DeepSeek V4.1 Flash (OpenCode) <[email protected]>
🤖 Agent: one items.json snapshot per load, keyed on the root path; overlapping loads of one root share the native hooks' answers, fine under the same-answer contract. Proof: union with #8751+#8763+#8798 on main a7df9ec: fmt, clippy -D warnings clean; item_defaults/loot/items/font/hud/item_render/cit tests pass (playhorizon).
🤖 Agent: server fonts measure without an atlas; galactic_widths is now zero on a server but only the enchanting table's draw reads it. Proof: union with #8751+#8763+#8798 on main a7df9ec: fmt, clippy -D warnings clean; item_defaults/loot/items/font/hud/item_render/cit tests pass (playhorizon).
🤖 Agent: a headless load now skips OptiFine CIT; every reader of item_renderer.cit is a draw path (armour stands, elytra, glint upload), so nothing server-side changes. Proof: union with #8751+#8763+#8798 on main a7df9ec: fmt, clippy -D warnings clean; item_defaults/loot/items/font/hud/item_render/cit tests pass (playhorizon).
🤖 Agent: Review by Ludovic's AI agent (Claude), not by Ludovic himself. check_predicate now decodes an argument starting with { as inline SNBT and sends it through the same evaluator, source entity and origin as a named predicate, as ExecuteCommand.checkCustomPredicate does; the codec now requires terms for all_of/any_of and term for inverted, so a malformed inline predicate fails at parse with no callback, as CompositeLootItemCondition.createCodec does. Merges cleanly into today's main; the merger waits for verify and parity on this head.
launcher/src/backend.rs keeps both Settings::theme (upstream) and
Settings::performance (this branch). Each launcher/lang/*.json takes upstream's
table and gets the two Performance mode strings added again.
🤖 Agent: main fix: removes only the three keys #8873 dropped from en_us (menu_navigation, menu_focus, menu_pointer) from the 51 tables added after its base; afterwards no table in assets/horizon/lang has a key en_us lacks, which is what lang::tests checks.
#8873 removed horizon.options.menu_navigation, menu_focus and menu_pointer from
en_us.json and the 35 tables its branch had; the 51 tables main gained since
kept them, so lang::tests::bundled_files_are_served_and_have_no_stale_or_repeated_keys
fails on main (cv_cu first).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: launcher-only fix, CI green on this head (launcher, verify); main merged in (lang tables only); ThinkPad: fmt, clippy -D warnings, 480+89 launcher tests pass, incl. the new pin/on_base tests and the 86-language i18n check.
Dolphin.tick on a client: a dolphin in water whose squared speed is
over 0.03 (and that has AI) puts four dolphin particles a tick behind it,
0.3 to either side, set back along its view vector by 0.5 to 1.2 drawn
from its own random. client_ai_step had no dolphin, so the window never
made them. It runs over the window's copies of the mobs, so single player,
LAN guests and servers all get the trail.
Fixes#8566
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
🤖 Agent: the setup now draws the launcher's scene and glass plate with the player's accent; I made the main actions Kind::Primary and slowed the settings poll from 16 ms to 500 ms so the setup does not redraw at 60 fps for it.
🤖 Agent: this head carries all 40 of TheMrZZ's open PRs as one fast-forward chain (age order, main merged), because 38 of them append to tools/command_exec_corpus.py and conflicted pairwise; each one's current head is an ancestor, so GitHub marks all 40 merged with this one. Two hand merges to check: #8847, #8986 and #9101 now share one canBeABaby == false branch in mob_to_nbt that drops Age, ForcedAge and AgeLocked (AgeableMob.addAdditionalSaveData writes none of them), and data_of tries #9174's comparator view, then this PR's pot view. Proof: verify passed on 94ccd9c8e (this head = that + main); clippy -D warnings (also --no-default-features) and horizon-client-core/horizon-world tests pass on the union on playhorizon; the merger waits for verify and parity / parity here.
🤖 Agent: Requeued after merging #8200's main merge (12e979554) into it, no conflict. Live status heartbeat interval; lands after #8200. Fixes in this PR: the log reads the interval after setting it, as vanilla does, and a set after a cancelled heartbeat is refused, as ManagementServer does (b6204bf860). management_protocol --fresh PASS on the union of this wave plus the fix. On this head: horizon-server fmt, clippy -D warnings and 140 tests clean. The rest of the selection runs in CI run-parity.
Keeps the Paddle checkout from main and the clock and unknown-state fix. Both sides added tests at the end of wardrobe/tests.rs and an item to the same import in wardrobe_page/shop.rs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JLHp7yEJwPTJ2kw29LWdk1
🤖 Agent: Requeued at rdbt's main merge 12e979554 (clean, no conflict hunks; it carries #8128, now merged). Live accept-transfers, log line as setAcceptsTransfers. management_protocol --fresh on the union of this wave (with #8128 and #8204): every accept-transfers case matches vanilla. The union passed fmt, clippy -D warnings, 3388 tests and the Python suite; rdbt reran the management_methods and accepting_transfers tests on this head. The rest of the selection runs in CI run-parity.
tools/command_exec_corpus.py merged per function (main's new groups kept);
the harness keeps main's destroy_progress records and the chain's record-count check.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The launcher feels slow on older computers (i5-7500, Intel HD Graphics 630):
every frame rebuilds the page, the scene redraws its moving parts, and the
glass plates blur the scene again whenever the accent or the blur changes.
Settings > Launcher > Performance mode now turns on the cheaper path: the
scene does not restart on every mouse move, the sky is baked at a quarter of
the window's resolution, the plates' blur is three box passes instead of a
Gaussian, a window resize is baked in the background, and the plates are a
solid colour (no glass, no blur, no backdrop to sample). In that mode a new
accent reaches the background in the same frame as the buttons.
Outside the mode, the accent no longer re-blurs the plates: the backdrop is
blurred once and tinted as it is read, and a tint change is baked in the
background, one bake at a time, the last tint always landing.
🤖 Agent: matches Entity.spawnSprintParticle drawing from this.random; the window's own player has no client-side random, so it keeps the particle engine's, and the golem's nextInt(5) and offsets now come from the same random in vanilla's order.
🤖 Agent: the Windows thread_name reads Rust's own handle, and the BUSY guard already answers a nested allocation from thread::current(); I shortened the loader names to load-<step> so Linux's 15-byte limit keeps core and collision apart.
🤖 Agent: matches Warden.isPushable (!isDiggingOrEmerging && super), applied both in pushable() and on the receiving side of push_entities, while the warden still pushes others; I removed the two "digging" parity cases that actually spawned a standing warden.
🤖 Agent: address is set in all three places NativeServerPlayer is built (guest list, the acting player via lan_acting_uuid, and the command path), as IP only with no port; I added the missing API fragment (server_player_address.json) so it gets a number at stamping.
data_dir(), build_dir() and game_home() still expect()ed on a location error.
The quiet installer runs before data_location::startup(), and retry() clears
FORCE_DEFAULT before re-reading, so a background thread could hit the panic
the review asked to remove. A location that does not open now stands in as the
default folders there, as startup() makes it for the window. Also joins the
startup problems with "\n" instead of a literal line break.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: release_keyboard_mouse now releases only what Source::Keyboard holds, so a splitscreen handoff no longer drops the pad's held jump or sneak, and pad_button replays the actions stored at press time on release, so a binding changed mid-hold can't leave a key stuck. Players who chose Pointer in the removed Menu Navigation option get focus in menus after this.
Every actions/* pin now runs on Node.js 24 instead of the deprecated Node.js 20 runtime the runners currently force:
- actions/checkout v4 -> v7: v5.1+ blocks fork-PR checkouts under pull_request_target/workflow_run; this repo only checks out ref: main in those workflows (pr-labels, overlap-note) and the workflow_run release checkout resolves to the default branch, so nothing changes. The PR-head checkout in ci.yml runs under plain pull_request.
- actions/upload-artifact v4 -> v7: v7's direct uploads are opt-in (archive: false) and the ESM migration is transparent to callers.
- actions/download-artifact v4 -> v8: v5's path change only affects artifact-ids downloads, which no workflow uses; v8's enforced digest checks and skip-decompress only surface for direct uploads.
- actions/setup-python v5 -> v7: the removed pip-install input is unused (only python-version: '3.12' is set).
- actions/setup-java v4 -> v6: v4 itself now emits a deprecation warning (v4.9.1); temurin/25 usage is unchanged in v6.
GitHub-hosted runners ship 2.327.1+, so the node24 minimum is met.
Co-Authored-By: ZCode <[email protected]>
A filesystem without file locks or a native folder linked to another drive made
Cache::acquire fail, and logged() then refused the build itself, which worked
before the cache existed (martipops' review). Only Busy still refuses; any other
lease error is a build.log warning and skips the trim.
The launcher check failed on lang/ca.json: main added 51 locales since the last
main merge, so each gets the five cache messages.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: merging. Mining speed now reads the player's computed `minecraft:mining_efficiency` (Player.getDestroySpeed), and held Efficiency joins the equipment modifiers with its slot group, so an offhand Efficiency pickaxe no longer speeds mining. Proof: CI parity passed on this head, including the 9 new `mining_efficiency_9021` destroy-progress cases compared bit for bit with vanilla's getDestroyProgress.
🤖 Agent: only approximate tiles with width >= 16 stop at depth 2, and the test proves the Full tile still paints below depth 2, so the Reduced assertion cannot pass vacuously.
🤖 Agent: the hook gets session.offers[index], the live offer, while trade_with_villager keeps the pre-hook copy; a mod raising max_uses on a shift-click only takes effect after that click, as the docs say.
🤖 Agent: the hook runs after destroyVanishingCursedItems and before the random throws, and the retain only drops stacks a mod emptied, so with no mod the drops and their RNG draws are unchanged.
🤖 Agent: matches Armadillo.rollUp/rollOut, gameEvent(ENTITY_ACTION) before makeSound and independent of isSilent; the new creatures.rs arm comes after the flap arm, so chicken/parrot flaps are unaffected.
🤖 Agent: the guard keys on flat_min_sections.is_some(), so DX12 without flat page groups (no pulled pipelines) keeps GPU culling, and the test pins both DX12 cases.
🤖 Agent: launcher-only. The claim opens a checkout URL only on Horizon's own /shop/pay page (prefix allowlist, tested), and the 3 s poll stops after 20 min or once the set is claimed; without a checkout in the answer the one-click claim is unchanged.
🤖 Agent: TemptGoal.shouldFollow and TemptingSensor test both hands; player_view now fills off_hand, and lan_guest_views swaps each guest's off hand in through the same function, so single player on the server thread gets it too.
🤖 Agent: default ascii.png glyphs keep their 0..8 box, so sign text without Force Unicode draws exactly as before; only Unifont's half-scale glyphs change width.
🤖 Agent: the message is trimmed and the Chat option (Commands Only, Hidden) applied as the chat screen does; the test needs prepared resources and is #[ignore]d, so CI does not run it.
🤖 Agent: Only Show Secure Chat now drops a line before mods hear it (ChatListener.showMessageToPlayer's order, then onClientPlayerChat), and chat_received returns at once with no mods loaded, so the chat-type registry lookup costs nothing without them.
🤖 Agent: controlled particles are dropped on a resource reload so a stale sprite-set index cannot pick another set, and the only cost for vanilla particles is one more match arm in tick and in the translucent test.
sync::client_tick took an events vector in c0cd050fac; main's newer
remote_mob_data test still called it with two arguments.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: one dispatch per frame, each non-finite value falls back to vanilla's on its own, and posed_rotation is only set when the pose differs, so billboards keep the vanilla rotation path when no mod moves the camera.
🤖 Agent: the 32 KiB cap is enforced on both encode and decode, a vanilla client ignores the unknown horizon:menu_extra channel, and the lan_bot test pins that the payload arrives right before its own window's OpenScreen.
🤖 Agent: an explicit passed:false or a result with zero executed checks now stays Partial, and a legacy count-only result with passes still reads harness green, as carried_harness_keeps_current_and_legacy_successes pins.
🤖 Agent: a drag saves the option and rebuilds the pack once, on release, not on every pointer move; the manifest already refuses min >= max and step <= 0, so slider_position and slider_value cannot divide by zero.
🤖 Agent: the pack stack is rebuilt only when a mod registered a listener, so a /reload without native mods pays nothing, and folder_ok refuses '..' and absolute paths, so a listener cannot read outside data/<namespace>/.
🤖 Agent: GUI glint now takes vanilla's ITEMS-atlas rectangles (Stitcher's order, split and filtering padding reproduced) while CIT glint keeps sprite-local UVs; the cost is one more decode of the item textures per pack load in prepare_glint_atlas, nothing per frame.
🤖 Agent: re-running tools/stamp_native_hooks.py on this PR's base (38df83828) reproduces the tree byte for byte, and main has not touched a fragment since; the native-hook-stamp workflow that should have opened this PR has failed its last five runs, which the orchestrator will look at.
- When the cosmetics service answers a claim with a checkout (the 0 CHF Paddle checkout
Ludovic chose for founder claims), the launcher opens it in the browser, but only
Horizon's own checkout page (https://playhorizon.dev/shop/pay?…). It then asks the
service every 3 s, for 20 minutes at most, until Paddle's webhook has granted the set.
The button says "Waiting for the checkout…" and a link opens the checkout again.
- The Wardrobe tab's claim button takes the same path.
- "Your purchases" under the founder panel: date, item, price (Free at 0), state (Paid,
Partly refunded, Refunded, Charged back) and the order number from Paddle's receipt,
for Mojang's purchase-history rule.
- The claim note no longer promises "no card asked" (unconfirmed at 0 CHF).
- 11 new strings in all 86 tables; the dropped one removed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: matches ExperienceOrbRenderer: getBlockLightLevel is block+7 clamped with sky untouched (was a floor of 10 on both), the quad spans (-0.5,-0.25)..(0.5,0.75) at 0.3, and light is read at the eye (0.425).
- Prevent Play more button click from bubbling or launching the game
- Fix missing gaps between items in virtualized lists (cull::column) for versions and patch notes
- Match small field height (36px) and tokens for Motd, Port, Token, AddPlayer, and DeleteServer
- Do not apply 24px baseline blur when blur is set to 0
- Stop scroll event propagation on dropdowns, version lists, and nav tabs
Fixes#9148Fixes#9169
Managed by Axxio.
Co-Authored-By: Antigravity <[email protected]>
🤖 Agent: without HORIZON_HDR_OUTPUT, offscreen_output() is None and every new branch is skipped; the crash marker is only written with a surface, so an offscreen HDR run cannot turn HDR off for the next windowed start.
Mob::block_jump_factor is the one callers use; the free function and rabbit's
re-export had no callers.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: inert until gpu-culling is switched on (only control.rs and scene_replay do), and the fade-end heap means a frame with no fade due does no extra work; martipops' read found every fade start sets the flag before prepare.
The gizmo helpers went in between translucent_batchable's doc comment and the
function, so rustdoc showed the batching text on debug_line_opaque.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A fast clock closed a window the service still called open, hiding the Claim button on a set that's retired for good. Each answer's Date header now shows how far the clock is ahead, and the Shop reads the window's dates with that taken off. A clock on time or behind reads as before.
A claim state the launcher doesn't know now parses instead of failing the catalogue and the account's answer. It offers no claim and doesn't say the set is over.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JLHp7yEJwPTJ2kw29LWdk1
has_guests counts only guests a projectile can hit (alive, loaded, here, not
spectating), so gating dead_guests and guest_entities on it dropped a lone
dead player's pearl from ender_pearls_vanish_on_death (pearl_death harness)
and a dead shooter's arrow from its owner. Both lists are built every tick
again; only the guest target copy stays gated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: switch() now ANDs translucent_batching_offered() exactly as hdr_smooth_gradients already does, and the saved preference is untouched, so a device that can batch gets it back.
🤖 Agent: the loop now asserts the outbox really holds bytes (pending > 0 three times 50 ms apart) before sending Disconnect, which the old 64 MiB burst only assumed; the 256-MiB cap fails loudly instead of hanging.
🤖 Agent: only Public tree and Python tests move beside cargo, and every Python test that names cargo mocks it, so they never fight cargo for the target dir; Parity stays after cargo since it builds.
🤖 Agent: skipIf(os.name == "nt") sits above the bash/openssl skip, so Windows never reaches System32's WSL bash (#5383), and CI's Linux job still runs all signature cases.
Service::item_cached built its path from catalogue values unchecked. It now refuses an entry
whose id or hash isn't 1 to 64 of a-z, A-Z, 0-9 and _, the rule the game already applies
(horizon_cosmetics::fetch), before the disk or the service is touched.
The hash isn't checked against the bytes: nothing in this repository says what it is a digest of.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JLHp7yEJwPTJ2kw29LWdk1
The tracker sends AbstractMinecart's DATA_ID_CUSTOM_DISPLAY_BLOCK (entry
11, optional block state) and DATA_ID_DISPLAY_OFFSET (entry 12, the kind's
default offset), and the client reads them back into the cart, so a cart's
custom block shows over the network and in single player.
Fixes#8050.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
be258bc235 sent every MobEvent::ParticleAt as a particle packet with a speed
of 0.1. The squid's ink velocity was already multiplied by 0.1, so clients got
a hundredth of it. The other ParticleAt events (hearts, splashes, wither smoke,
glow, bubbles) are client-side addParticle calls in vanilla that the clients
draw themselves, so they were drawn twice.
Squid.spawnInk is ServerLevel.sendParticles(count 0, speed 0.1): it is now a
MobEvent::LevelParticles, which draws it here and sends it to the players
within 32 blocks, and ParticleAt stays local.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Install/Update, Uninstall and Launch Horizon are each screen's one main action:
Kind::Primary, as the launcher marks them. The live-settings wake drew the
window every 16 ms and read settings.json's metadata each frame; 500 ms still
picks a change up while the setup is open.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Both strings had a run of spaces where an editor wrapped them, so the note
read "a Horizon game build."
Co-Authored-By: Claude Opus 5.5 <[email protected]>
rdbtCVS's agent merged main into four of the stacked branches. Merging those
heads here lands every PR of the stack with #8691.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Up to about 45% more far tiles while a zoom is held, and a far tile takes
seconds: a quick spyglass look queues work that lands after it. The extra stays
in horizon-extras.txt (lodZoomDetail:true) until a measurement shows it pays.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Linux keeps 15 bytes of a thread name, so "horizon-load-core" and
"horizon-load-collision" both read "horizon-load-co" in the heap census and the
startup trace there. "load-<step>" keeps every loader apart.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Shulker.setPos resets DATA_PEEK on any block change after the first tick,
passenger or not; only the teleport slide is skipped for a passenger. The
slide is cleared by startRiding (on_start_riding), not by every move.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: The freeze came from map searches opened from chests, which built full jigsaw starts and scanned every chunk of each saved region for each candidate. Same answers on main and this branch (24 targets × 5 points × 4 runs); on a pregenerated world the bamboo-camp map search drops from 2.1–3.6 s to 0.04–0.07 s of server-thread CPU, and main hit the 60 s watchdog in 4 of 9 runs. fmt, both clippies and the touched crates' tests pass, plus 10 harnesses incl. server_world_gen (/locate against vanilla); dedicated_server's vanilla oracle crashed on the loaded desktop, so CI runs it.
They spawned a warden with no flag, which stands: nothing in the fixture starts
a dig, so they compared a standing warden under a digging name. The emerging
cases stay; the unit test covers digging through set_pose.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A player's native builds kept compiling 9d979ca (Nightly 2026-10-31)
whatever Nightly or build profile they picked: Right-Click Crops 1.0.0
pins that commit and names no hook points' version, so the pin chose the
build's commit while the Mods page said "built on Horizon <picked Nightly>".
The build record now keeps the picked version's own commit and the mods
whose pin chose another; the Mods page names them, and "Rebuild on
Horizon" builds every mod on the picked version's commit (on_base,
native-build --ignore-pins), which later rebuilds keep. Older records
whose commit differs from their Nightly's read the pins from the
instance's mods. Also translates "Paste a friend's invite code".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
orbs_after_client_respawn was only ever called with true, so the helper
and its test only restated Vec::new(). clear_remote_objects now clears the
orbs itself, which also makes the connect path's own orbs.clear() redundant.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The field said "API next" without a fragment, so stamping would never give it
a number. tools/native-hook-fragments/server_player_address.json requests one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Armadillo.brushOffScute returns false for a baby, so the brush falls through
to FAIL (rolled up) or Mob.mobInteract's PASS instead of ending the click.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- /rotate on a server's player sends ClientboundPlayerRotationPacket
(ServerPlayer.forceSetRotation) when its turn ends, riding or not,
instead of a zero-motion teleport (or nothing for a rider).
- The guest's boarding cooldown counts down once per tick in
guest_server_tick, not once per enter_guest; a vehicle dropped in
guest_vehicle_tick also starts it.
- A teleported vehicle's riding guests hear the vehicle's teleport
(ClientboundTeleportEntityPacket), so a driven boat is not put back
by the client's next MoveVehicle.
Found by martipops's review.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The 26.3 client's Animal.mobInteract answers CONSUME for an adult's food
(SUCCESS for a baby that can age up), and Sheep.mobInteract answers CONSUME
for shears whether or not the sheep is sheared: only the server checks
canFallInLove and readyForShearing. So both keep taking the click. Keep the
dye change, which matches DyeItem.interactLivingEntity, and add its
isSheared check: a sheared sheep passes any dye.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts resolved per function: every top-level def matches one side (the
harness main() keeps both sides' options), every groups() entry is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts resolved per function: every top-level def matches one side (the
harness main() keeps both sides' options), every groups() entry is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The 26.3 client's AbstractBoat.interact answers SUCCESS (a swing) whenever
the player isn't sneaking and the boat isn't out of control; only the
server's startRiding checks for room, so a full boat or a riding player
doesn't pass on the client. AbstractChestBoat passes only out of control,
not sneaked at, with room; otherwise it opens the chest. Minecart.interact
is the one that answers CONSUME and doesn't swing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts resolved per function: every top-level def matches one side (the
harness main() keeps both sides' options), every groups() entry is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merging main left a test initializer without the field main added
(TridentSave.fire_ticks / Interface.initial_values and
Resources.shadow_linear), so the test target stopped compiling.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merging main left a test initializer without the field main added
(TridentSave.fire_ticks / Interface.initial_values and
Resources.shadow_linear), so the test target stopped compiling.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FishingHook takes the plunge from syncronizedRandom, reseeded each tick
from the hook's UUID and the game time, not from the level's random: a
draw there shifts every later level draw out of vanilla's order. The
plunge is also computed in float as Mth.nextFloat does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Conflicts resolved per function: every top-level def matches one side (the
harness main() keeps both sides' options), every groups() entry is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: Server API backup goldens: test-only, the download case reads the real streamed bytes. The union of this wave's 15 PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop. management_protocol (--fresh, on that union): every case of this PR matches vanilla; the only 3 differences were #8204's heartbeat cases, fixed there. Other harnesses PASS on the union: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container. dedicated_server could not run locally (the vanilla oracle's world generation hit its watchdog under the desktop's memory pressure), so it and the rest of the selection run in CI run-parity.
Conflicts resolved per function: every top-level def matches one side (the
harness main() keeps both sides' options), every groups() entry is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: Server API lifecycle goldens: test-only, type-checked replacement of the volatile fields. The union of this wave's 15 PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop. management_protocol (--fresh, on that union): every case of this PR matches vanilla; the only 3 differences were #8204's heartbeat cases, fixed there. Other harnesses PASS on the union: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container. dedicated_server could not run locally (the vanilla oracle's world generation hit its watchdog under the desktop's memory pressure), so it and the rest of the selection run in CI run-parity.
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches
one side, every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches one side,
every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Drop the ZIP structure validation from the download path. Vanilla's
DownloadedPackSource checks only the SHA-1 (checkExistingFile), and the
strict zip-crate validator rejected the Java-compatible streamed archive
that started this PR, which Horizon's own pack reader already reads; any
other archive Java opens but the zip crate doesn't would have been refused
too. It also decompressed the whole pack on every cache hit.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Corpus conflict resolved per function: every top-level def matches one side,
every groups() entry of both sides is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: Entity broadcast range: vanilla logs the requested percentage, then clamps 10..1000 and saves the clamped value. The union of this wave's 15 PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop. management_protocol (--fresh, on that union): every case of this PR matches vanilla; the only 3 differences were #8204's heartbeat cases, fixed there. Other harnesses PASS on the union: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container. dedicated_server could not run locally (the vanilla oracle's world generation hit its watchdog under the desktop's memory pressure), so it and the rest of the selection run in CI run-parity.
ManagementServer.scheduleHeartbeat cancels the running heartbeat and
schedules a new one only above 0. A set to 0 or less that stopped a
running heartbeat leaves the cancelled future in place, and cancel(true)
on it returns false, so vanilla refuses every later set until the server
restarts: it logs that the interval was not updated, keeps nothing and
answers with the interval in force. The management_protocol harness
showed it (vanilla answered 0 to the last set to 30, saved 0 and read 0
after the restart; Horizon took 30).
Horizon now keeps that state beside the interval. The harness cancels
with -5 instead of 0, so the value saved and read back after the restart
differs from the default, and expects vanilla's -5.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`copy_pack` walks a dropped folder with `let _ = fs::copy(...)` in every
branch and answers `true` for anything that holds a `pack.mcmeta`, so a folder
that half-copied (a held file, a full disk, a path too long) was announced as
installed and the pack appeared with files missing.
`copy_dir` now returns whether every copy landed and logs each file it could
not write; `copy_pack` passes that answer up, and the drop handler says the
pack is one it could not copy. A pack that is no pack still answers false with
no log line.
The test copies a real pack into a path that cannot be made and asserts false,
then copies it into a real folder and asserts the file arrives.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
Use the vanilla infection/conversion level events and the client cure-start entity event. Respect silent mobs, draw cure volume before pitch on each client and avoid duplicate captured sound packets.
Fixes#8892
Co-Authored-By: Codex <[email protected]>
🤖 Agent: Ludovic approved the shop and the dark founder set (11-04). verify, launcher, parity-scope green on this exact head (rdbtCVS's options-test fix included); desktop fmt/clippy/tests passed on the shop changes. The claim window stays closed on the service until the Paddle 0 CHF checkout follow-up lands, so merging only shows the shop and worn cosmetics.
🤖 Agent: Prometheus entity/chunk counts read only when the supervisor samples server-status; main merged (rdbt's d938f6a1dd). The union of this wave's 15 PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop. Harnesses PASS on that union: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container. boat_submerged, boat_paddle_reset and dedicated_server did not run locally: the vanilla oracle's world generation hit its watchdog 3 times under the desktop's memory pressure, before any comparison. They and the rest of the selection run in CI run-parity.
🤖 Agent: Boat powder snow matches PowderSnowBlock.entityInside (stuck 0.9/1.5/0.9, nextBoolean then two randomBetween draws). The union of this wave's 15 PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop. Harnesses PASS on that union: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container. boat_submerged, boat_paddle_reset and dedicated_server did not run locally: the vanilla oracle's world generation hit its watchdog 3 times under the desktop's memory pressure, before any comparison. They and the rest of the selection run in CI run-parity.
🤖 Agent: Rider frost walker / block effects for passengers; old_position reset keeps the sweep to the vehicle's cell. The union of this wave's 15 PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop. Harnesses PASS on that union: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container. boat_submerged, boat_paddle_reset and dedicated_server did not run locally: the vanilla oracle's world generation hit its watchdog 3 times under the desktop's memory pressure, before any comparison. They and the rest of the selection run in CI run-parity.
/item ... block, execute if items block and /loot insert|replace block
only found slots in a chest, so a furnace, brewing stand, crafter,
chiseled bookshelf, shelf or jukebox answered "does not have slot". They
now take every block entity that is a Container in vanilla
(BlockItemAccessor.getContainer), and each one sets its slot through its
own Container.setItem: a furnace restarts cooking only for a new input, a
crafter enables the slot again, a bookshelf takes only books and a jukebox
starts or stops its song. Any other block answers "is not a container".
/loot checks canPlaceItem first, as LootCommand does.
Fixes#8685
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Both items were filed help-wanted and their issues are closed, so
`python tools/roadmap.py check` answers "every linked issue and pull request is
closed: ship or drop it" for each: the work landed and the roadmap never
learned which pull request did it, so `sync` cannot move either item.
Links added: #1928 for end-city-banners, #1911 and #2037 for end-city-loot,
each merged on 2026-10-26, plus the sentence in `dev` that says what the fix
did. ROADMAP.md and roadmap/roadmap.json are what `roadmap.py build` writes
from the toml.
Status stays help-wanted: `now` needs an owner and a tracking issue and the Now
list is already at its 8-item cap, while `shipped` needs a release tag and
these went into Nightly builds after v0.2.x froze.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
Each row below was marked `missing`, and the Rust function it should point at is
in the tree, with a doc comment naming the vanilla method it mirrors. Verified
by reading each function, not by the note the row carried.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
In Vanilla Minecraft 26.3 (Animal.mobInteract and Sheep.mobInteract):
- Right-clicking an adult animal with breeding food when unable to breed
returns PASS on the server; the client does not swing or spawn feed particles.
- Right-clicking a sheared sheep with shears returns PASS and does not swing.
- Right-clicking a sheep with matching dye returns PASS and does not swing.
Guard these interactions in client's remote_mob_takes so the client does not
falsely predict swing arm and feed particles.
Managed by Axxio.
Co-Authored-By: Antigravity <[email protected]>
Vanilla poisons any living thing the sting hurts, so a villager or a fox was taking the hit and walking away clean.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Leave randomizable-container inventories empty when their NBT supplies a valid loot table, allowing the existing command and chunk loading paths to retain the table. Add a red/green regression and a real vanilla inventory-load comparison.
Fixes#8920
Co-Authored-By: Codex <[email protected]>
main carries 40 fragments whose markers have not been consumed, so
`python tools/stamp_native_hooks.py --check` exits 1 there. This is one run of
that tool on current main: it numbers the fragments in first-parent merge
order, writes the markers into the hand-written API types, and inserts each
`doc_summary` as an `API N adds ...` paragraph in docs/native-mods.md.
No hand-written line: the stamp pass owns native-hooks.json, NATIVE_HOOKS_API
and docs/native-mods.md, and editing any of them by hand is what the fragments
replaced.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
A cobblestone stack limited to 16 was merging to 64 after the component was dropped on the way to the window.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
A pack with an integer colortex0 and no `final` left to draw it (none, or
one that is skipped) has no colours the screen can show: #9007 made the
screen only clear, so Arc v0.15.2 drew a black world. `PackPost::new` now
refuses such a pack, `Renderer::set_shader_pack` returns the reason, and
the game turns the pack off with the usual log line and chat message, as
a pack that fails to load, so the world draws without it. An integer
colortex0 with a working `final` still loads and draws.
Fixes#9165
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Settings::save writes options.txt with `let _ = fs::write(...)`, so a write that
fails (a held file, a read-only folder, a full disk) leaves the player's
options, key bindings and volumes at whatever the last successful save put
there, and the game says nothing. Every option change goes through this call.
This logs the error where the rest of the crate warns (`log::warn!` in
`audio.rs`) and leaves the other files alone: `horizon.save`,
`controller.save`, `extras.save` and `mods.save` return no Result, so widening
their signatures is a separate change.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
🤖 Agent: execute on owner resolves the owner guest first. the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
🤖 Agent: Per-worker idle release; cross-worker idle is mutexed, per-job cost a lock + Instant::now. the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
BlockItem.place's FAIL ends the click but does not consume the action, so
the server must still send build.tooHigh/build.tooLow. The guest path
counted the failed hand use as consuming and skipped the message.
Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
🤖 Agent: World pack tags merged only for registries with tag files. the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
🤖 Agent: Bucket ray uses ClipContext.Block.OUTLINE like BucketItem.use; main merged. the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
🤖 Agent: Shader bool/bvec buffer rewrite; rdbt's main merge 0e010734d9 (one mod-line hunk) re-tested: horizon-shaders 249 tests OK. the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
🤖 Agent: Routing of flat worlds through the pipeline; lands after #8163 (carries its commits). the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
🤖 Agent: Superflat features match FlatLevelGeneratorSettings.adjustGenerationSettings. the union of all 15 of this wave's PRs on main acd184c1 passed fmt, clippy -D warnings, 3388 tests and the Python suite on the desktop; harness subset on that union PASS: flat_generation, flat_place, chunk_generation, datapack_worldgen, command_exec, pick_block_data, powder_snow_collision, snow_freeze, boat_authority, vehicle_container (only a subset ran locally; the full selection runs in CI run-parity).
Opening a generated chest with an exploration map nobody searched yet (a camp chest's camp
or secret map, a shipwreck's treasure map) runs the map's structure search on the server
thread. Two things made one such UseItemOn cost seconds on the official server (#8669):
- Every candidate chunk got its full starts built (all of its sets, jigsaw layouts
included). Vanilla's StructureCheck.canCreateStructure only places the wanted
structure's start piece and checks its biome. `may_start` now does that for jigsaws
(`place_start` / `lay_out_children` split out of `assemble_drawing`), and `locate`
builds a chunk's starts only where a wanted structure may start.
- Each candidate asked whether its chunk was old through the blender's region scan,
which decodes every chunk record of each region file it touches. Vanilla's
StructureCheck reads the one chunk. `OldWorld::is_old_chunk` now answers from a
scanned region's bits, else from that chunk's record alone.
The slow-event line also names the item, block, position and face of a use, and the use
is split into use_mods / use_block / use_item / open_loot / open_maps /
use_advancements spans (`spans::guard` ends a span where its scope does).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Wardrobe page drops the result of every write it makes: the outfit it keeps
on disk (`wardrobe::Saved::save`), the game's cosmetics switches
(`horizon_cosmetics::prefs::Prefs::save`) and the line recording what the
service confirmed (`prefs::set_confirmed`). All three return an `io::Result`,
so a failed write left the page showing the new outfit while the file on disk
still held the old one, and nothing said so.
This prints the error where the launcher already speaks with `eprintln!`
(`instances.json`, `settings.json`, accounts) and changes nothing else: the
in-memory state still carries the change.
Co-Authored-By: Hermes Agent (Nous Research) <[email protected]>
Entity.spawnSprintParticle draws the crumb's x and z from this.random.
Horizon drew them from the particles' random for iron golems and other
players (the rabbit hop already uses the rabbit's own), so a golem walking
out of sight changed every particle drawn after it, such as a campfire's
smoke. The window's own player keeps the particles' random, which stands
in for its own as elsewhere.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Keep the trust notice above the project and results, and scroll it into view when installation pauses for consent.
Fixes#8978
Co-Authored-By: Codex <[email protected]>
Horizon read only `location` from a fragment output's layout, so
`layout(location = 1, component = 1) out uvec3 x;` was written from
channel 0, and two outputs splitting one location by component became two
declarations at that location, which naga rejects. Each such output is now
a private global copied into its components of one vector per location
after the pack's `main`; overlapping, mismatched or overflowing components
are errors, as glslangValidator reports them.
Fixes#9135
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In Vanilla Minecraft Java Edition 26.3, interacting with non-interactive
objects (paintings, fixed or empty item frames with empty hands, sneaking
or occupied boats without chests, and non-interactive minecarts) returns
InteractionResult.PASS, which leaves the click to the held item without
animating a hand swing. Furthermore, boarding a boat or rideable minecart
answers InteractionResult.CONSUME on the client, which ends the use
without predicting an arm swing.
Update remote_use_entity to check object interact passes and prevent
predicting hand swing animations on non-interactive objects or when
boarding vehicles.
Managed by Axxio.
Co-Authored-By: Antigravity <[email protected]>
In vanilla 26.3 (FishingHook), when a bite occurs, DATA_BITING is set to true, triggering onSyncedDataUpdated on both server and client to apply an initial downward plunge impulse to velocity.y of -0.4F * Mth.nextFloat(syncronizedRandom, 0.6F, 1.0F) (-0.24 to -0.40).
Co-Authored-By: Antigravity <[email protected]>
The Windows setup window drew the Night sky and its violet pixel buttons, so
it looked nothing like the launcher it installs.
It now draws the redesign's scene behind the dark window (the dawn sky behind
the light one), tints the scene with the player's accent exactly as the
launcher does, and reads Glass, Blur, Accent and Appearance from settings.json
every frame, so a change made in the launcher applies on the next frame. The
card is a glass plate, its buttons are the launcher's rounded translucent ones
and its switch takes the accent.
Co-Authored-By: OpenCode <[email protected]>
Vanilla sends each player their own horn, thirteen blocks toward the wave, so people further along the raid were hearing nothing.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
`uniform mat3 normalMatrix` in a gbuffers program stayed a frame uniform
nothing fills, so it read zero. In a stage whose #version is 150 or later
and doesn't name the compatibility profile it is now the normal matrix the
compatibility profile's gl_NormalMatrix already uses; in the compatibility
profile it still reads zero. Our probe pack's Iris 1.11.7 pictures fit
this at 330 core, 330, 150 and 330 compatibility.
The GPU test's draw code moves into a helper both matrix tests share.
Fixes#9136
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Vanilla deflects every projectile but a wind charge, so the trident was dealing its full damage and could call down lightning.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Vanilla treats a minecart as pickable, so the hook was flying through carts and a reel never pulled them.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Formatting mute and temporary-ban replies as English discarded their translation structure before clients received them. Preserve nested components and duration units, with readable fallbacks for vanilla clients that do not have Horizon's language bundles.
Fixes#8255
Co-Authored-By: Codex <[email protected]>
In Iris 1.11.7 a custom uniform or variable whose expression has another
scalar type than the declared one reads 0 as a whole: an int given 2.0
or 7 / 2, a float or int given a comparison, a bool given a number. So
does one naming `true` or `false`, which Iris's custom uniforms don't
know, or calling `round`, `ifb`, `lerp`, `print` or any other function
they don't have. Horizon evaluated all of these.
custom.rs: #9119's `Shape` becomes `Ty`, which tells int, float and bool
apart, and int vectors from vectors. Numbers keep whether they were
written as floats, the built-ins get the types our probes found in Iris
(INT_NAMES, BOOL_NAMES; the rest are floats), and the operators and
functions follow rules fitted to our probe packs' values and warnings in
Iris. `centerDepthSmooth` joins HIDDEN: Iris warns it is unknown.
Based on #9119 (shaderpacks/custom-uniform-type-mismatch). In main's
`expressions_follow_c_precedence_and_file_order`, `c` (`|| false`) and
`d` (`int = -7 / 2`) now read 0, and `i` is declared `bool`, which keeps
it covering the BIOME_* notes.
Fixes#9126
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: clean-room check passed (black-box probes of their own, no source). Merged main and fixed#8999's test call to the removed Config::finish. Verified main + this head on the desktop: fmt, clippy -D warnings (shaders, render, all targets), 1270 tests, 0 failures; GPU fixtures not run.
Since f2c8e2ab1 the vanilla solid pipelines read their vertices and
records from the arena page by @builtin(vertex_index), per-section draws
too. DX12's count draws (multi_draw_indexed_indirect_count, which GPU
culling draws with) leave each draw's base vertex out of vertex_index:
wgpu-hal's draw_indexed_indirect_count sets its first-vertex constant to
0 and uses the command signature without it. GPU frames there read every
section's quads from the start of its page: most solid terrain missing,
stray quads in its place. Vulkan's vertex_index has the base vertex.
GPU culling is now not offered on DX12 with flat page groups (where the
pulled pipelines draw), so the word `gpu-culling on` is refused there,
until GPU culling's draws carry their base vertex some other way.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Divergence workgroups must all finish reading the histograms before either is replaced. Finalize in a separate dispatch so the reduction also observes every partial sum, without relying on a relaxed atomic completion counter.
Fixes#8627
Co-Authored-By: Codex <[email protected]>
Resolves the management handlers, the port map and the harness side by side.
Also: management_int's Codec.INT doc comment back on management_int, and the
interval's log line as vanilla writes it (MinecraftServerSettingsServiceImpl
reads the interval after setting it, so both numbers are the new one).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
horizon-ctl block reports the client's own moving piston at a position
(moving: progress, extending). A head that only arrives as the server's
moving_piston block, with no move of the client's, doesn't count.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A repeating command block placed by /setblock with auto:1b never got its
first tick in Horizon, so the second extension didn't happen.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The early broadcast in tick_lan sent the blocks as they were after the
tick's block events: a block placed by a scheduled tick and then pushed
went out as the moving block, and the client couldn't run the push. The
blocks now go out in tick_blocks, after the random ticks and before the
block events, as ServerLevel.tick runs ServerChunkCache.tick. piston-slide's
second extension pushes a stone a command block placed that tick.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ServerChunkCache.tick broadcasts the changed blocks before runBlockEvents,
so what the last tick's block entities changed (a retracted piston's base
put back) reaches the clients ahead of a block event that builds on it.
tick_lan now sends the changes before the block events, and holds the
tick's own late ones as before. piston-slide also powers the piston again
the tick after its base is back, with a repeating command block.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ServerLevel.tick broadcasts the changed blocks (ServerChunkCache.tick)
after the scheduled and random ticks, before the block events, the
entities and the block entities, so what those change goes out with the
next tick's. Horizon sent it the same tick: the block a moving piston
placed reached the clients while their own copy was still a tick from the
end of its move, and at /tick rate 1 it jumped the rest. The writes after
that point are held out of the log while it is sent; the guest move check
still sees them as unsent. lan_e2e's piston-slide check covers it.
Fixes#8430
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#9087 removes Config::finish (its only work was the gdepth rule); the test reads the settings as they are.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
ElderGuardian.customServerAiStep sends GUARDIAN_ELDER_EFFECT with
isSilent() ? 0.0F : 1.0F, and ClientPacketListener.handleGameEvent plays
the curse sound only for 1. Horizon sent 1 to guests and played the sound
for the host whatever the elder's Silent flag.
The curse event now carries the flag. tools/test_elder_curse_parity.py
compares the parameter a client is sent by a loud and a silent elder with
vanilla's dedicated server (VanillaProtocolClient's new elder-curse mode;
the goat-voices mode shares its phased-scene plumbing).
Fixes#8932
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this merge head; the merge keeps #9091's clickable edition tabs with the new grass block and brand icon.
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this merge head; the merge keeps both new Launcher fields (settings_marked beside #9099's mods_sticky).
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this merge head; the main merge only re-applied the 14 px inset to Home's new head layout from #9091.
🤖 Agent: updated onto main after #8042, #8510 and #9002 landed (merge of main; #8999 fixture gets item_id_declared/material_maps; #9007 is stacked on #9005 so the trailing test modules resolve once). Verified on the desktop, main + #8999 + #9007 (+ #9005): fmt, clippy -D warnings (shaders, render, all targets), 1268 tests, 0 failures; GPU fixtures not run (no adapter over ssh).
🤖 Agent: updated onto main after #8042, #8510 and #9002 landed (merge of main; #8999 fixture gets item_id_declared/material_maps; #9007 is stacked on #9005 so the trailing test modules resolve once). Verified on the desktop, main + #8999 + #9007 (+ #9005): fmt, clippy -D warnings (shaders, render, all targets), 1268 tests, 0 failures; GPU fixtures not run (no adapter over ssh).
🤖 Agent: updated onto main after #8042, #8510 and #9002 landed (merge of main; #8999 fixture gets item_id_declared/material_maps; #9007 is stacked on #9005 so the trailing test modules resolve once). Verified on the desktop, main + #8999 + #9007 (+ #9005): fmt, clippy -D warnings (shaders, render, all targets), 1268 tests, 0 failures; GPU fixtures not run (no adapter over ssh).
The founder set is now navy and charcoal (Ludovic, 11-04). On the dark
appearance's near-black well they all but vanished (well 17,11,31 against a
tee front of 33,32,41), so the dark well is a violet grey, lighter at the
top like a showcase. The light well stays.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head (473+85); menus open at once because an animation inside a deferred menu kept its invisible first frame under GPUI Fast (seen on the desktop run), pages and toasts keep the 200 ms pop.
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
🤖 Agent: verified in a union of the 21 open shader-pack PRs on main 3fb4c3138 (desktop): fmt, clippy -D warnings on all targets, 3766 tests, 0 failures. GPU fixtures not run (no adapter over ssh); harnesses not run (shader-pack-only code).
Cached oracle runs replace java on PATH, so looking beside that executable points into the cache shim directory instead of the JDK. Resolve keytool directly and support JAVA_HOME when it is not on PATH.
Fixes#9079
Co-Authored-By: Codex <[email protected]>
Clippy rejects &mut on a events field that is already a mutable reference.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
MinecraftServerSettingsServiceImpl.setEntityBroadcastRangePercentage logs the
requested percentage before DedicatedServerProperties clamps it to 10..1000.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head; Modrinth's Java mods stay listed for Horizon instances with the existing Works/Partly/Doesn't run mark, and installs still check SHA-512 before writing.
In Iris 1.11.7 a custom uniform or variable whose expression doesn't give
its declared shape (a float given skyColor, a vec2 given a vec3), or that
joins a vector and a scalar with an operator (vec3 * 1.0), reads 0 as a
whole. Horizon evaluated it anyway.
custom.rs now checks each item's shape once, on the first eval, after the
unknown-name check of #9015: Shape and shape() follow rules fitted to our
probe packs' values in Iris (operators, vecN constructors, which functions
take vectors, matrices, the declared type). A failing item reads 0 with a
note, and #9015's pass marks everything using it.
The load-time dry run (pack_post.rs) gave every built-in as a scalar, so
skyColor looked like a float there; it now gives each one at its size
(pack_uniforms::zero).
Based on #9015 (shaderpacks/custom-uniform-unknown-names); its test's
`w = vec3(...) * 0.0 + 2.0` and main's `e = vec3(...) * 2` now read 0,
as Iris reads them.
Fixes#9086
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head (474+83); one session-server lookup per account per 24 h, the empty answer (default skin) cached too, so an offline launcher doesn't retry each frame.
The pop animation inside a deferred menu kept its first frame under GPUI Fast: the
version menu never showed on the desktop run, the Language list lost its plate. Menus
open at once again (pages and toasts keep the pop); the Language list is anchored and
opens upwards when there is no room below.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: vanilla: PlayerPredicate lookingAt over every non-spectator entity; tick/location gated by may_look. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: indirectMagic(potion|cloud, owner) instead of main's Damage::player; overlaps #9053 (TheMrZZ), second to land resolves. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: 26.3 EntityPredicate is a dispatchedMap by sub-predicate id; TagPredicate.id is a HolderSet. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: hurtServer fires PLAYER_HURT_ENTITY at 0 damage outside i-frames; interact trigger after filled_bucket. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: WitherBoss.makeStuckInBlock is empty; berry damage kept. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: ContainerOpenersCounter edges for CONTAINER_OPEN/CLOSE; tautological test removed. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: ElderGuardian.customServerAiStep setHomeTo(blockPosition, 16); tests trimmed; carries #8966's commits (guardian.rs conflict). Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: Guardian.aiStep flop under !isSilent; tests folded into one. Lands before #8952 (stacked on it). Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: SUMMONABLE_ENTITIES = canSummon types; only player and fishing_bobber are noSummon in 26.3. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: AbstractBoat.tick startRiding branch, a refused rider is neither seated nor pushed (#8916 closed as its duplicate). Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: GlowSquid.hurtServer dims only if Squid.hurtServer is true, which needs getLastHurtByMob. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: fixed on the branch: the refusal is WitherBoss.addEffect's (Mob::add_effect); canBeAffected stays vanilla so AreaEffectCloud keeps the wither as a victim. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: MobEffectInstance.tickServer returns false at 0 (hasRemainingDuration), tickEffects removes it. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
🤖 Agent: vanilla: OldMinecartBehavior/NewMinecartBehavior seat through startRiding, WitherBoss.canRide false. Proof: union of main b1f5b238 + this batch's 14 heads on the desktop: fmt, clippy -D warnings, tests of horizon-client/-lib/-core/horizon-world green (GPU gfx/post_chain/menu_blur skipped). Harness subset only (not the full parity.py selection, which CI runs on this head): 22 passed (active_effect_tick active_effects effect_notifications status_effect consume_effect sculk block_entity_anim chest_pair command_parse chat_screen command_exec peaceful_summon living_hurt living_damage damage_source player_hurt damage_reduction server_player_damage boat_authority vehicle_container powder_snow_collision squid_client); dedicated_server and server_entities failed on the vanilla oracle's watchdog under desktop load, mob_ai not finished (oracle 1 h timeout under load): left to CI.
An atomic function on a component of a shared integer vector (`atomicMin(mn.x, i)`) was
rewritten only when the vector had a declaration of its own. Two other forms reached naga
unsplit and failed with "Atomic operation is invalid: Pointer [..] to atomic is invalid":
- a declaration naming several variables, `shared ivec3 mn, mx;`: each name is now declared
on its own, and the ones atomic functions use by component are split as before;
- a member of a shared struct whose type is defined in place,
`shared struct { ivec3 mn; uint other; } sh;`: the member becomes `int mn_hz[3];` in the
struct, with `hz_get_sh_mn()` / `hz_set_sh_mn(v)` for whole-vector reads and writes, through
the member paths #8994 added for buffer blocks. A struct type whose name is used anywhere
else stays as written.
Based on #8994 (shaderpacks/ssbo-vector-atomics), whose member-path rewrite this reuses.
Fixes#9085
Co-Authored-By: Claude Opus 5.5 <[email protected]>
After each trade made with a villager or a wandering trader, the mods are
asked with the live MerchantOffer in the trading session (uses counted):
uses, max_uses, demand, special_price_diff, price_multiplier and xp may be
changed and the change stands for the next click and the offers sent to the
player. Bukkit's PlayerTradeEvent#getTrade is mutable the same way. The
existing trade_with_villager stays listen-only and hears the offer as the
trade left it. A collect-contract hook with an API fragment.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The two branches each added a test module at the end of guardian.rs, so
whichever lands second conflicts. Carry #8966 here; land #8966 first.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
# Conflicts:
# crates/horizon-client/src/mobs/guardian.rs
Sign text drew every glyph as an 8x8 quad at the pen. Vanilla's
BakedSheetGlyph draws x+left..x+right and y+up..y+down, which the HUD
already does. With Force Unicode Font a Latin letter is an 8x16 Unifont
glyph at half scale (4 units wide, advance 5), so stretching it to 8
units overlapped its neighbours.
Fixes#8699
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head (473+84 passed); below 1280 px the mods button folds into ⋯ so the invite field keeps a 150 px minimum to the right of Play (screenshots at 1000×700).
Follow AgeableMob save gating for zombie nautiluses while retaining modeled
age values for normal nautiluses. Cover stale raw data and the command path.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head; the GitHub mark is our own SVG in horizon-theme's glass icons, the Sculk card keeps its 2 px hover lift without the border.
🤖 Agent: desktop fmt/build/clippy -D warnings/tests 0 at this head; the card re-renders only when its offset changes (on_scroll + next frame), so a long list costs nothing extra while scrolling; a scrollbar-thumb drag catches up on the next event (noted in the body).
From three days up the span showed whole days rounded down, so a seven-day
window read "6 days left" a minute after it opened.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Game::player_view left PlayerView.off_hand as None, so TemptGoal, the
animal brains' TemptingSensor, piglins' loved items, goats, happy
ghasts and taming never saw what the player holds in the off hand.
Vanilla's TemptGoal.shouldFollow and LivingEntity.isHolding check both
hands. Fill it from the off-hand slot, as main_hand is filled.
Fixes#8858
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A section's bounds from the ScrollHandle are its layout position before the scroll, so
the list stayed on the first section until the pane reached its end (seen on the desktop
run: Account still marked over the Launcher card).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
DrawableGizmoPrimitives.getGroup puts a line whose alpha is 255 in the
opaque group, which GizmoFeatureRenderer.buildLines draws with
RenderTypes.lines (pipeline/lines: DepthStencilState.DEFAULT, depth
written); only lines with alpha below 255 use
linesTranslucentNoDepthWrite. Horizon drew every depth-tested gizmo line
without writing depth, so translucent terrain and clouds drawn later
covered F3+B hitboxes and F3+G chunk borders in front of them.
The opaque lines now upload first and draw with a depth-writing
pipeline; the translucent ones (the chunk border's outer columns) keep
the old one.
Fixes#8465
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Read the computed attribute when calculating destroy speed, including active
hand enchantments in the map without activating them in the wrong slot.
Add nine differential real-game probes against vanilla Player.getDestroySpeed.
Fixes#9021
Co-Authored-By: Codex <[email protected]>
Upstream added 52 launcher language tables on main; they predate this branch's
data-location strings, and the launcher's i18n completeness test requires every
table to carry every key. Add the missing entries with the English text, and
the Chinese translation for the new startup message.
Verified with fmt --check, clippy --all-targets -D warnings and the launcher
lib tests on the merged tree (482 here, 486 on Linux in WSL).
Co-Authored-By: ZCode <[email protected]>
A gbuffers vertex stage that declared the core-profile `uniform mat4
textureMatrix` got a frame uniform the game has no value for, so it read
zeros, and packs computing their UVs as `textureMatrix * vaUV0` sampled
one texel per face. In the vertex stage it is now gl_TextureMatrix[0], as
projectionMatrix and modelViewMatrix already are their compatibility
matrices. Our probes read the identity there in Iris 1.11.7, and zero in
the fragment stage, which keeps its own frame slot.
Tests: the vertex stage's textureMatrix takes no frame slot while the
fragment stage's keeps one; on a host GPU, the vertex stage reads the
identity, a UV through it is the UV, and the fragment stage reads zero.
Fixes#9080
Co-Authored-By: Claude Opus 5.5 <[email protected]>
naga's GLSL frontend read `s.member` on the right-hand side out of a loaded
copy of the whole struct. Once an atomic function marks that member atomic,
the copy's member is an atomic value no operator, conversion, call or store
takes ("Incompatible operands: Atomic(...) as Uint"). The member is now
loaded through a pointer to it, as array elements already were; constant
expressions keep the value form.
Tests: every read the #9081 probe makes (assignment, operators,
constructors, min, subgroupBroadcastFirst) on a shared struct member, a
buffer-block member, a member of a shared struct array and a nested member;
constants' members in constant expressions; a member beside a runtime-sized
array; and, on a host GPU, the values those reads return.
Fixes#9081
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The launcher job stopped with exit code 101 while verify succeeded and the same
fmt, clippy and lib tests pass on Linux locally (486 passed).
Co-Authored-By: ZCode <[email protected]>
Menus and popovers take the cards' glass with a shadow instead of the darker float, and
arrive as the website's hzl-pop (fade and 6 px rise, 200 ms); Settings' Language list is
one of them now (it was the old square box and ran off the window). Hovers ease on the
design's quick curve, pages and toasts pop, the glass switch's knob slides; reduced
motion draws each at its end. In light, the Play group's icons take the accent's ink and
the dawn sky is washed with white.
Addresses dezer-x's launcher feedback (points 7, 8 and 11).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The Shop and Wardrobe tabs on glass plates in both appearances (Geist type, the
glass ink, light wells a soft violet grey so cream and violet items keep their
edges); the founder panel stacks under a 1280 px window. The Wardrobe gets a Shirt
row; its launcher theme row is gone: launcher themes are free for everyone in
Settings > Appearance (Launcher theme: Horizon or First Light), never claimed.
The top bar's Wardrobe follows the cosmetics service only. Shop previews use the
7-day window. The Shop strings in the 61 languages main added since, and the new
ones everywhere.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A shirt's sleeves ride the arms: a top-level part may name its own bone (Item::limbs,
one root per bone under the item's attachment, Item::roots). The game draws each root
on its bone, the launcher's preview too. Slot::Torso, hidden under a chestplate.
Cosmetics run by default (Ludovic, 2026-11-04: on when the shop opens); other
players' and your own already default to shown. HORIZON_COSMETICS=0 turns them off;
horizon_cosmetics::forced() is HORIZON_COSMETICS=1 for the launcher's Wardrobe.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: reviewed by literal-review (agent-state/literal-review.md): a far chunk is reduced only to the cell width that reads it (405 → 103 µs per chunk in its bench), same output; verify + launcher green at this head.
Probe packs of ours, run in Iris 1.11.7, set colortexNFormat in many places. Horizon now
follows what Iris did with them:
- a format in a block comment counts only where `const` starts its line (our probes' Iris
values fit this; it isn't a rule Iris states): not on the `/*` line, not after ` * `, not
after another declaration on the line;
- a format in a vertex shader doesn't count;
- the colortex formats of the shadow programs' fragment shaders are read when the shadow pass
doesn't run (observed in our probes for shadow.fsh and shadowcomp.fsh); nothing else of
those files is read then (Horizon's choice: nothing else was probed);
- declaring `gdepth` no longer makes colortex1 RGBA32F.
Fixes#9063
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A player whose drive is unplugged, whose location.json is damaged, or whose
migration lock is held used to get a silent exit: eprintln goes nowhere in the
Windows release build or from a desktop launcher. Startup now falls back to the
default folders and records the error, so the window opens on Settings with the
message, Retry and Use the default folder. Retry restarts into the configured
folders when they are readable again; Use the default folder keeps the old
pointer as location.json.old and restarts. Nothing in the moved folders is
deleted, and no launcher path reaches its expect() before the window exists.
Merge upstream/main (017c84f1f) while doing so: keep the launcher render env
strip and account-session removal alongside HORIZON_HOME, keep both the server
location_busy and stopped_line methods, keep one WorldLock, and keep the
explicit unlock in the world-lock test. The data-location strings the newer
language tables did not have yet are added (English fallback), with a Chinese
translation for the new message.
Tested: launcher lib 482 passed, bin 84 passed, integration suites passed;
cargo fmt --check and clippy --all-targets -D warnings pass.
Co-Authored-By: ZCode <[email protected]>
The Vanilla mark was baked from Mojang's grass textures in the prepared files, so the
Java Edition tab and the New instance card showed a letter until the game was prepared.
It is now an original drawing (tools/launcher_grass_block.py), always there. Horizon's
mark was a redrawn tile with the bar in the accent colour; it is now the brand icon.
Addresses dezer-x's launcher feedback (points 5 and 6).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
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]>
🤖 Agent: management server/stop now ends horizon-server as vanilla's does. Desktop: management_protocol FAIL on main 017c84f1fe (supervisor TimeoutExpired), PASS on e132eeba6c (--fresh, 167 s); dedicated_server PASS both; horizon-server fmt/clippy -D warnings/134 tests pass; the new supervisor test fails with the fix reverted.
dezer-x's launcher feedback, point 14. The chip draws the account's head from its saved skin URL;
an account saved without one (older sign-ins, or a profile answered without its skin) fell back to
the default skin from a prepared version's files, and with none prepared to the user icon.
Such an account now asks Mojang's public session server (no token) for its skin, keeps the URL a
day beside the cached skins, and the face comes from the skin as before (textures.minecraft.net
only). Signed out or offline with nothing cached, the user icon stays.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dezer-x's launcher feedback, points 12 and 13:
- Sponsor on GitHub carries GitHub's mark (github.svg in the glass icons, drawn for Horizon:
filled, its cat cut out by a mask).
- Sculk's card stays at the sidebar's foot on every page, Servers too; its border is gone (it
still lifts under the pointer).
- On Servers, Sculk's banner sits right under the server, where it shows without scrolling past
the server's tabs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dezer-x's launcher feedback, points 1, 2 and 15:
- Overview (glass look) ends with the screenshots and the patch log: the Resources and
Minecraft folder rows (and their Sign in with Microsoft) are gone; Prepare stays in Play's
menu, the folder in the folder menu, signing in in the top bar.
- The invite code stays on the actions' row at every width; under 1280 px Play and the version
are narrower, the puzzle gives way (the Mods tab does the same) and the field takes the rest,
with the shorter "Paste an invite code".
- The Java Edition / Rust Edition tabs switch: to that edition's instance played last, or to the
New instance dialog on Vanilla or Horizon when there is none.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Ludovic's point 16 on dezer-x's launcher feedback: mod translators are coming and the launcher
plays Java instances, so the Mods page searches Modrinth again (undoes what 0416fe600c hid, in
the 0.2.38 design).
- Tabs: Mods, Modpacks, Resource packs, Shader packs, Data packs.
- Mods, Modpacks and Resource packs pick their source under the search: Horizon's registry or
Modrinth, CurseForge beside them as coming soon, inert. Shader packs stay on the registry
(Horizon's .hshader), data packs on Modrinth, into the world picked there (its worlds read again
when the tab opens; source_for gave data packs Horizon's registry, which has none).
- A Horizon instance's Modrinth mods are listed, each marked Works, Partly or Doesn't run in
Horizon once its jar is checked; a Java instance's tabs still search Modrinth for its version and
loader. Installs keep the SHA-512 check before writing.
- docs/mod-browser.md, launcher/README.md and the Mods page's module comments say so.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Restore the modeled flag independently of Owner and serialize its current value. Cover defaults, owner removal, raw-None writes and model mutation against stale raw NBT, with a frozen Game command regression.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
dezer-x's launcher feedback, points 3 and 10:
- The project card beside the results stays in view as the page scrolls (the mockup's
lg:sticky lg:top-0): sticky.rs measures the row while it paints and moves the card down by what
the page scrolled past it, never past the row's end. A scrolled page is drawn from its layer,
so the page's scroll asks on the next frame whether the card must follow, and redraws only then.
- Sort by is on the search's right, as tall and as round as the search, its choices on a glass
popover with the chosen one ticked; Modrinth's filter bar no longer repeats it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A raw (`.dat`) custom texture is sampled linear and clamped unless its
`.mcmeta` says otherwise, each key overriding its own default only; PNGs
stay nearest and repeating. A PNG (the pack's or a game resource) under
`texture.<stage>.<name>` whose name is no sampler of the game's is not
bound. Iris 1.11.7 read these values with a probe pack of ours; the
binding rule is a fit to its cases.
Fixes#9064
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dezer-x's launcher feedback, point 9. GPUI Fast draws a scrolled pane from its cached layer
without rendering the view, so the list only moved when something else redrew the page; at
the end the mockup's rule then jumped straight to Data collection.
- The pane's scroll asks, on the next frame, which section is read, and redraws only when it
changed.
- The reading line sits at 30 % of the pane, then slides to its bottom over the last 70 % of a
pane of scroll, so About and Data collection, too short to reach 30 %, each come in turn.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dezer-x's launcher feedback, point 4:
- Each Versions and Patch notes card carries the 10 px bottom margin cull::column already
counted as their gap (the mockup's gap-2.5): the cards were fused.
- The glass look's scroll area starts 14 px under the top bar, so cards scrolled up stop short of
it; the pages' heads hold 14 px less above their titles, so nothing moves at rest.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
These formats live in 8-bit wgpu textures, so a pack read back 8-bit values where Iris 1.11.7
reads fewer bits. What a pass writes into such a buffer, and its clear colour, now keep the bits
Iris kept in our probe pack p8106c: the 8-bit byte's top 5, 5, 5 and 1 bits for RGB5_A1, 5, 6
and 5 for RGB565 and R3_G3_B2, repeated to fill 8. This is a fit to the probe's Iris values on
one driver (all 600 values match), not a rule Iris states.
Fixes#8106
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: union B6 (fur li lmo oc sah se szl vec: 16 PRs) stacked on #8610, ALL = 87 languages: tables complete at main's 1093 strings, controller labels written as commands fixed; desktop launcher fmt/clippy/test + horizon-client-core green (619 passed); verify + launcher green.
🤖 Agent: union B5 (tt yi yo zu ba br cv fo: 15 PRs + #8600 closed) stacked on #8579: zu_za game table dropped (vanilla 26.3 ships no zu_za), Bashkir's two broken {done}/{total} placeholders fixed; desktop launcher fmt/clippy/test + horizon-client-core green (619 passed).
🤖 Agent: union B4 (gd lb ky kn mt eo haw ig la: 18 PRs) stacked on #8496: Esperanto now has a table, so the two launcher tests that used "eo" as a table-less language (i18n pick, settings parse) use "tlh"; desktop launcher fmt/clippy/test + horizon-client-core green (619 passed).
🤖 Agent: union B3 (ga eu gl fil ta mn lo so fy: 18 PRs) stacked on #8450: Lao's 323 U+200B removed, 56 Tamil entries with Horizon/Minecraft in Tamil script restored to Latin, missing strings filled; desktop launcher fmt/clippy/test + horizon-client-core green (619 passed); verify + launcher green.
It derived the open and close edges in the test from recheck_opener_count's
return, which the existing opener tests already pin; it never reached the
game events this PR gates.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Keep the home and keep-existing-home cases and the restriction they give
in one test right after elder_server_ai_step (so it does not collide with
the flop tests #8966 appends to guardian.rs), drop the test that pinned
extra.home staying empty, and keep Mob::toward private.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: union B2 (az uz kk ka hy bs mk sq cy: 18 PRs) stacked on #8425: missing launcher strings filled, Instance written as "example" in hy/mk fixed, product names restored; desktop launcher fmt/clippy/test + horizon-client-core green (619 passed); verify + launcher green.
WitherBoss overrides addEffect to return false and canBeAffected to refuse
the wither effect only. AreaEffectCloud.serverTick picks its victims with
canBeAffected, so a cloud of strength or healing still takes the boss as a
victim: its instant effects land and the cloud shrinks. Keep
mob_can_be_affected and Mob::can_be_affected vanilla's canBeAffected and
put the blanket refusal in Mob::add_effect.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: union B1 (ca et lv sl sr is af ms be: 18 PRs, octopus of their heads + fixes): 66/58 missing launcher strings filled per table, 152 Serbian entries had Horizon/Minecraft transliterated (Latin again), game sr table now serves vanilla's Cyrillic sr_sp and a Latin transliteration for sr_cs; desktop: launcher fmt, clippy -D warnings, cargo test + horizon-client-core fmt/clippy/test green (619 passed); verify + launcher green.
The respawn rule returns a Vec, and the client stores orbs in a JoinList, so verify could not assign one to the other.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
The game crate's tests cannot see the library's cfg(test) mob fixture, so verify failed while compiling them.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Shulker.hurtServer returns false for an AbstractArrow while the shell is closed, and AbstractArrow.onHitEntity then deflects REVERSE at power 0.2. The hit path was dropping that refusal.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
A new ClientLevel starts empty, but the old orbs stayed and followed the player after the end fountain, so they were never picked up.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
MobEffectInstance stores amplifier as an unsigned NBT byte. Sign-extending that byte turned 255 into -1, and the effect constructor then clamped it to 0.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
The stitched atlas now draws every sprite into each level with a small render
pass instead of copies. The padding around a sprite repeats its nearest edge
pixel, as vanilla's TextureAtlas.uploadInitialContents does: it blits with a
clamp-to-edge sampler, and animate_sprite.vsh stretches the UVs over the
padding. Packs that filter or sample just past a sprite's edge read its own
colour instead of an empty pixel.
Part of #9037
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With a pack, flat terrain draws now read a block atlas laid out by vanilla's
Stitcher, with SpriteLoader's mip level and padding. Every sprite keeps its own
size, copied from the array level where the arrays hold it unscaled, and its
place goes to the sprite table. atlasSize and the texel distances packs derive
from it now match Iris 1.11.7: 2048 x 2048 on 26.3's sprites, where the grid
of 64 px cells gave 2304. Draws without the flat path keep the grid. The
padding stays empty for now.
Part of #9037
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Shulker.createInterpolationHandler is NO_OP, so setPos runs when the packet arrives, from the block the shulker occupied before it. client_tick only counts the slide down.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
An Iris-format pack's shadow map held no faces turned away from the light,
for two reasons: the shadow and shadow_water pipelines got the game's
terrain geometry with back-face culling on, and the shadow lists kept only
the quad buckets that can face the light. Under a hill at low sun such
faces (cave ceilings) are often all that shadows a cave, so packs drew
sunlight and shafts inside it. Iris 1.11.7 keeps both sides in its shadow
map (probe in #9033).
The pack shadow pipelines now draw both sides, and pack shadow views ask
for every face of their sections; Horizon's own packs keep the facing
selection.
Fixes#9033
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Retain loaded cloud timing, radius and potion settings, and keep live cloud identity during memory pruning. Add a loader contract and preserve a strict diagnostic for separate dose-phase and damage-source gaps.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Flat terrain draws now look a sprite layer's corner and side up in a table
(set 3, binding 2: x | y << 16, side) instead of working out a grid cell. The
atlas is still the grid, so packs see the same coordinates; the table lets the
atlas place sprites of different sizes next.
Part of #9037
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: Hub::set_simulation_distance broadcasts SetSimulationDistance and state.view.1 keeps the status reply in step; third of the management stack, after #8118.
🤖 Agent: max(2).min(view) replaces clamp(2, view), which panicked when a management value below 2 made the bounds cross; second of the management stack, after #8108.
🤖 Agent: hub.spawn_protection is the radius the block checks read, so the live set applies at once; base of the management stack (#8118, #8122, #8128 carry it in that order).
🤖 Agent: merged main; since #8046 can_target_player already refuses a player in Peaceful (spares_players), so I dropped the goal's own difficulty check and the Peaceful test still covers it.
🤖 Agent: only may_reach_out answers are cached (8 sections); the chunk queries keep vanilla's one-column cache, and the block_collision_scan harness checks that query trace against the oracle. Collision samples −21 % in a profile; A/B in the noise.
🤖 Agent: small win (tick_sculk_entities −0.2 to −0.3 ms, 3/3 pairs). Risk point: listener order. The cell lookup sorts back by insertion rank, and a randomized test checks it against the old full-list filter through inserts, removals and retains. sculk, server_player_sculk and mob_ai pass.
🤖 Agent: random_ticks −3.9 to −4.4 ms in 3/3 A/B pairs. Six #[inline] attributes, no body changed; random_tick, random_tick_sections, mob_ai, server_entities, natural_spawn and villager_farming match vanilla.
Carry the resolved management stack into the entity broadcast range PR while preserving all routes, port-ledger entries, and parity cases from current main.
Co-Authored-By: Codex (GPT-5.6) <[email protected]>
Since #8245 a stop that doesn't come from the supervisor's stdin or the
control API leaves the supervisor in its stopped phase. The management
`server/stop` only set `stop`, so horizon-server kept running after it,
where vanilla's process exits (the management_protocol harness timed out).
It now shuts down as `POST /api/v1/stop` does, through one helper.
Fixes#9027
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In Vanilla Java Edition 26.3, WitherBoss.makeStuckInBlock overrides Entity.makeStuckInBlock as an empty NO-OP.
While Cobweb (WebBlock) already ignored Wither alongside Spiders, Wither was still getting stuck in and having its fall distance reset by Sweet Berry Bushes and Powder Snow.
This aligns effects_from_blocks with vanilla Java bytecode:
- Wither is immune to slowdown and fall distance resets from sweet berry bushes and powder snow.
- Wither still takes sweet berry bush damage when moving in mature bushes.
- Powder snow snowflake particles continue to spawn when moving.
Co-Authored-By: Antigravity <[email protected]>
The shadow pass drew a block entity's plain faces but left out its End portal or gateway faces
(the portal run of #8361). A pack's shadow pass sees block entities whole, so the portal faces
cast too, with end_portal.png bound as for the gbuffers draw; beams still do not cast.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every frame's span was `item_frame`, so a pack's entity.properties could not tell glow frames
(and the item or map in them) from plain ones. Each frame, and the item or map it holds, now
takes its own frame's type.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`Codec.INT` reads a JSON number through `Number.intValue`, so a pack.mcmeta with
`"min_format": [97.1]` declares format 97 and is compatible. Horizon rejected the decimal,
so such packs (Patrix 26.3) were listed as incompatible.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: vanilla Sniffer/ClientPacketListener event 63 and SnifferSoundInstance checked; with the head merged into main, ambient_sound, server_entities, sound_engine, sound_event and dedicated_server pass on playhorizon.
🤖 Agent: options failed on main (69ab59ef0) with 17524 differing cases from the extra threeDSkinLayers line. With this head it passes on playhorizon. The switch moves to horizon-extras.txt, and the old options.txt line is read once, so a player's setting is kept (unit test). fmt, clippy -D warnings and 3506 tests pass on the desktop.
🤖 Agent: command_exec failed on main (69ab59ef0) with one mismatch: a stand's summon-tick /data get printed attributes [movement_speed] where vanilla prints []. With this head it passes, 4374/4374 commands, on playhorizon. Vanilla only creates that instance in aiStep's removeFrost (AttributeMap.getInstance computeIfAbsent). fmt, clippy -D warnings and 2489 tests pass on the desktop.
#8091 wrote threeDSkinLayers into options.txt, a key vanilla doesn't have,
so every options.txt Horizon saved was one line off vanilla's. It now lives
in horizon-extras.txt with Horizon's other switches. A threeDSkinLayers line
in options.txt is read once, while horizon-extras.txt has none of its own,
so a player who turned it on keeps it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: both the portal-tick trigger and an entity entering now go through triggerCooldown's block event 1 to the window, so the beam starts there; gateway_available keeps reading the server copy's cooldown.
🤖 Agent: the packet is count 1, no spread, speed 1, so each client draws a Gaussian velocity, matching PotionItem.useOn's sendParticles(SPLASH, …, 1, 0, 0, 0, 1.0); the positions still come from the server's random.
🤖 Agent: hub.land already sent level event 1032 at BlockPos.ZERO; playing it as local ambience (pitch nextFloat()*0.4+0.8, volume 0.25), as LevelEventHandler does, is what makes it audible. Nothing else in Horizon plays block.portal.travel, so there is no double sound.
🤖 Agent: wobble is a Level.blockEvent (event 1, the WobbleStyle ordinal) and the dust is sendParticles(DUST_PLUME, 7), so both now reach the window; the server's own block_entity_event stays for its copy.
🤖 Agent: oSquish is copied before the step toward targetSquish, then decreaseSquish (0.9 for magma cubes, 0.6 otherwise), the same order as AbstractCubeMob.tick, so the client's squish animates between packets.
🤖 Agent: event 70 only sets the client's fuse to 80 (MinecartTNT.handleEntityEvent -> primeFuse on a client), and the window counts it down with the smoke; the explosion stays the server's.
🤖 Agent: the nextFloat() < 0.05 draw happens for every defending fox, silent or not, then Entity.playSound skips a silent one: the same random order as Fox.aiStep after super.aiStep.
🤖 Agent: the smoke is added after the fuse decrement and the discard, at the moved position, as PrimedTnt.tick does on a client; the server's addParticle never reached the window.
🤖 Agent: BowItem.releaseUsing and CrossbowItem.performShooting play at the shooter's getX/Y/Z, so the feet are vanilla; the eye-height source a few cm from the listener was what panned hard.
🤖 Agent: only the nautilus's breath (ambient) skips the creative/spectator gate. Vanilla's Dolphin's Grace also reaches creative players (DolphinSwimWithPlayerGoal uses forNonCombat targeting), but main already blocked that before this PR, so it is a separate gap.
🤖 Agent: the remove-all/re-add batches (effects, equipment, enchantments) use set_modifier_unclamped and clamp once afterwards, so an unrelated effect refresh keeps health_boost hearts; LivingEntity.onAttributeUpdated clamps only on a real max_health drop.
🤖 Agent: Tab on Create World sets focus=2, so has_caret_field() is false while a tabbed button is focused and Space still presses it; only a click into a field drops the button focus, as Screen.setFocused does.
LivingEntity.aiStep's removeFrost makes the movement_speed instance through
getAttribute on the stand's first server tick; AttributeMap.load makes it for
a save that lists it. A /data get in the summon tick showed it since #8420.
A stand now records when that instance exists and saves it from then on.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
🤖 Agent: −4.8 to −5.0 ms MSPT in 3/3 A/B pairs (fast profile, which native mod builds use). Only #[inline] attributes, no body changed; 10 harnesses incl. mob_ai, entity_move and collision pass.
🤖 Agent: tick_lan −0.3 to −0.6 ms in 3/3 A/B pairs; the 9 attribute transcript harnesses (server_entities, mob_attributes, attribute_updates…) match vanilla. Risk point: the per-type cache holds only the type's default and synced id, never a mob's own modifiers, which still go through base_value_with per mob.
🤖 Agent: the NoAI branch now runs ravager::ai_step after ageable_step, as Ravager.aiStep does outside serverAiStep. The corpus group pins the stun-to-roar boundary at tick 2 for both AI modes.
🤖 Agent: release now rechecks nextDamageWillBreak after the wet/passenger test, as TridentItem.releaseUsing does, and the stack's max_damage component is sent over the network, so both peers admit the same throws.
🤖 Agent: I collapsed the growl's if-let into a let chain, which was the clippy failure. The dead path follows EnderDragon.aiStep after tickDeath: growl (pitch, then nextInt(200)) before the per-tick EXPLOSION, both at the risen position.
🤖 Agent: I added the missing RandomSource import and made water_entry pub, since only gameplay calls it and horizon-client-lib flagged it as dead code. The item splash draws from a random seeded per item (id, ticks), not the entity's own; that only affects particle spread.
🤖 Agent: I moved the block lookup, clamp and velocity into one sprint_particle helper shared with sprint_dust, so the hop's crumb differs only in drawing from the rabbit's own random (x then z), as Entity.spawnSprintParticle does.
🤖 Agent: Allay.updateDuplicationCooldown runs in aiStep, outside serverAiStep, so NoAI allays count down too; the normal path calls the same helper once, from allay::ai_step.
🤖 Agent: DyeColor.byId uses ByIdMap's ZERO strategy, so any color byte above 15 reads as white; masking with & 15 had turned 17 into 1. The new dedicated-server harness builds its binary the way test_dedicated_server_parity does.
A box across a chunk border goes back and forth between two columns on
every row, so the single remembered may_reach_out answer was recomputed
(a palette walk) at each crossing. The scan now keeps the last eight
(chunk, section) answers; the cells read and the chunk queries are
unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every frame now starts with texture A as each colortex buffer's "main". A
buffer that isn't cleared and ended the last frame on B has B copied to A
first; B keeps what was last written into it. So where a program leaves
pixels alone (discard) or blends, the texture it writes holds what Iris
1.11.7 shows there, measured with probe packs of our own: the previous
frame's last write in #9009's case 1, one accumulation per frame for a
buffer only blended onto, and 0 where a buffer flipped twice a frame was
never written.
Fixes#9009
Co-Authored-By: Claude Opus 5.5 <[email protected]>
With a shader pack lighting the faces (`oldLighting` off), the mesher gave every block and fluid
face 1.0. Iris 1.11.7 gives our probe pack 0.9 (229 of 255) on every Nether face, lava sides
included, and 1.0 in the overworld. These values fit the dimension's up-face value of vanilla's
CardinalLighting (NETHER up 0.9, DEFAULT up 1.0); that is a fit of our probe's Iris values, not an
established Iris rule. Fluid sides under a pack drop vanilla's side factor.
Fixes#9012
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The entities group leaves pigs loaded, so the single-pig check saw 3 when it
runs after it, as it does in the full corpus.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every game event (each mob's step is one) filtered the level's whole list
of sculk block entities by distance. The index now also keeps them by
32-block cell with their insertion rank, and an event reads the cells its
radius reaches (at most eight), sorted back by rank: the same listeners in
the same order as the filtered list. A test checks it against that filter
through inserts, removals and retains.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In Iris 1.11.7 a `uniform.*`/`variable.*` expression that names
something its custom uniforms don't know fails as a whole and reads 0,
even when the name is in an `if` branch that isn't taken, and so does
every uniform or variable that uses it (probe packs of our own). Horizon
read only the name as 0 and kept the rest, and saw fogStart, fogColor
and eight more built-in names that Iris's custom uniforms don't.
Custom now works out, on its first evaluation, which items name an
unknown or hidden name, directly or through another item, and gives
them 0. Two names Iris sees that Horizon doesn't give yet
(currentRenderedItemId, lightningBoltPosition) still read 0 alone.
Fixes#8995
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Mob::species, alive and bounds (read by the game crate for every mob),
BlockFacts::get (an index into the state table), RandomTickMask::may_tick
(a bit test per drawn position) and World::block (a chunk lookup and a
palette read) ran as calls from the game crate in the fast profile that
native mod builds use. Marked #[inline]; bodies unchanged.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A pack without `gbuffers_clouds` left the clouds to the game, so they never reached the pack's
buffers. Iris 1.11.7 draws them with `gbuffers_textured`, else `gbuffers_basic` (not
`gbuffers_textured_lit`), blended, as its ShaderDoc's gbuffers table lists and as our probe packs
measure.
Fixes#9011
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`flip.<program>.<buffer> = true` on a buffer the program also writes was
ORed with the write's own flip, so the buffer flipped once. Iris 1.11.7
leaves it unflipped (probe packs of our own): a later program samples the
side the program didn't write (0 for a cleared buffer), and a blended
write lands on what the program wrote (0.25 + 0.5 reads 0.749). The
forced flips are now XORed with the written ones.
Fixes#9010
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Without LTO across crates (the fast profile, which native mod builds use
as performance), a non-generic function from horizon-core is only inlined
into another crate when it is marked #[inline] or is a tiny leaf. Aabb::new,
Aabb::max, max_position, deflate, Vec3's arithmetic, BlockPos::offset and
chunk and PalettedContainer::is_global ran as calls on the server's hottest
paths (the collision scan, the snapshot, mob movement), each returning its
box or position through memory. They are marked #[inline]; their bodies are
unchanged, so every value is the same.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Iris 1.11.7 accepts the names of `iris.features.optional` and
`iris.features.required` in any case, and defines `IRIS_FEATURE_<name>`
with the name as the pack wrote it (probe packs of our own). Horizon
compared them with its uppercase list exactly, so `ssbo` defined nothing
and `compute_shaders` as required was noted as unsupported. The
HIGHER_SHADOWCOLOR check now matches in any case too.
Fixes#8996
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The world blit wrote its float colour into colortex0 whatever its
format, so a pack giving colortex0 an integer format (RGBA32UI, Arc
v0.15.2) failed wgpu's pipeline validation and was turned off. An
integer colortex0 now gets only what the pack writes: the blit leaves it
out (still copying depth and clearing the other buffers), it is cleared
in a pass of its own, and a pack without `final` gets a cleared screen
instead of a float copy of it.
Fixes#8459
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A `const` local whose initializer is a constant expression is a
constant expression itself (GLSL 4.60, 4.3.3, as #8462 quotes it).
naga's GLSL frontend kept it as a local variable, so a texel offset
given by one failed with "Sample offset must be a const-expression". It
now becomes a module constant, as a global `const` does, also inside a
loop.
Fixes#8462
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`.length()` of an explicitly sized array is a constant expression
whether or not the array is (GLSL 4.60, 4.3.3, as #8463 quotes it). In
a constant context (an array size) naga's GLSL frontend lowered the
array itself there and failed with "Unexpected runtime-expression"; the
array is now lowered outside it, for its type only.
Fixes#8463
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Iris 1.11.7 filters shadowtex0 and shadowtex1 linearly when a program reads
them through a plain sampler2D (probe packs of our own: a quarter texel past a
texel's centre moves a quarter of the way to its neighbour, in gbuffers and in
composite), unless the pack sets shadowtex0Nearest, shadowtexNearest or
shadow0MinMagNearest (shadowtex0), or shadowtex1Nearest or
shadow1MinMagNearest (shadowtex1). Horizon read the nearest texel, so a lookup
next to a block's edge took the higher block's depth and shadowed faces Iris
lights, with stripes on far terrain.
wgpu filters a depth format only in a comparison, so a shadowtex read that way
now reads an R32Float copy of the final depth (copied through a buffer after
the shadow pass's terrain), with the linear sampler, on devices with
FLOAT32_FILTERABLE. Others keep the nearest texel.
Part of #8464
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every tick's entity snapshot looked movement speed up by name for every
mob: the catalog's id, the type's synced default (two string-keyed maps)
and the type's own default base (a SipHash of the attribute's name).
They depend only on the type, so a snapshot keeps them per type; each
mob's base still comes from its own finalized bases first. The synced
instances are the same.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
GLSL 4.60 8.11 lets an atomic memory function take a single component
of a vector in a buffer, as RenderPearl's hand light does with
atomicAdd(hand_light.right.x, rg); naga has no atomic vectors, so the
stage failed with "Pointer to atomic is invalid" and was skipped.
The rewrite that turns such shared vectors into arrays of components
now also covers members of std430 buffer blocks (named or not), in
graphics stages as in compute ones. The block keeps its std430 layout:
a padding member where the vector's alignment moved it, and four
elements per 3-component vector of an array. Other layouts, runtime-
sized arrays and blocks whose layout isn't known up to the vector stay
as written.
Fixes#8977
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A GPU frame drew every solid quad of a section it kept and left the back
faces to the rasterizer, where a CPU frame draws only the runs of buckets
that can face the eye (Sides::visible_from, its MARGIN included). Each
record now carries where its buckets end and what visible_from compares
the eye with, and the tables the eye less each origin, both as u32 keys
that order as those floats do, so cull compares integers and writes a draw
per run, at most four per record.
A mesh sorted for two passes, which GPU culling never meets, keeps one run
of all its quads, and a frame whose eye less an origin is NaN is the CPU's.
Regions hold four draws per record, and cull counts the kept sections
itself.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A stage that enables GL_AMD_shader_trinary_minmax gets the extension's
min3, max3 and mid3 (genType, genIType and genUType overloads: the
per-component minimum, maximum and median of x, y and z) in its prelude,
for each one it calls and doesn't define itself. naga has none of them,
so such programs were skipped with "Unknown function 'max3'".
Fixes#8460
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Input parity (pad and keyboard reach the game the same way):
- Held keys record which device holds them; splitscreen's keyboard
handoff releases only the keyboard's, so the other player's controller
keeps its holds.
- The pad sends Shift and Ctrl through the keyboard's modifier state, so
the stack throw in inventories throws the whole stack again.
- Every bindable controller action has an explicit route, checked by a
test; screenshot and smooth camera work from a controller binding, and
pad look counts for the tutorial and zoom like the mouse.
- tools/pad_parity_e2e.py and headless Game tests compare pad and
keyboard outcomes.
Menus and inventories:
- Menus use focus; inventories, containers and the screens whose
clickable parts have no focus targets use a crosshair pointer centred on
the point it clicks. The Menu Navigation option and the right stick
click's swap are removed.
- A snapping engine settles the pointer: a glide onto the nearest slot,
flicks commit to the neighbour they head for, the D-pad hops a slot.
- Pointer speed, scroll speed and navigation repeat settings per player.
- Focus starts in vanilla's tab order, returns to the widget a screen was
left on, and only one widget is ever highlighted.
- Only a new press or real stick movement takes input from the mouse; a
screen, focus or keyboard change releases held buttons until let go.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JLHp81zX4YZ9N1mLLAwzKH
The window's item splashes ran while r.head_lerps was still borrowed; they
now run after it is released. Main's item_areas test builds an ItemEntity,
which needs was_touching_water.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
horizon-client-lib builds without gameplay, so a pub(crate) water_entry and
its ItemWater were dead code there (clippy -D warnings).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The hop's crumb reused a copy of sprint_dust's block lookup, clamp and
velocity; both now call one sprint_particle helper and differ only in the
random that places the crumb.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bind the existing registry to shared collision tables and resource/world tags, then test the thin eye box against the actual suffocating shape. Keep probe worlds and partial-block integration controls on the runtime binding.
Co-Authored-By: Codex <[email protected]>
Iris 1.11.7 reads a custom uniform's or variable's line in
shaders.properties with the macros expanded: the pack's options, the
standard macros and the file's own #defines (function-like ones too),
in the name as well as the expression (probe pack of our own). Horizon
read them raw, so an option such as RenderPearl's FOG read 0.
#define in .properties files now goes through the preprocessor's own
parsing (Macros::define_line), so function-like macros work there too.
Fixes#8976
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Pass the rule's fire flag from the impact arm while preserving the shared
non-fire explosion default. Cover bounded enabled/disabled and TNT scenes,
with explicit fire-presence gates and unmodified raw count diagnostics.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Use the exact Java value instead of the stale double-literal expectation; preserve the original motion behavior and strengthen the assertion.
Co-Authored-By: Codex <[email protected]>
Preserve the live modeled liked-player fields when a whole-Brain data edit omits or invalidates the required memories map. Keep valid empty-map and individual-key clears working.
Co-Authored-By: Codex <[email protected]>
Reuse the mob world snapshot without cloning per mob, skip unloaded work before nearest-player and difficulty queries, cache difficulty by chunk, and avoid guest-target allocations when no LAN guests exist. Empty projectile ticks now flush queued effects and return without scanning mobs or constructing projectile state.\n\nCo-Authored-By: OpenAI Codex <[email protected]>
Use Java float inertia values in the shared helper, retain its existing branch order, and pin exact motion with focused dry, submerged and custom-acceleration controls.
Co-Authored-By: Codex <[email protected]>
In vanilla Java 26.3, `GameEvent.CONTAINER_OPEN` and `CONTAINER_CLOSE`
are fired exclusively when `ContainerOpenersCounter.openerCountChanged`
detects an opener count transition across zero (0 -> 1 on open, 1 -> 0
on close). Spectators never join `ContainerOpenersCounter`, and
subsequent openers on an already open container do not re-trigger edges.
Guarding `post_block_game_event` with `if first` and `if last` prevents
spectators from emitting vibrations that alert sculk sensors and wardens.
Co-Authored-By: Antigravity <[email protected]>
- Launcher tables get every string main has added since they were written, and lose strings the
code no longer has.
- Product names translated or transliterated as words (Horizon, Minecraft, Java, Mojang…) are back
in Latin script.
- Fixed the meanings machine translation got wrong: a crash written as a vehicle crash, Nightly
as "every night", instance as "example", tick as a checkmark, the controller labels written
as commands, and similar.
- Removed the U+200B pairs that came with the translation tool.
- Game tables drop entries identical to en_us.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merges the heads of #8755, #8757, #8761, #8764, #8767, #8768, #8770, #8771, #8777, #8781, #8792, #8793, #8794, #8797, #8800, #8802 as they are (each one's table, its Language entry in
launcher/src/i18n.rs and its Bundled arm in lang.rs), so each PR is marked merged when this lands.
Their edits to existing tables are left out: main's versions are newer and more accurate.
The next commit fixes the tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Launcher tables get every string main has added since they were written, and lose strings the
code no longer has.
- Product names translated or transliterated as words (Horizon, Minecraft, Java, Mojang…) are back
in Latin script.
- Fixed the meanings machine translation got wrong: a crash written as a vehicle crash, Nightly
as "every night", instance as "example", tick as a checkmark, the controller labels written
as commands, and similar.
- Removed the U+200B pairs that came with the translation tool.
- Game tables drop entries identical to en_us.
- Zulu: vanilla 26.3 ships no zu_za language, so the game table could never be picked:
removed (the launcher table stays).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merges the heads of #8580, #8581, #8585, #8587, #8596, #8597, #8599, #8600, #8601, #8603, #8605, #8606, #8607, #8608, #8609, #8610 as they are (each one's table, its Language entry in
launcher/src/i18n.rs and its Bundled arm in lang.rs), so each PR is marked merged when this lands.
Their edits to existing tables are left out: main's versions are newer and more accurate.
The next commit fixes the tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Launcher tables get every string main has added since they were written, and lose strings the
code no longer has.
- Product names translated or transliterated as words (Horizon, Minecraft, Java, Mojang…) are back
in Latin script.
- Fixed the meanings machine translation got wrong: a crash written as a vehicle crash, Nightly
as "every night", instance as "example", tick as a checkmark, the controller labels written
as commands, and similar.
- Removed the U+200B pairs that came with the translation tool.
- Game tables drop entries identical to en_us.
- The launcher test used "eo" as a language without a table: it now uses "tlh".
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merges the heads of #8528, #8529, #8530, #8532, #8533, #8535, #8537, #8538, #8540, #8544, #8550, #8551, #8556, #8560, #8564, #8568, #8574, #8579 as they are (each one's table, its Language entry in
launcher/src/i18n.rs and its Bundled arm in lang.rs), so each PR is marked merged when this lands.
Their edits to existing tables are left out: main's versions are newer and more accurate.
The next commit fixes the tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Launcher tables get every string main has added since they were written, and lose strings the
code no longer has.
- Product names translated or transliterated as words (Horizon, Minecraft, Java, Mojang…) are back
in Latin script.
- Fixed the meanings machine translation got wrong: a crash written as a vehicle crash, Nightly
as "every night", instance as "example", tick as a checkmark, the controller labels written
as commands, and similar.
- Removed the U+200B pairs that came with the translation tool.
- Game tables drop entries identical to en_us.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merges the heads of #8451, #8452, #8453, #8454, #8455, #8456, #8458, #8467, #8468, #8469, #8472, #8473, #8475, #8477, #8483, #8484, #8495, #8496 as they are (each one's table, its Language entry in
launcher/src/i18n.rs and its Bundled arm in lang.rs), so each PR is marked merged when this lands.
Their edits to existing tables are left out: main's versions are newer and more accurate.
The next commit fixes the tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Launcher tables get every string main has added since they were written, and lose strings the
code no longer has.
- Product names translated or transliterated as words (Horizon, Minecraft, Java, Mojang…) are back
in Latin script.
- Fixed the meanings machine translation got wrong: a crash written as a vehicle crash, Nightly
as "every night", instance as "example", tick as a checkmark, the controller labels written
as commands, and similar.
- Removed the U+200B pairs that came with the translation tool.
- Game tables drop entries identical to en_us.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merges the heads of #8427, #8428, #8431, #8432, #8434, #8435, #8436, #8437, #8439, #8440, #8441, #8442, #8444, #8445, #8446, #8447, #8449, #8450 as they are (each one's table, its Language entry in
launcher/src/i18n.rs and its Bundled arm in lang.rs), so each PR is marked merged when this lands.
Their edits to existing tables are left out: main's versions are newer and more accurate.
The next commit fixes the tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Launcher tables get every string main has added since they were written, and lose strings the
code no longer has.
- Product names translated or transliterated as words (Horizon, Minecraft, Java, Mojang…) are back
in Latin script.
- Fixed the meanings machine translation got wrong: a crash written as a vehicle crash, Nightly
as "every night", instance as "example", tick as a checkmark, the controller labels written
as commands, and similar.
- Removed the U+200B pairs that came with the translation tool.
- Game tables drop entries identical to en_us.
- Also removed stray U+200B from main's bg, fi, he launcher tables and the da_dk game table.
- Serbian: the Cyrillic game table is vanilla's sr_sp (Српски); sr_cs is vanilla's Latin
Serbian, so it now gets the same table transliterated.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Merges the heads of #8394, #8395, #8396, #8398, #8401, #8402, #8405, #8408, #8410, #8412, #8413, #8414, #8415, #8416, #8417, #8418, #8424, #8425 as they are (each one's table, its Language entry in
launcher/src/i18n.rs and its Bundled arm in lang.rs), so each PR is marked merged when this lands.
Their edits to existing tables are left out: main's versions are newer and more accurate.
The next commit fixes the tables.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Keep the decoded state on the TNT model and encode it in command, chunk and portal save views. Invalid inputs fall back to the default TNT state.
Co-Authored-By: Codex <[email protected]>
Set the mannequin's live avatar pose from its saved lowercase value,
using the five accepted poses and standing for absent or invalid inputs.
Keep existing dimension math and raw saved-field writing unchanged.
Cover exact native eye anchors, UUIDs, body positions and invalid controls.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Load and save the independent one-slot inventory, preserving stack components and item limits. Route existing inventory callers through that state.
Co-Authored-By: Codex <[email protected]>
A client mod can now send any serverbound play packet, a plugin channel's
custom payload included, to any server, a vanilla one too. mod_api
re-exports the packet type as ServerboundPlayPacket. An error before the
player is in a server's play state, and for a custom payload past
ServerboundCustomPayloadPacket.MAX_PAYLOAD_SIZE.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011R7zRSugxibySUu8PosW5U
Apply item Health damage with stack resistance and source eligibility,
retain its display name for lethal feedback, and reuse destroyed contents.
Cover real command results, Health, resistance, and selective removal.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
A client mod is told of each chat line from the server just before it
shows, and may replace or cancel it: system messages (chat and action
bar), player chat and disguised chat. Chat Delay's queue now keeps each
message's sender and chat type, so the hook fires when the message
leaves the queue, as vanilla's showMessageToPlayer does, and a
cancelled message lets the next one through.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A client mod sends what the player could type, through send_chat
(ClientPacketListener.sendChat / sendCommand): a leading / is a command,
anything else signed chat. No client chat event and no chat history. An
error when not in a server's play state, for an empty message, and when the
Chat option blocks the message.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fall back to the retained Owner UUID for execute on origin when there is
no mob/player binding. Preserve existing player, guest and mob bindings.
Cover loaded stand/pig owners and unknown/absent owner controls.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Player.dropEquipment: after vanishing-curse items are gone and before the
rest is thrown, the mods may add to, change or take out the stacks. The
context names the player (entity id, minecraft:player), no table. Not
heard with keep_inventory, as vanilla keeps the items then. No new hook:
an API fragment extends native_loot_drops.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
`HORIZON_HDR_OUTPUT=pq` (or `scrgb`) now offers that output to an
`--offscreen` renderer, which has no display to ask. HDR is drawn as with
a window (the 16-bit frame included) and a screenshot writes its `-hdr.png`
beside the SDR one; nothing is presented, and Auto takes 203 and 1000 nits.
A 16-bit frame with HDR off reaches the offscreen target as it reaches a
swapchain. Nothing changes without the variable or with a window.
Fixes#8879
Co-Authored-By: Claude Opus 5.5 <[email protected]>
EndGatewayBlock.entityInside starts that beam through triggerCooldown's block event. The server copy was the only one cooling down, so the window kept drawing nothing.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
A client shulker that changed block only slid with ordinary position
interpolation. Shulker.getRenderPosition pulls the model back toward
the block it left for 6 ticks.
Fixes#8901
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
EnderDragon.aiStep still growls and adds one EXPLOSION each tick after tickDeath has started the rise. The window returned before both.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
The traveling player was sent that event and never heard block.portal.travel.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
PotionItem.useOn sends five SPLASH particles with ServerLevel.sendParticles. Adding them on the server Game never reaches the client window.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Main split item ticking into tick_move and tick_settle. The splash now runs on that path, before the move and again after the second fluid push.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Inserting a sherd broadcast the sound, but the block event and the dust plume stayed on the server. Vanilla wobbles through Level.blockEvent and sends the dust with ServerLevel.sendParticles.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
AbstractCubeMob.tick updates the squish scale on the client as well as the server. The window only ran the landing splash, so the model stayed rigid.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Track item falls until ground contact and dispatch HIT_GROUND from both
item movement and the armor stand landing path. Cover real Game dispatch
with fresh sculk listeners and matched NoGravity controls.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Entity.doWaterSplashEffect draws bubble and splash particles on the client. Dropped items never called it, and mob particles were only added on the server, so the window never drew them.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
The window's cart kept its fuse at -1, so it never showed the smoke, the white flash or the swell.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Fox.aiStep plays FOX_AGGRO through the server's playSound, so a server-thread player hears it at the fox.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Vanilla Rabbit.handleEntityEvent(1) calls spawnSprintParticle and then
starts the hop clocks. The client played the hop and skipped the crumb.
Fixes#8867.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
PrimedTnt.tick adds one SMOKE particle each lit fuse tick on the client. The window ticks that fuse but never spawned the particle, and the server's Level.addParticle does not reach it.
Co-Authored-By: Grok <grok-4.7> <[email protected]>
Co-authored-by: Cursor <[email protected]>
Squid.hurtServer reports a hit only when a living entity caused it, and GlowSquid.hurtServer dims the squid only when that returns true. Horizon dimmed on every hit, so a glow squid on a campfire, suffocating or drying out lost its glow.
Fixes#8724
Co-Authored-By: OpenCode (Jay's Unintelligence) <[email protected]>
Carry current main, spawn protection, and view distance into the stacked simulation-distance PR while retaining every management route and harness case.
Co-Authored-By: Codex (GPT-5.6) <[email protected]>
WitherBoss.addEffect returns false, so nothing lands on the boss. Horizon refused only the wither effect itself (the WitherSkeleton rule), so splash potions, area clouds, /effect and tipped arrows all worked on it.
Both paths that add an effect now refuse every effect for the wither; the wither skeleton keeps its own rule.
Fixes#8776
Co-Authored-By: OpenCode (Jay's Unintelligence) <[email protected]>
Carry current main and the spawn-protection management route into the stacked view-distance PR while preserving both parity harness ranges.
Co-Authored-By: Codex (GPT-5.6) <[email protected]>
Share only the positive cooldown decrement with the NoAI path and cover
both AI modes and signed loader controls on real dedicated servers.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Preserve the spawn-protection management path alongside the operator, status reply, and online-player visibility management changes now on main.
Co-Authored-By: Codex (GPT-5.6) <[email protected]>
Keep owned sprite-set indices from referring to a different declared particle after the resource sets are rebuilt.
Co-authored-by: Codex <[email protected]>
Keep hidden controller ticks and population accounting while emitting no geometry, matching visibility-gated source particles.
Co-Authored-By: Codex <[email protected]>
LivingEntity.tickEffects drops an effect whose duration is 0, because MobEffectInstance.hasRemainingDuration is false there. Horizon counted it down from 0 to -1, the infinite-duration sentinel, so an effect loaded with duration 0 stayed forever and even took its first tick.
Fixes#8721
Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
WitherBoss.canRide returns false, so OldMinecartBehavior.pushAndPickupEntities cannot seat the boss in a moving cart. can_ride_cart excluded only the warden.
Fixes#8790
Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
A hopper, cauldron or composter reaches y=1 with its rim, so its collision
bounds looked like a full block and a mob shadow was drawn across the top.
EntityRenderer.extractShadowPiece draws a shadow piece only when the block
below isCollisionShapeFullBlock; the same gate now applies here.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The overlap-note check timed out and a rerun needs admin
rights, so this push starts it again on current main.
Co-Authored-By: Grok <[email protected]>
CI compiled this branch against a main that still built the
composite shader test's Resources without its rgb field.
Co-Authored-By: Grok <[email protected]>
native_client_packet hears every play packet the window's game handles,
decoded and in order, just before it is handled: handle_packet, plus the
chunk and ForgetLevelChunk paths in poll_remote that bypass it. It only
reads. mod_api re-exports the packet enum as ClientboundPlayPacket so
trait mods can name it.
Closes#8820
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Add reusable JSON golden cases for the stable status, metrics, logs, start, stop, and restart response contracts. Normalize only release, process, and elapsed-time values while checking their types.
Fixes#8816
Co-Authored-By: Codex (GPT-5.6) <[email protected]>
A client mod can move and turn the camera a frame is drawn from: after
vanilla placed it, native_camera_pose gets its position, yaw and pitch and
may set them (a cinematic, replay or film camera). The picture, culling, the
sound's listener and what faces the camera follow it; the player, their aim,
the hand and chunk loading stay the player's. Values that aren't finite keep
vanilla's.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Vèneto strings so vec_it players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Vèneto as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Ślōnskŏ strings so szl players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Ślōnskŏ as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Davvisámegiella strings so se_no players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Decode full packed color bytes with the DyeColor zero fallback and cover
valid, invalid and unknown-pattern controls on real dedicated servers.
Co-Authored-By: Codex gpt-6.1-sol <[email protected]>
Registers Davvisámegiella as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Саха тыла strings so sah_sah players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Саха тыла as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Occitan strings so oc_fr players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Occitan as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Lombard strings so lmo players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Lombard as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Limburgs strings so li_li players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Limburgs as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Furlan strings so fur_it players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Furlan as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
`lod_grid_bench` printed a mean of 5.3 to 5.9 spans a column. A mean
alone says nothing about the shape of the distribution, which is what
decides whether a column's spans fit a fixed inline capacity or take a
heap block; sizing `Spans` off the mean would be a guess.
Print the distribution beside it, with a running total so the share that
fits any given capacity can be read straight off.
Measured at seed 0, 40 tiles a level, Full far detail: four spans or
fewer covers 38% of columns at level 0, 28% at level 2, 26% at level 4
and 32% at level 6, with a tail reaching 14 to 16.
These are the spans worldgen returns, before the client's `shade_sky`
splits fluid and leaf runs a light level at a time.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011paghWkrnyQRBhJRodZpG2
A chunk's detail arrived as `ReducedColumns`, which reduced the 16x16
columns to cells 2, 4, 8 and 16 blocks wide up front: 85 columns beside
the chunk's 256, and four passes of `Column::reduced` over every span of
every footprint.
One chunk is covered by one far tile, so one of the four widths is what
gets read, and a chunk whose detail arrives while full-detail terrain
still draws it reads none. Building all four cost 405 us of a far
terrain thread for every chunk the world sent (measured over 200 chunks
of 5.7 spans a column, the mean `lod_grid_bench` reports); reducing on
the first read of a width costs 103 us, and nothing at all for a chunk
no far tile draws reduced.
`OnceLock` a level each, so a second mesh job reading the same width
takes the reduction already built rather than racing to repeat it.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011paghWkrnyQRBhJRodZpG2
Windows takes a write of any size whole while its buffer has room, so the 64 MiB the test sent all went
through and the disconnect with it. Fixes#8734.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Content::check read each declared block, item, mob effect, creative tab,
entity type and menu with Content::file, which opens the mod's archive
again and parses its whole central directory, unbuffered, every time.
Loading a packaged mod was quadratic in its size. Checking chipped's
.hmod (6,981 blocks, 58,563 entries) took over 20 minutes; with one
reader it takes 2 seconds.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A moving block at full progress now supports like the block it carries, as vanilla's
moving block entity does (getExtendedProgress is 0 at progress 1.0). Wall coral fans
and the carpets on them survived in vanilla when a slime column landed; here the fan
popped because the slime block behind it was still a moving piston, so the carpet
duplication machine had nothing to duplicate.
Fixes#8490
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
`cmd_attribute` looked the entity up in the command source's level only, while
a selector with no spatial constraint searches every loaded level
(`EntitySelector.findEntities`). A target in another dimension therefore came
back as an id the level did not hold: the generic path answered "Entity
entity. has no attribute <name>" and max_health, movement_speed and
attack_damage silently did nothing.
Run the attribute work with the target's level in place through the existing
`in_target_level` helper, the one /data, /kill and /tp already use.
Co-Authored-By: Hermes <[email protected]>
A mod block opening its content mod's menu type asks native_menu_extra_data for bytes
of the mod's own; a horizon:menu_extra payload carries them with the window and the
block's position to Horizon clients right before OpenScreen. The client takes the
block from it instead of the last clicked one, and native_screen_pos /
native_screen_extra_data read both while the mod's screen is open.
Fixes#8675
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`horizon-ctl memory` falls back to a thread's name for allocations made
outside any step, span or job. On Windows `thread_name` returned nothing
at all -- the stub for every platform without `pthread_getname_np` -- so
every untagged allocation on every thread fell into one `unnamed thread`
bucket. That bucket was 580 MiB of a playing game's 1219 MiB resident
set: the largest of all of them, and useless, because it named no thread.
Rust keeps the name `Builder::name` set in its own thread handle, so the
fallback reads it from there. No new dependency, and nothing new in a
release binary: `GetThreadDescription` would have wanted Windows 10 1607
and an import in every build, where this is the name Rust already holds.
The resource loaders had no name to read either: they are spawned through
`Step::spawn` and bare `scope.spawn`, which leave a thread unnamed. They
go through a new `named_scope`, which covers the eight core steps, the
five world-rest loaders and the panorama. The job pool already named its
workers, and so did far terrain.
What the same run reports now, where it reported one 580 MiB bucket:
| MiB | tag |
|---:|---|
| 328.2 | Far sampling |
| 76.4 | unnamed thread |
| 52.0 | Far decoration |
| 35.4 | Far terrain |
| 13.9 | Far meshing |
| 12.4 | World data preload |
| 8.2 | Worldgen loader |
| 8.0 | main |
Far terrain holds ~430 MiB of the heap across its four threads, beside
the 661 MiB of far-tile vertices already measured in video memory. None
of that was visible before.
The startup trace gains the same names: 13 of its 17 lanes read
`unnamed`, which a trace viewer cannot lay out usefully.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_011paghWkrnyQRBhJRodZpG2
Entity.teleportPassengers: teleporting a boat, minecart or mob takes its mob,
player and guest riders along at once. /rotate is Entity.forceSetRotation:
rotation fields only, pitch clamped before the setter. Ender pearl and bed
entry stop riding at their source instead of at guest-turn teardown. Players
and guests get Entity.boardingCooldown (60 ticks) checked before boarding.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
`Turtle.aiStep` broadcasts LevelEvent 2001 while it digs; the handler drew the
particles into the local buffer instead, which a serving client never renders
and no client hears. Route it through `level_event_at(2001, ...)` like every
broken block does, so the sand crumbs and the break sound both follow.
Co-Authored-By: Hermes <[email protected]>
`Warden.clientDiggingParticles` is client work, but `client_tick` discarded the
`DigParticles` events it had already computed (`animate(m, &mut Vec::new())`),
and `sync::client_tick` had no sink to hand them to. Thread the game's event
vector through; it lands in `warden_dig_particles`, which draws the 30 block
particles from the block under the warden.
Co-Authored-By: Hermes <[email protected]>
- jukebox_playable: EitherHolder.streamCodec is either(holder, key), so
its flag is set for a holder; it was read the other way round, and an
item with a song by key broke the rest of its packet (on a 1.21.11
server a whole container_set_content at login).
- container and use_remainder (and sulfur_cube_content) hold item
stacks: their bytes were kept as the server sent them, in its item and
component numbering, and before 26.1 as ItemStacks (a count first). Read
from an older server, they are now read whole and written again as
pinned templates.
- pot_decorations writes its items' pinned ids, and a value rewritten
this way is read back in the pinned numbering.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NbhTr6rUbVKx6iB2X73DNG
The owner already had previousPlayerGameType; a guest had no such field,
and the save removed the key, so the game mode switcher of a guest who
rejoined had nothing to go back to. A guest now keeps it as
ServerPlayerGameMode.changeGameModeForPlayer does (the mode left becomes
the previous one; the mode in use changes nothing), and its file writes it
when there is one and reads it back.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PlayerMotion.ticks_frozen never reached the file: a guest who left inside
powder snow came back thawed, and one who thawed kept whatever TicksFrozen
the file it joined from had. The saved body now carries it, written only
above 0 as Entity.saveWithoutId does (the key is removed otherwise), and read
back with Entity.load's default of 0.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
store set the food level and saturation but left foodExhaustionLevel and
foodTickTimer at 0, so a guest who left mid-sprint came back with no
exhaustion and the regeneration timer restarted. The saved body now carries
both from the live FoodData (FoodData.addAdditionalSaveData) and puts them
back on the next body.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
store never set Motion, so a guest's file always said the player stood
still. The saved body now carries the live delta movement, written as
Motion (Entity.saveWithoutId) and read back for the next body with
Entity.load's rule: a component over 10 blocks a tick reads as 0.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PlayerPredicate.matches looks for the entity the player looks at
(ProjectileUtil.getEntityHitResult over every non-spectator entity but
the player, then hasLineOfSight) whatever the trigger. Horizon searched
only the mobs, and only for using_item, so a looking_at boat, minecart,
armor stand, frame, painting or crystal never matched, and nothing
matched in tick, location or any other trigger.
looking_at_entity now walks every entity list plus frames, paintings
and crystals, and player_entity sets looking_at for every trigger. The
per-tick tick and location triggers cast the ray only when one of their
criteria may ask (names looking_at or a reference predicate), worked
out once per tree.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
The Python tests and the public-tree check only read files, yet cargo
waited for them: about two minutes of every run. They now run in a
thread beside rustfmt, clippy and the tests; the harnesses, which build
with cargo, still come after it, and --verbose keeps everything in
order so the output doesn't interleave.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Three components kept their names but changed their stream codecs, so an
older server's item holding one failed to decode (with a vanilla 1.21.11
server: "1 extra bytes" and "NBT truncated" on container_set_slot):
- pot_decorations (26.3): a list of up to four item ids, a brick for a
plain side, became four optional item stack templates;
- jukebox_playable (26.1): an EitherHolder, a flag then the song's key or
holder, became a holder; a key has no pinned holder and is dropped;
- damage_resistant (26.1): a bare damage type tag became a HolderSet.
Two quirks say which a version has, and one reader (read_added) now
serves the slot, template and wire patch readers alike: it drops the
components the pinned version lacks, rewrites these three into the
pinned layout and reads the rest as before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NbhTr6rUbVKx6iB2X73DNG
A harming splash potion or lingering cloud hurt mobs through Mob::hurt, a
player_attack from the player whoever threw it, and never recorded the thrower
in last_hurt_by_player, so on the server thread the kill reached nobody's
player_killed_entity. They now deal indirectMagic(potion or cloud, owner)
(HealOrHarmMobEffect.applyInstantaneousEffect), the thrower's kill when a
player threw it, and the mob keeps the potion or cloud as the killing blow's
direct entity (Mob::last_direct).
A falling block hitting the player now fires entity_hurt_player with the
falling block as causing and direct entity (FallingBlockEntity.causeFallDamage,
LivingEntity.hurtServer).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
`MobEvent::ParticleAt` was drawn with `self.particles.add` only, and a serving
client has no window: the squid's 30 ink particles never left the server. Send
them as packets like every other server-thread particle site; with count 0 the
packet's deltas are the particle's motion.
Co-Authored-By: Hermes <[email protected]>
26.3 removed the map_color and swing_animation data components. A 1.21.x,
26.1 or 26.2 server still sends them in item patches (an explorer map's
color, a 1.21.11 weapon's swing), and the item readers, which renumber
the component id to -1 there, could not read the value: the whole packet
was skipped, so a container holding such an item showed empty (seen on a
Folia 1.21.11 server: container_set_content, set_entity_data and
update_advancements undecodable).
The registry id generator now lists the components an older version has
and the pinned one lacks, and the item readers read their values past in
that version's layout (an int; two varints) and drop them, from added and
removed components alike. tooltip_display's hidden component ids are
renumbered as well, both ways.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NbhTr6rUbVKx6iB2X73DNG
Neither nautilus had an arm in `remote_mob_takes`, so a tame adult's mount or
screen click fell through, and the generic `Animal.mobInteract` arm claimed any
`kind.food` item for an untamed one although `AbstractNautilus.mobInteract`
only takes `#minecraft:nautilus_taming_items` until it is tamed.
Co-Authored-By: Hermes <[email protected]>
`IronGolem.mobInteract` takes an iron ingot on a damaged golem and
`CopperGolem.mobInteract` takes an empty hand while it holds an item or shears
on its antenna; both were missing from the client's interaction check, so the
click fell through to the item and to the off hand.
Co-Authored-By: Hermes <[email protected]>
`Allay.mobInteract` returns SUCCESS for a holding allay only when the click
came from an empty main hand; everything else is PASS so the held item is
still used. The client answered a flat true whenever the allay held anything,
which swallowed the click, and the server's take-back path ignored the hand.
Co-Authored-By: Hermes <[email protected]>
A data pack that writes an id, tag or registry key without a namespace
("panda", "#planks", "the_nether", "inventory_changed") never matched:
the predicates compared the JSON string literally. Vanilla reads them
through Identifier codecs, where a missing namespace is minecraft.
`full` qualifies the id wherever a predicate compares one: id_matches
(plain id and #tag), the location dimension, entity sub-predicate keys,
effect keys, the loot condition type, the trigger name, the inventory and
recipe indexes, and recipe_unlocked / changed_dimension. damage_source's
tags[].id is a holder set (TagPredicate) and goes through id_matches.
The entity predicate's short key aliases follow from the qualification;
the non-vanilla "type" alias is gone (vanilla 26.3 refuses that key).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
`AbstractHorse.handleEating` (and the llama and camel ones) gates both the age
up and the particle on `isBaby() && !isAgeLocked()`. The client's copy only
asked for `alive() && is_baby()`, so feeding an age-locked baby drew a particle
the server never agreed to.
The decision moves into `ages_on_food`, where the lock belongs.
Co-Authored-By: Hermes <[email protected]>
The firework glide boost in follow_own_player read the look direction from
super::view_vector (Rust f64 sin/cos), while the server derives the player's
rocket boost from getLookAngle()'s float sine table. travelFallFlying already
uses the table; this boost was the one path left on f64 trig, so boosting
under a rocket while gliding drifted the client off the server's position and
tripped the movement check. Use horizon_world::view_direction::view_vector
(the float table), matching the server and the rest of the glide. Covers the
remote path too, which now routes through follow_own_player.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Leaving a multiplayer server goes from close_world straight to
leave_server, which never stopped the sounds: the biome's ambient loop
played on over the title screen until the next world. leave_server now
does what finish_close_world does for single player, as vanilla's
updateLevelInEngines(null) on Minecraft.disconnect: it clears the
ambience, lets the music manager go of its track and stops every sound.
A kick takes the same path.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01NbhTr6rUbVKx6iB2X73DNG
`AbstractHorse.isFood` is the `#minecraft:horse_food` tag and `ZombieHorse`
overrides it with `#minecraft:zombie_horse_food`; the food table was shared by
both, so a zombie horse refused its mushroom and a red mushroom in hand fell
through to a horse's `handleEating` and healed it.
The table moves into `eating(species, item)`, which applies the per-subclass
tag rule and the eat sound gains ZombieHorse's own. A tamed skeleton horse now
eats horse food too, as it inherits that tag (an untamed one still passes).
Co-Authored-By: Hermes <[email protected]>
/tp <entity> x y z <yaw> <pitch> set the rotation only on mobs and players.
Items, orbs, TNT, falling blocks, rockets, armor stands, boats, minecarts,
projectiles and tridents dropped the pitch (and several the yaw), so
/data get Rotation read [0, 0] where vanilla reads [90, 10].
Entity gets rotation() and set_rotation() (Entity.teleportSetPosition:
setYRot, setXRot clamped to -90..90, setOldRot). The kinds with no rotation
field gain one (pitch for armor stands and boats), /tp calls the trait
method for every kind, and the entity saves write the field.
Part of #8024
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
`Turtle.canFallInLove` is `super.canFallInLove() && !this.hasEgg()`, and
`Animal.mobInteract` only eats when `getAge() == 0 && canFallInLove()`. The
food gate only looked at age and the love timer, so an egg-carrying turtle ate
seagrass, entered love mode and played the heart particles.
Co-Authored-By: Hermes <[email protected]>
A dedicated server's console source is bound to the overworld. Horizon ran a
console line in whichever level was in place, which after a tick with forced
chunks in the nether is the nether: summons, fills and selectors landed there.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The launcher could already install a `horizon-client` of your own beside
the releases (`build_import`), to try a merged change before the next
Nightly, but only through the Versions page's file picker or the
`import-build` command. Dropping the program on the window answered
"horizon-client.exe can't be imported: drop a .mrpack, a .zip or a
.hshader", which is the one file the window would not take.
It now takes it. `Dropped::Build` covers the program itself, a release
archive and a GitHub Actions artifact -- a zip around the release's own
archive, which `read_program` already looks into. An `.exe`, `.gz` or
`.tgz` is taken on its extension unread, so `build_import` is the one to
say why a file by that name is not a game, which is a better answer than
"nothing in it that Horizon reads". A file with no extension (a Linux or
macOS build) and a zip nothing else claims are read and checked through
the new `build_import::holds_game`, last, because that reads the whole
program.
The drop starts the same job the picker does: `start_build_import` is
split out of `import_build` so there is one path, one `Msg::Imported`
and one guard against a second import or a removal running at the same
time.
Co-Authored-By: Claude Opus 5 <[email protected]>
The status of each online player (server-status, and /api/v1/players built on it) already
carries the position; it now also carries the dimension the player is in, for example
minecraft:the_nether. The ROUTES text and the generated reference name it, and
tools/server_admin_e2e.py checks the dimension and the three coordinates on a real server.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The Wardrobe page gets Wardrobe | Shop tabs when the cosmetics service shows the
Shop. The Shop has the founder set: when it can be claimed until, the time left, one
Claim button, the four items on cards (Free, Owned, Equipped, Soon), and every state
the mockups list: signed out, loading, offline, service down, claiming, claimed,
owned, not open yet, a preview for one account, closed (the items are gone; owned
ones stay), the claim failing. Equip stays in the Wardrobe. No price anywhere.
HORIZON_SHOP_STATE=<state> previews each one in development builds.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`Plan::visit`'s falloff keeps a far tile's cells roughly the same size on
screen, which silently assumes the field of view never changes. A
spyglass takes a tenth of it, and the zoom mod as much again: the same
tile then covers many times more pixels, so its cells look as coarse as
a tile ten times nearer would. Looking through a spyglass at the horizon
showed exactly the blocky cells it was given for an unzoomed screen.
`ZoomAim` carries what the plan needs to answer that: the view
direction, the cone the narrowed view covers, and how much finer to go.
Tiles inside the cone split further; every other tile keeps the plan it
would have had, tile for tile.
The cone is the point. Lifting the whole circle to a tenth of the cell
size asks for about a hundred times the tiles, which at the 4078 tiles
and ~1500 quads a tile measured at `lodDistance` 256 is gigabytes of
vertices. `MAX_ZOOM_BOOST` caps it at three times finer as well, so the
worst case is roughly 45% more far tiles while the zoom is held, given
back when it is released.
Reads the field of view actually in use rather than any one zoom, so it
covers all three: the spyglass (`getFieldOfViewModifier` while
`isScoping`), the zoom mod (`native_zoom`) and any mod that narrows the
view through `native_compute_fov`. The yaw is rounded to five degrees
before it reaches the plan, and the cone widened by as much, so turning
the mouse does not rebuild the quadtree every frame; the aim is part of
`Lod::update`'s area, so a zoom starting or ending replans exactly once.
The `lodZoomDetail` extra switches it off. It does nothing unless far
terrain is on and the view is actually zoomed, so an unzoomed frame
plans as it always did.
Co-Authored-By: Claude Opus 5 <[email protected]>
Use upstream's neutral light, color, AO, render type and shade defaults in the generated glint fixture. Preserve its geometry, UVs and assertions.
Co-Authored-By: Codex (gpt-6.1-sol) <[email protected]>
`Game::target_with_uuid` answered `Target::Player` for the level's own player
UUID. During a guest's turn the player in place is that guest, so a wolf
whose owner is the world's player (and not among the players online, for
example a single-player world moved to a dedicated server) made
`execute as <wolf> on owner run give @s ...` act on whoever ran the command.
Vanilla's `on owner` is `OwnableEntity.getOwner`, which resolves the stored
UUID through the level (`EntityReference.getLivingEntity`, then the level's
UUID lookup): an owner who is not in the level gives no entity. The player in
place is now the acting guest's UUID during a guest's turn and the level's
player otherwise. An owner who is online as another guest was already found
first by `target_by_uuid`.
Fixes#8488
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A player's snowball, egg or ender pearl that hurts a mob (0 damage
included, as LivingEntity.hurtServer reports it) now credits the hit to
the thrower and fires player_hurt_entity with the projectile as the
direct entity, as the content-mod throwable arm already did. Scooping a
fish, axolotl or tadpole into a water bucket now fires
player_interacted_with_entity with the water bucket and the mob, as
ServerGamePacketListenerImpl.handleInteract does after
Bucketable.bucketMobPickup succeeds.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UE3PMKbnTcxfBSeT5uQWCK
Bundles Horizon's own Føroyskt strings so fo_fo players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Føroyskt as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
These tables were generated before the latest strings landed, so the
launcher completeness test fails on main and on every PR. Add the
missing translations.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Чӑвашла strings so cv_cu players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Чӑвашла as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Brezhoneg strings so br_fr players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Brezhoneg as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Башҡортса strings so ba_ru players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Башҡортса as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own isiZulu strings so zu_za players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers isiZulu as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Yorùbá strings so yo_ng players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Yorùbá as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
These ten tables were generated before the latest settings, native-mod
and instance strings landed, so the launcher completeness test fails on
main and on every PR. Add the missing translations.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own ייִדיש strings so yi_de players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers ייִדיש as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Татарча strings so tt_ru players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Татарча as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Latina strings so la_la players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
A dark cell packs block light 7 where the old code packed 10 in both nibbles,
torchlight 9 clamps to 15, and daylight keeps the sky byte; the quad's four
corners resolve to a quarter of its height below the orb.
ExperienceOrbRenderer.getBlockLightLevel is the level's block light plus
seven, clamped, with the sky light left alone; the pass raised both nibbles
to a floor of 10 instead. submit's quad runs from (-0.5, -0.25) to
(0.5, 0.75) under a 0.3 scale after translate(0, 0.1, 0), so the sprite is a
whole block tall about the orb and hangs a quarter of it below; Horizon drew
a symmetric 0.3 square 0.075 too low. The probe is the orb's eye, half its
box above its feet.
Registers Latina as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
HDR does two jobs: an HDR canvas, and Horizon's look on it. Off, nothing in the world is
lifted, light sources, the sun and sunlight included, and the lighting passes don't run, so
HDR output matches SDR: the vanilla look on an HDR desktop, and a neutral base for packs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Igbo strings so ig_ng players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Igbo as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own ʻŌlelo Hawaiʻi strings so haw_us players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers ʻŌlelo Hawaiʻi as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Esperanto strings so eo_uy players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Esperanto as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Malti strings so mt_mt players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Malti as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own ಕನ್ನಡ strings so kn_in players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
`[shadow] option` names the option the map is drawn while it is not 0: off,
there is no map, no shadow pass and `has_shadow` reads 0, as `[reflection]
option` does for the water mirror. `resolution_option` and `distance_option`
name an int option, or a choice whose values are numbers, whose value replaces
`resolution` or `distance`, checked against the same ranges; changing one
rebuilds the map, as any option change reloads the pack. The options sizing
the map need no `override`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Registers ಕನ್ನಡ as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Кыргызча strings so ky_kg players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Кыргызча as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Lëtzebuergesch strings so lb_lu players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Lëtzebuergesch as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Gàidhlig as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Gàidhlig strings so gd_gb players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
After a world loads, the client keeps queueing a few meshes a second for a
minute or more (vanilla's leaf distance pass reshapes the trees). Two things
in the shared pool then kept the server's generator buffers and caches,
which nothing reads until the player moves into new ground:
- Every wake restarted every sleeping worker's idle wait, even a worker
that got no job, so with jobs queued every few seconds no worker ever
reached IDLE_RELEASE. A worker now counts from its own last job.
- `all_idle` (#7519 empties the generator's shared caches there) needs
every worker idle at once, which never happens while one source stays
busy. A source with nothing queued or running for IDLE_RELEASE is now
told on its own: `idle` for each worker's state and `all_idle`, once
until its next job. The release frees nothing a later job needs: the
generator's caches are emptied whole, as at their limit (#7519).
Each freed release hands the pages back to the OS (`release_free_memory`).
Measured with the alloc-census build, seed 1234, RD 12, offscreen, 150 s
after opening a new world (two runs): stream.generate 171.8 -> 45.3 MB,
the biome cache 1366 chunks -> 0, the live heap 645 -> 527 MB, the resident
set 1063 -> 1001-1014 MB.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Nine tables were generated before the remaining settings and native-mod
strings landed, so the launcher completeness test fails on main. Add the
missing translations.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Strengthen only the original synthetic oracle: fractional contrasting data, hostile unused mip contents and deliberately invalid filtering sampler negative control. Production/API code is byte-identical to the already completed full-check head ec6054c.
Co-Authored-By: OpenAI Codex <[email protected]>
`PowderSnowBlock.entityInside` makes any entity that is not a living one stuck
(`makeStuckInBlock` 0.9, 1.5, 0.9) and, on the server, sends a snowflake when
the entity moved horizontally. Boats did neither: no particle showed when a
boat entered powder snow, and it was not slowed (#8156).
A boat whose box, or the box it had before its move, reaches into powder snow
now keeps a stuck multiplier at the end of its tick, as `AbstractBoat.tick`'s
`applyEffectsFromBlocks` does, and its next move goes its velocity times the
multiplier and spends the velocity (`Entity.move`). The server also sends the
snowflakes, twice a tick as `AbstractBoat.tick` applies the block effects twice,
for boats a player drives as for the others. A boat that is not in powder snow
moves exactly as before. Only the boat's own box is scanned.
Refs #8156
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The game's status now lists each level's loaded chunks and entities
(`levels`), the level in place and the parked ones counted the same way
(players and block entities apart). prometheus() turns them into
horizon_loaded_chunks{dimension} and horizon_entities{dimension}; a level
with no count has no line rather than a 0. The docs drop the item from
"Not there yet".
Fixes#8191
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
goals.rs: main's peaceful_targets_tests (#8046's fix) and this branch's
avoid_entity_targeting_tests sit at the file's end; both kept. Since that
fix, can_target_player already refuses a player in Peaceful through
spares_players, so the goal's own difficulty check is dropped.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Frysk strings so fy_nl players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Frysk as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Iris 1.11.7 reads shaders.properties with IRIS_FEATURE_<name> defined for
the features it has, whether the pack lists them as optional, as required
or not at all (probe pack); its programs still see only the optional ones.
Horizon defined them only after reading the file, so a custom uniform or
a screen behind `#ifdef IRIS_FEATURE_*` was left out. The Shader Options
page reads the file with the same macros.
Fixes#8493
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Iris 1.11.7's values in our probe fit a half-life of a tenth of the fade
time's seconds (probe pack across the scene suite's weather changes):
smooth(rainStrength, 20, 20) reads 0.87 four seconds after the rain is
full, where Horizon's fade of 20 seconds gave 0.2. Horizon's smooth()
lagged ten times behind those values.
Fixes#8492
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Soomaali strings so so_so players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Soomaali as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own ລາວ strings so lo_la players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers ລາວ as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
A column changed by World::edit_runs (a mod's native_edit_blocks) goes whole only to the players it was sent to.
The single-player window's far terrain kept drawing an unsent column as the window last saw it (Lod::saved),
so a strike edited while the player was away left the old land in far terrain until the player came within
view distance again. The hub now hands such columns to its memory-connected window (handoff::changed), which
gives them to far terrain to summarize (Lod::observe), as it does columns it unloads.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Монгол strings so mn_mn players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
On a Horizon pack's options page a float or int option is a slider, as FOV
is, where it was a button stepping through every value. A float takes the
nearest step from its minimum (the last slot its maximum), an int whole
numbers, rounded to the f32 the pack's override gets so a slider back in the
middle is the default exactly. The value is saved, and the pack rebuilt, once
when the slider is let go, and only if it changed. Shift-click puts it back
to its default; Tab, Enter and the arrows work it as they do vanilla's
sliders, a step at a time and stopping at the ends. Bool and choice options
stay buttons.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Registers Монгол as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own தமிழ் strings so ta_in players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers தமிழ் as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Filipino strings so fil_ph players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Filipino as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Galego strings so gl_es players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
`serversettings/status_heartbeat_interval` and `/set` were not answered, and the
supervisor started its heartbeat only when the interval was above 0 at start,
with that first value for good.
The heartbeat thread is now always there and counts its seconds itself. It
reads the interval each second and starts counting again at every set, as
vanilla cancels the heartbeat and schedules a new one
(`ManagementServer.scheduleHeartbeat`: the first after as many seconds), so a
server that began with none can have one and a server that had one can stop it,
with no restart. 0 or less means none, and the interval is kept as it was set,
as vanilla keeps any int.
The set writes `status-heartbeat-interval` to server.properties and to
server.toml's `[properties]`, logs vanilla's "Updated status heartbeat
interval from {} to {}" and answers with the interval now in force. A value
that is not an integer is refused as the other settings' are.
The port map moves `DedicatedServer.setStatusHeartbeatInterval` out of
`skip:server` and the management protocol parity harness compares the get, the
set, an invalid value, the saved property and the value after a restart with
vanilla's. That harness runs a real vanilla server and was not run here; the
unit tests cover the live heartbeat and the persistence.
Fixes#8190
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Registers Galego as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Log in by transfer on a server whose listener is not bound (a local connection):
turned away with `multiplayer.disconnect.transfers_disabled` while transfers are
off, taken once `Shared::set_accepts_transfers(true)` has run, and turned away
again after it is set back. With the handshake reading the fixed
`config.accepts_transfers` again, the middle login fails.
Refs #8190
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
`serversettings/accept_transfers` and `/set` (`ServerSettingsService`,
`DedicatedServer.setAcceptsTransfers`) were not answered. The listener read
`accepts-transfers` once at start, from a fixed field of its configuration.
The listener's shared state now holds it as an atomic, as it holds the live
login limit, and the transfer handshake of `lan/conn.rs` reads that. The
management method changes it at once, writes `accepts-transfers` to
server.properties and, through the supervisor, to server.toml's `[properties]`
so a restart keeps it, and logs vanilla's "Update accepts transfers from {} to
{}". A value that is not a boolean is refused as the other settings' are.
The port map moves `DedicatedServer.setAcceptsTransfers` out of `skip:server`
and the management protocol parity harness compares the get, the set, an
invalid value, the saved property and the value after a restart with vanilla's.
That harness runs a real vanilla server and was not run here.
Refs #8190
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Bundles Horizon's own Euskara strings so eu_es players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Euskara as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Gaeilge strings so ga_ie players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Gaeilge as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Cymraeg strings so cy_gb players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Preserve existing fixture behavior with absent companion maps and no block-surface scope. Consulted only the necessary current-main struct construction sites for this integration.
Co-Authored-By: OpenAI Codex <[email protected]>
The independent candidate reserves block companions for terrain; the newly added main line draw has no colour surface identity and explicitly uses defaults.
Co-Authored-By: OpenAI Codex <[email protected]>
Registers Cymraeg as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Shqip strings so sq_al players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Shqip as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Proposed independently developed replacement for closed#7800, addressing #7747. Preserve colour-layer identity across split arrays, nearest encoded data transport, neutral defaults, resource ownership and colour-selected companion frames. Add original CPU and actual-GPU controls with a pinned input/exposure ledger. Frozen candidate production hunks preserved; integration adjusts a test-module append and clarifies comments.
Co-Authored-By: OpenAI Codex <[email protected]>
Bundles Horizon's own Македонски strings so mk_mk players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Македонски as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Bosanski strings so bs_ba players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Bosanski as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Հայերեն strings so hy_am players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Հայերեն as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own ქართული strings so ka_ge players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers ქართული as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Қазақша strings so kk_kz players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Қазақша as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Proposed independently developed replacement for closed#7842, addressing #7811. Preserve compiler-evaluated constants in actual UBO layout, retain runtime-write precedence, and add original typed and real-GPU controls. Public research input ledger records pinned permissive shader-pack inputs, frozen candidate lineage and exposure limits.
Co-Authored-By: OpenAI Codex <[email protected]>
Bundles Horizon's own Oʻzbekcha strings so uz_uz players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Oʻzbekcha as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Azərbaycanca strings so az_az players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Azərbaycanca as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Беларуская strings so be_by players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Беларуская as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Ghast.addAdditionalSaveData writes ExplosionPower (default 1). An ownerless
projectile has left its owner after its first tick, so a trident saves
LeftOwner. AbstractHurtingProjectile.tick ignites a fireball for a second
every tick (wind charges do not burn).
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Stacks the management series so the queue lands them in order; every
handler, setter, port-map row and harness check of the four is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Bahasa Melayu strings so ms_my players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Stacks the management series so the queue lands them in order; every
handler, setter, port-map row and harness check of the three is kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Registers Bahasa Melayu as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Stacks the management series so the queue lands them in order: both add
handlers, a lan.rs setter, a port-map row and harness checks at the same
places; all of both are kept.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Afrikaans strings so af_za players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Afrikaans as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Íslenska strings so is_is players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Íslenska as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Српски strings so sr_cs players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Српски as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
native_add_server_reload_listeners lists a mod's listeners (NeoForge's
AddServerReloadListenersEvent): an id and a folder under
data/<namespace>/. On each data load of a server (a world opening,
/reload), before native_server_data_loaded,
native_server_reload_listener_apply hands over the folder's .json files
as vanilla's SimpleJsonResourceReloadListener reads them: <ns>:<path>
ids, the top pack's file for each id over the resource root and the
world's enabled data packs, a file that isn't JSON logged and left out.
Fixes#8400.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bundles Horizon's own Slovenščina strings so sl_si players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Slovenščina as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Latviešu strings so lv_lv players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Latviešu as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Bundles Horizon's own Eesti strings so et_ee players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Eesti as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Vanilla's surface rules reach eight blocks down, layering dirt under
grass and sand under a beach. A far tile 256 or 1024 blocks across draws
at most a block or two of each column's vertical face, so the six below
that are work no view resolves.
Reduced far detail now stops at depth 2 for tiles 16 blocks a column or
wider. Depth 1 is still painted, so a tile's surface -- its height, its
top state, its water and its biome -- is exactly what it was: dumping
every column of 25 tiles at levels 4 and 6 gives a file identical to the
one before this change, all 12800 columns. Only the interior of a span,
seen on a cliff face, loses its vanilla material. Full far detail, the
default, is untouched, and so are narrow tiles, whose faces are tall
enough in view to show the layering.
Measured with `lod_grid_bench` over 100 tiles a run, five runs, taking
the least-interfered run of each (this machine's spread is wide):
| level | stride | before | after |
|---|---|---|---|
| 2 | 4 | 10.6 ms | 10.8 ms (gated off) |
| 4 | 16 | 11.1 ms | 10.3 ms (-7.2%) |
| 6 | 64 | 8.7 ms | 8.2 ms (-5.7%) |
Co-Authored-By: Claude Opus 5 <[email protected]>
Bundles Horizon's own Català strings so ca_es players see translated
menus and options instead of the English fallback.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Registers Català as a launcher language with a full table translated
from the English strings.
Co-Authored-By: DeepSeek V4.1 Flash Free <[email protected]>
Entity.move ends with getBlockSpeedFactor for every entity; items and
primed TNT now call the shared helper from #8096.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Since the pass culls the near solid sections itself, a section it draws
appears whole where a CPU frame fades it in or out (vanilla's chunk
fade-in, far terrain's fades). A recorded section now gets FADING in its
record, which cull skips, and its walk mark, so the CPU draws it with its
fade, exactly while the instance loop's own expression for it is not a
whole section's (section_visibility and the far-terrain fade, bit for bit).
The flag is decided at upload, when a section leaves or is held for far
terrain, and anew for every record when the fade-in time changes.
A heap of fade ends in GpuCulling says when to look again, so a frame with
no end due does no fade work; Records counts the flagged records, and
switching GPU culling off forgets the flags with the records. The debug
check also compares each flag and mark with what the fades say.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
TagNetworkSerialization.serializeToNetwork sends each synchronized registry's
tags as TagLoader bound them from the whole pack stack. Horizon's server read
the resource root's tag files only and merged the world's data packs into
the dialog tags alone, so no client (vanilla or Horizon) was told that a
pack put dirt in #minecraft:mineable/pickaxe or a block in #climbable. After
/reload, keep_registries read the root's tags again without any pack, the
packs' dialog tags included.
merge_pack_tags merges, for every synchronized registry the world's packs
have tag files for (tags/<path>, a mod's registry under tags/<ns>/<path> as
Registries.tagsDirPath has it), the root's files and then each pack's in
order ("replace": true, nested tags expanded), at load and on /reload.
Registries no pack touches keep load_tags' tags.
Refs #7843
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Complete relocation strings in new language tables, explicitly release completed world-operation locks, and retain unsaved settings when a move cannot save them.
Co-Authored-By: Codex <[email protected]>
pick_fluid stopped at any non-air cell without a fluid instead of clipping
the block's outline, so a water bucket could not fill through the empty part
of a torch's cell. ClipContext.Block.OUTLINE lets the ray through; the ray
now stops only where it meets an outline box. This covers the buckets
(empty, fish), glass bottle, lily pad / frogspawn and spawn eggs, which
all use this ray.
Fixes#8180
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
GLSL gives a `bool` in a `layout(std430)` buffer a size and an alignment of
4. naga does not let a bool into a storage buffer at all, so the program
failed with "Global variable [6] '' is invalid: ... The type is not
host-shareable": no name, no member, and the line of the include site (#8175).
Such a member now becomes a `uint` of the same size and every use of it is
rewritten before the stage is scanned: a read is `(flag != 0u)` (also through
an instance, `state.flag`, and an array, `flags[i]`), a plain assignment is
`flag = uint(...)`. Nothing is added or removed from a line, so the pack's
line numbers stay right. It applies to render and compute programs.
What the rewrite cannot make sure of is refused with the member's name and its
line, instead of naga's anonymous error: a compound assignment (`flag |= x`),
an assignment used as a value, a local or parameter of the same name, a `bool`
vector member and an instance array of such a buffer.
Tests: the five shapes of the issue translate; the refusals name the member and
the line; the rewritten text is checked exactly; a compute program reads and
writes a bool member. Before the change the first test fails with the exact
message of the issue for every shape.
Fixes#8175
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A superflat world that decorates (`features` or `lakes`) but generates no
structure set, because `generate_structures` is off or its
`structure_overrides` is `[]`, still went through FlatTerrain, which lays the
layers and the Void platform only. FlatLevelSource decorates with
adjustGenerationSettings whatever its structures do.
FlatTerrain::structure_settings becomes pipeline_settings: the settings of a
superflat world that lets a structure set generate or that decorates. World
loading streams such a world on the flat pipeline when its structures generate
or it decorates; the pipeline then has no structure starts when
generate_structures is off, and no set when the overrides are empty.
FlatTerrain keeps the worlds with neither, and the Void.
Refs #2912
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A player carried by a boat only ran `passenger_pose_tick`, never the part of
`LivingEntity.aiStep` that applies the effects of the blocks it is in. Powder
snow's FREEZE never added a tick of frost to the window's own player, and
nothing thawed it, so `ticks_frozen`, which the frostbite overlay reads, stayed
where it was: the server froze and hurt the rider, who saw no frost (#8156).
`passenger_block_effects_tick` samples the blocks the passenger is in, as the
client does on foot, and thaws two ticks a tick out of powder snow as the
server does; the riding branch of the client tick calls it after the pose.
The server's copy of a riding guest is untouched: it already freezes in
`server_block_damage`.
Refs #8156
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
tools/test_flat_generation_parity.py runs VanillaChunkGenerationOracle with
HORIZON_FLAT=<flat_level_generator_preset>, which builds a real FlatLevelSource
from the preset registry (with ChunkMap's random state for a generator without
noise, and createState's structure state), and chunk_dump with the same
variable on OverworldGenerator::flat. Every block, quart biome and block entity
of the target chunks is compared after decoration, for the three presets that
decorate (Overworld, Desert, Tunnelers' Dream) and three that only place layers
and structures. A decorating preset must hold blocks beyond its layers in
vanilla, so the decoration is known to be covered.
Refs #2912
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A superflat world on the structure pipeline (Generator::flat, #5509) built its
decoration with no placed feature at all. FlatLevelSource decorates with
FlatLevelGeneratorSettings.adjustGenerationSettings of its biome (26.3
bytecode): the lava lakes of createLakesList in the lakes step when `lakes` is
on; the biome's own features when `features` is on and the layers are not all
air (or the biome is the_void), except those of the underground and surface
structure steps, and of the lakes step when `lakes` is on.
FlatSettings now carries `features` and `lakes`, and Decoration::new_with takes
that adjustment. The FillLayerFeatures stay last in TOP_LAYER_MODIFICATION, as
the builder adds them after the biome's features.
Refs #2912
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`AvoidEntity::can_use` picked what to flee with a distance and height test,
where `AvoidEntityGoal` targets through `TargetingConditions.forCombat()`:
`canAttack` (no player is a target at all in Peaceful), the range scaled by
`getVisibilityPercent` with a floor of 2, and line of sight. Fish, ocelots,
foxes, rabbits, pandas and illusioners fled a player standing behind a wall or
on the other side of a hill, a sneaking or invisible one from the full 8 or 16
blocks, and still fled in Peaceful; creepers fled cats and skeletons fled
wolves through walls.
The player arm now runs `Mob::can_target_player` (the existing port of
`TargetingConditions.test`) after the goal's own predicate, and the species arm
needs `Mob::sees`. The target lookup moved into `AvoidEntity::avoid_target`, so
the conditions are testable without the random retreat position and the path.
Co-Authored-By: Hermes <[email protected]>
Fix Linux clippy::non_octal_unix_permissions without changing the unreadable-source fixture or its assertions.
Co-Authored-By: Codex <[email protected]>
Limit fast/release compiler outputs after builds and expose cache inspection and cleanup. Coordinate builds and cleanup with OS/Cargo locks; preserve installed versions and player data.
`currentRenderedItemId` was a frame uniform reading 0 in every program, and
a hand program that read it without declaring it failed to translate, so
the hand fell back to gbuffers_textured_lit.
- `HzDraw`'s fourth int, a pad until now, is `currentRenderedItemId`: -1 for
terrain, water and the sky, 0 for entity runs (items drawn in the level
are not done).
- The hand draws one run per arm and held item, each with its own `HzDraw`
slot. A block item reads its block's block.properties id, or 0 when that
file lacks it, whatever item.properties says; any other item reads its
item.properties id, 65535 when the file lacks it, and 0 without the file.
- The hand's programs may read `currentRenderedItemId` undeclared; terrain's
and entities' may not.
This is what Iris 1.11.7 does, observed with probe packs of our own.
Part of #6812
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Modded now lists the chosen loader's versions for the chosen Minecraft
version, asked of its service once per loader and version: Newest stable
first, then every version newest first, betas marked. The choice goes to
loaders::choose when the instance is made, and goes back to the newest
stable one when the loader or the game version changes. The loader card
shows the version chosen. Its four strings are in every language.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Armadillo.rollUp and Armadillo.rollOut call gameEvent(ENTITY_ACTION)
before their sound, silent or not; sculk sensors, shriekers and wardens
now hear it.
Fixes#8714
instance import <file> --java makes a Minecraft: Java Edition instance from a
Modrinth pack, as Prism Launcher imports one: the Minecraft version and the
mod loader its index names (minecraft, fabric-loader, quilt-loader, forge,
neoforge), every override (overrides/, client-overrides/) and file it
carries, files checked against their hash; a server-only file and
server-overrides/ are left out, and a path that leaves the folder is
refused. A pack that fails half way leaves no instance behind. Without
--java a modded pack still goes to the Modpacks import.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The processors are planned (steps) before they run, so a test checks the
client steps three real install profiles ask for (NeoForge 26.3.0.101,
Forge 26.3-66.1.0 and 1.20.1-47.4.0, recorded without icon and library
lists) against values read off the profiles by hand. The ignored real
install now also builds Play's command and runs it with the JVM's
--dry-run: module path, classpath and main class resolve, nothing of the
game runs, no account is involved.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
forge_install downloads the installer (checked against the .sha1 its
repository publishes), takes the libraries from its maven/ folder or the
repository (each sha1 checked), runs the client's processors on the
instance's Java as java -cp <jar+classpath> <Main-Class> <args> with the
install profile's data, skips a processor whose outputs already match and
refuses one that leaves another sha1. The profile is kept as
versions/<id>/<id>.json with a copy of the game's jar named after it, as
Forge's ignoreList (${version_name}.jar) expects; java_launch::resolve now
lets a child name its own jar.
java_game picks the Java before installing the loader, so the installer
runs on the Java the game runs on. The new instance's loader picker shows
every loaders::Kind with its logo.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The block texture array's pixels (21 MB with the default resources) stayed in
RenderAssets for the whole session, though the GPU holds them and the copy
only serves a renderer made again. Once a renderer exists they are
lz4-compressed on a thread of their own, as the GUI atlas is (#6843); a
renderer built again uncompresses them.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Add a two-step data-folder move that copies and verifies launcher, game and build data offline, preserves source recovery copies, and atomically commits an independent location pointer before reopening. Protect migration with process leases, reject links and overlapping destinations, preserve Windows access permissions and remap managed structured paths.
Fixes#7218
Co-Authored-By: Codex <[email protected]>
Preserve main's face-normal and sprite-rectangle caches while keeping GUI
vanilla atlas coordinates separate from CIT sprite-local glint UVs.
Reject malformed texture sections before stitching and read metadata from
the same prepared snapshot as rendered textures. Add rejection, control,
prepared-resource and real-oracle emitted-UV regression coverage.
Co-Authored-By: Codex (gpt-6.1-sol) <[email protected]>
Reconstruct the pinned item atlas layout from the active sprite sources so
standard GUI glint receives the same atlas UVs as vanilla. Use the device
limit and selected filtering when rebuilding the renderer; keep the HUD
texture coordinates and CIT glint coordinates separate.
Add independent vanilla UV and packing regressions, including animation,
generated sources, padding, invalid metadata and atlas-limit boundaries.
Co-Authored-By: Codex (gpt-6.1-sol) <[email protected]>
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
799 changed files with 139384 additions and 7928 deletions
gh pr create --base main --head "$branch" --title 'Stamp native hook API fragments' --body 'Assign API numbers to the pending native hook fragments. Close and reopen this PR to run CI.'
# The repo doesn't let GitHub Actions open pull requests (that setting would also let it approve them):
# the branch is pushed, and a maintainer opens the PR from it.
if ! gh pr create --base main --head "$branch" --title 'Stamp native hook API fragments' --body 'Assign API numbers to the pending native hook fragments. Close and reopen this PR to run CI.'; then
echo "::warning::Stamped fragments are on $branch; open a pull request from it (GitHub Actions may not open one here)."
@@ -868,7 +868,7 @@ Banners in End cities show as plain magenta instead of with their pattern.
<details><summary>Technical</summary>
Compare the banner block entities the End city templates place with vanilla's (`EndCityPieces`, the templates' block entity NBT, `BannerBlockEntity`'s patterns), in `crates/horizon-world/src/worldgen/structure/`. Issue [#1438](https://github.com/horizon-rust/horizon/issues/1438); possibly related: [#526](https://github.com/horizon-rust/horizon/issues/526).
Compare the banner block entities the End city templates place with vanilla's (`EndCityPieces`, the templates' block entity NBT, `BannerBlockEntity`'s patterns), in `crates/horizon-world/src/worldgen/structure/`. Issue [#1438](https://github.com/horizon-rust/horizon/issues/1438); possibly related: [#526](https://github.com/horizon-rust/horizon/issues/526). The templates' block entities now keep their patterns ([#1928](https://github.com/horizon-rust/horizon/issues/1928)).
</details>
@@ -878,7 +878,7 @@ Armour and tools in End city chests should come enchanted, as in vanilla.
<details><summary>Technical</summary>
`loot.rs` implements `enchant_with_levels`: find why the End city chest table's rolls come out bare, and compare them with vanilla's for a few seeds. Issues [#1437](https://github.com/horizon-rust/horizon/issues/1437), [#1660](https://github.com/horizon-rust/horizon/issues/1660).
`loot.rs` implements `enchant_with_levels`: find why the End city chest table's rolls come out bare, and compare them with vanilla's for a few seeds. Issues [#1437](https://github.com/horizon-rust/horizon/issues/1437), [#1660](https://github.com/horizon-rust/horizon/issues/1660). The loot's enchantment functions now reach every table that rolls ([#1911](https://github.com/horizon-rust/horizon/issues/1911), [#2037](https://github.com/horizon-rust/horizon/issues/2037)).
"Hidden: every Horizon player sees you without your cosmetics, you included. The same switch as the launcher's Wardrobe."
}
Item::CosmeticsOthers=>{
"What other Horizon players wear: everything, only their name tag styles, or nothing. Hidden, the game never asks what they wear."
"What other Horizon players wear: everything, only their name tag styles, or nothing. Hidden unless you own cosmetics, until you choose. Hidden, the game never asks what they wear."
}
Item::CosmeticsAuras=>"Auras and trails other players wear. Off by default.",
Item::Pvp(o)=>o.description(),
Item::WheelCyclesSettings=>{
"The scroll wheel over a button in the settings changes its value, as in vanilla. Off, the wheel only scrolls the list."
Loaded 100 of 799 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.