Compare commits

...
Author SHA1 Message Date
Ludovic Marie 7e05a39a92 Merge commit '38da7d8d6e78526c0522904717143125453d32c7' into union/pt3-w1 2026-10-29 16:39:14 +01:00
Ludovic Marie 02ef54254b Merge commit '0dcc9a15fdc2850bf669e9b3564a9ac535aec289' into union/pt3-w1 2026-10-29 16:39:14 +01:00
Ludovic Marie bb5bcf52dd Merge commit '191b66303a3067d1410ed25e85e32504db281e79' into union/pt3-w1 2026-10-29 16:39:13 +01:00
Ludovic Marie 12f1b2cc00 Merge commit '3451e4e29a9276326eb0c0dca2b38cf36ecef468' into union/pt3-w1 2026-10-29 16:39:13 +01:00
Ludovic Marie 7565ea2f17 Merge commit '25e39a2f2ef036d981e977a4138a82170de16016' into union/pt3-w1 2026-10-29 16:39:13 +01:00
Ludovic Marie 1a90ff4382 Merge commit '5a1c095724048b869e725b2f369ae5ff0bd409b6' into union/pt3-w1 2026-10-29 16:39:13 +01:00
Ludovic Marie 02b0a7bc65 Merge commit 'bc78cba5b9118e396117f65885d3d2ab71eaddea' into union/pt3-w1 2026-10-29 16:39:13 +01:00
Ludovic Marie 2a62069c2f Merge commit 'd7662a97da9c4112a6fb449ab4fd18d7f01255a0' into union/pt3-w1 2026-10-29 16:39:12 +01:00
Ludovic Marie fdfe30e026 Merge commit '4623d2e59fc36dfda3ae5f35e3eb568d003a9120' into union/pt3-w1 2026-10-29 16:39:12 +01:00
Ludovic Marie af7dc5fae0 Merge commit '558904775f69091c5bfaac537550aa414b262680' into union/pt3-w1 2026-10-29 16:39:12 +01:00
Ludovic Marie ecc61a5421 Merge commit '8ce20ba5bdda3fa24ca2f1d5e71e9e64ad23f76a' into union/pt3-w1 2026-10-29 16:39:12 +01:00
Ludovic Marie 7e46f5ec8d Merge commit '32967a2f0feb50a4a86c4ffc28c51e886cc1c45f' into union/pt3-w1 2026-10-29 16:39:12 +01:00
Ludovic Marie 5c4cbda32e Merge commit 'f7300bd96b34320065e5db77f62df2eafadd5828' into union/pt3-w1 2026-10-29 16:39:11 +01:00
Ludovic Marie 41d5dade66 Merge commit '479d10e794f368ab244476745b6a489394233023' into union/pt3-w1 2026-10-29 16:39:11 +01:00
Ludovic Marie 1205c6abdf Merge commit '5e6bed2e427af05f7a3feb58a413c33f3efb0837' into union/pt3-w1 2026-10-29 16:39:11 +01:00
Ludovic Marie 62a23ba025 Merge pull request #3325 from ThatCakeIsAPie/feat/create-world-data-packs
🤖 Agent: verified by Ludovic's AI agent (Claude): follows CreateWorldScreen's temp data pack folder flow; main merged, clippy and the datapack/title/pack screen tests pass, verify green. Queued for the merger.
2026-10-29 16:37:10 +01:00
Ludovic MarieandClaude Opus 5.5 38da7d8d6e Merge main into this branch
brush.rs: main's player_generates_container_loot trigger (#33c15a6d7) is
kept in unpack_brush_loot, which now reads the Brushable block entity.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 16:24:59 +01:00
Ludovic MarieandClaude Opus 5.5 5e6bed2e42 Merge main into this branch; the column fill uses the palette scan
#3253 (on main) replaced BlockSection's local_ids map with a scan of the
live palette and a last-lookup cache. fill_column now finds the state's id
with id_in, clears the cache when the old state's slot is freed, and sets
it when the section becomes uniform.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 16:23:23 +01:00
Ludovic Marie 8bb23aa1f7 Merge remote-tracking branch 'origin/main' into pt3/2927 2026-10-29 16:21:14 +01:00
Ludovic MarieandClaude Opus 5.5 558904775f Merge main into this branch
Text displays: main's text_display::draw and Lines (#2812) replace this
branch's inline drawing, with this branch's display_light (the same light);
this branch's display_data and transformation are kept beside them.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 14:10:43 +01:00
Ludovic MarieandClaude Opus 5.5 191b66303a Merge main into this branch
tools/port_publish.py: main already writes the store path with Posix
separators and ~ (the same fix), so main's version is kept; the roadmap
UTF-8 reads and writes remain.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 14:05:50 +01:00
Ludovic MarieandClaude Opus 5.5 5a1c095724 Merge main into this branch
hud.rs: main's name_tag (and its test) and this branch's draw_inline_object
(and its tests) both kept.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 14:00:51 +01:00
Ludovic MarieandClaude Opus 5.5 bc78cba5b9 Merge main into this branch
remote.rs: main's spectator check and off-hand anchor charge are kept with
this branch's InteractionResult: an anchor charged from the off hand is
SUCCESS (RespawnAnchorBlock.useItemOn) and swings, a jukebox taking a disc
is SUCCESS (JukeboxPlayable.tryInsertIntoJukebox), an anchor left to the
off hand's glowstone is PASS. level/tests.rs: both new tests kept.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 13:59:19 +01:00
levzzzandClaude Opus 5.5 479d10e794 Tutorial hints are recorded by the window only: the server thread no longer saves options.txt from its stale copy of the settings when a guest picks up a log or breaks one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 17:56:06 +05:00
Ludovic MarieandClaude Opus 5.5 98c0883c8f Merge main into this branch; suspicious blocks are not containers
remote.rs: main's spectator check (a spectator's use predicts nothing) and
this branch's shelf prediction are both kept, the spectator first.

machines.rs: the new Brushable block entity made the dispenser harness's
dropper under suspicious sand treat it as an empty container and drop
nothing; BrushableBlockEntity is no Container, so the dropper drops in
front of it as vanilla does.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 13:55:05 +01:00
levzzz b5b762b840 Merge remote-tracking branch 'hr/main' into pr-2964
# Conflicts:
#	crates/horizon-client/src/game/remote.rs
2026-10-29 17:41:04 +05:00
damnurmumandCodex a5a0e1bb98 Merge main into inline object text
Resolve HUD text rendering conflict by preserving inline player and atlas objects alongside the new world text shadow and depth behavior.

Co-Authored-By: Codex <[email protected]>
2026-10-29 15:18:19 +03:00
SolomonNumb1 0dcc9a15fd smithing cleanup 2026-10-29 16:14:17 +05:00
Ludovic MarieandClaude Opus 5.5 a20aaf5396 Text objects: vanilla's default fallback when none is given
ObjectContents.visit uses the object's defaultFallback without one:
[item/porkchop], [porkchop@gui] off the blocks atlas, [Steve head].

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:51:40 +01:00
Ludovic Marie 1d01a2d696 Merge remote-tracking branch 'origin/main' into upd/3325 2026-10-29 10:51:09 +01:00
Ludovic MarieandClaude Opus 5.5 49cf77a312 Merge main into this branch, stub the tutorial in the remote mining test
game.rs/remote.rs: main's creative screen reopen (#3187) and code of conduct
reset are kept beside this branch's tutorial steps. tests/test_remote_mining.py
compiles remote.rs's mining against its own small Game, which now needs a
no-op tutorial_destroy (verify failed with E0599 there).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:33:29 +01:00
GIGABAIT93andClaude Opus 5.5 479f53624c Python tools: read and write UTF-8 in roadmap.py and port_publish.py
roadmap.py reads and writes ROADMAP.md and the roadmap TOML as UTF-8, so
build writes the · as git has it and build --check doesn't call a fresh
checkout out of date on Windows. port_publish.py decodes gh's and
node's output as UTF-8, so an issue body's arrows survive an update, and
writes the store path as #3441 does, so the two pull requests agree.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 11:23:53 +02:00
Ludovic MarieandClaude Opus 5.5 1eb34fa68e Merge main into this branch
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:18:40 +01:00
Ludovic MarieandClaude Opus 5.5 d7662a97da Merge main into this branch
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:18:35 +01:00
Ludovic MarieandClaude Opus 5.5 4623d2e59f Merge main into this branch
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:18:33 +01:00
GIGABAIT93andClaude Opus 5.5 0f4880bacd Python tools and tests: the same results on Windows
port_publish names the version store with forward slashes, so an issue
reads the same whoever publishes it (test_port_publish expected
~/code/... and Windows wrote ~\code\...), and writes the issue body as
UTF-8 for gh whatever the code page. test_roadmap reads ROADMAP.md as
UTF-8. All 408 Python tests now pass on Windows, with or without
PYTHONUTF8.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 10:55:09 +02:00
Username59138andClaude Opus 5.5 3451e4e29a Command blocks: keep the command in the edit screen, suggest as vanilla
Command blocks barely worked from the default single player (the window
is a client of its server thread), a LAN guest or a dedicated server:

- ServerPlayer.openCommandBlock: the server now sends the block's data
  (saveCustomOnly) to the player whose use opened it, and the open
  screen refills from it (handleBlockEntityData, updateGui). The chunk's
  update tag leaves the command out, so the screen showed an empty box
  and Done then wiped the block's command.
- Screen.extractBackground of an isInGameUi screen: the dimmed
  gradient, not the in-world menu background.
- CommandSuggestions in the command box with the arguments
  AbstractCommandBlockEditScreen passes (commands without a slash,
  completions from the start, 7 lines under the box, fill 0x80000000):
  the chat's suggestions take a SuggestLayout. Server completions
  (ask_server) reach the box too.
- horizon-ctl key presses reach the command block screen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 11:53:14 +03:00
Kacpherek 25e39a2f2e Follow the crate split: repoint 1,272 map rows to their files' new crates 2026-10-29 09:07:15 +01:00
Kacpherek 630f3feec5 Merge branch 'main' of https://github.com/ludovic111/horizon into tools/port-ledger-harness
# Conflicts:
#	docs/port-ledger.md
#	tools/port_ledger.py
2026-10-29 09:07:15 +01:00
Kacpherek 451720bb56 Port ledger: link parity harnesses to the methods they cover; list untested ports 2026-10-29 06:40:06 +01:00
Ludovic MarieandClaude Opus 5.5 cef862471f Merge main into this branch
Main now has the render crate split (#3186); Git followed the moved files,
and nothing in this branch needed changing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 06:13:13 +01:00
Ludovic MarieandClaude Opus 5.5 8ce20ba5bd Merge main into this branch
Main now has the render crate split (#3186); Git followed the moved files,
and nothing in this branch needed changing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 06:13:12 +01:00
Ludovic MarieandClaude Opus 5.5 f7300bd96b Merge main into fix/multiplayer-safety-notice
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 02:12:57 +01:00
Ludovic MarieandClaude Opus 5.5 326719539d Merge main into fix/shelf-interaction
main's #2952 added banner, vault and trial spawner arms to lan::chunks::entity_tag next to this branch's brushable and shelf arms; both stay.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 23:32:54 +01:00
Ludovic MarieandClaude Opus 5.5 d3559e2a5f Proceed past the safety notice in the F5 server list test
main's f5_reloads_the_server_list (4c4fcedf4) came after this branch: its first Multiplayer click now opens SafetyScreen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 23:00:28 +01:00
Ludovic MarieandClaude Opus 5.5 c90893c29c Merge main into fix/multiplayer-safety-notice
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 23:00:18 +01:00
Ludovic MarieandClaude Opus 5.5 b85a9e8350 Merge main into fix/server-core-parity
main added the pack prompt and server dialogs to the screens that stay open when the window loses focus;
they move into pause_if_inactive with the rest of that check.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 22:54:25 +01:00
Kacpherek 2f95ce431c Follow the furnace code to furnace.rs on main; answer Fox.getBreedOffspring 2026-10-28 20:15:39 +01:00
Kacpherek 0536ebbe98 Merge remote-tracking branch 'origin/main' into tools/port-ledger 2026-10-28 20:11:46 +01:00
damnurmumandCodex dd130f1902 Render player heads and atlas sprites in text components
Parse Minecraft object components into inline spans and draw player heads and atlas sprites with the existing HUD atlas. Resolve head profiles through the skin cache and preserve fallback text for plain output.

Co-Authored-By: Codex <[email protected]>
2026-10-28 22:07:28 +03:00
Kacpherek 59538c7dc1 Map the remaining vanilla methods: commands, network, packs, advancements and the last ten 2026-10-28 20:05:02 +01:00
ThatCakeIsAPieandClaude Opus 5.5 24e316855e Create World: the Data Packs screen
The More tab's Data Packs button opens vanilla's PackSelectionScreen (the
resource pack screen's port, titled dataPack.title) on a new mcworld-
folder: its packs, with their icons, and the built-in one, re-listed when
the folder changes. Create New World copies the folder's packs into the
world's datapacks/ and writes datapacks.json with the selection, as
CreateWorldScreen.copyTempDataPackDirToNewWorld does. Cancel deletes the
folder. Worlds made without opening the screen are unchanged.

The pack screen parity harness also runs the screen under dataPack.title.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 12:50:12 -05:00
Muhammad Asif 1a9040ad79 Swing the arm when opening containers
MultiPlayerGameMode.useItemOn swings on InteractionResult.SUCCESS
(SwingSource.CLIENT). The remote client only swung when the held item
was a block, so opening a chest, barrel, furnace, or similar storage
did not start the arm animation.
2026-10-28 22:33:23 +05:00
Kacpherek 2c10febff1 issue: read registry names, so a mooshroom report finds MushroomCow 2026-10-28 18:27:10 +01:00
Kacpherek a32e0ac4ec Add a vanilla-parity skill: start parity fixes from the port ledger 2026-10-28 18:09:19 +01:00
Kacpherek fd8f1a02a1 Map client screens, toasts, recipe book and world screens 2026-10-28 17:43:08 +01:00
Kacpherek a1cf544de7 map-check: accept full Class#method keys 2026-10-28 17:29:51 +01:00
Kacpherek 8d8737a266 Map client rendering, particles, sounds and resources 2026-10-28 17:29:16 +01:00
Kacpherek c045245e8e Map client packet handling, entity renderers and models, block renderers
Also let PORT_LEDGER_NO_MAP build without the verdict map, to measure the
automatic matches on their own.
2026-10-28 16:54:18 +01:00
Kacpherek 91358d8088 Map the rest of the game logic: classes with no Rust trace, then method batches 2026-10-28 16:26:00 +01:00
Kacpherek 969749da3d Map 13 game-logic batches and add map-check
map-check checks verdict-map files against the last build without
rebuilding, so several mappers can check their own rows at once.
2026-10-28 14:42:02 +01:00
Kacpherek 5a8b9687e5 Document class homes, structural matches and the verdict map 2026-10-28 13:53:58 +01:00
Kacpherek 0f7036f9b1 Map the first three batches: animals, inventory screens, world generation 2026-10-28 13:53:58 +01:00
Kacpherek 12c503e154 Port ledger: class homes, structural matches and the verdict map
Give every vanilla class its Rust home files, weighed from all its matches.
In those files, match a method to the fn that touches the same fields and
reaches the ports of the same callees. Read tools/port_map/*.tsv, where a
person or agent records a verdict for what nothing else finds (port, inline,
missing, skip with a reason), and list the next unanswered batch with todo.
Count field-only constructors as trivial and fold initializer lambdas into
<clinit> and <init>.
2026-10-28 13:53:58 +01:00
Kacpherek 2dd963a539 Document the port ledger's new matching, gaps and commands 2026-10-28 13:16:02 +01:00
Kacpherek cd42938b88 Port ledger: bytecode calls, wider matching, drift, issue and check
Read the game jar's bytecode for exact call targets, constants and ids, and
resolve Rust calls through the receiver's type. Match more methods: same-named
fns in an impl or file named for the class (the impl type must fit the class),
and callees of known pairs linked through the call graph. Leave trivial methods
out of coverage.

New gap kind drift: a port that never names a sound, particle, item, block,
effect or game event its vanilla method uses, or lacks one of its rare numbers.
Seam gaps on the old in-frame path sort last; maths and geometry callees no
longer make seam or callee gaps.

New commands: issue (the classes, Rust code and gaps a bug report points at),
check (what a branch touches, gaps it opens and closes against its base), diff,
and a searchable offline report.html.
2026-10-28 13:16:01 +01:00
Kacpherek ef304f30c9 Document the port ledger 2026-10-28 11:23:50 +01:00
Kacpherek e36fd24008 Add the port ledger: vanilla methods next to the Rust functions that port them
tools/port_ledger.py indexes the decompiled sources and the Rust tree into .local/port-ledger/ledger.json and answers where/what/class/coverage queries both ways, with the gaps where a port isn't wired like vanilla (seam, client, class, callee, stale).
2026-10-28 11:23:50 +01:00
Kacpherek 345f64e47c Import the Sounds trait for the elytra sound 2026-10-28 06:23:27 +01:00
Kacpherek 8f84c2cd48 Play the elytra's flying sound while gliding
Horizon had no ElytraOnPlayerSoundInstance, so gliding and diving were silent. The loop starts when the player starts gliding, fades in after a second, and follows the player's whole speed, so a straight dive is the loudest.
2026-10-28 06:16:05 +01:00
Kacpherek e0a48b3f66 Document the 2..128 render distance range 2026-10-28 05:56:49 +01:00
Kacpherek d35efa25ec Accept render distances up to 128 from the command line and horizon-ctl
--render-distance and horizon-ctl render-distance check against the same cap as the options.
2026-10-28 05:56:48 +01:00
Kacpherek b8b15b1682 Raise the render distance cap from 64 to 128 chunks
The options slider and options.txt now accept 2..128. 128 is where the server protocol's view distance (an i8) tops out.
2026-10-28 05:56:48 +01:00
Kacpherek 05f8ec650d Pass the safety notice in the direct connection test
Multiplayer now opens SafetyScreen first, so the test proceeds through it.
2026-10-28 05:45:51 +01:00
Kacpherek 1944dd45e4 Fix display light borrow and format
display_light took &self while text displays were borrowed mutably; it now takes the world. Also rustfmt.
2026-10-27 22:35:25 +01:00
Ludovic MarieandClaude Opus 5.5 44448d941f Merge #2706 into #2927: the unchanged-block skip reads the column cache
#2706 lands first; with #2927's surface column cache the check reads the
cached state instead of decoding the section.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-27 22:29:15 +01:00
Kacpherek fece4c6a76 Run function commands at function-permission-level
Function lines parsed at whatever level the caller had, so a tick or load function did nothing in a world without cheats and an owner's function could run /stop. Vanilla compiles every function line at the library's permission (function-permission-level, 2 elsewhere).
2026-10-27 22:26:19 +01:00
Kacpherek a0b19a4820 Stop a dedicated server whose tick runs past max-tick-time
max-tick-time was read and never used. Vanilla's ServerWatchdog (DedicatedServer.initServer, when the value is above 0) logs and writes a crash report once a tick is that far past its due time, then exits with status 1.
2026-10-27 22:26:19 +01:00
Kacpherek 02b1d1f430 Pause on lost focus only after 500 ms without it
Horizon paused the moment the window lost focus. Vanilla's pauseIfInactive waits until focus has been missing for more than 500 ms, so a brief focus steal does not pause.
2026-10-27 22:26:19 +01:00
Kacpherek b910cdd257 Draw block and item display entities on clients
A client only had an arm for text displays. DisplayRenderer draws a block display's model or an item display's item under the same billboard and transformation, with the brightness override or the light at the entity.
2026-10-27 22:25:37 +01:00
Kacpherek 3934833369 Send text, block and item display data to clients
Summoned displays reached clients as bare entities, so a text display showed nothing. Vanilla syncs Display's entries 8 to 22 and each type's own (text 23 to 27, block state 23, item and context 23 and 24) from the saved compound.
2026-10-27 22:25:37 +01:00
Kacpherek 621473f60e Send the ominous item spawner to guests and draw its floating item
The spawner existed only on the server, so a client never saw the item grow and turn. Vanilla tracks it with DATA_ITEM; the client draws OminousItemSpawnerRenderer and runs tickClient's particles.
2026-10-27 22:21:29 +01:00
Kacpherek 2b2dc1929f Show tipped and spectral arrows to guests and clients
A server sent every arrow as a plain one. Vanilla sends a spectral arrow as its own type and a tipped arrow's ID_EFFECT_COLOR, and the client draws arrow_spectral.png and sheds the effect swirls (Arrow.tick) and sparkles (SpectralArrow.tick).
2026-10-27 22:20:33 +01:00
Kacpherek 052dac817a Drop a guest that misses a keep-alive for 15 seconds
The server waited 30 s for the answer. Vanilla disconnects with a timeout when the last keep-alive is still pending 15 s after it was sent; 30 s is only the read timeout.
2026-10-27 22:19:12 +01:00
Kacpherek 42388d2512 Swap items with shelves and powered shelf chains 2026-10-27 22:02:24 +01:00
Kacpherek 2deaab2602 Render items stored in shelves 2026-10-27 22:02:24 +01:00
Kacpherek 797482183c Show tutorial hints and track their progress 2026-10-27 22:02:18 +01:00
Kacpherek ca28a0edad Show items revealed by brushing suspicious blocks 2026-10-27 22:02:18 +01:00
Kacpherek 694568a89c Show the multiplayer safety notice on the first Multiplayer click
Horizon opened the server list at once and never read skipMultiplayerWarning. Vanilla TitleScreen shows SafetyScreen first, with a do-not-show-again box saved to options.txt, unless that option is set.
2026-10-27 21:56:00 +01:00
Hector Eccles 20d7d111e5 Merge branch 'ludovic111:main' into perf/terrain-rustgen-ports 2026-10-27 15:39:08 -04:00
Hector EcclesandOpenCode fb769e55e0 Worldgen: rustfmt the terrain performance changes
Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
2026-10-27 15:25:06 -04:00
Hector EcclesandOpenCode 01d0170821 Worldgen: keep the skipped aquifer decisions' pending fluid flag
The fill no longer calls compute_substance for positive density or for air
above the aquifer's skip height. Both old paths cleared the aquifer's pending
fluid update; reproduce that side effect so the terrain-fill probe's
should_schedule_fluid_update matches vanilla (it caught the difference).

Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
2026-10-27 15:01:42 -04:00
Hector EcclesandOpenCode e71f98adde Worldgen: write positive-density fill runs through the section once
A positive-density run is exactly the default block, so the fill no longer
calls set_block_raw and the settled heightmap checks per block. One palette
lookup per section segment writes the run, its non-air count follows the air
blocks it replaced, and the heightmap is updated at the run's top only, as
rustgen's fill_initial_solid_cell does for uniform cells.

Noise 1.74 -> 1.57 ms/chunk one thread and 2.27 -> 2.10 at 13; terrain +4.4%
(min) and +1.2% (min) at 13. Block snapshots identical.

Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
2026-10-27 14:39:52 -04:00
Hector EcclesandOpenCode e319dd578f Worldgen: resolve each surface column once into a reused buffer
The surface walk read every column from paletted sections at least twice (the
top-down pass and the stone-depth look-behind). Column now keeps the resolved
ids for the read range, refilled into one buffer per chunk and updated by
set_block, as rustgen's SurfaceSystem does with read_column.

Surface 1.46 -> 1.41 ms/chunk one thread, 4.19 -> 3.89 at 13; terrain +1.4%
(min 2.6%) and +3.7% at 13. Block snapshots identical.

Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
2026-10-27 14:20:16 -04:00
Hector EcclesandOpenCode 0f596d9e3c Worldgen: one material worker per carving pass
Every restored dirt block under a carved cell built a fresh
MaterialDensitySources and MaterialConditions, compiled the whole surface
rule and allocated its bindings. A carver now builds one worker per pass and
moves only the 1x1x1 bindings to the cell, as rustgen's CarvingContext does.

Carvers 0.44 -> 0.40 ms/chunk on one thread and 0.62 -> 0.49 at 13 threads;
terrain +0.6% one thread and +0.98% (median) at 13. Block snapshots identical.

Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
2026-10-27 14:14:48 -04:00
Hector EcclesandOpenCode 7671219f1a Worldgen: skip the aquifer for solid and high air blocks in the fill
The fill called compute_substance for every block although the aquifer only
does work for blocks below its skip height. Positive density always yields the
default block, and above both the skip height and the fluid level a
non-positive density is air, so the fill now decides both cases itself.

One-thread terrain 4.30 -> 4.08 s (noise 1.95 -> 1.75 ms/chunk); 13-thread
noise 2.51 -> 2.27 ms/chunk. Block snapshots are identical.

Co-Authored-By: OpenCode (DeepSeek V4.1 Flash) <[email protected]>
2026-10-27 14:04:59 -04:00
145 changed files with 5134 additions and 1606 deletions

No files matched your search

+106 -2
View File
@@ -1,6 +1,6 @@
//! Text components from commands: `ComponentArgument` reads an SNBT (or JSON)
//! value, `ComponentSerialization` turns it into styled text.
use crate::text::{Style, Text, named_color};
use crate::text::{InlineObject, Style, Text, named_color};
use horizon_world::nbt::Tag;
use serde_json::{Map, Value};
@@ -296,6 +296,10 @@ pub fn to_text_with(
let style = object_style(o);
let content = if let Some(t) = contents(o) {
t
} else if let Some(object) = inline_object(o, resolve, contents) {
let mut text = Text::literal("\u{fffc}");
text.spans[0].style.inline_object = Some(object);
text
} else if let Some(t) = o.get("text") {
match t {
Value::String(s) => Text::literal(s.clone()),
@@ -332,12 +336,74 @@ pub fn to_text_with(
{
out.push(to_text_with(extra, resolve, contents).with_style(&style));
}
out
if o.contains_key("object") || o.contains_key("player") || o.contains_key("sprite") {
out.with_component(Value::Object(o.clone()))
} else {
out
}
}
Value::Null => Text::empty(),
}
}
fn inline_object(
object: &serde_json::Map<String, Value>,
resolve: &mut dyn FnMut(&str) -> Text,
contents: &mut dyn FnMut(&serde_json::Map<String, Value>) -> Option<Text>,
) -> Option<InlineObject> {
let kind = object.get("object").and_then(Value::as_str);
let fallback = object
.get("fallback")
.map(|value| to_text_with(value, resolve, contents).plain());
match kind {
Some("player") | None if object.contains_key("player") => {
let profile = object.get("player")?.clone();
// PlayerSprite.defaultFallback.
let fallback = fallback.unwrap_or_else(|| {
match profile
.as_str()
.or_else(|| profile.get("name").and_then(Value::as_str))
{
Some(name) => format!("[{name} head]"),
None => "[unknown player head]".to_owned(),
}
});
Some(InlineObject::Player {
profile,
hat: object.get("hat").and_then(Value::as_bool).unwrap_or(true),
fallback,
})
}
Some("atlas") | None if object.contains_key("sprite") => {
let atlas = object
.get("atlas")
.and_then(Value::as_str)
.unwrap_or("minecraft:blocks")
.to_owned();
let sprite = object.get("sprite")?.as_str()?.to_owned();
// AtlasSprite.defaultFallback: short names, the atlas unless blocks.
let fallback = fallback.unwrap_or_else(|| {
let short = |id: &str| match id.split_once(':') {
Some(("minecraft", path)) => path.to_owned(),
Some(_) => id.to_owned(),
None => id.to_owned(),
};
if short(&atlas) == "blocks" {
format!("[{}]", short(&sprite))
} else {
format!("[{}@{}]", short(&sprite), short(&atlas))
}
});
Some(InlineObject::Atlas {
atlas,
sprite,
fallback,
})
}
_ => None,
}
}
/// `CustomName` as text: a string keeps its legacy formatting codes, anything
/// else is a component (`ComponentSerialization`).
pub fn name_text(tag: &Tag) -> Text {
@@ -351,6 +417,44 @@ pub fn name_text(tag: &Tag) -> Text {
mod tests {
use super::*;
#[test]
fn player_object_survives_text_parsing_and_keeps_its_siblings() {
let component = serde_json::json!({
"text": "<",
"extra": [
{"object": "player", "player": {"name": "elyapluggin"}, "hat": false,
"fallback": "[head]"},
{"text": " >", "color": "gold"}
]
});
let text = to_text(&component, &mut |_| Text::empty());
assert_eq!(text.plain(), "<[head] >");
assert!(matches!(
&text.spans[1].style.inline_object,
Some(InlineObject::Player { hat: false, .. })
));
assert!(text.spans[2].style.inline_object.is_none());
assert_eq!(text.component(), component);
let sprite = serde_json::json!({"object": "atlas", "sprite": "minecraft:item/porkchop"});
let text = to_text(&sprite, &mut |_| Text::empty());
assert!(matches!(
&text.spans[0].style.inline_object,
Some(InlineObject::Atlas { sprite, .. }) if sprite == "minecraft:item/porkchop"
));
// ObjectContents.visit without a fallback: the sprite's defaultFallback.
assert_eq!(text.plain(), "[item/porkchop]");
let head = serde_json::json!({"object": "player", "player": {"name": "Steve"}});
assert_eq!(
to_text(&head, &mut |_| Text::empty()).plain(),
"[Steve head]"
);
let gui = serde_json::json!({"atlas": "gui", "sprite": "hud/heart/full"});
assert_eq!(
to_text(&gui, &mut |_| Text::empty()).plain(),
"[hud/heart/full@gui]"
);
}
#[test]
fn snbt_and_json_components() {
let input = "{text:'Hi ',color:red,extra:[{text:\"there\",bold:1b}]} rest";
+31 -1
View File
@@ -58,6 +58,28 @@ pub enum ClickEvent {
OpenFile(String),
}
/// A non-character `minecraft:object` embedded in a text component.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InlineObject {
Player {
profile: Value,
hat: bool,
fallback: String,
},
Atlas {
atlas: String,
sprite: String,
fallback: String,
},
}
impl InlineObject {
pub fn fallback(&self) -> &str {
match self {
Self::Player { fallback, .. } | Self::Atlas { fallback, .. } => fallback,
}
}
}
/// Text style; `None` fields inherit from the enclosing style.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Style {
@@ -77,6 +99,8 @@ pub struct Style {
/// The font (`FontDescription.Resource`), a full id like
/// `minecraft:alt`; the default font when unset.
pub font: Option<String>,
/// Content metadata for a single U+FFFC object span; never inherited.
pub inline_object: Option<InlineObject>,
}
/// A style's `font` field: an identifier (`alt` is `minecraft:alt`).
pub fn font_id(v: &Value) -> Option<String> {
@@ -337,7 +361,13 @@ impl Text {
}
/// Component.getString: the plain characters.
pub fn plain(&self) -> String {
self.spans.iter().map(|s| s.text.as_str()).collect()
self.spans
.iter()
.map(|s| match &s.style.inline_object {
Some(object) if s.text == "\u{fffc}" => object.fallback(),
_ => s.text.as_str(),
})
.collect()
}
pub fn is_empty(&self) -> bool {
self.spans.iter().all(|s| s.text.is_empty())
+177 -43
View File
@@ -653,6 +653,42 @@ pub struct Commands<'a> {
pub registries: &'a Registries,
}
/// `CommandSuggestions`' constructor arguments: how a screen's suggestions
/// parse and where they are drawn.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SuggestLayout {
/// `commandsOnly`: the input is a command without a leading `/`.
pub commands_only: bool,
/// `onlyShowIfCursorPastError`: completions from the command's start,
/// not only past the `/`.
pub only_past_error: bool,
/// `suggestionLineLimit`.
pub line_limit: usize,
/// `anchorToBottom`: the list and usage over a box at the bottom, else
/// under one at the top (y 72).
pub anchor_to_bottom: bool,
/// `fillColor`: behind the list and the usage lines.
pub fill: i32,
}
impl SuggestLayout {
/// ChatScreen.init's `CommandSuggestions`.
pub const CHAT: Self = Self {
commands_only: false,
only_past_error: false,
line_limit: 10,
anchor_to_bottom: true,
fill: FILL,
};
/// AbstractCommandBlockEditScreen.init's `CommandSuggestions`.
pub const COMMAND_BLOCK: Self = Self {
commands_only: true,
only_past_error: true,
line_limit: 7,
anchor_to_bottom: false,
fill: i32::MIN,
};
}
/// The open chat screen: vanilla's `ChatScreen` with its `EditBox` and
/// `CommandSuggestions` (argument colouring, usage lines, parse errors,
/// the suggestion list, Tab completion, history).
@@ -680,6 +716,7 @@ pub struct ChatScreen {
pub auto_suggestions: bool,
/// `CommandSuggestions.setRestrictions`: what the Chat option allows.
pub abilities: ChatAbilities,
pub layout: SuggestLayout,
}
/// Local completions waiting for the server's reply to request `id`.
struct Awaiting {
@@ -750,6 +787,43 @@ impl ChatScreen {
keep_suggestions: false,
auto_suggestions: true,
abilities,
layout: SuggestLayout::CHAT,
};
s.update_command_info(m, c);
s
}
/// `AbstractCommandBlockEditScreen.init`: the command box at the top,
/// focused, holding `command`, with suggestions from the start.
pub fn command_block(
m: &Measure,
c: &Commands,
command: &str,
width: i32,
height: i32,
) -> Self {
let mut input = TextField::new(width / 2 - 150, 50, 300, 20);
input.max_length = 32500;
input.focused = true;
input.set_value(m, command);
let mut s = Self {
input,
width,
height,
history_buffer: String::new(),
history_pos: 0,
parse: None,
pending: None,
awaiting: None,
request: None,
suggestions: None,
usage: Vec::new(),
usage_position: 0,
usage_width: 0,
allow_suggestions: true,
keep_suggestions: false,
auto_suggestions: true,
abilities: ChatAbilities::new(ChatVisibility::Full),
layout: SuggestLayout::COMMAND_BLOCK,
};
s.update_command_info(m, c);
s
@@ -768,7 +842,11 @@ impl ChatScreen {
let value = self.input.value.clone();
let auto = self.auto_suggestions;
let abilities = self.abilities;
*self = Self::new(m, c, &value, self.history_pos, width, height, abilities);
*self = if self.layout == SuggestLayout::CHAT {
Self::new(m, c, &value, self.history_pos, width, height, abilities)
} else {
Self::command_block(m, c, &value, width, height)
};
self.auto_suggestions = auto;
}
}
@@ -814,11 +892,18 @@ impl ChatScreen {
self.usage.clear();
let cursor = self.input.cursor;
let cursor_b = byte_at(&command, cursor);
if command.starts_with('/') {
let slash = command.starts_with('/');
if self.layout.commands_only || slash {
let start = usize::from(slash);
if self.parse.is_none() {
self.parse = Some(c.dispatcher.parse_at(&command, 1, c.registries));
self.parse = Some(c.dispatcher.parse_at(&command, start, c.registries));
}
if cursor >= 1 && (self.suggestions.is_none() || !self.keep_suggestions) {
let from = if self.layout.only_past_error {
start
} else {
1
};
if cursor >= from && (self.suggestions.is_none() || !self.keep_suggestions) {
let parse = self.parse.as_ref().expect("parsed above");
let (range, list, ask) =
c.dispatcher
@@ -1002,7 +1087,11 @@ impl ChatScreen {
0,
self.input.screen_x(m, 0) + self.input.inner_width() - width,
);
let y = self.height - 12;
let y = if self.layout.anchor_to_bottom {
self.height - 12
} else {
72
};
// sortSuggestions: those starting with the word at the cursor first.
let partial = &value[..byte_at(&value, self.input.cursor)];
let word = partial[last_word_index(partial)..].to_lowercase();
@@ -1011,9 +1100,16 @@ impl ChatScreen {
s.text.starts_with(&word) || s.text.starts_with(&format!("minecraft:{word}"))
});
first.extend(rest);
let n = first.len().min(10) as i32;
// SuggestionsList: beside a bordered box, or over an unbordered one.
let n = first.len().min(self.layout.line_limit) as i32;
let bordered = i32::from(self.input.bordered);
let top = if self.layout.anchor_to_bottom {
y - 3 - n * 12
} else {
y - bordered
};
let mut l = SuggestionList {
rect: [x - 1, y - 3 - n * 12, width + 1, n * 12],
rect: [x - (1 - bordered), top, width + 1, n * 12],
original: value,
list: first,
offset: 0,
@@ -1042,11 +1138,12 @@ impl ChatScreen {
}
fn cycle(&mut self, l: &mut SuggestionList, dir: isize) {
self.select(l, l.current as isize + dir);
let max = l.list.len().saturating_sub(10);
let limit = self.layout.line_limit;
let max = l.list.len().saturating_sub(limit);
if l.current < l.offset {
l.offset = l.current.min(max);
} else if l.current > l.offset + 9 {
l.offset = (l.current as isize + 1 - 10).clamp(0, max as isize) as usize;
} else if l.current >= l.offset + limit {
l.offset = (l.current as isize + 1 - limit as isize).clamp(0, max as isize) as usize;
}
}
/// `SuggestionsList.useSuggestion`.
@@ -1074,7 +1171,57 @@ impl ChatScreen {
ctrl: bool,
) -> ChatAction {
use winit::keyboard::KeyCode as K;
// CommandSuggestions.keyPressed.
if self.suggestions_key(m, c, key, shift) {
return ChatAction::None;
}
match key {
K::Escape => return ChatAction::Close,
K::Enter | K::NumpadEnter => {
// ChatScreen.keyPressed: without `hasAllowedInput` the input
// stays, unsent, and the screen stays open.
if !self.abilities.allows(&self.input.value) {
return ChatAction::None;
}
return ChatAction::Submit(self.normalized());
}
K::ArrowUp => self.move_in_history(m, c, history, -1),
K::ArrowDown => self.move_in_history(m, c, history, 1),
_ => {
self.field_key(m, c, key, shift, ctrl);
}
}
ChatAction::None
}
/// The input box's own keys (`EditBox.keyPressed`), the suggestions
/// following an edit: whether the box took the key.
pub fn field_key(
&mut self,
m: &Measure,
c: &Commands,
key: winit::keyboard::KeyCode,
shift: bool,
ctrl: bool,
) -> bool {
match self.input.key(m, key, shift, ctrl) {
Some(changed) => {
if changed {
self.edited(m, c);
}
true
}
None => false,
}
}
/// `CommandSuggestions.keyPressed`: the list's arrows, Tab and Escape,
/// and Tab to show it. True when the suggestions took the key.
pub fn suggestions_key(
&mut self,
m: &Measure,
c: &Commands,
key: winit::keyboard::KeyCode,
shift: bool,
) -> bool {
use winit::keyboard::KeyCode as K;
if let Some(mut l) = self.suggestions.take() {
let handled = match key {
K::ArrowUp | K::ArrowDown => {
@@ -1091,37 +1238,18 @@ impl ChatScreen {
}
K::Escape => {
self.input.suggestion = None;
return ChatAction::None;
return true;
}
_ => false,
};
self.suggestions = Some(l);
if handled {
return ChatAction::None;
}
handled
} else if key == K::Tab {
self.show_suggestions(m);
return ChatAction::None;
true
} else {
false
}
match key {
K::Escape => return ChatAction::Close,
K::Enter | K::NumpadEnter => {
// ChatScreen.keyPressed: without `hasAllowedInput` the input
// stays, unsent, and the screen stays open.
if !self.abilities.allows(&self.input.value) {
return ChatAction::None;
}
return ChatAction::Submit(self.normalized());
}
K::ArrowUp => self.move_in_history(m, c, history, -1),
K::ArrowDown => self.move_in_history(m, c, history, 1),
_ => {
if self.input.key(m, key, shift, ctrl) == Some(true) {
self.edited(m, c);
}
}
}
ChatAction::None
}
/// `ChatScreen.moveInHistory`.
fn move_in_history(&mut self, m: &Measure, c: &Commands, history: &[String], dir: isize) {
@@ -1175,7 +1303,7 @@ impl ChatScreen {
if !l.contains(mouse.0, mouse.1) {
return false;
}
let max = l.list.len().saturating_sub(10) as i32;
let max = l.list.len().saturating_sub(self.layout.line_limit) as i32;
l.offset = ((l.offset as f64 - amount.clamp(-1.0, 1.0)) as i32).clamp(0, max) as usize;
true
}
@@ -1246,7 +1374,9 @@ impl ChatScreen {
) -> Vec<Draw> {
let (w, h) = (self.width, self.height);
let mut out = Vec::new();
d::fill(&mut out, 2, h - 14, w - 2, h - 2, background);
if self.layout.anchor_to_bottom {
d::fill(&mut out, 2, h - 14, w - 2, h - 2, background);
}
let format = |s: &str, o: usize| self.format(s, o);
self.input.draw(&mut out, m, blink_ms, Some(&format));
if let Some(mut l) = self.suggestions.take() {
@@ -1254,14 +1384,18 @@ impl ChatScreen {
self.suggestions = Some(l);
} else {
for (i, line) in self.usage.iter().enumerate() {
let y = h - 27 - 12 * i as i32;
let y = if self.layout.anchor_to_bottom {
h - 27 - 12 * i as i32
} else {
72 + 12 * i as i32
};
d::fill(
&mut out,
self.usage_position - 1,
y,
self.usage_position + self.usage_width + 1,
y + 12,
FILL,
self.layout.fill,
);
d::text(&mut out, line.clone(), self.usage_position, y + 2, -1, true);
}
@@ -1275,7 +1409,7 @@ impl ChatScreen {
l: &mut SuggestionList,
mouse: (i32, i32),
) {
let limit = l.list.len().min(10);
let limit = l.list.len().min(self.layout.line_limit);
let [rx, ry, rw, rh] = l.rect;
let has_prev = l.offset > 0;
let has_next = l.list.len() > l.offset + limit;
@@ -1284,8 +1418,8 @@ impl ChatScreen {
l.last_mouse = mouse;
}
if has_prev || has_next {
d::fill(out, rx, ry - 1, rx + rw, ry, FILL);
d::fill(out, rx, ry + rh, rx + rw, ry + rh + 1, FILL);
d::fill(out, rx, ry - 1, rx + rw, ry, self.layout.fill);
d::fill(out, rx, ry + rh, rx + rw, ry + rh + 1, self.layout.fill);
if has_prev {
for x in (0..rw).step_by(2) {
d::fill(out, rx + x, ry - 1, rx + x + 1, ry, -1);
@@ -1300,7 +1434,7 @@ impl ChatScreen {
let mut hovered = false;
for i in 0..limit {
let y = ry + 12 * i as i32;
d::fill(out, rx, y, rx + rw, y + 12, FILL);
d::fill(out, rx, y, rx + rw, y + 12, self.layout.fill);
if mouse.0 > rx && mouse.0 < rx + rw && mouse.1 > y && mouse.1 < y + 12 {
if moved {
self.select(l, (i + l.offset) as isize);
@@ -74,9 +74,28 @@ pub enum BlockEntity {
/// `DaylightDetectorBlockEntity`: no data, only the ticker
/// (`DaylightDetectorBlock.tickEntity`).
DaylightDetector,
/// Suspicious sand and gravel: saved loot and the transient brushed face.
Brushable(Box<Brushable>),
/// A shelf holds three displayed item stacks.
Shelf(Box<Shelf>),
/// `ChiseledBookShelfBlockEntity`: a `Container` of six one-book slots.
ChiseledBookshelf(Box<ChiseledBookshelf>),
}
/// `BrushableBlockEntity`: the loot table is resolved on the first brush.
#[derive(Clone, Debug, Default)]
pub struct Brushable {
pub loot_table: Option<horizon_world::nbt::Tag>,
pub loot_seed: Option<horizon_world::nbt::Tag>,
pub item: Option<ItemStack>,
/// Direction's legacy network id; not saved to disk by vanilla.
pub hit_direction: Option<i32>,
}
/// `ShelfBlockEntity`'s displayed slots and alignment flag.
#[derive(Clone, Debug, Default)]
pub struct Shelf {
pub items: [Option<ItemStack>; 3],
pub align_to_bottom: bool,
}
/// `ChiseledBookShelfBlockEntity`: six slots and `lastInteractedSlot`.
#[derive(Clone, Debug, PartialEq)]
pub struct ChiseledBookshelf {
+24 -5
View File
@@ -2,8 +2,8 @@
//! kinds, ticking as `AbstractFurnaceBlockEntity.serverTick` with fuel times
//! from the data-driven `context_int_provider`/`context_float_provider` files.
pub use crate::chunk::block_entity::{
Banner, Beacon, BlockEntity, Campfire, ChiseledBookshelf, Crafter, CreakingHeart, EndGateway,
Furnace, FurnaceKind, Jukebox, Lectern, Skull, SkullSkin,
Banner, Beacon, BlockEntity, Brushable, Campfire, ChiseledBookshelf, Crafter, CreakingHeart,
EndGateway, Furnace, FurnaceKind, Jukebox, Lectern, Shelf, Skull, SkullSkin,
};
use crate::items::ItemStack;
use std::collections::HashMap;
@@ -230,6 +230,14 @@ impl BlockEntity {
recipes_used: HashMap::new(),
}));
}
if matches!(
name,
"minecraft:suspicious_sand"
| "minecraft:suspicious_gravel"
| "minecraft:brushable_block"
) {
return Some(Self::Brushable(Box::default()));
}
if name == "minecraft:creaking_heart" {
return Some(Self::CreakingHeart(Box::default()));
}
@@ -292,6 +300,9 @@ impl BlockEntity {
if name == "minecraft:campfire" || name == "minecraft:soul_campfire" {
return Some(Self::Campfire(Box::default()));
}
if name == "minecraft:shelf" || name.ends_with("_shelf") {
return Some(Self::Shelf(Box::default()));
}
if name == "minecraft:chiseled_bookshelf" {
return Some(Self::ChiseledBookshelf(Box::default()));
}
@@ -334,8 +345,10 @@ impl BlockEntity {
Self::Skull(_) => "minecraft:skull",
Self::EndGateway(_) => "minecraft:end_gateway",
Self::DaylightDetector => "minecraft:daylight_detector",
Self::Brushable(_) => "minecraft:brushable_block",
Self::Campfire(_) => "minecraft:campfire",
Self::ChiseledBookshelf(_) => "minecraft:chiseled_bookshelf",
Self::Shelf(_) => "minecraft:shelf",
}
}
pub fn contents(&self) -> Vec<ItemStack> {
@@ -354,13 +367,15 @@ impl BlockEntity {
| Self::CommandBlock(_)
| Self::EndGateway(_)
| Self::Skull(_)
| Self::DaylightDetector => Vec::new(),
| Self::DaylightDetector
| Self::Brushable(_) => Vec::new(),
Self::Lectern(l) => l.book.iter().cloned().collect(),
Self::Sculk(_) => Vec::new(),
Self::Banner(_) => Vec::new(),
Self::Crafter(c) => c.items.iter().flatten().cloned().collect(),
Self::Campfire(c) => c.items.iter().flatten().cloned().collect(),
Self::ChiseledBookshelf(b) => b.items.iter().flatten().cloned().collect(),
Self::Shelf(b) => b.items.iter().flatten().cloned().collect(),
}
}
pub fn slots(&self) -> &[Option<ItemStack>] {
@@ -376,9 +391,11 @@ impl BlockEntity {
| Self::Banner(_)
| Self::EndGateway(_)
| Self::Skull(_)
| Self::DaylightDetector => &[],
| Self::DaylightDetector
| Self::Brushable(_) => &[],
Self::Crafter(c) => &c.items,
Self::ChiseledBookshelf(b) => &b.items,
Self::Shelf(b) => &b.items,
Self::CreakingHeart(_)
| Self::Spawner(_)
| Self::TrialSpawner(_)
@@ -402,9 +419,11 @@ impl BlockEntity {
| Self::Banner(_)
| Self::EndGateway(_)
| Self::Skull(_)
| Self::DaylightDetector => &mut [],
| Self::DaylightDetector
| Self::Brushable(_) => &mut [],
Self::Crafter(c) => &mut c.items,
Self::ChiseledBookshelf(b) => &mut b.items,
Self::Shelf(b) => &mut b.items,
Self::CreakingHeart(_)
| Self::Spawner(_)
| Self::TrialSpawner(_)
+19
View File
@@ -308,6 +308,25 @@ fn deliver(home: &Path, report: Report) -> Option<PathBuf> {
}
}
/// The report for a hung server tick, written by the watchdog thread
/// (`ServerWatchdog`): the stuck thread's stack is not available to Rust, so
/// the report carries none.
pub fn report_watchdog(home: &Path, side: &'static str, message: String) -> Option<PathBuf> {
deliver(
home,
Report {
time: Local::now(),
description: "Watching Server".into(),
error: format!("{message} (Watching Server)"),
stack: String::new(),
thread: thread_name(),
side,
details: system_details(),
log: crate::logging::recent_lines(),
},
)
}
fn panic_message(info: &std::panic::PanicHookInfo) -> String {
let payload = info.payload();
let text = payload
@@ -125,6 +125,114 @@ pub fn discover(world: &Path) -> Vec<DataPack> {
packs
}
// ---- Create World ------------------------------------------------------------
/// Create World's Data Packs screen (`PackSelectionScreen` on vanilla's
/// `mcworld-` folder): the folder's packs (`PackSource.WORLD`) and the
/// built-in one (`resources` holds its `pack.png`), which can be unselected
/// and stays at the bottom. Horizon has no experiments, so their feature
/// packs are not offered.
pub fn screen_packs(dir: &Path, resources: &Path) -> Vec<crate::pack_screen::PackInfo> {
use crate::{
pack_screen::{Compat, PackInfo, Source, load_icon},
packs::Position,
text::{Style, Text},
};
let format = horizon_core::version::DATA_PACK_FORMAT;
let mut infos: Vec<PackInfo> = crate::packs::folder(dir, format)
.into_iter()
.map(|p| PackInfo {
icon: p.icon_png().as_deref().and_then(load_icon),
id: p.id,
title: p.title,
description: p.raw_description,
description_style: p.description_style,
source: Source::World,
compat: p.compatibility,
required: false,
position: Position::Top,
fixed: false,
})
.collect();
infos.push(PackInfo {
id: "vanilla".into(),
title: Text::translate("dataPack.vanilla.name", &[]),
description: Text::translate("dataPack.vanilla.description", &[]),
description_style: Style::default(),
source: Source::BuiltIn,
compat: Compat::Compatible,
icon: std::fs::read(resources.join("pack.png"))
.ok()
.as_deref()
.and_then(load_icon),
required: false,
position: Position::Bottom,
fixed: false,
});
infos
}
/// A new empty folder for Create World's packs
/// (`Files.createTempDirectory("mcworld-")`).
pub fn temp_folder() -> std::io::Result<PathBuf> {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
let dir = std::env::temp_dir().join(format!("mcworld-{}-{nanos}", std::process::id()));
std::fs::create_dir_all(&dir)?;
Ok(dir)
}
/// What's in a folder of packs, to notice packs added or removed while the
/// screen shows it (`PackSelectionScreen.Watcher`).
pub fn folder_stamp(dir: &Path) -> Vec<(String, Option<std::time::SystemTime>)> {
let mut stamp: Vec<_> = std::fs::read_dir(dir)
.into_iter()
.flatten()
.flatten()
.map(|e| {
let modified = e.metadata().and_then(|m| m.modified()).ok();
(e.file_name().to_string_lossy().into_owned(), modified)
})
.collect();
stamp.sort();
stamp
}
/// Create World's packs into the new world before it opens
/// (`copyTempDataPackDirToNewWorld`): every pack of `dir` goes to
/// `<world>/datapacks`, and `datapacks.json` enables those `selected`
/// (lowest priority first) and disables the rest.
pub fn install(dir: &Path, world: &Path, selected: &[String]) -> Result<(), String> {
let err = |p: &Path, e: std::io::Error| format!("{}: {e}", p.display());
let target = world.join("datapacks");
std::fs::create_dir_all(&target).map_err(|e| err(&target, e))?;
let mut disabled = Vec::new();
for pack in crate::packs::folder(dir, horizon_core::version::DATA_PACK_FORMAT) {
let (crate::packs::Source::Dir(from) | crate::packs::Source::Zip(from)) = &pack.source;
copy(from, &target.join(pack.id.trim_start_matches("file/")))?;
if !selected.contains(&pack.id) {
disabled.push(pack.id);
}
}
if !selected.iter().any(|id| id == "vanilla") {
disabled.push("vanilla".into());
}
let json = serde_json::json!({ "enabled": selected, "disabled": disabled });
let file = world.join("datapacks.json");
std::fs::write(&file, json.to_string()).map_err(|e| err(&file, e))
}
/// A file, or a folder and everything in it.
fn copy(from: &Path, to: &Path) -> Result<(), String> {
let err = |e: std::io::Error| format!("{} -> {}: {e}", from.display(), to.display());
if !from.is_dir() {
return std::fs::copy(from, to).map(drop).map_err(err);
}
std::fs::create_dir_all(to).map_err(err)?;
for e in std::fs::read_dir(from).map_err(err)?.flatten() {
copy(&e.path(), &to.join(e.file_name()))?;
}
Ok(())
}
// ---- functions ---------------------------------------------------------------
/// A `.mcfunction`: plain command lines and macro lines.
@@ -566,4 +674,51 @@ mod tests {
assert_eq!(p.list_kinds(&kinds), wanted);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn create_world_installs_its_packs() {
let root = std::env::temp_dir().join(format!("hz-datapack-install-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&root);
let (dir, world) = (root.join("mcworld"), root.join("world"));
let write = |pack: &str, p: &str, t: &str| {
let path = dir.join(pack).join(p);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(path, t).unwrap();
};
write("fns", "pack.mcmeta", r#"{"pack":{"pack_format":121}}"#);
write("fns", "data/x/function/f.mcfunction", "say hi");
write("off", "pack.mcmeta", r#"{"pack":{"pack_format":121}}"#);
std::fs::create_dir_all(&dir).unwrap();
let mut zip = zip::ZipWriter::new(std::fs::File::create(dir.join("old.zip")).unwrap());
zip.start_file("pack.mcmeta", zip::write::SimpleFileOptions::default())
.unwrap();
std::io::Write::write_all(&mut zip, br#"{"pack":{"pack_format":48}}"#).unwrap();
zip.finish().unwrap();
let infos = screen_packs(&dir, &root);
let ids: Vec<&str> = infos.iter().map(|p| p.id.as_str()).collect();
assert_eq!(ids, ["file/fns", "file/off", "file/old.zip", "vanilla"]);
let compat: Vec<_> = infos.iter().map(|p| p.compat).collect();
use crate::pack_screen::Compat;
assert_eq!(
compat,
[
Compat::Compatible,
Compat::Compatible,
Compat::TooOld,
Compat::Compatible
]
);
let selected = ["vanilla", "file/old.zip", "file/fns"].map(String::from);
install(&dir, &world, &selected).unwrap();
let packs = discover(&world);
let ids: Vec<&str> = packs.iter().map(|p| p.id.as_str()).collect();
assert_eq!(ids, ["file/fns", "file/off", "file/old.zip"]);
let saved: serde_json::Value =
serde_json::from_slice(&std::fs::read(world.join("datapacks.json")).unwrap()).unwrap();
assert_eq!(
saved,
serde_json::json!({"enabled": selected, "disabled": ["file/off"]})
);
let _ = std::fs::remove_dir_all(&root);
}
}
+3
View File
@@ -896,6 +896,9 @@ impl Font {
std::mem::take(&mut self.cache.borrow_mut().region.pending)
}
pub fn advance(&self, c: char, style: &Style) -> f32 {
if c == '\u{fffc}' && style.inline_object.is_some() {
return 8.0;
}
let g = self.glyph_styled(c, style);
g.advance + if style.is_bold() { g.offset } else { 0.0 }
}
+188 -16
View File
@@ -59,6 +59,8 @@ pub struct HudAtlas {
pub width: u32,
pub height: u32,
pub sprites: HashMap<String, Rect>,
/// Resolved player-profile names and UUIDs for inline head components.
pub object_skins: HashMap<String, String>,
/// Sprites with a 0 < alpha < 255 texel (`SpriteContents.transparency().hasTranslucent`),
/// which puts their particles on vanilla's translucent layer.
pub translucent: HashSet<String>,
@@ -252,6 +254,24 @@ fn atlas_sprites(root: &Path, packed: &[PackedImage]) -> Vec<PackedImage> {
out.into_iter().map(|(_, image)| image).collect()
}
impl HudAtlas {
/// Keep a ready profile skin when another source only has its default.
pub fn set_object_skin(&mut self, key: String, skin: String) {
use std::collections::hash_map::Entry;
if self.object_skins.len() >= 1024 && !self.object_skins.contains_key(&key) {
self.object_skins.clear();
}
match self.object_skins.entry(key) {
Entry::Occupied(entry)
if skin.starts_with("entity/player/") && self.sprites.contains_key(entry.get()) => {
}
Entry::Occupied(mut entry) => {
entry.insert(skin);
}
Entry::Vacant(entry) => {
entry.insert(skin);
}
}
}
/// A font glyph's atlas cell (8x8 GUI pixels) and advance.
pub fn glyph(&self, ch: char) -> Option<(Rect, f32)> {
let g = self.font.glyph(ch);
@@ -592,6 +612,7 @@ impl HudAtlas {
width,
height,
sprites,
object_skins: HashMap::new(),
translucent,
flags,
sprite_animations,
@@ -641,6 +662,8 @@ pub struct HudBatch {
pub glint_alpha: f32,
/// Screen's first vertex: the preceding HUD is part of its blurred background.
pub blur_at: u32,
/// Player object profiles encountered while painting text this frame.
pub inline_profiles: Vec<serde_json::Value>,
}
/// How a run of HUD vertices blends and tests depth.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
@@ -692,6 +715,7 @@ impl HudBatch {
end_portal: EndPortalFill::default(),
glint_alpha: 0.75,
blur_at: 0,
inline_profiles: Vec::new(),
}
}
/// Draw the vertices added since `start` with the inverting blend.
@@ -1042,22 +1066,43 @@ impl HudBatch {
let mut cursor = x;
let mut previous = None;
for (i, (ch, style)) in text.chars().enumerate() {
let object = (ch == '\u{fffc}')
.then_some(style.inline_object.as_ref())
.flatten();
if let Some(crate::text::InlineObject::Player { profile, .. }) = object
&& self.inline_profiles.len() < 256
&& !self.inline_profiles.contains(profile)
{
self.inline_profiles.push(profile.clone());
}
// Font.PreparedTextBuilder.accept: lines start 1 left of a
// sequence's first character. Language.getVisualOrder makes a
// sequence of each run of one style, which world text has.
let first = i == 0 || world && previous != Some(style);
previous = Some(style);
// The style's font (`Style.getFont`), the default one unless set.
let mut g = font.glyph_styled(ch, style);
let mut g = if object.is_some() {
crate::font::Glyph {
rect: None,
left: 0.0,
top: 0.0,
right: 0.0,
bottom: 8.0,
advance: 8.0,
offset: 0.0,
}
} else {
font.glyph_styled(ch, style)
};
// Font.StringRenderOutput.accept: obfuscated characters draw a
// random glyph of the same width each frame.
if style.obfuscated == Some(true) && ch != ' ' {
if object.is_none() && style.obfuscated == Some(true) && ch != ' ' {
g = font.random_glyph(style, g.advance);
}
let c = style.color.map_or(color, |rgb| {
rgba((rgb >> 16) as u8, (rgb >> 8) as u8, rgb as u8, alpha)
});
let bold = style.is_bold();
let bold = object.is_none() && style.is_bold();
let advance = g.advance + if bold { g.offset } else { 0.0 };
glyphs.push((
cursor,
@@ -1069,6 +1114,7 @@ impl HudBatch {
style.strikethrough == Some(true),
first,
advance,
object.cloned(),
));
cursor += advance;
}
@@ -1086,20 +1132,26 @@ impl HudBatch {
)
};
for &is_shadow in passes {
for &(gx, g, c, bold, italic, underline, strike, first, advance) in &glyphs {
for (gx, g, c, bold, italic, underline, strike, first, advance, object) in &glyphs {
if let Some(object) = object {
if !is_shadow {
self.draw_inline_object(atlas, object, *gx, y, alpha);
}
continue;
}
// In the world a glyph whose shadow is 0 has none (hasShadow).
let has_shadow = shadow && !(world && shade(c) == 0);
let has_shadow = shadow && !(world && shade(*c) == 0);
if is_shadow && !has_shadow {
continue;
}
let (dx, col) = if is_shadow {
(g.offset, shade(c))
(g.offset, shade(*c))
} else {
(0.0, c)
(0.0, *c)
};
let (px, py) = (gx + dx, y + dx);
let shear = |v: f32| if italic { 1.0 - 0.25 * v } else { 0.0 };
let thick = if bold { 0.1 } else { 0.0 };
let (px, py) = (*gx + dx, y + dx);
let shear = |v: f32| if *italic { 1.0 - 0.25 * v } else { 0.0 };
let thick = if *bold { 0.1 } else { 0.0 };
let draw = |batch: &mut Self, ox: f32| match g.rect {
Some(r) => {
let (x0, x1, y0, y1) = (
@@ -1144,24 +1196,86 @@ impl HudBatch {
let start = self.vertices.len();
draw(self, 0.0);
lift(self, start, base);
if bold {
if *bold {
let start = self.vertices.len();
draw(self, g.offset);
lift(self, start, base + 0.001);
}
let x0 = if first { px - 1.0 } else { px };
let x0 = if *first { px - 1.0 } else { px };
let start = self.vertices.len();
if strike {
self.rect_uv(x0, py + 3.5, px + advance - x0, 1.0, white, col);
if *strike {
self.rect_uv(x0, py + 3.5, px + *advance - x0, 1.0, white, col);
}
if underline {
self.rect_uv(x0, py + 8.0, px + advance - x0, 1.0, white, col);
if *underline {
self.rect_uv(x0, py + 8.0, px + *advance - x0, 1.0, white, col);
}
lift(self, start, base + 0.01);
}
}
cursor - x
}
fn draw_inline_object(
&mut self,
atlas: &HudAtlas,
object: &crate::text::InlineObject,
x: f32,
y: f32,
alpha: u8,
) {
use crate::text::InlineObject;
let tint = rgba(255, 255, 255, alpha);
match object {
InlineObject::Player { profile, hat, .. } => {
let id = crate::skins::parse_profile(profile).id;
let name = inline_profile_name(profile);
let by_id = atlas.object_skins.get(&format!("id:{id:032x}"));
let by_name = name.and_then(|name| {
atlas
.object_skins
.get(&format!("name:{}", name.to_ascii_lowercase()))
});
let resolved = if profile.get("id").is_some() {
by_id.or(by_name)
} else {
by_name.or(by_id)
};
let default = crate::tab_list::default_skin(id);
let skin = resolved
.filter(|path| atlas.sprites.contains_key(*path))
.map_or(default, String::as_str);
let Some(rect) = atlas.sprites.get(skin).copied() else {
return;
};
for u in [8.0, 40.0].into_iter().take(if *hat { 2 } else { 1 }) {
let du = (rect.u1 - rect.u0) / 64.0;
let dv = (rect.v1 - rect.v0) / 64.0;
self.rect_uv(
x,
y,
8.0,
8.0,
Rect {
u0: rect.u0 + du * u,
v0: rect.v0 + dv * 8.0,
u1: rect.u0 + du * (u + 8.0),
v1: rect.v0 + dv * 16.0,
w: 8,
h: 8,
},
tint,
);
}
}
InlineObject::Atlas { sprite, .. } => {
let key = sprite.strip_prefix("minecraft:").unwrap_or(sprite);
if let Some(rect) = atlas.sprites.get(key).copied() {
self.rect_uv(x, y, 8.0, 8.0, rect, tint);
}
}
}
}
/// SubmitNodeCollection.submitNameTag's text in its own space (x right,
/// y down, in GUI pixels): centred at `-Font.width / 2`, drawn as
/// Font.prepareText draws any text (styles, fonts and glyph boxes; no
@@ -1190,6 +1304,13 @@ impl HudBatch {
behind
}
}
fn inline_profile_name(profile: &serde_json::Value) -> Option<&str> {
profile
.as_str()
.or_else(|| profile.get("name").and_then(serde_json::Value::as_str))
}
#[repr(C)]
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
struct HudUniform {
@@ -1904,6 +2025,56 @@ mod tests {
assert!(missing.rect.is_none() && missing.right == 5.0);
}
#[test]
fn player_object_draws_an_inline_head() {
let root = two_glyph_font("inline-head");
write_png(&root, "entity/player/slim/alex", 64, 64);
write_png(&root, "entity/player/wide/steve", 64, 64);
let mut atlas = HudAtlas::build(&root).unwrap();
let text = crate::component::to_text(
&serde_json::json!({"object":"player","player":{"id":"00000000-0000-0000-0000-000000000000"}}),
&mut |_| crate::text::Text::empty(),
);
let mut batch = HudBatch::new([320, 240]);
assert_eq!(
batch.text_styled(&atlas, &text, 10.0, 10.0, u32::MAX, false),
8.0
);
assert_eq!(batch.vertices.len(), 12); // face and hat, six vertices each
assert_eq!(batch.inline_profiles.len(), 1);
atlas.set_object_skin("name:elyapluggin".into(), "entity/player/wide/steve".into());
let named = crate::component::to_text(
&serde_json::json!({"object":"player","player":{"name":"elyapluggin"}}),
&mut |_| crate::text::Text::empty(),
);
batch.vertices.clear();
batch.text_styled(&atlas, &named, 10.0, 10.0, u32::MAX, false);
let skin = atlas.sprites["entity/player/wide/steve"];
assert_eq!(batch.vertices[0].uv[0], skin.u0 + (skin.u1 - skin.u0) / 8.0);
fs::remove_dir_all(root).unwrap();
}
#[test]
fn atlas_object_draws_an_item_sprite_inline() {
let root = two_glyph_font("inline-item");
write_png(&root, "item/porkchop", 16, 16);
let atlas = HudAtlas::build(&root).unwrap();
let text = crate::component::to_text(
&serde_json::json!({
"text": "a",
"extra": [{"object": "atlas", "sprite": "minecraft:item/porkchop"}]
}),
&mut |_| crate::text::Text::empty(),
);
let mut batch = HudBatch::new([320, 240]);
let width = batch.text_styled(&atlas, &text, 10.0, 10.0, u32::MAX, false);
assert_eq!(width, atlas.font.glyph('a').advance + 8.0);
assert_eq!(batch.vertices.len(), 12); // glyph and one sprite
let sprite = atlas.sprites["item/porkchop"];
assert_eq!(batch.vertices[6].uv, [sprite.u0, sprite.v0]);
fs::remove_dir_all(root).unwrap();
}
#[test]
fn name_tags_draw_bold_text_and_tall_glyphs_like_any_text() {
// `ascii.png`'s 8x8 'a' (4 pixels wide) and `accented.png`'s 9x12
@@ -2149,6 +2320,7 @@ mod tests {
end_portal: EndPortalFill::default(),
glint_alpha: 0.75,
blur_at: 0,
inline_profiles: Vec::new(),
};
for (image_width, image_height) in [(195, 136), (176, 166), (176, 222)] {
assert_eq!(
@@ -87,6 +87,9 @@ const MODEL_PARTS: [&str; 7] = [
];
const GRAPHICS_BACKEND: &[&str] = &["default", "opengl", "vulkan"];
const GRAPHICS_PRESET: &[&str] = &["fast", "fancy", "fabulous", "custom"];
/// Horizon's render distance cap (vanilla stops at 32): the server protocol's
/// view distance tops out at 127 anyway.
pub const MAX_RENDER_DISTANCE: i32 = 128;
const INACTIVITY: &[&str] = &["minimized", "afk"];
const CLOUDS: &[&str] = &["false", "fast", "true"];
const MAIN_HAND: &[&str] = &["left", "right"];
@@ -159,7 +162,7 @@ static TABLE: LazyLock<Vec<Def>> = LazyLock::new(|| {
b("reducedDebugInfo", false),
def("renderClouds", O(Clouds), V::Int(2)),
i("cloudRange", 2, 128, 128),
i("renderDistance", 2, 64, 12),
i("renderDistance", 2, MAX_RENDER_DISTANCE, 12),
i("simulationDistance", 5, 32, 12),
u("screenEffectScale", 1.0),
def("soundDevice", O(AnyStr), V::Str(String::new())),
+85 -10
View File
@@ -278,7 +278,11 @@ impl Opt {
| Opt::GlintStrength
| Opt::PanoramaSpeed => Kind::Slider(s.file.double(self.file_key().unwrap()) as f32),
Opt::Fov => unit(s.fov, 30.0, 110.0),
Opt::RenderDistance => unit(s.render_distance as f32, 2.0, 64.0),
Opt::RenderDistance => unit(
s.render_distance as f32,
2.0,
crate::options_file::MAX_RENDER_DISTANCE as f32,
),
Opt::SimulationDistance => unit(s.simulation_distance as f32, 5.0, 32.0),
Opt::Sensitivity => Kind::Slider(s.sensitivity),
Opt::WheelSensitivity => unit(s.mouse_wheel_sensitivity, 0.01, 10.0),
@@ -647,7 +651,10 @@ impl Opt {
crate::options_file::V::Double(f64::from(v)),
),
Opt::Fov => s.fov = step(30.0, 110.0),
Opt::RenderDistance => s.render_distance = step(2.0, 64.0) as i32,
Opt::RenderDistance => {
s.render_distance =
step(2.0, crate::options_file::MAX_RENDER_DISTANCE as f32) as i32
}
Opt::SimulationDistance => s.simulation_distance = step(5.0, 32.0) as i32,
Opt::Sensitivity => s.sensitivity = v,
Opt::WheelSensitivity => s.mouse_wheel_sensitivity = 0.01 + v * 9.99,
@@ -1012,7 +1019,11 @@ pub enum Event {
Language(String),
/// The pack selection changed (reload resources).
Packs(Vec<String>),
/// Create World's Data Packs screen closed with a new selection.
DataPacks(Vec<String>),
OpenPackFolder,
/// Data Packs' Open Pack Folder: create the folder if needed and open it.
OpenDataPackFolder(std::path::PathBuf),
OpenModFolder,
/// The Shader Packs page opened: list `shaderpacks/` into `shader_packs`.
ListShaderPacks,
@@ -1078,6 +1089,13 @@ pub struct OptionsUi {
pub pack_selection: Vec<String>,
/// The open pack screen, made at its first frame.
pub pack_screen: Option<crate::pack_screen::PackScreen>,
/// The Packs page is Create World's Data Packs screen on this folder.
data_pack_dir: Option<std::path::PathBuf>,
/// The game's resources, for the built-in data pack's icon.
data_pack_resources: std::path::PathBuf,
/// The folder's entries when its packs were listed, and when they were
/// last compared with it.
data_pack_stamp: (Vec<(String, Option<std::time::SystemTime>)>, Instant),
/// A reload failure, dismissed before returning to the current page.
pub resource_error: Option<String>,
/// When the pack screen's search box took the focus (its cursor blink).
@@ -1112,6 +1130,9 @@ impl Default for OptionsUi {
pack_infos: Vec::new(),
pack_selection: Vec::new(),
pack_screen: None,
data_pack_dir: None,
data_pack_resources: Default::default(),
data_pack_stamp: (Vec::new(), Instant::now()),
resource_error: None,
pack_focus: Instant::now(),
in_world: false,
@@ -1219,9 +1240,48 @@ impl OptionsUi {
pub fn open(&mut self, in_world: bool) {
self.open_at(in_world, Page::Main);
}
/// Create World's Data Packs (`openDataPackSelectionScreen`): the Packs
/// page on the new world's pack folder `dir`, `selected` chosen;
/// `resources` holds the built-in pack's icon.
pub fn open_data_packs(
&mut self,
dir: std::path::PathBuf,
selected: Vec<String>,
resources: std::path::PathBuf,
) {
self.open_at(false, Page::Packs);
self.pack_infos = crate::datapack::screen_packs(&dir, &resources);
self.data_pack_resources = resources;
self.pack_selection = selected;
self.data_pack_stamp = (crate::datapack::folder_stamp(&dir), Instant::now());
self.data_pack_dir = Some(dir);
}
/// `PackSelectionScreen.tick`'s watcher: once a second, the Data Packs
/// folder's packs are listed again if it changed, the selection kept
/// (the search text and scroll start over).
fn watch_data_packs(&mut self, atlas: &HudAtlas, size: (f32, f32)) {
let Some(dir) = &self.data_pack_dir else {
return;
};
if self.data_pack_stamp.1.elapsed().as_secs() < 1 {
return;
}
let stamp = crate::datapack::folder_stamp(dir);
let changed = stamp != self.data_pack_stamp.0;
self.data_pack_stamp = (stamp, Instant::now());
if !changed {
return;
}
self.pack_infos = crate::datapack::screen_packs(dir, &self.data_pack_resources);
if let Some(p) = self.pack_screen.take() {
self.pack_selection = p.commit();
self.packs(atlas, size).changed = p.changed;
}
}
/// Open a page whose Done/Escape returns directly to the calling screen.
pub fn open_at(&mut self, in_world: bool, page: Page) {
self.stack.clear();
self.data_pack_dir = None;
self.push(page);
self.in_world = in_world;
self.selected_key = None;
@@ -2273,6 +2333,7 @@ impl OptionsUi {
return;
}
if self.page() == Page::Packs {
self.watch_data_packs(atlas, (w, h));
ui::menu_background(batch, atlas, 0.0, 0.0, w, h, self.in_world);
let blink = self.pack_focus.elapsed().as_millis() as u64;
let m = crate::screen_draw::Measure(&atlas.font);
@@ -2568,7 +2629,10 @@ impl OptionsUi {
self.pack_focus = Instant::now();
}
match action {
crate::pack_screen::Action::OpenFolder => events.push(Event::OpenPackFolder),
crate::pack_screen::Action::OpenFolder => events.push(match &self.data_pack_dir {
Some(dir) => Event::OpenDataPackFolder(dir.clone()),
None => Event::OpenPackFolder,
}),
crate::pack_screen::Action::Done => events.extend(self.back(s)),
crate::pack_screen::Action::None => {}
}
@@ -2820,8 +2884,14 @@ impl OptionsUi {
}
None => {
self.pack_focus = Instant::now();
let title = if self.data_pack_dir.is_some() {
"dataPack.title"
} else {
"resourcePack.title"
};
self.pack_screen = Some(crate::pack_screen::PackScreen::new(
&m,
crate::text::Text::translate(title, &[]),
w,
h,
self.in_world,
@@ -2853,13 +2923,18 @@ impl OptionsUi {
}
Page::Packs => {
// PackSelectionScreen.onClose: PackSelectionModel.commit.
let data = self.data_pack_dir.take();
if let Some(p) = self.pack_screen.take()
&& p.changed
{
let ids = p.commit();
s.resource_packs = ids.clone();
self.pack_selection = ids.clone();
events.push(Event::Packs(ids));
if data.is_some() {
events.push(Event::DataPacks(ids));
} else {
s.resource_packs = ids.clone();
self.pack_selection = ids.clone();
events.push(Event::Packs(ids));
}
}
}
_ => {}
@@ -3158,7 +3233,7 @@ mod tests {
#[test]
fn render_distance_slider_round_trips_through_extended_options_range() {
let mut s = Settings::default();
for (position, distance) in [(0.0, 2), (0.5, 33), (1.0, 64)] {
for (position, distance) in [(0.0, 2), (0.5, 65), (1.0, 128)] {
set_slider(Opt::RenderDistance, &mut s, position);
assert_eq!(s.render_distance, distance);
let reloaded = Settings::parse(&s.serialize());
@@ -3169,10 +3244,10 @@ mod tests {
);
}
let mut file = crate::options_file::OptionsFile::default();
file.set_text("renderDistance", "64").unwrap();
assert!(file.set_text("renderDistance", "65").is_err());
file.set_text("renderDistance", "128").unwrap();
assert!(file.set_text("renderDistance", "129").is_err());
assert!(file.set_text("renderDistance", "1").is_err());
assert_eq!(file.int("renderDistance"), 64);
assert_eq!(file.int("renderDistance"), 128);
}
fn atlas() -> HudAtlas {
HudAtlas::build(std::path::Path::new("/nonexistent/horizon-test-assets")).unwrap()
@@ -318,6 +318,8 @@ pub enum Action {
/// The pack screen and its state.
#[derive(Clone, Debug)]
pub struct PackScreen {
/// `resourcePack.title`, or `dataPack.title` from Create World.
pub title: Text,
pub width: i32,
pub height: i32,
pub in_world: bool,
@@ -342,6 +344,7 @@ impl PackScreen {
/// `PackSelectionScreen.init`: the lists filled, the search box focused.
pub fn new(
m: &Measure,
title: Text,
width: i32,
height: i32,
in_world: bool,
@@ -360,6 +363,7 @@ impl PackScreen {
.filter_map(|p| Some((icon_texture(&p.id), p.icon.clone()?)))
.collect();
let mut s = Self {
title,
width,
height,
in_world,
@@ -382,7 +386,7 @@ impl PackScreen {
}
/// The header layout: title, drop info and search box, centred.
fn header(&self, m: &Measure) -> [(i32, i32); 3] {
let tw = m.width(&tr("resourcePack.title"));
let tw = m.width(&self.title);
let dw = m.width(&tr("pack.dropInfo"));
let col = tw.max(dw).max(200);
let frame = self.width.max(col);
@@ -837,7 +841,7 @@ impl PackScreen {
return out;
}
let [(tx, ty), (dx, dy), _] = self.header(m);
d::string_widget(&mut out, m, &tr("resourcePack.title"), tx, ty, 0);
d::string_widget(&mut out, m, &self.title, tx, ty, 0);
d::string_widget(
&mut out,
m,
@@ -1105,7 +1109,7 @@ mod icon_tests {
pack("high_contrast", Some(contrast.clone())),
pack("file/Iconless", None),
];
let screen = PackScreen::new(&m, 480, 320, false, packs, &[]);
let screen = PackScreen::new(&m, tr("resourcePack.title"), 480, 320, false, packs, &[]);
let mut draws = screen.draw(&m, (0, 0), 0);
let mut patches = Vec::new();
screen.bind_icons(&mut draws, &atlas, &mut patches);
@@ -1152,7 +1156,8 @@ mod click_sound_tests {
crate::hud::HudAtlas::build(std::path::Path::new("/nonexistent/horizon-test-assets"))
.unwrap();
let m = Measure(&atlas.font);
let mut screen = PackScreen::new(&m, 480, 320, false, Vec::new(), &[]);
let title = tr("resourcePack.title");
let mut screen = PackScreen::new(&m, title, 480, 320, false, Vec::new(), &[]);
assert!(!screen.button_at(&m, 0.0, 0.0));
assert!(!screen.button_at(
&m,
+21 -6
View File
@@ -181,9 +181,15 @@ pub fn compatible(meta: &serde_json::Value) -> bool {
/// `PackCompatibility.forVersion`: too old, too new, compatible, or unknown
/// when the metadata names no format.
pub fn compatibility(meta: &serde_json::Value) -> crate::pack_screen::Compat {
compatibility_for(meta, RESOURCE_FORMAT)
}
/// `compatibility` against `current`, the resource or the data pack format.
pub fn compatibility_for(
meta: &serde_json::Value,
current: (i64, i64),
) -> crate::pack_screen::Compat {
use crate::pack_screen::Compat;
let pack = &meta["pack"];
let current = RESOURCE_FORMAT;
let range = if let (Some(min), Some(max)) = (
format_of(&pack["min_format"]),
format_of(&pack["max_format"]),
@@ -275,6 +281,10 @@ fn read_meta(source: &Source) -> Option<serde_json::Value> {
serde_json::from_slice(&bytes).ok()
}
fn pack(id: String, title: Text, source: Source) -> Option<Pack> {
pack_for(id, title, source, RESOURCE_FORMAT)
}
/// A pack whose compatibility is against `format`.
fn pack_for(id: String, title: Text, source: Source, format: (i64, i64)) -> Option<Pack> {
let meta = read_meta(&source)?;
let (raw_description, description_style) = component_root(&meta["pack"]["description"]);
Some(Pack {
@@ -284,7 +294,7 @@ fn pack(id: String, title: Text, source: Source) -> Option<Pack> {
raw_description,
description_style,
compatible: compatible(&meta),
compatibility: compatibility(&meta),
compatibility: compatibility_for(&meta, format),
overlays: overlays_of(&meta),
filter: filter_of(&meta),
source,
@@ -305,7 +315,13 @@ pub fn discover(resources: &Path, packs_dir: &Path) -> Vec<Pack> {
out.push(p);
}
}
let mut user: Vec<Pack> = fs::read_dir(packs_dir)
out.extend(folder(packs_dir, RESOURCE_FORMAT));
out
}
/// The packs (folders and zips) in `dir`, by name, as `FolderRepositorySource`
/// finds them; their compatibility is against `format`.
pub fn folder(dir: &Path, format: (i64, i64)) -> Vec<Pack> {
let mut user: Vec<Pack> = fs::read_dir(dir)
.into_iter()
.flatten()
.flatten()
@@ -319,12 +335,11 @@ pub fn discover(resources: &Path, packs_dir: &Path) -> Vec<Pack> {
} else {
return None;
};
pack(format!("file/{name}"), Text::literal(name), source)
pack_for(format!("file/{name}"), Text::literal(name), source, format)
})
.collect();
user.sort_by(|a, b| a.id.cmp(&b.id));
out.extend(user);
out
user
}
/// A file a pack provides: its path (folder packs) and its name inside the pack.
type Provided = (Option<PathBuf>, String);
@@ -58,6 +58,8 @@ pub enum Ticking {
Bee { bee: u32, aggressive: bool },
/// `GuardianAttackSoundInstance`.
GuardianAttack { guardian: u32 },
/// `ElytraOnPlayerSoundInstance`: ticks since it started.
Elytra { time: i32 },
}
/// What a minecart's sound instances read about it.
#[derive(Clone, Copy, Debug)]
@@ -95,6 +97,12 @@ pub struct TickContext {
pub mobs: Vec<MobSound>,
/// `!tickRateManager().runsNormally()`.
pub frozen: bool,
/// The player's position.
pub player_position: [f64; 3],
/// `getDeltaMovement().lengthSqr()` of the player.
pub player_speed_sqr: f64,
/// `isFallFlying()` of the player.
pub player_fall_flying: bool,
}
/// `AbstractSoundInstance` and its subclasses' fields.
#[derive(Clone, Debug)]
@@ -390,6 +398,24 @@ impl SoundInstance {
};
s
}
/// `new ElytraOnPlayerSoundInstance(player)`: looping at volume 0.1 until
/// its first tick.
pub fn elytra(position: [f64; 3], random: LegacyRandom) -> Self {
let mut s = Self::new(
"minecraft:item.elytra.flying",
PLAYERS,
0.1,
1.0,
random,
true,
0,
Attenuation::Linear,
position,
false,
);
s.ticking = Ticking::Elytra { time: 0 };
s
}
pub fn tickable(&self) -> bool {
self.ticking != Ticking::No
}
@@ -494,6 +520,37 @@ impl SoundInstance {
self.volume = 0.0;
}
}
Ticking::Elytra { time } => {
*time += 1;
let time = *time;
if ctx.player_removed || (time > 20 && !ctx.player_fall_flying) {
self.stop();
return;
}
let [x, y, z] = ctx.player_position;
self.position = [
f64::from(x as f32),
f64::from(y as f32),
f64::from(z as f32),
];
let speed = ctx.player_speed_sqr as f32;
self.volume = if speed >= 1.0e-7 {
(speed / 4.0).clamp(0.0, 1.0)
} else {
0.0
};
// Silent for a second, then a second's fade in.
if time < 20 {
self.volume = 0.0;
} else if time < 40 {
self.volume *= (time - 20) as f32 / 20.0;
}
self.pitch = if self.volume > 0.8 {
1.0 + (self.volume - 0.8)
} else {
1.0
};
}
Ticking::GuardianAttack { guardian } => {
let id = *guardian;
// The client's guardian never has a target of its own, so
@@ -126,6 +126,7 @@ pub fn main() -> horizon_client::Result<()> {
.collect();
let mut screen = PackScreen::new(
&m,
Text::translate(c["title"].as_str().unwrap_or("resourcePack.title"), &[]),
int(&c["width"]),
int(&c["height"]),
c["inWorld"] == true,
+3
View File
@@ -164,6 +164,8 @@ pub struct ArrowState {
/// `AbstractArrow.firedFromWeapon`: the crossbow or bow it was shot from.
pub fired_from_weapon: Option<crate::items::ItemStack>,
pub no_physics: bool,
/// `Arrow.ID_EFFECT_COLOR` as a client has it from its server (-1: none).
pub effect_color: i32,
/// `AbstractArrow.getPierceLevel`.
pub pierce: u8,
/// `piercingIgnoreEntityIds`: the entities a piercing arrow has gone
@@ -214,6 +216,7 @@ impl ArrowState {
pickup_item: crate::items::ItemStack::new("minecraft:arrow", 1),
fired_from_weapon: None,
no_physics: false,
effect_color: -1,
pierce: 0,
pierced: Vec::new(),
fire_ticks: 0,
@@ -425,7 +425,7 @@ pub const COMMANDS: &[Cmd] = &[
&[BOX[0], BOX[1], BOX[2], BOX[3], BOX[4], BOX[5], p("block", Ty::Str, "block state")], mcp: true, local: false),
cmd!("container", World, "container X Y Z [ITEM COUNT]", "list a container's items, or add items to it", "", ["horizon-ctl container 3 64 1", "horizon-ctl container 3 64 1 diamond 3"],
&[BLOCK_XYZ[0], BLOCK_XYZ[1], BLOCK_XYZ[2], opt("item", Ty::Str, "item to add"), opt("count", Ty::Int, "how many")], mcp: true, local: false),
cmd!("render-distance", World, "render-distance N", "chunks, 2..64", "", ["horizon-ctl render-distance 8"], &[p("chunks", Ty::Int, "render distance")], mcp: false, local: false),
cmd!("render-distance", World, "render-distance N", "chunks, 2..128", "", ["horizon-ctl render-distance 8"], &[p("chunks", Ty::Int, "render distance")], mcp: false, local: false),
cmd!("wait", World, "wait TICKS", "wait until TICKS game ticks have passed (20 per second)",
"Keys and mouse buttons held with key ... down or mouse ... down stay held while it waits. Release them with key ... up, release or stop.",
["horizon-ctl wait 40", "horizon-ctl key w down && horizon-ctl wait 40 && horizon-ctl key w up"],
+1 -9
View File
@@ -27,7 +27,7 @@ impl Ingredient {
pub fn of(items: Vec<String>) -> Self {
Self(items.iter().cloned().collect(), items)
}
fn parse(v: &Value, items: &Items) -> Option<Self> {
pub(crate) fn parse(v: &Value, items: &Items) -> Option<Self> {
let mut list: Vec<String> = Vec::new();
let mut add = |s: &str| {
let more: Vec<String> = match s.strip_prefix('#') {
@@ -43,14 +43,6 @@ impl Ingredient {
match v {
Value::String(s) => add(s),
Value::Array(a) => a.iter().filter_map(Value::as_str).for_each(&mut add),
Value::Object(o) => {
if let Some(s) = o.get("item").and_then(Value::as_str) {
add(s);
}
if let Some(t) = o.get("tag").and_then(Value::as_str) {
add(&format!("#{t}"));
}
}
_ => return None,
}
(!list.is_empty()).then(|| Self::of(list))
+101 -18
View File
@@ -174,6 +174,7 @@ mod server_mods;
mod server_packs;
mod server_travel;
mod shader_packs;
mod shelf;
mod shield;
mod shoulders;
mod sign_edit;
@@ -199,6 +200,7 @@ mod trading;
mod trial_spawner;
mod trial_visuals;
mod trident;
mod tutorial;
mod tweaks;
mod ui_control;
mod vault;
@@ -394,7 +396,7 @@ impl Options {
match arg.as_str() {
"--help" | "-h" => {
println!(
"Horizon — Minecraft Java Edition {} in Rust\n\n --resources PATH Prepared resources (horizon-prepare)\n --render-distance N Chunks, 2..64 (default 12)\n --world NAME World folder under saves/ (default \"New World\")\n --seed N World seed for new worlds (default 0)\n --width N, --height N Window size (default 1280 x 720)\n --creative Creative mode (default survival)\n --test-terrain Simple test terrain instead of vanilla generation\n --frames N Exit after N frames (testing)\n --world-frames N Exit after N frames drawn in the world (testing)\n --smoke-report PATH Write a JSON report on exit\n --benchmark SCENARIO Run a benchmark (standard, village, forest, ocean, mountain), write its report to benchmarks/ and quit\n --control Accept horizon-ctl commands on a local socket\n --control-socket PATH Control socket path (default $XDG_RUNTIME_DIR/horizon-control.sock)\n --server HOST[:PORT] Join a multiplayer server (offline mode) at start\n --quickPlaySingleplayer WORLD Open this world of saves/ at start, only if it exists (vanilla's)\n --quickPlayMultiplayer HOST[:PORT] The same as --server (vanilla's name)\n --name NAME Player name for multiplayer (default: generated once, kept in horizon-player.txt)\n --session-file PATH Signed-in account from the launcher (read once, then deleted)\n --dev-mod PATH A Horizon mod (.hmod or folder) to develop: always on, reloaded when rebuilt\n --in-frame Run single player's world in the frame, not on its server thread\n --pregen Add Horizon's /pregen command (docs/pregeneration.md)\n\nControls: mouse look, WASD move, Space jump, Left Shift sneak, Left Ctrl sprint,\nleft click break, right click place/use, 1-9/scroll hotbar, E inventory,\nQ drop, F3 debug, Esc pause.",
"Horizon — Minecraft Java Edition {} in Rust\n\n --resources PATH Prepared resources (horizon-prepare)\n --render-distance N Chunks, 2..128 (default 12)\n --world NAME World folder under saves/ (default \"New World\")\n --seed N World seed for new worlds (default 0)\n --width N, --height N Window size (default 1280 x 720)\n --creative Creative mode (default survival)\n --test-terrain Simple test terrain instead of vanilla generation\n --frames N Exit after N frames (testing)\n --world-frames N Exit after N frames drawn in the world (testing)\n --smoke-report PATH Write a JSON report on exit\n --benchmark SCENARIO Run a benchmark (standard, village, forest, ocean, mountain), write its report to benchmarks/ and quit\n --control Accept horizon-ctl commands on a local socket\n --control-socket PATH Control socket path (default $XDG_RUNTIME_DIR/horizon-control.sock)\n --server HOST[:PORT] Join a multiplayer server (offline mode) at start\n --quickPlaySingleplayer WORLD Open this world of saves/ at start, only if it exists (vanilla's)\n --quickPlayMultiplayer HOST[:PORT] The same as --server (vanilla's name)\n --name NAME Player name for multiplayer (default: generated once, kept in horizon-player.txt)\n --session-file PATH Signed-in account from the launcher (read once, then deleted)\n --dev-mod PATH A Horizon mod (.hmod or folder) to develop: always on, reloaded when rebuilt\n --in-frame Run single player's world in the frame, not on its server thread\n --pregen Add Horizon's /pregen command (docs/pregeneration.md)\n\nControls: mouse look, WASD move, Space jump, Left Shift sneak, Left Ctrl sprint,\nleft click break, right click place/use, 1-9/scroll hotbar, E inventory,\nQ drop, F3 debug, Esc pause.",
horizon_core::VANILLA_VERSION
);
return Ok(None);
@@ -422,8 +424,9 @@ impl Options {
"--render-distance" | "--radius" => {
o.distance = value.parse()?;
o.distance_override = Some(o.distance);
if !(2..=64).contains(&o.distance) {
return Err("render distance must be 2..64".into());
let max = horizon_client::options_file::MAX_RENDER_DISTANCE;
if !(2..=max).contains(&o.distance) {
return Err(format!("render distance must be 2..{max}").into());
}
}
"--seed" => {
@@ -1511,6 +1514,9 @@ struct Game<'a> {
cursor_icon: horizon_client::widgets::Cursor,
captured: bool,
focused: bool,
/// When the window lost focus, while it is still without
/// (`Minecraft.lastActiveTime`: pausing waits 500 ms).
focus_lost: Option<Instant>,
/// The keyboard's modifier state (`KeyEvent.modifiers`).
modifiers: winit::keyboard::ModifiersState,
/// The window's fullscreen request and reported state.
@@ -1585,6 +1591,8 @@ struct Game<'a> {
cart_sounds: HashSet<u32>,
/// The minecart the riding sounds were started for (`LocalPlayer.startRiding`).
riding_cart_sounds: Option<u32>,
/// `LocalPlayer.wasFallFlying` for the elytra's flying sound.
was_fall_flying: bool,
/// Bees whose buzz is playing, and whether it is the aggressive one.
bee_sounds: HashMap<u32, bool>,
/// Guardians whose attack hum is playing.
@@ -1686,6 +1694,8 @@ struct Game<'a> {
attack_clicks: u32,
hand_strength: horizon_client::attack_strength::AttackStrength,
settings: Settings,
tutorial: tutorial::Tutorial,
tutorial_toasts: Vec<tutorial::HintToast>,
/// Where the options screen returns: true = title, false = pause menu.
options_from_title: bool,
dragging: bool,
@@ -2370,6 +2380,12 @@ impl Game<'_> {
}
/// Inventory.add: returns the stack that did not fit.
fn give(&mut self, mut stack: ItemStack) -> Option<ItemStack> {
let tutorial_item = matches!(
self.tutorial.step,
tutorial::Step::FindTree | tutorial::Step::PunchTree | tutorial::Step::CraftPlanks
)
.then(|| stack.clone());
let mut added = false;
let max = self
.res
.items()
@@ -2394,7 +2410,9 @@ impl Game<'_> {
let moved = (max - slot.count).min(stack.count);
slot.count += moved;
stack.count -= moved;
added |= moved > 0;
if stack.count == 0 {
self.tutorial_get_item(tutorial_item.as_ref());
return None;
}
}
@@ -2407,11 +2425,16 @@ impl Game<'_> {
..stack.clone()
});
stack.count -= moved;
added |= moved > 0;
if stack.count == 0 {
self.tutorial_get_item(tutorial_item.as_ref());
return None;
}
}
}
if added {
self.tutorial_get_item(tutorial_item.as_ref());
}
Some(stack)
}
/// The block's first up face (or any face) and its fixed tint, for block
@@ -4350,6 +4373,14 @@ impl Game<'_> {
self.swing_arm();
return Ok(true);
}
if let Some(swings) = self.use_shelf(hit) {
let used = held.unwrap_or_else(|| ItemStack::new("minecraft:air", 0));
self.trigger_block("minecraft:item_used_on_block", hit.pos, &used);
if swings {
self.swing_arm();
}
return Ok(true);
}
if let Some(swings) = self.use_chiseled_bookshelf(hit, held.as_ref()) {
if swings {
self.swing_arm();
@@ -5209,6 +5240,7 @@ impl Game<'_> {
}
self.tick_debug_keys()?;
self.tick_debug_charts();
self.tick_tutorial();
if self.remote.is_some() {
return self.tick_remote();
}
@@ -5789,6 +5821,7 @@ impl Game<'_> {
.mouse
.handle_accumulated_movement(time, active, grabbed, look)
{
self.tutorial.mouse(xo, yo);
let mut rotation = Rotation {
x_rot: self.pitch,
y_rot: self.yaw,
@@ -5831,6 +5864,26 @@ impl Game<'_> {
) || self.book.is_some()
|| self.win_screen_pauses())
}
/// `Minecraft.pauseIfInactive`: a window without focus for more than 500 ms
/// pauses the game. An open screen (books, signs, the pack prompt, a server
/// dialog) stays instead of pausing (`Gui.setPauseScreen`).
fn pause_if_inactive(&mut self) {
if self
.focus_lost
.is_some_and(|t| t.elapsed() > Duration::from_millis(500))
&& self.control.is_none()
&& self.screen == Screen::Playing
&& self.player.is_some()
&& !self.options.no_pause
&& self.settings.file.bool("pauseOnLostFocus")
&& self.book.is_none()
&& self.sign_edit.is_none()
&& self.server_packs.prompt.is_none()
&& !self.dialog_open()
{
self.screen = Screen::Paused;
}
}
/// `MouseHandler.grabMouse` / `releaseMouse`. Both put the pointer at
/// the window's centre, so a screen opened from gameplay (inventory,
/// chest, pause, chat, sign, book, death) starts with the cursor in the
@@ -6100,6 +6153,7 @@ impl Game<'_> {
self.frame_graph
.draw(self.settings.horizon.overlay, &mut batch, &self.gui.atlas);
self.draw_pad_cursor(&mut batch);
self.resolve_inline_profiles(&batch.inline_profiles);
batch
}
fn hud_layers(&mut self, size: [u32; 2]) -> HudBatch {
@@ -6390,6 +6444,7 @@ impl Game<'_> {
self.draw_saving_indicator(&mut batch);
// ToastManager.extractRenderState: F1 hides the toasts too.
self.draw_toasts(&mut batch, !show_hud);
self.draw_tutorial_toasts(&mut batch, !show_hud);
self.draw_pack_toasts(&mut batch, !show_hud);
if self.server_packs.prompt.is_none() {
self.remote_hud(&mut batch);
@@ -6451,7 +6506,9 @@ impl Game<'_> {
| BlockEntity::Skull(_)
| BlockEntity::DaylightDetector
| BlockEntity::Campfire(_)
| BlockEntity::ChiseledBookshelf(_),
| BlockEntity::ChiseledBookshelf(_)
| BlockEntity::Brushable(_)
| BlockEntity::Shelf(_),
) => {}
None => {
v.extend((0..self.craft_size * self.craft_size).map(|i| 100 + i));
@@ -6735,7 +6792,9 @@ impl Game<'_> {
| BlockEntity::Skull(_)
| BlockEntity::DaylightDetector
| BlockEntity::Campfire(_)
| BlockEntity::ChiseledBookshelf(_),
| BlockEntity::ChiseledBookshelf(_)
| BlockEntity::Brushable(_)
| BlockEntity::Shelf(_),
) => {}
None if self.mount_active() => self.draw_mount_background(batch, ox, oy),
None => {
@@ -8212,6 +8271,8 @@ impl Game<'_> {
// `CampfireRenderer`.
self.mark_entity(out.len(), "");
self.campfire_geometry(camera, &mut out);
self.brushable_geometry(camera, &mut out);
self.shelf_geometry(camera, &mut out);
self.mark_entity(out.len(), "minecraft:ominous_item_spawner");
self.ominous_item_spawner_geometry(camera, alpha, &mut out);
// Mobs and their projectiles (a span each).
@@ -8223,6 +8284,7 @@ impl Game<'_> {
self.guest_model_geometry(camera, alpha, &mut out);
self.mark_entity(out.len(), "minecraft:evoker_fangs");
self.fangs_geometry(camera, alpha, &mut out);
self.block_item_display_geometry(camera, alpha, &mut out);
let mut see_through = std::mem::take(&mut self.see_through_vertices);
see_through.clear();
self.name_tag_geometry(camera, alpha, &mut out, &mut see_through);
@@ -9145,6 +9207,15 @@ impl Game<'_> {
return Ok(());
}
self.join_world_rest()?;
// Create World's data packs, in the world before it opens.
if let Some(dir) = create.and_then(|o| o.pack_dir.as_deref()) {
let world = std::env::current_dir()?.join("saves").join(folder);
let packs = create.map_or(&[][..], |o| &o.data_packs[..]);
if let Err(e) = horizon_client::datapack::install(dir, &world, packs) {
log::warn!("Horizon: data packs for {folder}: {e}");
}
let _ = std::fs::remove_dir_all(dir);
}
if self
.options
.execution_role
@@ -9183,6 +9254,7 @@ impl Game<'_> {
}
fn finish_open_world(&mut self, prepared: world_loading::PreparedWorld) -> Result<()> {
self.reset_tutorial();
let world_loading::PreparedWorld {
save_root,
level,
@@ -9629,6 +9701,7 @@ impl Game<'_> {
));
if let Some(title) = &mut self.title {
title.last_server = self.settings.file.string("lastServer");
title.skip_multiplayer_warning = self.settings.file.bool("skipMultiplayerWarning");
}
self.capture(false);
Ok(())
@@ -12438,6 +12511,9 @@ impl Game<'_> {
Screen::Playing => {
// key.inventory while riding a tamed mount opens its inventory.
if !self.open_ridden_mount_menu() {
if self.tutorial.open_inventory() {
self.persist_tutorial_step();
}
if self.creative {
self.screen = Screen::Creative;
self.creative_screen.reopen();
@@ -13022,24 +13098,12 @@ impl ApplicationHandler for Game<'_> {
}
WindowEvent::Focused(focused) => {
self.focused = focused;
self.focus_lost = (!focused).then(Instant::now);
if !focused && self.control.is_none() {
self.keys.clear();
self.left = false;
self.right = false;
self.capture(false);
// Gui.setPauseScreen: an open screen (books, signs, the
// pack prompt, a server dialog) stays instead of pausing.
if self.screen == Screen::Playing
&& self.player.is_some()
&& !self.options.no_pause
&& self.settings.file.bool("pauseOnLostFocus")
&& self.book.is_none()
&& self.sign_edit.is_none()
&& self.server_packs.prompt.is_none()
&& !self.dialog_open()
{
self.screen = Screen::Paused;
}
}
}
WindowEvent::CursorMoved { position, .. } => {
@@ -13139,6 +13203,9 @@ impl ApplicationHandler for Game<'_> {
if self.screen == Screen::Chat && d != 0.0 {
self.chat_scroll(d);
}
if self.screen == Screen::CommandBlock && d != 0.0 {
self.command_block_scroll(d);
}
if self.screen == Screen::Options && d != 0.0 {
self.options_scroll(d);
}
@@ -13267,6 +13334,13 @@ impl ApplicationHandler for Game<'_> {
Action::Connect { address } => {
self.connect_server(&address, &self.options.player_name())?
}
Action::DataPacks { dir, selected } => {
self.keys.clear();
self.screen = Screen::Options;
self.options_from_title = true;
let resources = self.vanilla_root();
self.ui.options.open_data_packs(dir, selected, resources);
}
Action::None => {}
}
}
@@ -13906,6 +13980,7 @@ impl ApplicationHandler for Game<'_> {
return;
}
self.poll_pads(event_loop);
self.pause_if_inactive();
if self.options.frames.is_some() && self.started.elapsed() > self.options.timeout {
self.error = Some("frame-limited run timed out".into());
event_loop.exit();
@@ -13984,6 +14059,9 @@ impl<'a> Game<'a> {
.map(Ok)
.unwrap_or_else(|| GameCpuResources::load(&root))?;
let world = World::new(res.facts().air, 0);
let tutorial = tutorial::Tutorial::new(tutorial::Step::from_option(
settings.file.int("tutorialStep"),
));
let creative = options.creative;
let inventory = vec![None; 36];
let now = Instant::now();
@@ -14063,6 +14141,7 @@ impl<'a> Game<'a> {
cursor_icon: horizon_client::widgets::Cursor::Arrow,
captured: false,
focused: true,
focus_lost: None,
modifiers: winit::keyboard::ModifiersState::empty(),
fullscreen: horizon_client::window::FullscreenState::new(false),
mouse: MouseLook::default(),
@@ -14113,6 +14192,7 @@ impl<'a> Game<'a> {
sound_paused: false,
cart_sounds: HashSet::new(),
riding_cart_sounds: None,
was_fall_flying: false,
bee_sounds: HashMap::new(),
guardian_sounds: HashSet::new(),
dropped: Vec::new(),
@@ -14172,6 +14252,8 @@ impl<'a> Game<'a> {
attack_clicks: 0,
hand_strength: Default::default(),
settings,
tutorial,
tutorial_toasts: Vec::new(),
options_from_title: false,
dragging: false,
avatar: Default::default(),
@@ -15267,6 +15349,7 @@ fn start_game<'a>(
&game.options.resources,
);
title.last_server = game.settings.file.string("lastServer");
title.skip_multiplayer_warning = game.settings.file.bool("skipMultiplayerWarning");
game.title = Some(title);
}
}
@@ -1549,7 +1549,7 @@ impl Game<'_> {
.iter()
.filter_map(|t| t.slot)
.chain(packs)
.fold(0, |used, slot| used | 1 << slot)
.fold(self.tutorial_toast_slots(), |used, slot| used | 1 << slot)
}
/// The `AdvancementToast` or `RecipeToast` at `index` in its slot at `y`.
fn draw_toast(&mut self, batch: &mut HudBatch, index: usize, y: f32, multiplier: f64) {
+3
View File
@@ -611,6 +611,9 @@ impl Game<'_> {
json!({ "mode": "multiplayer", "disconnected": reason })
}
Mode::Multiplayer(_) => json!({ "mode": "multiplayer" }),
Mode::MultiplayerWarning { check } => {
json!({ "mode": "multiplayer-warning", "check": check })
}
}
}
+1
View File
@@ -801,6 +801,7 @@ impl Game<'_> {
self.screen = super::Screen::Inventory;
self.capture(false);
self.right = false;
self.swing_arm();
return true;
}
if sneaking
+94 -6
View File
@@ -1,8 +1,11 @@
//! Brushing suspicious sand and gravel: `BrushItem.onUseTick` and
//! `BrushableBlockEntity`. The block's loot table stays in its saved block
//! entity (like a decorated pot's) until the first counted stroke rolls it.
use super::{Game, Hit, decorated_pot, spill, view_vector};
use super::{Game, Hit, decorated_pot, view_vector};
use horizon_client::{
block_entity_render::vertex_light,
containers::BlockEntity,
mesher::Vertex,
particles::{ParticleOptions, ParticleType},
save,
};
@@ -114,6 +117,20 @@ impl Game<'_> {
let time = self.world.game_time;
let mut brush = self.brushing.remove(&pos).unwrap_or_default();
brush.hit_face.get_or_insert(face);
let direction = match brush.hit_face.unwrap() {
[0, -1, 0] => 0,
[0, 1, 0] => 1,
[0, 0, -1] => 2,
[0, 0, 1] => 3,
[-1, 0, 0] => 4,
[1, 0, 0] => 5,
_ => return false,
};
if let Some(BlockEntity::Brushable(b)) =
self.world.block_entities.get_mut(&(pos[0], pos[1], pos[2]))
{
b.hit_direction = Some(direction);
}
brush.resets_at = time + 40;
if time < brush.cooldown_ends_at {
self.brushing.insert(pos, brush);
@@ -139,13 +156,19 @@ impl Game<'_> {
/// `BrushableBlockEntity.unpackLootTable`: the table's roll becomes the
/// block entity's item.
fn unpack_brush_loot(&mut self, pos: [i32; 3]) {
let Some(mut tag) = spill::saved_entity(&self.world, pos) else {
let key = (pos[0], pos[1], pos[2]);
let Some(BlockEntity::Brushable(b)) = self.world.block_entities.get(&key) else {
return;
};
let Some(horizon_world::nbt::Tag::String(table)) = tag.get("LootTable") else {
let Some(horizon_world::nbt::Tag::String(table)) = &b.loot_table else {
return;
};
let table = table.to_string_lossy();
let mut tag = save::encode_block_entity(
key,
&BlockEntity::Brushable(b.clone()),
"minecraft:brushable_block",
);
self.trigger_loot_table(&table);
let loot = horizon_client::structure_blocks::loot_data(&self.options.resources);
decorated_pot::unpack_loot(
@@ -155,7 +178,12 @@ impl Game<'_> {
&mut self.rand_sequences,
self.level.seed,
);
spill::put_saved_entity(&mut self.world, pos, tag);
if let Some(BlockEntity::Brushable(b)) = self.world.block_entities.get_mut(&key) {
b.loot_table = tag.get("LootTable").cloned();
b.loot_seed = tag.get("LootTableSeed").cloned();
b.item = tag.get("item").and_then(save::item_from_nbt);
}
self.world.modified.insert((pos[0] >> 4, pos[2] >> 4));
}
/// `BrushableBlockEntity.brushingCompleted`: the item drops out of the
@@ -168,8 +196,10 @@ impl Game<'_> {
_ => "minecraft:air",
};
// dropContent: the item at the middle of the block beside that face.
let item = spill::saved_entity(&self.world, pos)
.and_then(|tag| tag.get("item").and_then(save::item_from_nbt));
let item = match self.world.block_entities.get(&(pos[0], pos[1], pos[2])) {
Some(BlockEntity::Brushable(b)) => b.item.clone(),
_ => None,
};
if let Some(mut item) = item {
let face = face.unwrap_or([0, 1, 0]);
let take = 10 + self.world.random.next_int_bound(21).unwrap_or(0);
@@ -223,12 +253,70 @@ impl Game<'_> {
if brush.count != 0 {
self.brushing.insert(pos, brush);
self.schedule_brushable_tick(pos);
} else if let Some(BlockEntity::Brushable(b)) =
self.world.block_entities.get_mut(&(pos[0], pos[1], pos[2]))
{
b.hit_direction = None;
}
if before != after {
self.set_dusted(pos, after);
}
}
/// `BrushableBlockRenderer`: reveal the item from the first brushed face.
pub(super) fn brushable_geometry(&self, camera: glam::DVec3, out: &mut Vec<Vertex>) {
use horizon_assets::item_model::DisplayContext;
for (key, entity) in &self.world.block_entities {
let BlockEntity::Brushable(b) = entity else {
continue;
};
let (Some(item), Some(face)) = (&b.item, b.hit_direction) else {
continue;
};
let at = glam::DVec3::new(f64::from(key.0), f64::from(key.1), f64::from(key.2));
if at.distance_squared(camera) >= 64.0 * 64.0 {
continue;
}
let state = self.world.block(key.0, key.1, key.2);
let progress = self
.pack
.assets
.registry
.state(state)
.and_then(|s| s.properties.get("dusted"))
.and_then(|s| s.parse::<u8>().ok())
.unwrap_or(0);
if progress == 0 {
continue;
}
let offset = f32::from(progress) * 0.075;
let (translation, adjacent, east_west) = match face {
0 => (glam::Vec3::new(0.5, -0.23 - offset, 0.5), [0, -1, 0], false),
1 => (glam::Vec3::new(0.5, 0.25 + offset, 0.5), [0, 1, 0], false),
2 => (glam::Vec3::new(0.5, 0.0, 0.25 - offset), [0, 0, -1], false),
3 => (glam::Vec3::new(0.5, 0.0, 0.73 + offset), [0, 0, 1], false),
4 => (glam::Vec3::new(0.25 - offset, 0.0, 0.5), [-1, 0, 0], true),
5 => (glam::Vec3::new(0.73 + offset, 0.0, 0.5), [1, 0, 0], true),
_ => continue,
};
let item = self.resolve_item(item, DisplayContext::Fixed, None, 0);
if item.is_empty() {
continue;
}
let pose = glam::Mat4::from_translation(
(at - camera).as_vec3() + glam::Vec3::new(0.0, 0.5, 0.0) + translation,
) * glam::Mat4::from_rotation_y(
(86.0_f32 + if east_west { 90.0 } else { 0.0 }).to_radians(),
) * glam::Mat4::from_scale(glam::Vec3::splat(0.5));
let light = self.world.light(
key.0 + adjacent[0],
key.1 + adjacent[1],
key.2 + adjacent[2],
);
self.submit_item_world(&item, pose, vertex_light(light), out);
}
}
/// Level event 3008 (`LevelEventHandler`): the finished block's sound
/// and break particles.
pub(super) fn brush_complete_event(&mut self, pos: [i32; 3], data: i32) {
+1 -1
View File
@@ -20,7 +20,7 @@ use std::{
/// The tree the chat parses and completes with: a server's, once it has
/// sent one (ClientPacketListener.commands), else the game's own.
fn chat_tree<'a>(
pub(super) fn chat_tree<'a>(
remote: &'a Option<super::remote::Remote>,
mods: &'a super::mods::ModsState,
) -> &'a horizon_client::command::Dispatcher {
+178 -29
View File
@@ -4,18 +4,21 @@
//! `CommandBlockEditScreen` with what `handleSetCommandBlock` does with it.
use super::{Game, Screen, commands::execute::Source, lan::LanHost};
use horizon_client::{
chat::{ChatScreen, Commands},
command_block::{self, CommandBlock, Mode},
containers::BlockEntity,
hud::{HudBatch, rgba},
screen_draw::Measure,
text::{self, Text},
ui::{self, EditBox},
world::World,
};
use horizon_core::position::BlockPos;
use horizon_protocol::packets::play::{self, Serverbound as S};
use horizon_protocol::packets::play::{self, Clientbound as C, Serverbound as S};
use horizon_world::{
chunk::BlockState,
level::flags,
nbt::Tag,
registry::{BlockRegistry, BlockStateId},
};
use winit::{
@@ -28,7 +31,10 @@ type Pos = (i32, i32, i32);
/// The open `CommandBlockEditScreen`.
pub(super) struct CommandBlockScreen {
pos: Pos,
command: EditBox,
/// The command box with its `CommandSuggestions`.
command: ChatScreen,
/// When the command box was focused, for its cursor's blink.
opened: std::time::Instant,
previous: EditBox,
track_output: bool,
mode: Mode,
@@ -93,6 +99,9 @@ impl CommandBlockScreen {
Button::Cancel => tr("gui.cancel"),
}
}
pub(super) fn pos(&self) -> Pos {
self.pos
}
/// `updatePreviousOutput`.
fn show_previous(&mut self, block: &CommandBlock) {
let shown = if self.track_output {
@@ -446,10 +455,14 @@ impl Game<'_> {
let Some(state) = self.block_state_at(pos) else {
return;
};
let mut command = EditBox::new(0.0, 50.0, 300.0, 20.0);
command.max_length = 32500;
command.set_value(&block.command);
command.focused = true;
let (w, h) = self.gui_size();
let m = Measure(&self.gui.atlas.font);
let c = Commands {
dispatcher: super::chat::chat_tree(&self.remote, &self.mods),
registries: &self.ui.registries,
};
let mut command = ChatScreen::command_block(&m, &c, &block.command, w as i32, h as i32);
command.auto_suggestions = self.settings.auto_suggestions;
let mut previous = EditBox::new(0.0, 135.0, 276.0, 20.0);
previous.max_length = 32500;
previous.text_color = UNEDITABLE;
@@ -457,6 +470,7 @@ impl Game<'_> {
let mut screen = CommandBlockScreen {
pos,
command,
opened: std::time::Instant::now(),
previous,
track_output: block.track_output,
mode: Mode::of_block(&state.name).unwrap_or(Mode::Redstone),
@@ -485,7 +499,14 @@ impl Game<'_> {
let atlas = &self.gui.atlas;
let (w, h) = (batch.width, batch.height);
let mid = (w / 2.0).floor();
ui::menu_background(batch, atlas, 0.0, 0.0, w, h, true);
// Screen.extractBackground of an isInGameUi screen: the dimmed world,
// with no blur and no menu background.
batch.fill_gradient(
atlas,
(0.0, 0.0, w, h),
rgba(0x10, 0x10, 0x10, 0xC0),
rgba(0x10, 0x10, 0x10, 0xD0),
);
let title = Text::translate("advMode.setCommand", &[]);
let tw = atlas.font.width_text(&title);
batch.text_styled(
@@ -499,8 +520,6 @@ impl Game<'_> {
let grey = rgba(160, 160, 160, 255);
let label = Text::translate("advMode.command", &[]);
batch.text_styled(atlas, &label, mid - 149.0, 40.0, grey, true);
s.command.x = mid - 150.0;
s.command.draw(batch, atlas, None);
if !s.previous.value.is_empty() {
let label = Text::translate("advMode.previousOutput", &[]);
batch.text_styled(atlas, &label, mid - 149.0, 125.0, grey, true);
@@ -511,12 +530,65 @@ impl Game<'_> {
let hover = ui::hovered(self.cursor, x, y, bw, 20.0);
ui::button(batch, atlas, x, y, bw, 20.0, &s.label(b), true, hover);
}
// The command box, then its suggestions over the widgets.
let m = Measure(&atlas.font);
let c = Commands {
dispatcher: super::chat::chat_tree(&self.remote, &self.mods),
registries: &self.ui.registries,
};
s.command.resize(&m, &c, w as i32, h as i32);
let mouse = (self.cursor.0.floor() as i32, self.cursor.1.floor() as i32);
let blink = s.opened.elapsed().as_millis() as u64;
let draws = s.command.draw(&m, mouse, blink, 0);
horizon_client::screen_draw::paint(batch, atlas, &draws);
self.command_block_screen = Some(s);
}
/// The wheel over the suggestion list (`CommandSuggestions.mouseScrolled`).
pub(super) fn command_block_scroll(&mut self, amount: f32) {
let mouse = (self.cursor.0.floor() as i32, self.cursor.1.floor() as i32);
if let Some(s) = self.command_block_screen.as_mut() {
s.command.scroll(mouse, f64::from(amount));
}
}
/// The command box's completion request for an `ask_server` node.
pub(super) fn command_block_suggestion_request(&mut self) -> Option<(i32, String)> {
self.command_block_screen.as_mut()?.command.take_request()
}
/// The server's completions for the command box's `ask_server` request.
pub(super) fn command_block_server_suggestions(
&mut self,
id: i32,
range: (usize, usize),
list: Vec<(String, Option<String>)>,
) {
let Some(mut s) = self.command_block_screen.take() else {
return;
};
let m = Measure(&self.gui.atlas.font);
let c = Commands {
dispatcher: super::chat::chat_tree(&self.remote, &self.mods),
registries: &self.ui.registries,
};
s.command.server_suggestions(&m, &c, id, range, list);
self.command_block_screen = Some(s);
}
pub(super) fn command_block_click(&mut self) {
let Some(mut s) = self.command_block_screen.take() else {
return;
};
// CommandSuggestions.mouseClicked first, then the command box.
{
let m = Measure(&self.gui.atlas.font);
let c = Commands {
dispatcher: super::chat::chat_tree(&self.remote, &self.mods),
registries: &self.ui.registries,
};
let (x, y) = (f64::from(self.cursor.0), f64::from(self.cursor.1));
if s.command.click(&m, &c, x, y) {
self.command_block_screen = Some(s);
return;
}
}
let size = self
.renderer
.as_ref()
@@ -552,8 +624,8 @@ impl Game<'_> {
}
self.command_block_screen = Some(s);
}
/// `AbstractCommandBlockEditScreen.keyPressed`: Enter is Done, Escape
/// cancels, the rest edits the command.
/// `AbstractCommandBlockEditScreen.keyPressed`: the suggestions first,
/// then Enter is Done, Escape cancels, the rest edits the command.
pub(super) fn command_block_key(&mut self, event: &KeyEvent) {
if event.state != ElementState::Pressed {
return;
@@ -561,27 +633,56 @@ impl Game<'_> {
let PhysicalKey::Code(key) = event.physical_key else {
return;
};
let shortcut = self.edit_shortcut(event);
self.command_block_key_code(key, shortcut, event.text.as_deref());
}
/// A key pressed on the command block screen, with the edit shortcut it
/// makes and the text it types.
pub(super) fn command_block_key_code(
&mut self,
key: KeyCode,
shortcut: Option<horizon_client::clipboard::EditShortcut>,
text: Option<&str>,
) {
let ctrl = self.keys.contains(&KeyCode::ControlLeft);
let shift = self.keys.contains(&KeyCode::ShiftLeft);
let Some(mut s) = self.command_block_screen.take() else {
return;
};
let m = Measure(&self.gui.atlas.font);
let c = Commands {
dispatcher: super::chat::chat_tree(&self.remote, &self.mods),
registries: &self.ui.registries,
};
if s.command.suggestions_key(&m, &c, key, shift) {
self.command_block_screen = Some(s);
return;
}
let typed = match key {
KeyCode::Escape | KeyCode::Enter | KeyCode::NumpadEnter => false,
_ => {
if let Some(shortcut) = shortcut {
s.command.shortcut(&m, &c, shortcut, &mut self.clipboard);
false
} else {
!s.command.field_key(&m, &c, key, shift, ctrl) && !ctrl
}
}
};
self.command_block_screen = Some(s);
if typed {
self.command_block_type(text.unwrap_or(""));
}
match key {
KeyCode::Escape => return self.close_command_block(),
KeyCode::Escape => self.close_command_block(),
KeyCode::Enter | KeyCode::NumpadEnter => {
if let Some(s) = self.command_block_screen.take() {
self.set_command_block(&s);
}
return self.close_command_block();
self.close_command_block();
}
_ => {}
}
let ctrl = self.keys.contains(&KeyCode::ControlLeft);
let shift = self.keys.contains(&KeyCode::ShiftLeft);
let shortcut = self.edit_shortcut(event);
let Some(s) = self.command_block_screen.as_mut() else {
return;
};
if let Some(shortcut) = shortcut {
s.command.shortcut(shortcut, &mut self.clipboard);
} else if !s.command.key(key, ctrl, shift) && !ctrl {
self.command_block_type(event.text.as_deref().unwrap_or(""));
}
}
/// Characters typed into the command box (`StringUtil.isAllowedChatCharacter`).
pub(super) fn command_block_type(&mut self, typed: &str) {
@@ -589,11 +690,19 @@ impl Game<'_> {
.chars()
.filter(|&c| c != '\u{a7}' && c >= ' ' && c != '\u{7f}')
.collect();
if let Some(s) = self.command_block_screen.as_mut()
&& !allowed.is_empty()
{
s.command.insert_text(&allowed);
if allowed.is_empty() {
return;
}
let Some(mut s) = self.command_block_screen.take() else {
return;
};
let m = Measure(&self.gui.atlas.font);
let c = Commands {
dispatcher: super::chat::chat_tree(&self.remote, &self.mods),
registries: &self.ui.registries,
};
s.command.type_text(&m, &c, &allowed);
self.command_block_screen = Some(s);
}
/// The edit screen's Done: a server's client sends the packet, the
/// window's own world applies it (`handleSetCommandBlock`).
@@ -604,7 +713,7 @@ impl Game<'_> {
}
let edit = CommandBlockEdit {
pos: s.pos,
command: s.command.value.clone(),
command: s.command.value().to_owned(),
track_output: s.track_output,
mode: s.mode,
conditional: s.conditional,
@@ -653,6 +762,46 @@ impl Game<'_> {
}
});
}
/// `ServerPlayer.openCommandBlock`: the command block's data
/// (`saveCustomOnly`) goes to the guest whose use opened it, as the
/// chunk's update tag leaves it out and the edit screen shows it.
pub(super) fn lan_open_command_block(&mut self, host: &mut LanHost, conn: u32, pos: Pos) {
if !host
.hub
.guest(conn)
.is_some_and(|g| g.creative() && g.permission >= 2)
{
return;
}
let Some(block) = self.command_block(pos) else {
return;
};
let tag = Tag::compound(block.save());
let state = self.world.block(pos.0, pos.1, pos.2).0;
let Some(kind) = host.hub.encoder.entity_type(state) else {
return;
};
host.hub.send_to(
conn,
&C::BlockEntityData(play::BlockEntityData {
pos: [pos.0, pos.1, pos.2],
kind,
tag,
}),
);
}
/// `ClientPacketListener.handleBlockEntityData`: new data for the command
/// block the edit screen shows refills it (`CommandBlockEditScreen.updateGui`).
pub(super) fn command_block_data_arrived(&mut self, pos: Pos) {
let open = self.screen == Screen::CommandBlock
&& self
.command_block_screen
.as_ref()
.is_some_and(|s| s.pos == pos);
if open {
self.open_command_block(pos);
}
}
/// What `handleSetCommandBlock` does once the player may edit the block.
fn apply_command_block(&mut self, s: &CommandBlockEdit) {
let pos = s.pos;
+12 -4
View File
@@ -22,7 +22,7 @@ const HELP: &[&str] = &[
"tp X Y Z teleport the player",
"hotbar 1-9 select a hotbar slot",
"give ITEM [COUNT] add items to the inventory",
"render-distance N chunks, 2..64",
"render-distance N chunks, 2..128",
"lod-distance N far surface chunks, 0 disables, up to1024",
"time TICKS set the time of day",
"summon KIND [X Y Z] [baby] spawn a mob (in front of the player without a position)",
@@ -349,7 +349,10 @@ impl Game<'_> {
self.native_key_event(physical, false, false);
}
// Text screens consume raw presses; releases follow key binds.
let typing = matches!(self.screen, Screen::Chat | Screen::Options);
let typing = matches!(
self.screen,
Screen::Chat | Screen::Options | Screen::CommandBlock
);
let key = if typing && arg(2)? != "up" {
key
} else {
@@ -517,8 +520,9 @@ impl Game<'_> {
}
"render-distance" => {
let n: i32 = arg(1)?.parse()?;
if !(2..=64).contains(&n) {
return Err("render distance must be 2..64".into());
let max = horizon_client::options_file::MAX_RENDER_DISTANCE;
if !(2..=max).contains(&n) {
return Err(format!("render distance must be 2..{max}").into());
}
self.settings.render_distance = n;
self.apply_settings();
@@ -855,6 +859,10 @@ impl Game<'_> {
if self.screen == Screen::Options {
return self.options_key(key, None);
}
if self.screen == Screen::CommandBlock {
self.command_block_key_code(key, None, None);
return Ok(());
}
if self.keys.insert(key) {
self.key_pressed(key)?;
}
+9 -1
View File
@@ -4651,7 +4651,15 @@ impl Game<'_> {
let Some(model) = self.arrow_model.as_ref() else {
continue;
};
let Some(r) = atlas.sprites.get("entity/projectiles/arrow").copied() else {
// SpectralArrowRenderer, and TippableArrowRenderer's `getColor() > 0`.
let texture = if a.is_spectral_arrow() {
"entity/projectiles/arrow_spectral"
} else if a.arrow.as_ref().is_some_and(|s| s.effect_color > 0) {
"entity/projectiles/arrow_tipped"
} else {
"entity/projectiles/arrow"
};
let Some(r) = atlas.sprites.get(texture).copied() else {
continue;
};
let m = glam::Mat4::from_translation(c)
+102 -1
View File
@@ -26,12 +26,105 @@ use horizon_world::nbt::{JavaString, Tag};
use std::{
io::Write,
path::PathBuf,
sync::{Arc, Mutex, OnceLock, mpsc},
sync::{
Arc, Mutex, OnceLock,
atomic::{AtomicBool, AtomicU64, Ordering},
mpsc,
},
time::{Duration, Instant},
};
mod status;
/// What the tick loop tells `ServerWatchdog`: when the tick in progress was
/// due (`getNextTickTime`), how long a tick is, and whether the server runs.
struct Watchdog {
base: Instant,
next_nanos: AtomicU64,
tick_nanos: AtomicU64,
running: AtomicBool,
}
impl Watchdog {
/// `DedicatedServer.initServer`: a thread that stops a server whose tick
/// runs `max_tick_time` ms past its due time; none when that is 0 or less.
fn start(max_tick_time: i64) -> Option<Arc<Self>> {
let max = Duration::from_millis(u64::try_from(max_tick_time).ok().filter(|m| *m > 0)?);
let watchdog = Arc::new(Self {
base: Instant::now(),
next_nanos: AtomicU64::new(0),
tick_nanos: AtomicU64::new(50_000_000),
running: AtomicBool::new(true),
});
let shared = watchdog.clone();
std::thread::Builder::new()
.name("Server Watchdog".into())
.spawn(move || shared.run(max))
.ok()?;
Some(watchdog)
}
/// The tick loop is about to run the tick due at `next`.
fn tick_due(&self, next: Instant, tick: Duration) {
let nanos = next.saturating_duration_since(self.base).as_nanos();
self.next_nanos
.store(u64::try_from(nanos).unwrap_or(u64::MAX), Ordering::Relaxed);
let tick = u64::try_from(tick.as_nanos()).unwrap_or(u64::MAX);
self.tick_nanos.store(tick, Ordering::Relaxed);
}
/// `ServerWatchdog.run`.
fn run(&self, max: Duration) {
let max = u64::try_from(max.as_nanos()).unwrap_or(u64::MAX);
while self.running.load(Ordering::Relaxed) {
let next = self.next_nanos.load(Ordering::Relaxed);
let now = u64::try_from(self.base.elapsed().as_nanos()).unwrap_or(u64::MAX);
let behind = now.saturating_sub(next);
if behind > max {
let took = format!("{:.2}", behind as f32 / 1e9);
let should = format!(
"{:.2}",
self.tick_nanos.load(Ordering::Relaxed) as f32 / 1e9
);
log_from(
"Server Watchdog",
"ERROR",
&format!("A single server tick took {took} seconds (should be max {should})"),
);
log_from(
"Server Watchdog",
"ERROR",
"Considering it to be crashed, server will forcibly shutdown.",
);
let message = format!(
"ServerWatchdog detected that a single server tick took {took} seconds (should be max {should})"
);
match horizon_client::crash::report_watchdog(
std::path::Path::new("."),
"server",
message,
) {
Some(path) => log_from(
"Server Watchdog",
"ERROR",
&format!(
"This crash report has been saved to: {}",
path.canonicalize().unwrap_or(path).display()
),
),
None => log_from(
"Server Watchdog",
"ERROR",
"We were unable to save this crash report to disk.",
),
}
std::process::exit(1);
}
// Thread.sleep(nextTickTime + maxTickTime - now).
let wait = (next + max).saturating_sub(now).max(1_000_000);
std::thread::sleep(Duration::from_nanos(wait));
}
}
}
/// Double.toString for the magnitudes positions have (no exponent form
/// between 1e-3 and 1e7).
pub(super) fn java_double(v: f64) -> String {
@@ -704,8 +797,13 @@ impl Game<'_> {
let pause_after = props.pause_when_empty_seconds * 20;
let idle_timeout = props.player_idle_timeout;
let mut next = Instant::now();
self.fns.permission = Some(props.function_permission_level.clamp(0, 4) as u8);
let watchdog = Watchdog::start(props.max_tick_time);
while !state.stop {
let tick_start = Instant::now();
if let Some(watchdog) = &watchdog {
watchdog.tick_due(next, self.clock.tick_duration());
}
while let Ok(line) = state.console.try_recv() {
self.console_line(&mut state, &line);
}
@@ -746,6 +844,9 @@ impl Game<'_> {
state.ticked(Instant::now());
self.wait_for_next_server_tick(&mut next, paused);
}
if let Some(watchdog) = &watchdog {
watchdog.running.store(false, Ordering::Relaxed);
}
self.stop_dedicated()
}
@@ -36,6 +36,8 @@ pub(super) struct FnState {
load_pending: bool,
pub schedule: Vec<Scheduled>,
next_seq: u64,
/// A dedicated server's `function-permission-level`.
pub permission: Option<u8>,
}
/// What a function reported through `return`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -45,6 +47,16 @@ pub(super) enum Outcome {
Fail,
}
impl FnState {
/// The level function files compile at (`ServerFunctionLibrary`'s
/// `functionCompilationPermissions`): `function-permission-level` on a
/// dedicated server, game master (2) otherwise. Whoever runs a function,
/// its commands need no more than this.
fn command_level(&self) -> u8 {
self.permission.unwrap_or(2)
}
}
impl Game<'_> {
// ---- loading -----------------------------------------------------------
@@ -278,6 +290,7 @@ impl Game<'_> {
}
self.exec.function_depth += 1;
let outer = self.exec.returned.take();
let level = std::mem::replace(&mut self.ui.registries.permission, self.fns.command_level());
let inner = Source {
silent: true,
store: None,
@@ -292,6 +305,7 @@ impl Game<'_> {
break;
}
}
self.ui.registries.permission = level;
let returned = std::mem::replace(&mut self.exec.returned, outer);
self.exec.function_depth -= 1;
Ok(match returned {
+13
View File
@@ -61,6 +61,11 @@ fn attack_range_contains(range: &serde_json::Value, distance: f64, creative: boo
impl Game<'_> {
/// Opening a screen stops breaking before the next game tick (which may pause).
pub(super) fn stop_mining(&mut self) {
if self.clicks.destroying.active {
let pos = self.clicks.destroying.pos;
let state = self.world.block(pos[0], pos[1], pos[2]);
self.tutorial_destroy(state, -1.0);
}
let mut destroying = std::mem::take(&mut self.clicks.destroying);
destroying.stop(&mut GameHands {
game: self,
@@ -141,6 +146,12 @@ impl Game<'_> {
progress: d.progress,
ticks: d.ticks as u32,
});
if let Some(mining) = &self.mining {
let pos = mining.pos;
let progress = mining.progress;
let state = self.world.block(pos[0], pos[1], pos[2]);
self.tutorial_destroy(state, progress);
}
Ok(())
}
/// `BlockBehaviour.getDestroyProgress` with `Player.getDestroySpeed`.
@@ -578,6 +589,8 @@ impl HandWorld for GameHands<'_, '_> {
{
return false;
}
let state = self.game.world.block(pos[0], pos[1], pos[2]);
self.game.tutorial_destroy(state, 1.0);
let r = self.game.break_block(pos);
self.keep(r);
true
@@ -626,7 +626,9 @@ impl Game<'_> {
}) => Some(key),
_ => None,
};
self.command_block_screen = host_command_block;
// A command block the guest's use opened (Player.openCommandBlock).
let guest_command_block =
std::mem::replace(&mut self.command_block_screen, host_command_block).map(|s| s.pos());
// A mount inventory the guest's action opened (shift + use, or the
// inventory key while riding).
let guest_mount = std::mem::replace(&mut self.mount_menu, host_mount_menu).opened_mob();
@@ -779,6 +781,9 @@ impl Game<'_> {
if let Some(key) = guest_lectern {
self.lan_open_lectern(host, conn, key);
}
if let Some(pos) = guest_command_block {
self.lan_open_command_block(host, conn, pos);
}
if let Some(pos) = opened_table {
self.lan_open_crafting(host, conn, pos);
}
+97 -2
View File
@@ -9,7 +9,7 @@ use horizon_client::lan::{
hub::Hub,
};
use horizon_protocol::entity_data::{Value, serializer};
use horizon_world::nbt::Tag;
use horizon_world::{nbt::Tag, registry::BlockStateId};
fn state(id: u32, kind: &str, position: [f64; 3], yaw: f32, on_ground: bool) -> EntityState {
EntityState {
@@ -276,18 +276,100 @@ impl Game<'_> {
}
out.push(e);
}
// DATA_ITEM, `ItemStack.EMPTY` by default.
for o in self.ominous_spawners.iter().filter(|o| o.id != 0) {
let mut e = state(
o.id,
"minecraft:ominous_item_spawner",
o.position,
0.0,
false,
);
e.meta.push((
8,
serializer::ITEM_STACK,
Value::Item(hub.stack(&Some(o.item.clone()))),
));
out.push(e);
}
self.lan_projectile_states(host_entity, hub, out);
for o in &self.others {
let p = o.position;
let mut e = state(o.id, &o.kind, [p.x, p.y, p.z], o.yaw, false);
e.pitch = o.pitch;
e.head_yaw = o.yaw;
if let Some(tag) = self.persist.raw.get(&o.id) {
self.lan_display_data(tag, hub, &mut e);
}
out.push(e);
}
}
}
impl Game<'_> {
/// The synched data of a text, block or item display kept unsimulated,
/// from its compound (`Display.readAdditionalSaveData`), with the
/// defaults to send when a value goes back to one.
fn lan_display_data(&self, tag: &Tag, hub: &mut Hub, e: &mut EntityState) {
use horizon_client::text_display::{display_data, text_display_data};
let empty = Tag::Compound(Default::default());
let (meta, defaults) = match e.kind.as_str() {
"minecraft:text_display" => (
text_display_data(tag, false),
text_display_data(&empty, true),
),
"minecraft:block_display" => {
// DATA_BLOCK_STATE_ID, air by default.
let state = |t: Option<BlockStateId>| {
(
23,
serializer::BLOCK_STATE,
Value::Id(t.map_or(0, |s| s.0 as i32)),
)
};
let air = self.pack.assets.registry.default_state("minecraft:air");
let shown = tag.get("block_state").and_then(|t| self.state_from_nbt(t));
(vec![state(shown.or(air))], vec![state(air)])
}
"minecraft:item_display" => {
// DATA_ITEM_STACK and DATA_ITEM_DISPLAY_ID (`ItemDisplayContext`).
let item = tag
.get("item")
.and_then(horizon_client::save::item_from_nbt);
let context = match tag.get("item_display") {
Some(Tag::String(s)) => match s.to_string_lossy().as_str() {
"thirdperson_lefthand" => 1,
"thirdperson_righthand" => 2,
"firstperson_lefthand" => 3,
"firstperson_righthand" => 4,
"head" => 5,
"gui" => 6,
"ground" => 7,
"fixed" => 8,
"on_shelf" => 9,
_ => 0,
},
_ => 0,
};
(
vec![
(23, serializer::ITEM_STACK, Value::Item(hub.stack(&item))),
(24, serializer::BYTE, Value::Byte(context)),
],
vec![
(23, serializer::ITEM_STACK, Value::Item(None)),
(24, serializer::BYTE, Value::Byte(0)),
],
)
}
_ => return,
};
e.meta = display_data(tag, false);
e.meta.extend(meta);
e.defaults = display_data(&empty, true);
e.defaults.extend(defaults);
}
/// Gives the entities Horizon keeps without an id one (`Entity.id`, from
/// the same counter as the rest) before they are first tracked.
pub(super) fn lan_assign_ids(&mut self) {
@@ -326,6 +408,9 @@ impl Game<'_> {
self.rockets.iter_mut().for_each(|r| give(&mut r.id));
self.crystals.iter_mut().for_each(|c| give(&mut c.id));
self.bolts.iter_mut().for_each(|b| give(&mut b.id));
self.ominous_spawners
.iter_mut()
.for_each(|o| give(&mut o.id));
self.potions.thrown_ids().for_each(&mut give);
self.end.eye_ids().for_each(&mut give);
self.breath_clouds.iter_mut().for_each(|b| give(&mut b.id));
@@ -377,7 +462,12 @@ impl Game<'_> {
}
for p in self.creatures.projectiles.iter().filter(|p| p.id != 0) {
use horizon_client::projectiles::ProjectileKind as K;
let kind = p.kind.id();
// A spectral arrow is its own entity type.
let kind = if p.is_spectral_arrow() {
"minecraft:spectral_arrow"
} else {
p.kind.id()
};
let mut e = state(p.id, kind, at(p.position), p.yaw, false);
e.pitch = p.pitch;
e.velocity = at(p.velocity);
@@ -396,6 +486,11 @@ impl Game<'_> {
a.map_or(0, |a| a.pierce),
a.is_some_and(|a| a.in_ground) || p.stuck,
));
// Arrow.ID_EFFECT_COLOR, -1 by default.
let color = p.arrow_effect_color();
if color != -1 {
e.meta.push((11, serializer::INT, Value::Int(color)));
}
}
// ThrownTrident.ID_LOYALTY (none for a mob's) and ID_FOIL, on
// AbstractArrow's flags.
+19 -7
View File
@@ -151,10 +151,14 @@ impl Containers<'_> {
});
}
let entity = self.world.block_entities.get(&pos)?;
// A beehive keeps bees, not items, and a campfire cooks its own: neither
// is a `Container` (HopperBlockEntity.getContainerAt), so a dropper drops
// in front of them and a hopper leaves them alone.
if matches!(entity, BlockEntity::Beehive(_) | BlockEntity::Campfire(_)) {
// A beehive keeps bees, not items, a campfire cooks its own and
// suspicious sand or gravel hides its loot: none is a `Container`
// (HopperBlockEntity.getContainerAt), so a dropper drops in front of
// them and a hopper leaves them alone.
if matches!(
entity,
BlockEntity::Beehive(_) | BlockEntity::Campfire(_) | BlockEntity::Brushable(_)
) {
return None;
}
let kind = match (entity, name) {
@@ -422,15 +426,17 @@ pub(super) fn shelf_signal(
_ => 0,
});
}
let tag = super::spill::saved_entity(world, [pos.x, pos.y, pos.z]);
// Only read from the back: a bit for each of the three slots in use.
let facing = info.properties.get("facing").and_then(|f| dir_from_name(f));
if facing.map(Direction::opposite) != Some(direction) {
return Some(0);
}
let items = horizon_client::save::decode_items(tag.as_ref().and_then(|t| t.get("Items")), 3);
let Some(BlockEntity::Shelf(shelf)) = world.block_entities.get(&(pos.x, pos.y, pos.z)) else {
return Some(0);
};
Some(
items
shelf
.items
.iter()
.enumerate()
.map(|(slot, item)| i32::from(item.is_some()) << slot)
@@ -473,6 +479,12 @@ impl Game<'_> {
return;
}
self.chiseled_bookshelf_synced(pos);
if matches!(
self.world.block_entities.get(&pos),
Some(BlockEntity::Shelf(_))
) {
self.mark_block_entity_updated(pos);
}
// A double chest's other half changes with it.
let halves: Vec<Pos> = std::iter::once(pos)
.chain(self.chest_other_half(pos))
+20 -1
View File
@@ -4,7 +4,7 @@ use super::Game;
use horizon_client::{
blocks::Fluid,
music::{BackgroundMusic, Music, MusicFrequency, Situation},
sound_engine::TickContext,
sound_engine::{SoundEngine, SoundInstance, Sounds, TickContext},
};
impl Game<'_> {
@@ -35,6 +35,22 @@ impl Game<'_> {
}
let (vehicle, carts) = self.start_cart_sounds();
let mobs = self.start_mob_sounds();
let (player_position, player_speed_sqr, player_fall_flying) =
self.player.as_ref().map_or(([0.0; 3], 0.0, false), |p| {
let at = p.position;
(
[at.x, at.y, at.z],
p.velocity.length_squared(),
p.fall_flying,
)
});
// LocalPlayer.onSyncedDataUpdated: starting to glide starts the
// elytra's flying sound.
if player_fall_flying && !self.was_fall_flying {
let instance = SoundInstance::elytra(player_position, SoundEngine::unseeded());
self.audio.play_instance(instance, false);
}
self.was_fall_flying = player_fall_flying;
let ctx = TickContext {
player_underwater: self.ambience.was_underwater(),
player_removed: self.player.is_none(),
@@ -42,6 +58,9 @@ impl Game<'_> {
carts,
mobs,
frozen: !self.clock.runs_normally(),
player_position,
player_speed_sqr,
player_fall_flying,
};
self.audio.tick(self.pause, &ctx);
}
@@ -21,6 +21,8 @@ const TICKS_SCALING: f32 = 50.0;
const ROTATION_SPEED: f32 = 40.0;
pub(super) struct OminousItemSpawner {
/// The entity id a server tracks it by (0 until it is tracked).
pub(super) id: u32,
pub(super) item: ItemStack,
pub(super) position: [f64; 3],
pub(super) spawn_item_after: i64,
@@ -65,6 +67,7 @@ impl Game<'_> {
delay: i32,
) {
self.ominous_spawners.push(OminousItemSpawner {
id: 0,
item,
position,
spawn_item_after: i64::from(delay),
@@ -82,6 +85,7 @@ impl Game<'_> {
return;
};
self.ominous_spawners.push(OminousItemSpawner {
id: 0,
item,
position: [at.x, at.y, at.z],
spawn_item_after,
@@ -121,6 +125,32 @@ impl Game<'_> {
kept.append(&mut self.ominous_spawners);
self.ominous_spawners = kept;
}
/// `handleAddEntity` for a spawner a server sent: its item comes with the
/// entity data (`ItemStack.EMPTY` until then, which draws nothing).
pub(super) fn add_remote_ominous_item_spawner(&mut self, id: u32, position: [f64; 3]) {
self.ominous_spawners.push(OminousItemSpawner {
id,
item: ItemStack::new("minecraft:air", 1),
position,
spawn_item_after: 0,
tick_count: 0,
uuid: [0; 4],
raw: None,
});
}
/// `OminousItemSpawner.tick` on a client: `tickCount` and `tickClient`,
/// the particles every 5 game ticks; only the server spawns the item.
pub(super) fn tick_remote_ominous_item_spawners(&mut self) {
let at: Vec<[f64; 3]> = self.ominous_spawners.iter().map(|s| s.position).collect();
for s in &mut self.ominous_spawners {
s.tick_count += 1;
}
if self.world.game_time % 5 == 0 {
for position in at {
self.ominous_spawner_particles(position);
}
}
}
/// `spawnItem`: a projectile shot down, or an item entity; level event
/// 3021 and the entity_place game event.
fn spawn_ominous_item(&mut self, s: &OminousItemSpawner) {
+16 -1
View File
@@ -19,12 +19,18 @@ pub(super) const CONTROL_HELP: &[&str] = &[
impl Game<'_> {
pub(super) fn save_title_options(&mut self) {
if let Some(title) = &self.title
&& title.last_server != self.settings.file.string("lastServer")
&& (title.last_server != self.settings.file.string("lastServer")
|| title.skip_multiplayer_warning
!= self.settings.file.bool("skipMultiplayerWarning"))
{
self.settings.file.set(
"lastServer",
horizon_client::options_file::V::Str(title.last_server.clone()),
);
self.settings.file.set(
"skipMultiplayerWarning",
horizon_client::options_file::V::Bool(title.skip_multiplayer_warning),
);
self.settings.save(&Self::options_path());
}
}
@@ -232,6 +238,15 @@ impl Game<'_> {
let _ = std::fs::create_dir_all(&dir);
super::packs::open_folder(&dir);
}
Event::DataPacks(ids) => {
if let Some(title) = &mut self.title {
title.set_data_packs(ids);
}
}
Event::OpenDataPackFolder(dir) => {
let _ = std::fs::create_dir_all(&dir);
super::packs::open_folder(&dir);
}
Event::OpenModFolder => {
let dir = Self::options_path().with_file_name(horizon_client::mod_list::DIR);
let _ = std::fs::create_dir_all(&dir);
+1 -1
View File
@@ -631,7 +631,7 @@ impl Game<'_> {
*self.persist.uuids.entry(id).or_insert_with(random_uuid)
}
/// `BlockState.CODEC`: a block name or `{id, properties}` (or legacy `{Name, Properties}`).
fn state_from_nbt(&self, tag: &Tag) -> Option<BlockStateId> {
pub(super) fn state_from_nbt(&self, tag: &Tag) -> Option<BlockStateId> {
let registry = self.pack.assets.registry;
let state = match tag.get("Name") {
Some(Tag::String(name)) => BlockState {
+115 -25
View File
@@ -39,6 +39,7 @@ use horizon_protocol::{
text::{Language, plain},
};
use horizon_world::{
level::InteractionResult,
nbt::Tag,
registry::BlockStateId,
stepped_interpolation::{Path, PosRot, Start, SteppedInterpolation},
@@ -325,7 +326,9 @@ impl Game<'_> {
&self.options.resources,
));
}
let skip = self.settings.file.bool("skipMultiplayerWarning");
if let Some(title) = &mut self.title {
title.skip_multiplayer_warning = skip;
title.failed(error);
}
self.capture(false);
@@ -347,6 +350,7 @@ impl Game<'_> {
local: Option<horizon_protocol::connection::Pipe>,
cookies: Option<horizon_client::net::Cookies>,
) -> Result<()> {
self.reset_tutorial();
self.perf.world_opening();
let root = self.options.resources.clone();
let builtin = Builtin::find(&root)
@@ -556,8 +560,10 @@ impl Game<'_> {
if let Some(mut r) = self.remote.take() {
r.session.disconnect();
}
self.gui.atlas.object_skins.clear();
self.server_packs_disconnect();
self.code_of_conduct = None;
self.reset_tutorial();
self.close_dialogs();
// Gui.setScreen -> KeyMapping.releaseAll: the title or disconnect
// screen releases every held key. Its release goes to that screen,
@@ -604,6 +610,7 @@ impl Game<'_> {
let saves = std::env::current_dir()?.join("saves");
let mut title = horizon_client::title::Title::new(saves.clone(), &self.options.resources);
title.last_server = self.settings.file.string("lastServer");
title.skip_multiplayer_warning = self.settings.file.bool("skipMultiplayerWarning");
if single_player && reason.is_none() {
self.title = Some(title);
self.capture(false);
@@ -1008,7 +1015,12 @@ impl Game<'_> {
if self.remote.is_none() {
return;
}
let Some((id, command)) = self.ui.chat_screen.as_mut().and_then(|s| s.take_request())
let Some((id, command)) = self
.ui
.chat_screen
.as_mut()
.and_then(|s| s.take_request())
.or_else(|| self.command_block_suggestion_request())
else {
return;
};
@@ -1048,7 +1060,8 @@ impl Game<'_> {
})();
if let Ok((id, start, length, list)) = decoded {
let range = (start.max(0) as usize, length.max(0) as usize);
self.chat_server_suggestions(id, range, list);
self.chat_server_suggestions(id, range, list.clone());
self.command_block_server_suggestions(id, range, list);
}
}
fn set_registries(&mut self, registries: Arc<Dynamic>) {
@@ -1243,10 +1256,14 @@ impl Game<'_> {
}
_ => {}
}
let command_block = matches!(loaded, BlockEntity::CommandBlock(_));
self.world.block_entities.insert(key, loaded);
// The section is drawn again with what the block entity shows.
let state = self.world.block(pos[0], pos[1], pos[2]);
let _ = self.world.set(pos[0], pos[1], pos[2], state);
if command_block {
self.command_block_data_arrived(key);
}
}
}
/// `handleAnimate`: a player wakes up, or an entity gets the critical
@@ -2770,6 +2787,7 @@ impl Game<'_> {
r.state_id = p.state;
}
let stack = self.to_stack(&p.item);
self.tutorial_get_item(stack.as_ref());
// ClientPacketListener.handleContainerSetSlot: a hotbar slot that
// gains items squeezes for 5 ticks.
if p.container == 0
@@ -2788,9 +2806,14 @@ impl Game<'_> {
self.set_menu_slot(p.container, i32::from(p.slot), stack);
self.remote_synced_since(&before);
}
C::SetCursorItem(p) => self.carried = self.to_stack(&p.item),
C::SetCursorItem(p) => {
let stack = self.to_stack(&p.item);
self.tutorial_get_item(stack.as_ref());
self.carried = stack;
}
C::SetPlayerInventory(p) => {
let stack = self.to_stack(&p.item);
self.tutorial_get_item(stack.as_ref());
let before = self.creative_stacks();
match p.slot {
0..=35 => self.inventory[p.slot as usize] = stack,
@@ -2978,7 +3001,10 @@ impl Game<'_> {
let text = |t: &Tag| {
let json = horizon_client::scoreboard::tag_to_json(t);
let text = horizon_client::scoreboard::comp_text(&json);
(!text.plain().is_empty()).then_some(text)
text.spans
.iter()
.any(|span| !span.text.is_empty())
.then_some(text)
};
self.tab_list.header = text(&p.header);
self.tab_list.footer = text(&p.footer);
@@ -3224,6 +3250,13 @@ impl Game<'_> {
.as_ref()
.and_then(|r| r.skins.get(&p.uuid).cloned())
.unwrap_or_else(|| horizon_client::tab_list::default_skin(p.uuid).to_owned());
self.gui
.atlas
.set_object_skin(format!("id:{:032x}", p.uuid), p.skin.clone());
self.gui.atlas.set_object_skin(
format!("name:{}", p.name.to_ascii_lowercase()),
p.skin.clone(),
);
}
let r = self.remote.as_ref()?;
let upside_down = players
@@ -3236,6 +3269,32 @@ impl Game<'_> {
.collect();
Some((players, r.online_mode, upside_down))
}
/// Resolve inline `object:player` profiles through the same skin cache as
/// player heads on items. The next frame uses the uploaded atlas texture.
pub(super) fn resolve_inline_profiles(&mut self, profiles: &[serde_json::Value]) {
use horizon_client::skins;
for profile in profiles {
let skin = skins::head_skin(
profile,
&mut self.skin_profiles.borrow_mut(),
&mut self.skin_downloads.borrow_mut(),
|location| self.gui.atlas.sprites.contains_key(location),
);
let id = skins::parse_profile(profile).id;
self.gui
.atlas
.set_object_skin(format!("id:{id:032x}"), skin.clone());
let name = profile
.as_str()
.or_else(|| profile.get("name").and_then(serde_json::Value::as_str));
if let Some(name) = name {
self.gui
.atlas
.set_object_skin(format!("name:{}", name.to_ascii_lowercase()), skin);
}
}
}
/// The signed-in account's `textures`, once the services answered.
fn own_textures(&self) -> Option<horizon_client::skins::Textures> {
use horizon_client::skins::{self, NameOrId, Resolve};
@@ -4146,6 +4205,7 @@ impl Game<'_> {
fn tick_remote_entities(&mut self, running: bool) {
if running {
self.tick_text_displays();
self.tick_remote_ominous_item_spawners();
}
// EntityFluidInteraction.update for the entities this window only displays: the
// server never sends the fluid contact, and the renderers read it (cod, salmon and
@@ -4583,6 +4643,8 @@ impl Game<'_> {
/// the attack strength again.
pub(super) fn stop_remote_mining(&mut self) {
if let Some((pos, _, _)) = self.remote.as_mut().and_then(|r| r.destroying.take()) {
let state = self.world.block(pos[0], pos[1], pos[2]);
self.tutorial_destroy(state, -1.0);
self.send(S::PlayerAction(play::PlayerAction {
action: 2,
pos,
@@ -4653,6 +4715,8 @@ impl Game<'_> {
}
if !same {
if let Some((old, _, _)) = self.remote.as_mut().and_then(|r| r.destroying.take()) {
let old_state = self.world.block(old[0], old[1], old[2]);
self.tutorial_destroy(old_state, -1.0);
self.send(S::PlayerAction(play::PlayerAction {
action: 2,
pos: old,
@@ -4667,6 +4731,7 @@ impl Game<'_> {
direction: face,
sequence: seq,
}));
self.tutorial_destroy(state, 0.0);
if progress >= 1.0 {
// startDestroyBlock: instant survival breaks have no destroy delay.
self.predict_break(hit.pos, state, seq);
@@ -4690,6 +4755,7 @@ impl Game<'_> {
return;
};
let done = done + progress;
self.tutorial_destroy(state, done.clamp(0.0, 1.0));
let ticks = self.mining.as_ref().map_or(0, |m| m.ticks) + 1;
if done >= 1.0 {
let seq = self.next_sequence();
@@ -4726,6 +4792,7 @@ impl Game<'_> {
}
/// MultiPlayerGameMode.destroyBlock: the predicted break.
fn predict_break(&mut self, pos: [i32; 3], state: BlockStateId, sequence: i32) {
self.tutorial_destroy(state, 1.0);
// BlockStatePredictionHandler.retainKnownServerState.
if let Some(r) = self.remote.as_mut() {
r.predictions
@@ -4848,18 +4915,32 @@ impl Game<'_> {
.and_then(|h| self.res.items().get(&h.item))
.is_some_and(|i| i.block.is_some());
if let Some(hit) = self.pick() {
// ShelfBlock.useItemOn consumes a nonempty main-hand click client-side
// without predicting the inventory swap or swinging.
let shelf_reacts = hand == Hand::Main
&& held.is_some()
&& !(self.keys.contains(&KeyCode::ShiftLeft)
&& (self.stack_in(self.selected).is_some() || self.offhand.is_some()))
&& self.shelf_hit(&hit).is_some();
let spectator = self.spectator();
let (reacts, changes) = if hand == Hand::Main && !spectator {
let (result, changes) = if hand == Hand::Main && !spectator {
self.remote_block_reacts(&hit, held.as_ref())
} else {
// useItemOn runs for the off hand too (useWithoutItem doesn't):
// RespawnAnchorBlock.useItemOn charges an anchor with its glowstone.
// RespawnAnchorBlock.useItemOn charges an anchor with its
// glowstone, SUCCESS.
let sneaking = self.keys.contains(&KeyCode::ShiftLeft);
let hands_full = self.stack_in(self.selected).is_some() || self.offhand.is_some();
let charges =
!(sneaking && hands_full) && self.anchor_takes(hit.pos, held.as_ref());
(charges, DryUse::default())
let result = if charges {
InteractionResult::Success
} else {
InteractionResult::Pass
};
(result, DryUse::default())
};
let reacts = result.consumes_action();
let seq = self.next_sequence();
let cursor = [
(hit.point[0] - f64::from(hit.pos[0])) as f32,
@@ -4887,9 +4968,17 @@ impl Game<'_> {
if let Some(r) = self.remote.as_mut() {
r.use_target = Some(hit.pos);
}
if shelf_reacts {
return true;
}
if reacts {
self.predict_use(&changes, seq);
self.open_command_block_if_editable((hit.pos[0], hit.pos[1], hit.pos[2]));
// MultiPlayerGameMode.useItemOn: SUCCESS SwingSource.CLIENT
// (a chest, barrel, furnace, …). CONSUME does not swing.
if result == InteractionResult::Success {
self.with_hand(hand, Game::swing_arm);
}
} else if self.predict_campfire_douse(hit.pos, held.as_ref(), seq) {
// CampfireBlock.useItemOn succeeded: this hand swings and the
// click ends, so a shield in the other hand is not raised.
@@ -4928,7 +5017,7 @@ impl Game<'_> {
// server's resend of the target it refused is no placement.
r.placing = None;
}
if reacts || placed.is_some() {
if placed.is_some() {
self.with_hand(hand, Game::swing_arm);
}
// BlockItem.place returns FAIL when placement is rejected:
@@ -5020,20 +5109,20 @@ impl Game<'_> {
&mut self,
hit: &super::Hit,
held: Option<&ItemStack>,
) -> (bool, DryUse) {
) -> (InteractionResult, DryUse) {
// Player.isSecondaryUseActive with something in either hand.
let hands_full = self.stack_in(self.selected).is_some() || self.offhand.is_some();
if self.keys.contains(&KeyCode::ShiftLeft) && hands_full {
return (false, DryUse::default());
return (InteractionResult::Pass, DryUse::default());
}
if self.jukebox_takes(hit.pos, held) {
return (true, DryUse::default());
return (InteractionResult::Success, DryUse::default());
}
// RespawnAnchorBlock.useItemOn: PASS when the off hand's glowstone is to
// charge the anchor, so useWithoutItem doesn't run and the off hand's turn
// comes (glowstone in this hand charges it in `use_item_on`).
if !self.anchor_takes(hit.pos, held) && self.anchor_takes(hit.pos, self.offhand.as_ref()) {
return (false, DryUse::default());
return (InteractionResult::Pass, DryUse::default());
}
// BeehiveBlock.useItemOn: shears or a glass bottle on a full hive
// (honey level 5) is SUCCESS, so the click ends after UseItemOn and
@@ -5043,7 +5132,7 @@ impl Game<'_> {
.hive_state(hit.pos)
.is_some_and(|(honey, _)| honey == Some(5))
{
return (true, DryUse::default());
return (InteractionResult::Success, DryUse::default());
}
use horizon_core::geometry::Direction;
let face = match hit.face {
@@ -5057,18 +5146,16 @@ impl Game<'_> {
let player = self.use_context();
self.with_level(|b, level, _| {
let mut level = DryLevel::new(level);
let reacts = b
.use_item_on(
&mut level,
&mut horizon_world::level::Ticks::default(),
horizon_core::position::BlockPos::new(hit.pos[0], hit.pos[1], hit.pos[2]),
face,
horizon_core::geometry::Vec3::new(hit.point[0], hit.point[1], hit.point[2]),
player,
held.map(|s| &*s.item),
)
.consumes_action();
(reacts, (level.changed.into_iter().collect(), level.sounds))
let result = b.use_item_on(
&mut level,
&mut horizon_world::level::Ticks::default(),
horizon_core::position::BlockPos::new(hit.pos[0], hit.pos[1], hit.pos[2]),
face,
horizon_core::geometry::Vec3::new(hit.point[0], hit.point[1], hit.point[2]),
player,
held.map(|s| &*s.item),
);
(result, (level.changed.into_iter().collect(), level.sounds))
})
}
@@ -5696,6 +5783,9 @@ impl Game<'_> {
}
KeyCode::KeyE => {
// The inventory opens without telling the server.
if self.tutorial.open_inventory() {
self.persist_tutorial_step();
}
self.recipe_ui.reset_screen();
if self.creative {
self.screen = Screen::Creative;
@@ -35,11 +35,18 @@ impl Game<'_> {
m.extra.leash = Some(Holder::Knot(block));
}
}
} else if kind == "minecraft:text_display" {
} else if let Some(shows) = match kind {
"minecraft:text_display" => Some(super::text_displays::Shows::Text),
"minecraft:block_display" => Some(super::text_displays::Shows::Block),
"minecraft:item_display" => Some(super::text_displays::Shows::Item),
_ => None,
} {
self.text_displays.insert(
id as i32,
super::text_displays::RemoteTextDisplay::new(position, yaw),
super::text_displays::RemoteTextDisplay::new(shows, position, yaw),
);
} else if kind == "minecraft:ominous_item_spawner" {
self.add_remote_ominous_item_spawner(id, position);
} else if let Some(cart) = super::minecarts::CartKind::from_id(kind) {
let mut c = super::minecarts::Minecart::new(id, cart, at);
c.yaw = yaw;
@@ -119,13 +126,33 @@ impl Game<'_> {
/// `handleSetEntityData` for an object: what changes how it looks.
pub(super) fn remote_object_data(&mut self, id: i32, values: &[(u8, i32, Value)]) {
if let Some(display) = self.text_displays.get_mut(&id) {
display.metadata(values);
if self.text_displays.contains_key(&id) {
// ItemDisplay.DATA_ITEM_STACK, read with the server's registries.
let item = values
.iter()
.find_map(|(index, _, value)| match (index, value) {
(23, Value::Item(stack)) => Some(self.to_stack(stack)),
_ => None,
});
if let Some(display) = self.text_displays.get_mut(&id) {
display.show(values, item);
display.metadata(values);
}
return;
}
let id = id as u32;
for (index, _, value) in values {
if self.item_frames.iter().any(|f| f.id == id) {
if let (8, Value::Item(stack)) = (index, value)
&& self.ominous_spawners.iter().any(|s| s.id == id)
{
// OminousItemSpawner.DATA_ITEM.
if let (Some(item), Some(s)) = (
self.to_stack(stack),
self.ominous_spawners.iter_mut().find(|s| s.id == id),
) {
s.item = item;
}
} else if self.item_frames.iter().any(|f| f.id == id) {
// HangingEntity.DATA_DIRECTION, ItemFrame.DATA_ITEM and DATA_ROTATION.
let item = match (index, value) {
(9, Value::Item(stack)) => Some(self.to_stack(stack)),
@@ -319,6 +346,7 @@ impl Game<'_> {
/// Every object a server sent (a new connection, level or dimension).
pub(super) fn clear_remote_objects(&mut self) {
self.text_displays.clear();
self.ominous_spawners.clear();
self.remote_knots.clear();
self.carts.clear();
self.boats.clear();
@@ -330,6 +358,7 @@ impl Game<'_> {
pub(super) fn remove_remote_object(&mut self, id: u32) {
self.text_displays.remove(&(id as i32));
self.ominous_spawners.retain(|s| s.id != id);
self.remote_knots.remove(&id);
self.carts.retain(|c| c.id != id);
self.boats.retain(|b| b.id != id);
@@ -3,6 +3,7 @@
//! and `handleSetEntityData`): the server simulates them, the client draws
//! them where it says and interpolates their moves.
use super::{FallStep, FallingBlock, Game, fireworks::fireworks_of, view_vector};
use horizon_client::items::ItemStack;
use horizon_client::projectiles::{Hit, Projectile, ProjectileKind, ProjectileWorld};
use horizon_client::{
collisions::SceneCollisions,
@@ -113,6 +114,10 @@ fn projectile_kind(kind: &str) -> Option<ProjectileKind> {
fn remote_arrow_tick(p: &mut Projectile, w: &impl ProjectileWorld) {
p.previous = p.position;
p.age += 1;
// AbstractArrow.tick: `inGroundTime` counts the ticks in a block.
if let Some(a) = p.arrow.as_mut() {
a.in_ground_time = if p.stuck { a.in_ground_time + 1 } else { 0 };
}
if p.stuck {
return;
}
@@ -154,6 +159,51 @@ pub(super) fn has_smoke_trail(kind: &ProjectileKind) -> bool {
}
impl Game<'_> {
/// `Arrow.tick` and `SpectralArrow.tick` on a client: a tipped arrow
/// sheds two entity-effect swirls in its colour while flying, one every
/// fifth tick in a block; a spectral arrow an effect sparkle at its
/// position while flying.
fn arrow_effect_particles(&mut self) {
// The arrow's box: `EntityType.ARROW` is 0.5 x 0.5.
const SIZE: f64 = 0.5;
for p in &self.creatures.projectiles {
let Some(a) = p.arrow.as_ref().filter(|_| p.is_arrow()) else {
continue;
};
let at = p.position;
if p.is_spectral_arrow() {
if !p.stuck {
let options = ParticleOptions::simple(ParticleType::Effect);
self.particles.add(&options, [at.x, at.y, at.z], [0.0; 3]);
}
continue;
}
let color = a.effect_color;
let count = match (p.stuck, a.in_ground_time % 5) {
(true, 0) => 1,
(true, _) => 0,
(false, _) => 2,
};
if color == -1 {
continue;
}
// ColorParticleOption.create(ENTITY_EFFECT, colour): ARGB as floats.
let channel = |shift: u32| (color as u32 >> shift & 255) as f32 / 255.0;
let options = ParticleOptions::colored(
ParticleType::EntityEffect,
[channel(16), channel(8), channel(0), channel(24)],
);
for _ in 0..count {
// getRandomX(0.5), getRandomY, getRandomZ(0.5).
let r = self.particles.random();
let x = at.x + SIZE * (2.0 * r.next_double() - 1.0) * 0.5;
let y = at.y + SIZE * r.next_double();
let z = at.z + SIZE * (2.0 * r.next_double() - 1.0) * 0.5;
self.particles.add(&options, [x, y, z], [0.0; 3]);
}
}
}
/// `AbstractHurtingProjectile.createParticleTrail`: one smoke puff half a
/// block above each position.
pub(super) fn smoke_trails(&mut self, at: impl IntoIterator<Item = Vec3>) {
@@ -253,6 +303,12 @@ impl Game<'_> {
.llama_spit_burst(position, [velocity.x, velocity.y, velocity.z]);
}
let mut p = Projectile::new(k, at, None);
// SpectralArrow: its own type; its pickup item says so.
if kind == "minecraft:spectral_arrow"
&& let Some(a) = p.arrow.as_mut()
{
a.pickup_item = ItemStack::new("minecraft:spectral_arrow", 1);
}
p.id = id;
p.velocity = velocity;
p.yaw = yaw;
@@ -370,6 +426,12 @@ impl Game<'_> {
(ProjectileKind::Arrow { .. }, 10, Value::Bool(in_ground)) => {
p.stuck = *in_ground;
}
// Arrow.ID_EFFECT_COLOR.
(ProjectileKind::Arrow { .. }, 11, Value::Int(color)) => {
if let Some(a) = p.arrow.as_mut() {
a.effect_color = *color;
}
}
// WitherSkull.DATA_DANGEROUS.
(ProjectileKind::WitherSkull { dangerous }, 8, Value::Bool(d)) => {
*dangerous = *d;
@@ -471,6 +533,7 @@ impl Game<'_> {
}
self.creatures.projectiles = projectiles;
self.tridents = tridents;
self.arrow_effect_particles();
let trails: Vec<Vec3> = self
.creatures
.projectiles
+260
View File
@@ -0,0 +1,260 @@
//! The displayed items of `ShelfBlockEntity`.
use super::{Game, Hit, machines::dir_from_name};
use horizon_assets::item_model::DisplayContext;
use horizon_client::{block_entity_render::vertex_light, containers::BlockEntity, mesher::Vertex};
use horizon_core::{
geometry::{Direction, Vec3},
position::BlockPos,
};
use horizon_world::level::hit_slot;
impl Game<'_> {
/// Slot and facing for a click on a shelf's front face.
pub(super) fn shelf_hit(&self, hit: &Hit) -> Option<(usize, Direction, bool)> {
let p = hit.pos;
if !matches!(
self.world.block_entities.get(&(p[0], p[1], p[2])),
Some(BlockEntity::Shelf(_))
) {
return None;
}
let state = self.world.block(p[0], p[1], p[2]);
let data = self.pack.assets.registry.state(state)?;
let facing = data
.properties
.get("facing")
.and_then(|s| dir_from_name(s))?;
let face = Direction::ALL
.into_iter()
.find(|d| d.normal() == hit.face)?;
let slot = hit_slot(
facing,
face,
BlockPos::new(p[0], p[1], p[2]),
Vec3::new(hit.point[0], hit.point[1], hit.point[2]),
1,
3,
)?;
Some((
slot,
facing,
data.properties.get("powered").is_some_and(|s| s == "true"),
))
}
/// `SideChainPartBlock.getAllBlocksConnectedTo`: left to right, at most three.
fn shelf_chain(&self, pos: [i32; 3], facing: Direction) -> Vec<[i32; 3]> {
let left = match facing {
Direction::North => Direction::East,
Direction::East => Direction::South,
Direction::South => Direction::West,
Direction::West => Direction::North,
_ => return Vec::new(),
};
let state = self.world.block(pos[0], pos[1], pos[2]);
let behaviours = self.res.behaviours();
if !behaviours
.tag("minecraft:wooden_shelves")
.is_some_and(|tag| tag.contains(behaviours.block(state)))
{
return Vec::new();
}
let mut result = vec![pos];
for (dir, end, prepend) in [(left, "left", true), (left.opposite(), "right", false)] {
let normal = dir.normal();
for step in 1..3 {
let p = [pos[0] + normal[0] * step, pos[1], pos[2] + normal[2] * step];
let state = self.world.block(p[0], p[1], p[2]);
let Some(info) = self.pack.assets.registry.state(state) else {
break;
};
let behaviours = self.res.behaviours();
let connectable = behaviours
.tag("minecraft:wooden_shelves")
.is_some_and(|tag| tag.contains(behaviours.block(state)))
&& info.properties.get("powered").is_some_and(|s| s == "true")
&& info.properties.get("facing").and_then(|s| dir_from_name(s)) == Some(facing);
if !connectable {
break;
}
let part = info
.properties
.get("side_chain")
.map(String::as_str)
.unwrap_or("unconnected");
if part == "center" || part == end {
if prepend {
result.insert(0, p);
} else {
result.push(p);
}
}
if part != "center" {
break;
}
}
}
result
}
/// `ShelfBlock.useItemOn`: a single swap, or a connected hotbar swap while powered.
pub(super) fn use_shelf(&mut self, hit: &Hit) -> Option<bool> {
use horizon_client::first_person::Hand;
if self.hand != Hand::Main {
return None;
}
let (slot, facing, powered) = self.shelf_hit(hit)?;
let pos = hit.pos;
let state = self.world.block(pos[0], pos[1], pos[2]);
if powered {
let chain = self.shelf_chain(pos, facing);
let mut swapped = false;
let count = chain.len();
for (i, p) in chain.into_iter().enumerate() {
let key = (p[0], p[1], p[2]);
let Some(BlockEntity::Shelf(shelf)) = self.world.block_entities.get_mut(&key)
else {
continue;
};
for n in 0..3 {
let index = 9_i32 - (count as i32 - i as i32) * 3 + n as i32;
if !(0..9).contains(&index) {
continue;
}
let index = index as usize;
swapped |= self.inventory[index].is_some() || shelf.items[n].is_some();
std::mem::swap(&mut self.inventory[index], &mut shelf.items[n]);
}
self.container_changed(key);
let s = self.world.block(p[0], p[1], p[2]);
self.post_block_game_event("minecraft:entity_interact", p, None, Some(s));
}
if !swapped {
return Some(false);
}
self.audio.play(
"minecraft:block.shelf.multi_swap",
Some(pos.map(|n| f64::from(n) + 0.5)),
1.0,
1.0,
);
Some(true)
} else {
let held = self.inventory[self.selected].clone();
let key = (pos[0], pos[1], pos[2]);
let Some(BlockEntity::Shelf(shelf)) = self.world.block_entities.get_mut(&key) else {
return None;
};
let removed = std::mem::replace(&mut shelf.items[slot], held.clone());
self.inventory[self.selected] = if self.creative && removed.is_none() {
held.clone()
} else {
removed.clone()
};
self.container_changed(key);
let vibrations = self.inventory[self.selected].as_ref().is_none_or(|stack| {
let default = self
.res
.items()
.get(&stack.item)
.is_none_or(|item| item.interact_vibrations);
let Some(data) = stack.data() else {
return default;
};
if data
.other
.iter()
.any(|(key, _)| key == "!minecraft:use_effects")
{
return true;
}
data.other
.iter()
.find(|(key, _)| key == "minecraft:use_effects")
.map_or(default, |(_, tag)| {
horizon_client::save::number(tag.get("interact_vibrations")).unwrap_or(1)
!= 0
})
});
if vibrations {
self.post_block_game_event(
"minecraft:item_interact_finish",
pos,
None,
Some(state),
);
}
let sound = match (held.is_some(), removed.is_some()) {
(false, false) => return None,
(true, false) => "minecraft:block.shelf.place_item",
(false, true) => "minecraft:block.shelf.take_item",
(true, true) => "minecraft:block.shelf.single_swap",
};
self.audio
.play(sound, Some(pos.map(|n| f64::from(n) + 0.5)), 1.0, 1.0);
Some(true)
}
}
/// `ShelfRenderer`: three items face out, aligned to the bottom or centre.
pub(super) fn shelf_geometry(&self, camera: glam::DVec3, out: &mut Vec<Vertex>) {
for (key, entity) in &self.world.block_entities {
let BlockEntity::Shelf(shelf) = entity else {
continue;
};
let at = glam::DVec3::new(f64::from(key.0), f64::from(key.1), f64::from(key.2));
if at.distance_squared(camera) >= 64.0 * 64.0 {
continue;
}
let block = self.world.block(key.0, key.1, key.2);
let facing = self
.pack
.assets
.registry
.state(block)
.and_then(|s| s.properties.get("facing"))
.map(String::as_str)
.unwrap_or("north");
let yaw: f32 = match facing {
"south" => 0.0,
"west" => -90.0,
"north" => -180.0,
"east" => -270.0,
_ => 180.0,
};
let packed = BlockPos::new(key.0, key.1, key.2).pack() as u64;
let seed = (packed ^ (packed >> 32)) as i32;
let light = vertex_light(self.world.light(key.0, key.1, key.2));
for (slot, stack) in shelf.items.iter().enumerate() {
let Some(stack) = stack else { continue };
let item = self.resolve_item(
stack,
DisplayContext::OnShelf,
None,
seed.wrapping_add(slot as i32),
);
if item.is_empty() {
continue;
}
let (lo, hi) = item.bounding_box();
let offset_y = -lo.y
- if shelf.align_to_bottom {
0.0
} else {
(hi.y - lo.y) / 2.0
};
let pose =
glam::Mat4::from_translation((at - camera).as_vec3() + glam::Vec3::splat(0.5))
* glam::Mat4::from_rotation_y(yaw.to_radians())
* glam::Mat4::from_translation(glam::Vec3::new(
(slot as f32 - 1.0) * 0.3125,
if shelf.align_to_bottom { -0.25 } else { 0.0 },
-0.25,
))
* glam::Mat4::from_scale(glam::Vec3::splat(0.25))
* glam::Mat4::from_translation(glam::Vec3::new(0.0, offset_y, 0.0));
self.submit_item_world(&item, pose, light, out);
}
}
}
}
+24 -6
View File
@@ -76,6 +76,7 @@ impl StartupMenu {
&self.root,
);
title.last_server = settings.file.string("lastServer");
title.skip_multiplayer_warning = settings.file.bool("skipMultiplayerWarning");
self.title = Some(title);
}
}
@@ -304,12 +305,11 @@ impl Loading {
}
fn save_menu_address(&mut self) {
if self
.menu
.title
.as_ref()
.is_some_and(|title| title.last_server != self.settings.file.string("lastServer"))
{
if self.menu.title.as_ref().is_some_and(|title| {
title.last_server != self.settings.file.string("lastServer")
|| title.skip_multiplayer_warning
!= self.settings.file.bool("skipMultiplayerWarning")
}) {
self.save_menu_settings();
}
}
@@ -320,6 +320,10 @@ impl Loading {
"lastServer",
horizon_client::options_file::V::Str(title.last_server.clone()),
);
self.settings.file.set(
"skipMultiplayerWarning",
horizon_client::options_file::V::Bool(title.skip_multiplayer_warning),
);
}
self.settings.save(&Game::options_path());
}
@@ -365,6 +369,15 @@ impl Loading {
let _ = std::fs::create_dir_all(&dir);
packs::open_folder(&dir);
}
Event::DataPacks(ids) => {
if let Some(title) = &mut self.menu.title {
title.set_data_packs(ids);
}
}
Event::OpenDataPackFolder(dir) => {
let _ = std::fs::create_dir_all(&dir);
packs::open_folder(&dir);
}
Event::OpenModFolder => {
let dir = Game::options_path().with_file_name(horizon_client::mod_list::DIR);
let _ = std::fs::create_dir_all(&dir);
@@ -426,6 +439,11 @@ impl Loading {
Action::Options => self.open_menu_options(Page::Main),
Action::Accessibility => self.open_menu_options(Page::Accessibility),
Action::Language => self.open_menu_options(Page::Language),
Action::DataPacks { dir, selected } => {
let resources = self.vanilla_root.clone();
self.menu.options.open_data_packs(dir, selected, resources);
self.menu.options_open = true;
}
action => {
let name = self
.options
+138 -19
View File
@@ -1,15 +1,34 @@
//! Server text displays: metadata, interpolation, billboard transforms and world text.
use super::Game;
use horizon_assets::item_model::DisplayContext;
use horizon_client::{
gfx::TEXT_POLYGON_OFFSET_OVERLAY,
hud::HudBatch,
items::ItemStack,
mesher::Vertex,
text_display::{self, Lines, TextDisplayData},
};
use horizon_protocol::entity_data::Value;
use horizon_world::registry::BlockStateId;
/// What a display shows besides its transformation: its text (in `data`),
/// a block state (`BlockDisplay`) or an item and how it is displayed
/// (`ItemDisplay`).
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum Shows {
Text,
Block,
Item,
}
pub(super) struct RemoteTextDisplay {
pub data: TextDisplayData,
shows: Shows,
/// `BlockDisplay.DATA_BLOCK_STATE_ID`.
block: Option<BlockStateId>,
/// `ItemDisplay.DATA_ITEM_STACK` and `DATA_ITEM_DISPLAY_ID`.
item: Option<ItemStack>,
item_display: u8,
from: TextDisplayData,
shown: TextDisplayData,
position: glam::DVec3,
@@ -41,9 +60,13 @@ fn renders(id: u8) -> bool {
}
impl RemoteTextDisplay {
pub fn new(position: [f64; 3], yaw: f32) -> Self {
pub fn new(shows: Shows, position: [f64; 3], yaw: f32) -> Self {
Self {
data: Default::default(),
shows,
block: None,
item: None,
item_display: 0,
from: Default::default(),
shown: Default::default(),
position: position.into(),
@@ -71,6 +94,24 @@ impl RemoteTextDisplay {
(((self.age - self.start) as f32 + partial) / self.duration as f32).clamp(0.0, 1.0)
}
}
/// The entries after `Display`'s: a block state, or an item with its
/// display context (the stack comes converted by the caller).
pub fn show(&mut self, values: &[(u8, i32, Value)], item: Option<Option<ItemStack>>) {
for (id, _, value) in values {
match (self.shows, id, value) {
(Shows::Block, 23, Value::Id(state)) => {
self.block = Some(BlockStateId(u32::try_from(*state).unwrap_or(0)));
}
(Shows::Item, 24, Value::Byte(context)) => self.item_display = *context as u8,
_ => {}
}
}
if let Some(item) = item
&& self.shows == Shows::Item
{
self.item = item;
}
}
pub fn metadata(&mut self, values: &[(u8, i32, Value)]) {
self.start_dirty |= values.iter().any(|v| v.0 == 8);
self.duration_dirty |= values.iter().any(|v| v.0 == 9);
@@ -143,6 +184,96 @@ impl Game<'_> {
display.tick();
}
}
/// The camera's yaw and pitch as `DisplayRenderer` reads them (the
/// front view turns around).
fn display_camera_angles(&self) -> [f32; 2] {
if self.camera_type == super::perspective::CameraType::ThirdPersonFront {
[self.yaw + 180.0, -self.pitch]
} else {
[self.yaw, self.pitch]
}
}
/// `DisplayRenderer.getBlockLightLevel` and `getSkyLightLevel`: the
/// brightness override, else the light at the entity.
fn display_light(
world: &horizon_client::world::World,
d: &TextDisplayData,
position: glam::DVec3,
) -> u32 {
if d.brightness == -1 {
let world_light = world.light(
position.x.floor() as i32,
position.y.floor() as i32,
position.z.floor() as i32,
);
horizon_client::block_entity_render::vertex_light(world_light)
} else {
((d.brightness as u32 >> 20 & 15) * 16) | (((d.brightness as u32 >> 4 & 15) * 16) << 8)
}
}
/// `DisplayRenderer.BlockDisplayRenderer` and `ItemDisplayRenderer`: the
/// block model or the item under the display's transformation, lit like
/// any entity and never tinted by a hurt overlay.
pub(super) fn block_item_display_geometry(
&mut self,
camera: glam::DVec3,
partial: f64,
out: &mut Vec<Vertex>,
) {
let angles = self.display_camera_angles();
let scale = self.view_scale();
let mut displays = std::mem::take(&mut self.text_displays);
for shows in [Shows::Block, Shows::Item] {
let kind = if shows == Shows::Block {
"minecraft:block_display"
} else {
"minecraft:item_display"
};
self.mark_entity(out.len(), kind);
for (id, display) in displays.iter_mut().filter(|(_, d)| d.shows == shows) {
display.last_progress = display.progress(partial as f32);
let d = display.shown.blend(&display.from, display.last_progress);
let position = display.previous.lerp(display.position, partial);
let range = f64::from(d.view_range) * 64.0 * scale;
if position.distance_squared(camera) >= range * range {
continue;
}
let rotation = std::array::from_fn(|i| {
display.old_rotation[i]
+ angle(display.rotation[i] - display.old_rotation[i]) * partial as f32
});
let matrix = glam::Mat4::from_translation((position - camera).as_vec3())
* d.matrix(rotation, angles);
if !matrix.is_finite() {
continue;
}
let light = Self::display_light(&self.world, &d, position);
if let Some(state) = display.block {
// BlockModelResolver.update: model seed 42.
self.block_model_vertices(state, 42, matrix, light, true, out);
} else if let Some(stack) = &display.item {
let context = match display.item_display {
1 => DisplayContext::ThirdPersonLeftHand,
2 => DisplayContext::ThirdPersonRightHand,
3 => DisplayContext::FirstPersonLeftHand,
4 => DisplayContext::FirstPersonRightHand,
5 => DisplayContext::Head,
6 => DisplayContext::Gui,
7 => DisplayContext::Ground,
8 => DisplayContext::Fixed,
9 => DisplayContext::OnShelf,
_ => DisplayContext::None,
};
// updateForNonLiving: seeded by the entity id.
let state = self.resolve_item(stack, context, None, *id);
let pose = matrix * glam::Mat4::from_rotation_y(std::f32::consts::PI);
self.submit_item_world(&state, pose, light, out);
}
}
}
self.mark_entity(out.len(), "");
self.text_displays = displays;
}
pub(super) fn text_display_geometry(
&mut self,
camera: glam::DVec3,
@@ -153,14 +284,12 @@ impl Game<'_> {
self.text_display_vertices = 0;
self.mark_translucent_entity(normal.len(), "minecraft:text_display");
let atlas = &self.gui.atlas;
let front = self.camera_type == super::perspective::CameraType::ThirdPersonFront;
let angles = if front {
[self.yaw + 180.0, -self.pitch]
} else {
[self.yaw, self.pitch]
};
let angles = self.display_camera_angles();
let scale = self.view_scale();
for display in self.text_displays.values_mut() {
if display.shows != Shows::Text {
continue;
}
display.last_progress = display.progress(partial as f32);
let d = display.shown.blend(&display.from, display.last_progress);
let position = display.previous.lerp(display.position, partial);
@@ -189,17 +318,7 @@ impl Game<'_> {
lines,
self.settings.text_background(0.25),
);
let world_light = self.world.light(
position.x.floor() as i32,
position.y.floor() as i32,
position.z.floor() as i32,
);
let light = if d.brightness == -1 {
horizon_client::block_entity_render::vertex_light(world_light)
} else {
((d.brightness as u32 >> 20 & 15) * 16)
| (((d.brightness as u32 >> 4 & 15) * 16) << 8)
};
let light = Self::display_light(&self.world, &d, position);
// Font.DisplayMode: SEE_THROUGH over everything, else POLYGON_OFFSET.
let through = d.flags & 2 != 0;
let (out, layer) = if through {
@@ -235,7 +354,7 @@ mod tests {
use super::*;
#[test]
fn metadata_and_position_interpolation_keep_their_separate_clocks() {
let mut d = RemoteTextDisplay::new([0.0; 3], 0.0);
let mut d = RemoteTextDisplay::new(Shows::Text, [0.0; 3], 0.0);
d.tick();
d.metadata(&[
(8, 1, Value::Int(0)),
+561
View File
@@ -0,0 +1,561 @@
//! Client tutorial progression (`net.minecraft.client.tutorial`).
/// The numeric values are the order in `options_file::TUTORIAL_STEPS`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum Step {
Movement = 0,
FindTree = 1,
PunchTree = 2,
OpenInventory = 3,
CraftPlanks = 4,
None = 5,
}
impl Step {
pub(super) fn from_option(value: i32) -> Self {
match value {
0 => Self::Movement,
1 => Self::FindTree,
2 => Self::PunchTree,
3 => Self::OpenInventory,
4 => Self::CraftPlanks,
_ => Self::None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum Hint {
Move,
Look,
FindTree,
PunchTree,
OpenInventory,
CraftPlanks,
}
/// The observations needed on the first tick of each step.
#[derive(Default)]
pub(super) struct Previous {
pub(super) tree_item: bool,
pub(super) log: bool,
pub(super) plank: bool,
pub(super) mined_tree: bool,
pub(super) crafted_plank: bool,
}
pub(super) struct Tutorial {
pub(super) step: Step,
pub(super) waiting: u32,
moved: bool,
turned: bool,
move_ticks: u32,
look_ticks: u32,
move_finished: Option<u32>,
look_finished: bool,
reset_count: u32,
pub(super) break_progress: f32,
}
impl Tutorial {
pub(super) fn new(step: Step) -> Self {
Self {
step,
waiting: 0,
moved: false,
turned: false,
move_ticks: 0,
look_ticks: 0,
move_finished: None,
look_finished: false,
reset_count: 0,
break_progress: 0.0,
}
}
/// Returns whether the persisted step changed.
fn set_step(&mut self, step: Step) -> bool {
if self.step == step {
return false;
}
*self = Self::new(step);
true
}
pub(super) fn input(&mut self) {
self.moved = true;
}
pub(super) fn mouse(&mut self, x: f64, y: f64) {
self.turned |= x.abs() > 0.01 || y.abs() > 0.01;
}
pub(super) fn tick(&mut self, survival: bool, previous: &Previous) -> bool {
self.waiting = self.waiting.saturating_add(1);
if self.step == Step::Movement {
self.move_ticks += u32::from(std::mem::take(&mut self.moved));
self.look_ticks += u32::from(std::mem::take(&mut self.turned));
if self.move_ticks > 40 && self.move_finished.is_none() {
self.move_finished = Some(self.waiting);
}
self.look_finished |= self.look_ticks > 40;
if self.move_finished.is_some() && self.look_finished {
return self.set_step(if survival { Step::FindTree } else { Step::None });
}
} else if self.step != Step::None && !survival {
return self.set_step(Step::None);
} else if self.waiting == 1 {
match self.step {
Step::FindTree if previous.tree_item || previous.mined_tree => {
return self.set_step(Step::CraftPlanks);
}
Step::PunchTree if previous.log || previous.mined_tree => {
return self.set_step(Step::CraftPlanks);
}
Step::CraftPlanks if previous.plank || previous.crafted_plank => {
return self.set_step(Step::None);
}
_ => {}
}
}
false
}
pub(super) fn look_at_tree(&mut self) -> bool {
self.step == Step::FindTree && self.set_step(Step::PunchTree)
}
pub(super) fn destroy(&mut self, is_log: bool, progress: f32) -> bool {
if self.step != Step::PunchTree {
return false;
}
if is_log && progress > 0.0 {
self.break_progress = progress;
if progress >= 1.0 {
return self.set_step(Step::OpenInventory);
}
} else {
self.break_progress = 0.0;
if is_log {
self.reset_count = self.reset_count.saturating_add(1);
}
}
false
}
pub(super) fn open_inventory(&mut self) -> bool {
self.step == Step::OpenInventory && self.set_step(Step::CraftPlanks)
}
pub(super) fn get_item(&mut self, tree: bool, log: bool, plank: bool) -> bool {
match self.step {
Step::FindTree if tree => self.set_step(Step::CraftPlanks),
Step::PunchTree if log => self.set_step(Step::CraftPlanks),
Step::CraftPlanks if plank => self.set_step(Step::None),
_ => false,
}
}
pub(super) fn hint(&self) -> Option<(Hint, Option<f32>)> {
match self.step {
Step::Movement if self.waiting >= 100 && self.move_finished.is_none() => {
Some((Hint::Move, Some(self.move_ticks as f32 / 40.0)))
}
Step::Movement
if !self.look_finished
&& self
.move_finished
.is_some_and(|t| self.waiting.saturating_sub(t) >= 20)
&& self.waiting >= 100 =>
{
Some((Hint::Look, Some(self.look_ticks as f32 / 40.0)))
}
Step::FindTree if self.waiting >= 6000 => Some((Hint::FindTree, None)),
Step::PunchTree if self.waiting >= 600 || self.reset_count > 3 => {
Some((Hint::PunchTree, Some(self.break_progress)))
}
Step::OpenInventory if self.waiting >= 600 => Some((Hint::OpenInventory, None)),
Step::CraftPlanks if self.waiting >= 1200 => Some((Hint::CraftPlanks, None)),
_ => None,
}
}
}
impl super::Game<'_> {
/// `Tutorial.setStep` persists immediately so it survives leaving a world.
pub(super) fn persist_tutorial_step(&mut self) {
self.settings.file.set(
"tutorialStep",
horizon_client::options_file::V::Int(self.tutorial.step as i32),
);
self.settings.save(&Self::options_path());
}
}
impl super::Game<'_> {
pub(super) fn reset_tutorial(&mut self) {
self.tutorial = Tutorial::new(Step::from_option(self.settings.file.int("tutorialStep")));
self.tutorial_toasts.clear();
}
fn tutorial_tagged(&self, item: bool, tag: &str, id: &str) -> bool {
let items = self.res.items();
let tags = if item {
&items.item_tags
} else {
&items.block_tags
};
tags.get(tag).is_some_and(|members| members.contains(id))
}
pub(super) fn tutorial_get_item(&mut self, stack: Option<&horizon_client::items::ItemStack>) {
// The server thread's settings are a stale copy of the window's: its
// guests' tutorial is their own client's to record.
if self.options.dedicated.is_some()
|| self.serving.is_some()
|| self.title.is_some()
|| self.player.is_none()
{
return;
}
let Some(stack) = stack else { return };
let id = &*stack.item;
let tree = self.tutorial_tagged(true, "minecraft:completes_find_tree_tutorial", id);
let log = self.tutorial_tagged(true, "minecraft:logs", id);
let plank = self.tutorial_tagged(true, "minecraft:planks", id);
if self.tutorial.get_item(tree, log, plank) {
self.persist_tutorial_step();
}
}
pub(super) fn tutorial_destroy(
&mut self,
state: horizon_world::registry::BlockStateId,
progress: f32,
) {
// The server thread's settings are a stale copy of the window's: its
// guests' tutorial is their own client's to record.
if self.options.dedicated.is_some()
|| self.serving.is_some()
|| self.title.is_some()
|| self.player.is_none()
{
return;
}
let name = &self.res.facts().get(state).name;
let is_log = self.tutorial_tagged(false, "minecraft:logs", name);
if self.tutorial.destroy(is_log, progress) {
self.persist_tutorial_step();
}
}
pub(super) fn tick_tutorial(&mut self) {
use winit::keyboard::KeyCode;
if self.title.is_some()
|| self.player.is_none()
|| self.options.dedicated.is_some()
|| self.serving.is_some()
{
return;
}
if self.screen == super::Screen::Playing
&& ([
KeyCode::KeyW,
KeyCode::KeyA,
KeyCode::KeyS,
KeyCode::KeyD,
KeyCode::Space,
]
.iter()
.any(|key| self.keys.contains(key))
|| self
.pad_move()
.is_some_and(|[left, forward]| left.abs() > 0.3 || forward.abs() > 0.3))
{
self.tutorial.input();
}
let items = self.res.items();
let in_tag =
|tag: &str, id: &str| items.item_tags.get(tag).is_some_and(|set| set.contains(id));
let mut previous = Previous::default();
if self.tutorial.waiting == 0 && !matches!(self.tutorial.step, Step::Movement | Step::None)
{
for stack in self
.inventory
.iter()
.chain(self.armor.iter())
.flatten()
.chain(self.offhand.iter())
{
previous.tree_item |= in_tag("minecraft:completes_find_tree_tutorial", &stack.item);
previous.log |= in_tag("minecraft:logs", &stack.item);
previous.plank |= in_tag("minecraft:planks", &stack.item);
}
if let Some(mined) = self.stats.values.get("minecraft:mined")
&& let Some(tree) = items
.block_tags
.get("minecraft:completes_find_tree_tutorial")
{
previous.mined_tree = mined
.iter()
.any(|(id, count)| *count > 0 && tree.contains(id));
}
if let Some(crafted) = self.stats.values.get("minecraft:crafted")
&& let Some(planks) = items.item_tags.get("minecraft:planks")
{
previous.crafted_plank = crafted
.iter()
.any(|(id, count)| *count > 0 && planks.contains(id));
}
}
let survival = self.mode == horizon_client::command::args::GameMode::Survival;
if self.tutorial.tick(survival, &previous) {
self.persist_tutorial_step();
}
if self.tutorial.step == Step::FindTree
&& self.pick_entity_hit().is_none()
&& let Some(hit) = self.pick()
{
let name = &self
.res
.facts()
.get(self.world.block(hit.pos[0], hit.pos[1], hit.pos[2]))
.name;
if self.tutorial_tagged(false, "minecraft:completes_find_tree_tutorial", name)
&& self.tutorial.look_at_tree()
{
self.persist_tutorial_step();
}
}
}
}
pub(super) struct HintToast {
hint: Hint,
lines: Vec<(horizon_client::text::Text, bool)>,
title_lines: usize,
progress: Option<f32>,
smooth: f32,
last_smooth: i64,
wanted: bool,
slot: Option<usize>,
slots: usize,
slide: horizon_client::toasts::Slide,
}
impl super::Game<'_> {
pub(super) fn tutorial_toast_slots(&self) -> u32 {
self.tutorial_toasts
.iter()
.filter_map(|t| t.slot.map(|s| ((1u32 << t.slots) - 1) << s))
.fold(0, |a, b| a | b)
}
fn tutorial_toast(&self, hint: Hint, progress: Option<f32>) -> HintToast {
use horizon_client::{keybinds, text::Text};
let key = |mapping: &str| keybinds::display_name(self.settings.keys.get(mapping)).plain();
let (title_key, fallback, description_key, description, icon_args) = match hint {
Hint::Move => (
"tutorial.move.title",
"Move with %1$s, %2$s, %3$s, %4$s",
"tutorial.move.description",
"Jump with %1$s",
vec![
key("key.forward"),
key("key.left"),
key("key.back"),
key("key.right"),
],
),
Hint::Look => (
"tutorial.look.title",
"Look around",
"tutorial.look.description",
"Use your mouse to turn",
vec![],
),
Hint::FindTree => (
"tutorial.find_tree.title",
"Find a tree",
"tutorial.find_tree.description",
"Punch it to collect wood",
vec![],
),
Hint::PunchTree => (
"tutorial.punch_tree.title",
"Punch the tree",
"tutorial.punch_tree.description",
"Hold %1$s to break",
vec![],
),
Hint::OpenInventory => (
"tutorial.open_inventory.title",
"Open inventory",
"tutorial.open_inventory.description",
"Press %1$s",
vec![],
),
Hint::CraftPlanks => (
"tutorial.craft_planks.title",
"Craft wooden planks",
"tutorial.craft_planks.description",
"The recipe book can help",
vec![],
),
};
let substitute = |mut text: String, values: &[String]| {
for (i, value) in values.iter().enumerate() {
text = text.replace(&format!("%{}$s", i + 1), value);
text = text.replacen("%s", value, 1);
}
text
};
let title = substitute(self.translate(title_key, fallback), &icon_args);
let desc_args = match hint {
Hint::Move => vec![key("key.jump")],
Hint::PunchTree => vec![key("key.attack")],
Hint::OpenInventory => vec![key("key.inventory")],
_ => vec![],
};
let description = substitute(self.translate(description_key, description), &desc_args);
let font = &self.gui.atlas.font;
let mut lines = font.split_lines(&Text::literal(title), 126.0);
let title_lines = lines.len();
lines.extend(font.split_lines(&Text::literal(description), 126.0));
let height = 10 + 11 * lines.len().max(2);
let slots = height.div_ceil(32);
HintToast {
hint,
lines,
title_lines,
progress,
smooth: 0.0,
last_smooth: 0,
wanted: true,
slot: None,
slots,
slide: Default::default(),
}
}
pub(super) fn draw_tutorial_toasts(
&mut self,
batch: &mut horizon_client::hud::HudBatch,
hidden: bool,
) {
let wanted = self.tutorial.hint();
for t in &mut self.tutorial_toasts {
t.wanted = wanted.is_some_and(|(hint, _)| hint == t.hint);
if t.wanted {
t.progress = wanted.and_then(|(_, progress)| progress);
}
}
if let Some((hint, progress)) = wanted
&& !self
.tutorial_toasts
.iter()
.any(|t| t.wanted && t.hint == hint)
{
let toast = self.tutorial_toast(hint, progress);
self.tutorial_toasts.push(toast);
}
let mut used = self.toast_slots_used();
for t in &mut self.tutorial_toasts {
if t.slot.is_none() && t.wanted && t.slots <= Self::TOAST_SLOTS {
let mask = (1u32 << t.slots) - 1;
if let Some(slot) =
(0..=Self::TOAST_SLOTS - t.slots).find(|s| used & (mask << s) == 0)
{
t.slot = Some(slot);
used |= mask << slot;
}
}
}
let atlas = &self.gui.atlas;
let mut i = 0;
while i < self.tutorial_toasts.len() {
let t = &mut self.tutorial_toasts[i];
if t.slot.is_none() {
if !t.wanted {
self.tutorial_toasts.remove(i);
} else {
i += 1;
}
continue;
}
let (sound, finished) = t.slide.update_now(|_| t.wanted);
if let Some(show) = sound {
let event = if show { "ui.toast.in" } else { "ui.toast.out" };
self.audio
.play(&format!("minecraft:{event}"), None, 1.0, 1.0);
}
if finished {
self.tutorial_toasts.remove(i);
continue;
}
if let Some(progress) = t.progress {
let delta = ((t.slide.fully_for - t.last_smooth) as f32 / 100.0).clamp(0.0, 1.0);
t.smooth += (progress - t.smooth) * delta;
t.last_smooth = t.slide.fully_for;
}
if !hidden {
let height = (10 + 11 * t.lines.len().max(2)) as f32;
let x = batch.width - 160.0 * t.slide.portion;
let y = 32.0 * t.slot.unwrap_or_default() as f32;
horizon_client::ui::nine_slice(
batch,
atlas,
"gui/sprites/toast/tutorial",
x,
y,
160.0,
height,
u32::MAX,
);
let icon = match t.hint {
Hint::Move => "movement_keys",
Hint::Look => "mouse",
Hint::FindTree | Hint::PunchTree => "tree",
Hint::OpenInventory => "recipe_book",
Hint::CraftPlanks => "wooden_planks",
};
batch.sprite_scaled(
atlas,
&format!("gui/sprites/toast/{icon}"),
x + 6.0,
y + 6.0,
20.0,
20.0,
u32::MAX,
);
let text_y = y + 7.0 + ((t.lines.len().max(2) - t.lines.len()) * 11) as f32 / 2.0;
for (n, (line, _)) in t.lines.iter().enumerate() {
batch.text_styled(
atlas,
line,
x + 30.0,
text_y + 11.0 * n as f32,
if n < t.title_lines {
0xFF50_0050
} else {
0xFF00_0000
},
false,
);
}
if let Some(progress) = t.progress {
batch.fill(atlas, x + 3.0, y + height - 4.0, 154.0, 1.0, u32::MAX);
let color = if progress >= t.smooth {
0xFF00_5500
} else {
0xFF55_0000
};
batch.fill(
atlas,
x + 3.0,
y + height - 4.0,
154.0 * t.smooth.clamp(0.0, 1.0),
1.0,
color,
);
}
}
i += 1;
}
}
}
+17
View File
@@ -940,6 +940,23 @@ pub fn entity_tag(entity: &BlockEntity) -> Option<Tag> {
match entity {
BlockEntity::Sign(sign) => Some(Tag::compound(sign.encode())),
BlockEntity::Spawner(s) => Some(s.update_tag()),
BlockEntity::Brushable(b) => {
let mut entries = Vec::new();
if let Some(face) = b.hit_direction {
entries.push(("hit_direction", Tag::Byte(face as i8)));
}
if let Some(item) = &b.item {
entries.push(("item", crate::save::item_to_nbt(item)));
}
Some(Tag::compound(entries))
}
BlockEntity::Shelf(s) => Some(Tag::compound([
("Items", crate::save::encode_items(&s.items)),
(
"align_items_to_bottom",
Tag::Byte(i8::from(s.align_to_bottom)),
),
])),
// BannerBlockEntity.getUpdateTag: saveWithoutMetadata, so the patterns,
// the custom name and the components.
BlockEntity::Banner(b) => {
+7 -4
View File
@@ -32,9 +32,12 @@ use std::{
time::{Duration, Instant},
};
/// ServerCommonPacketListenerImpl.KEEPALIVE_TIME and the disconnect timeout.
/// ServerCommonPacketListenerImpl.keepConnectionAlive: a keep-alive every 15 s,
/// and a client that has not answered the last one by the next is dropped.
const KEEP_ALIVE_EVERY: Duration = Duration::from_secs(15);
const KEEP_ALIVE_TIMEOUT: Duration = Duration::from_secs(30);
/// ReadTimeoutHandler(30) in ServerConnectionListener: a connection that sends
/// nothing for 30 s.
const READ_TIMEOUT: Duration = Duration::from_secs(30);
/// Packets queued for one client beyond this many bytes disconnect it.
const MAX_PENDING: usize = 96 << 20;
/// Vanilla's server-side disconnect during login is a JSON component.
@@ -957,7 +960,7 @@ fn offer_pack(
fn play(c: Connection, shared: &Arc<Shared>, parts: Parts, address: std::net::SocketAddr) {
let conn_id = shared.next_id();
let events = shared.events.clone();
let _ = c.reader.set_read_timeout(Some(KEEP_ALIVE_TIMEOUT));
let _ = c.reader.set_read_timeout(Some(READ_TIMEOUT));
let (mut reader, writer) = c.split();
let (tx, rx) = channel();
let pending = Arc::new(AtomicUsize::new(0));
@@ -1172,7 +1175,7 @@ fn write_loop(
let old = latency.load(Ordering::Relaxed);
latency.store((old * 3 + ms) / 4, Ordering::Relaxed);
sent_at = None;
} else if at.elapsed() > KEEP_ALIVE_TIMEOUT {
} else if at.elapsed() >= KEEP_ALIVE_EVERY {
let _ = writer.send(
&play::Clientbound::Disconnect(cfg::Disconnect {
reason: translatable("disconnect.timeout", &[]),
+32
View File
@@ -269,6 +269,38 @@ impl Projectile {
pub fn is_arrow(&self) -> bool {
matches!(self.kind, ProjectileKind::Arrow { .. })
}
/// Whether it is a `SpectralArrow` (its own entity type): a spectral
/// arrow's pickup item, or the glowing effect a dispenser shoots with.
pub fn is_spectral_arrow(&self) -> bool {
let ProjectileKind::Arrow { effect, .. } = &self.kind else {
return false;
};
effect.is_some_and(|(id, _)| id == "minecraft:glowing")
|| self
.arrow
.as_ref()
.is_some_and(|a| &*a.pickup_item.item == "minecraft:spectral_arrow")
}
/// `Arrow.ID_EFFECT_COLOR` (`updateColor`): the opaque colour of the
/// potion the arrow carries, from its tipped pickup item or the effect a
/// stray, bogged or parched adds; -1 for none.
pub fn arrow_effect_color(&self) -> i32 {
let ProjectileKind::Arrow { effect, .. } = &self.kind else {
return -1;
};
if self.is_spectral_arrow() {
return -1;
}
let rgb = match (effect, &self.arrow) {
(Some((id, _)), _) => crate::brewing::effect(id).map(|e| e.color),
(None, Some(a)) if &*a.pickup_item.item == "minecraft:tipped_arrow" => a
.pickup_item
.potion()
.map(|p| crate::brewing::potion_color(Some(p))),
_ => None,
};
rgb.map_or(-1, |rgb| (rgb | 0xFF00_0000) as i32)
}
pub fn is_fireball(&self) -> bool {
matches!(
self.kind,
+33
View File
@@ -483,6 +483,13 @@ pub fn encode_block_entity(
}
}
BlockEntity::Sculk(s) => entries.extend(s.to_nbt()),
BlockEntity::Shelf(shelf) => {
entries.push(("Items", encode_items(&shelf.items)));
entries.push((
"align_items_to_bottom",
Tag::Byte(i8::from(shelf.align_to_bottom)),
));
}
// ChiseledBookShelfBlockEntity.saveAdditional.
BlockEntity::ChiseledBookshelf(b) => {
entries.push(("Items", encode_items(&b.items)));
@@ -547,6 +554,16 @@ pub fn encode_block_entity(
BlockEntity::Vault(v) => entries.extend(v.save()),
BlockEntity::Beehive(h) => entries.extend(h.to_nbt()),
BlockEntity::CommandBlock(c) => entries.extend(c.save()),
BlockEntity::Brushable(b) => {
if let Some(table) = &b.loot_table {
entries.push(("LootTable", table.clone()));
if let Some(seed) = &b.loot_seed {
entries.push(("LootTableSeed", seed.clone()));
}
} else if let Some(item) = &b.item {
entries.push(("item", item_to_nbt(item)));
}
}
BlockEntity::DaylightDetector => {}
}
Tag::compound(entries)
@@ -724,8 +741,24 @@ pub fn decode_block_entity(tag: &Tag) -> Option<((i32, i32, i32), crate::contain
_ => 1.0,
};
}
BlockEntity::Brushable(b) => {
b.loot_table = tag.get("LootTable").cloned();
b.loot_seed = tag.get("LootTableSeed").cloned();
b.item = if b.loot_table.is_none() {
tag.get("item").and_then(item_from_nbt)
} else {
None
};
b.hit_direction = int("hit_direction").filter(|v| (0..=5).contains(v));
}
BlockEntity::Sign(sign) => sign.decode(tag),
BlockEntity::Sculk(s) => s.load(tag),
BlockEntity::Shelf(shelf) => {
for (slot, item) in decode_items(tag.get("Items"), 3).into_iter().enumerate() {
shelf.items[slot] = item;
}
shelf.align_to_bottom = int("align_items_to_bottom").unwrap_or(0) != 0;
}
// ChiseledBookShelfBlockEntity.loadAdditional.
BlockEntity::ChiseledBookshelf(b) => {
for (slot, item) in decode_items(tag.get("Items"), 6).into_iter().enumerate() {
+15 -20
View File
@@ -481,26 +481,7 @@ pub struct StationRecipes {
pub trim_materials: Vec<(String, String)>,
}
fn ingredient(v: &Value, items: &Items) -> Ingredient {
let mut list: Vec<String> = Vec::new();
for s in match v {
Value::String(s) => vec![s.clone()],
Value::Array(a) => a
.iter()
.filter_map(|x| x.as_str().map(str::to_owned))
.collect(),
_ => vec![],
} {
let more = match s.strip_prefix('#') {
Some(tag) => items.item_tag_order.get(tag).cloned().unwrap_or_default(),
None => vec![s],
};
for i in more {
if !list.contains(&i) {
list.push(i);
}
}
}
Ingredient::of(list)
Ingredient::parse(v, items).unwrap_or_else(|| Ingredient::of(Vec::new()))
}
impl StationRecipes {
pub fn load(root: &Path, items: &Items) -> Self {
@@ -1014,4 +995,18 @@ mod tests {
let xp = grindstone_experience(&e, &mut r, Some(&s), None);
assert!((12..24).contains(&xp));
}
#[test]
fn smithing_ingredient_parses_holders() {
let items = sample_items();
let a = ingredient(&serde_json::json!("minecraft:diamond_sword"), &items);
assert_eq!(a.1, vec!["minecraft:diamond_sword"]);
let b = ingredient(
&serde_json::json!(["minecraft:diamond_sword", "minecraft:diamond_axe"]),
&items,
);
assert_eq!(
b.1,
vec!["minecraft:diamond_sword", "minecraft:diamond_axe"]
);
}
}
+197 -2
View File
@@ -1,7 +1,11 @@
//! Display/TextDisplay synced data (26.3), checked against vanilla accessors
//! and ClientboundSetEntityDataPacket's own stream codec.
use crate::text::Text;
use horizon_protocol::entity_data::Value;
use crate::{
save::{float, number},
text::Text,
};
use horizon_protocol::entity_data::{Value, serializer};
use horizon_world::nbt::Tag;
use serde::Serialize;
use std::sync::Arc;
@@ -154,6 +158,197 @@ impl TextDisplayData {
}
}
/// One synched data entry: kept when it differs from its default, or always
/// with `all` (the defaults a client is sent when a value goes back to one).
fn entry(
out: &mut Vec<(u8, i32, Value)>,
all: bool,
id: u8,
kind: i32,
value: Value,
default: Value,
) {
if all || value != default {
out.push((id, kind, if all { default } else { value }));
}
}
/// `Display.readAdditionalSaveData`: the synched data entries (ids 8 to 22)
/// of a saved display, or with `all` their defaults. A matrix `transformation`
/// (`MATRIX4F`) is not decomposed: it stays the identity.
pub fn display_data(tag: &Tag, all: bool) -> Vec<(u8, i32, Value)> {
let int = |key: &str| number(tag.get(key)).map(|v| v as i32);
let real = |key: &str| float(tag.get(key)).map(|v| v as f32);
let mut out = Vec::new();
let mut set = |id: u8, kind: i32, value: Value, default: Value| {
entry(&mut out, all, id, kind, value, default);
};
let defaults = TextDisplayData::default();
// The start delay, the transformation duration, the teleport duration (0 to 59).
let ints = [
(8, "start_interpolation", 0, i32::MIN, i32::MAX),
(9, "interpolation_duration", 0, i32::MIN, i32::MAX),
(10, "teleport_duration", 0, 0, 59),
(22, "glow_color_override", -1, i32::MIN, i32::MAX),
];
for (id, key, default, low, high) in ints {
let value = int(key).unwrap_or(default).clamp(low, high);
set(id, serializer::INT, Value::Int(value), Value::Int(default));
}
// `Transformation.CODEC`: all four parts, else the identity.
let t = tag.get("transformation").and_then(transformation);
let (translation, left, scale, right) = t.unwrap_or((
defaults.translation,
defaults.left_rotation,
defaults.scale,
defaults.right_rotation,
));
let parts = [
(
11,
serializer::VECTOR3,
translation.to_vec(),
defaults.translation.to_vec(),
),
(
12,
serializer::VECTOR3,
scale.to_vec(),
defaults.scale.to_vec(),
),
(
13,
serializer::QUATERNION,
left.to_vec(),
defaults.left_rotation.to_vec(),
),
(
14,
serializer::QUATERNION,
right.to_vec(),
defaults.right_rotation.to_vec(),
),
];
for (id, kind, value, default) in parts {
set(id, kind, Value::Floats(value), Value::Floats(default));
}
let billboard = match tag.get("billboard") {
Some(Tag::String(s)) => match s.to_string_lossy().as_str() {
"vertical" => 1,
"horizontal" => 2,
"center" => 3,
_ => 0,
},
_ => 0,
};
set(15, serializer::BYTE, Value::Byte(billboard), Value::Byte(0));
// `Brightness.pack`: block light in bits 4 to 7, sky light in bits 20 to 23.
let brightness = tag.get("brightness").and_then(|b| {
let light = |key: &str| number(b.get(key)).filter(|v| (0..=15).contains(v));
Some((light("block")? as i32) << 4 | (light("sky")? as i32) << 20)
});
set(
16,
serializer::INT,
Value::Int(brightness.unwrap_or(-1)),
Value::Int(-1),
);
for (id, key, default) in [
(17, "view_range", 1.0),
(18, "shadow_radius", 0.0),
(19, "shadow_strength", 1.0),
(20, "width", 0.0),
(21, "height", 0.0),
] {
let value = real(key).unwrap_or(default);
set(
id,
serializer::FLOAT,
Value::Float(value),
Value::Float(default),
);
}
out
}
/// `TextDisplay.readAdditionalSaveData`: the text, line width, background,
/// opacity and style flags (ids 23 to 27), or with `all` their defaults.
pub fn text_display_data(tag: &Tag, all: bool) -> Vec<(u8, i32, Value)> {
let int = |key: &str| number(tag.get(key)).map(|v| v as i32);
let mut out = Vec::new();
let mut set = |id: u8, kind: i32, value: Value, default: Value| {
entry(&mut out, all, id, kind, value, default);
};
let empty = Tag::String("".into());
set(
23,
serializer::COMPONENT,
Value::Text(tag.get("text").unwrap_or(&empty).clone()),
Value::Text(empty.clone()),
);
set(
24,
serializer::INT,
Value::Int(int("line_width").unwrap_or(200)),
Value::Int(200),
);
let background = Value::Int(int("background").unwrap_or(0x4000_0000));
set(25, serializer::INT, background, Value::Int(0x4000_0000));
let opacity = Value::Byte(int("text_opacity").unwrap_or(-1) as i8);
set(26, serializer::BYTE, opacity, Value::Byte(-1));
// Shadow 1, see-through 2, default background 4, then the alignment: left 8, right 16.
let flag = |key: &str, bit: i8| {
if int(key).is_some_and(|v| v != 0) {
bit
} else {
0
}
};
let align = match tag.get("alignment") {
Some(Tag::String(s)) => match s.to_string_lossy().as_str() {
"left" => 8,
"right" => 16,
_ => 0,
},
_ => 0,
};
let flags = flag("shadow", 1) | flag("see_through", 2) | flag("default_background", 4) | align;
set(27, serializer::BYTE, Value::Byte(flags), Value::Byte(0));
out
}
/// `Transformation.CODEC`'s translation, left rotation, scale and right
/// rotation; None unless all four are there (the matrix form is not read).
fn transformation(tag: &Tag) -> Option<([f32; 3], [f32; 4], [f32; 3], [f32; 4])> {
let list = |tag: Option<&Tag>| -> Option<Vec<f32>> {
match tag? {
Tag::List(l) => l.iter().map(|v| float(Some(v)).map(|v| v as f32)).collect(),
_ => None,
}
};
let vector = |key: &str| -> Option<[f32; 3]> { list(tag.get(key))?.try_into().ok() };
// `ExtraCodecs.QUATERNIONF`: four components (normalized) or an axis and an angle.
let rotation = |key: &str| -> Option<[f32; 4]> {
let value = tag.get(key)?;
if let Some(q) = list(Some(value)) {
let [x, y, z, w]: [f32; 4] = q.try_into().ok()?;
let length = (x * x + y * y + z * z + w * w).sqrt();
return Some([x / length, y / length, z / length, w / length]);
}
let angle = float(value.get("angle"))? as f32;
let [x, y, z]: [f32; 3] = list(value.get("axis"))?.try_into().ok()?;
let (sin, cos) = (angle * 0.5).sin_cos();
let inverse = 1.0 / (x * x + y * y + z * z).sqrt();
Some([x * inverse * sin, y * inverse * sin, z * inverse * sin, cos])
};
Some((
vector("translation")?,
rotation("left_rotation")?,
vector("scale")?,
rotation("right_rotation")?,
))
}
/// `TextDisplay.CachedInfo`: each line and its width, and the widest.
pub struct Lines {
pub lines: Vec<(Text, f32)>,
+167 -1
View File
@@ -1,6 +1,7 @@
//! Title, world selection and world creation screens (TitleScreen,
//! SelectWorldScreen, CreateWorldScreen layouts), drawn as HUD quads.
use crate::{
dialog_screen::BOX,
game_rules_screen::{Exit, RulesScreen},
hud::{HudAtlas, HudBatch, rgba},
lang,
@@ -33,6 +34,12 @@ fn edit_top(h: f32) -> f32 {
pub(crate) fn confirm_top(h: f32, lines: usize) -> f32 {
((h.ceil() - 61.0 - lines as f32 * 9.0) / 2.0).floor()
}
/// The SafetyScreen's column (WarningScreen: title, 12 px around the message
/// box of its lines and 4 px padding, the checkbox, then the buttons, 8 px
/// apart): the title's top.
fn warning_top(h: f32, lines: usize) -> f32 {
((h.ceil() - 102.0 - lines as f32 * 9.0) / 2.0).floor()
}
fn translate(key: &str, fallback: &str, args: &[&dyn std::fmt::Display]) -> String {
let args: Vec<Text> = args
@@ -119,6 +126,11 @@ pub enum Mode {
return_to: Box<Mode>,
},
Multiplayer(crate::multiplayer::Screen),
/// SafetyScreen: the warning before the first Multiplayer click, with its
/// "Do not show this screen again" box.
MultiplayerWarning {
check: bool,
},
/// CreateFlatWorldScreen over Create New World: the fields that screen
/// keeps and the superflat editor on top of them.
CreateFlat {
@@ -150,11 +162,18 @@ pub enum Action {
Connect {
address: String,
},
/// Create World's Data Packs screen on the new world's pack folder.
DataPacks {
dir: PathBuf,
selected: Vec<String>,
},
}
pub struct Title {
pub mode: Mode,
/// Direct Connection's address, synchronized with `options.txt`'s `lastServer`.
pub last_server: String,
/// `skipMultiplayerWarning`, synchronized with `options.txt` the same way.
pub skip_multiplayer_warning: bool,
pub saves: PathBuf,
/// The prepared resource root: the flat preset list and block registry.
resources: PathBuf,
@@ -166,6 +185,8 @@ pub struct Title {
scroll: Cell<crate::ui::Scroll>,
create_return_to_main: bool,
message_lines: Cell<usize>,
/// The SafetyScreen's checkbox as last drawn: x, y, width, height.
warning_check: Cell<[f32; 4]>,
backup: Option<mpsc::Receiver<Result<u64, String>>>,
backup_shown: Cell<bool>,
/// The backup a `BackupBeforeUpgrade` asked for opens its world when done.
@@ -292,6 +313,7 @@ impl Title {
Self {
mode,
last_server: String::new(),
skip_multiplayer_warning: false,
saves,
resources: resources.to_owned(),
started: now,
@@ -301,6 +323,7 @@ impl Title {
scroll: Cell::default(),
create_return_to_main: false,
message_lines: Cell::new(1),
warning_check: Cell::new([0.0; 4]),
backup: None,
backup_shown: Cell::new(false),
backup_then_open: false,
@@ -384,6 +407,12 @@ impl Title {
row
}
fn cancel_create(&mut self) {
// removeTempDataPackDir.
if let Mode::Create { options, .. } = &self.mode
&& let Some(dir) = &options.pack_dir
{
let _ = std::fs::remove_dir_all(dir);
}
if self.create_return_to_main {
self.mode = Mode::Main;
} else {
@@ -448,6 +477,13 @@ impl Title {
};
}
}
/// The Data Packs screen's Done (`applyNewPackConfig`): its selection for
/// the new world.
pub fn set_data_packs(&mut self, ids: Vec<String>) {
if let Mode::Create { options, .. } = &mut self.mode {
options.data_packs = ids;
}
}
fn matches_search(&self, world: &WorldEntry) -> bool {
let filter = self.search.to_lowercase();
world.name.to_lowercase().contains(&filter) || world.folder.to_lowercase().contains(&filter)
@@ -1016,6 +1052,28 @@ impl Title {
),
]
}
Mode::MultiplayerWarning { .. } => {
let lines = self.message_lines.get();
let y = warning_top(h, lines) + 82.0 + lines as f32 * 9.0;
vec![
b(
(w / 2.0).floor() - 154.0,
y,
150.0,
&lang::get_or("gui.proceed", "Proceed"),
true,
70,
),
b(
(w / 2.0).floor() + 4.0,
y,
150.0,
&lang::get_or("gui.back", "Back"),
true,
71,
),
]
}
Mode::Backup { .. } => Vec::new(),
Mode::Multiplayer(screen) => screen
.buttons(w, h)
@@ -1347,6 +1405,74 @@ impl Title {
centered(atlas, batch, line, top + 17.0 + i as f32 * 9.0, u32::MAX);
}
}
Mode::MultiplayerWarning { check } => {
crate::ui::menu_background(batch, atlas, 0.0, 0.0, w, h, false);
let message = lang::get_or(
"multiplayerWarning.message",
"Caution: Online play is offered by third-party servers that are not owned, operated, or supervised by Mojang Studios or Microsoft. During online play, you may be exposed to unmoderated chat messages or other types of user-generated content that may not be suitable for everyone.",
);
// The message sits in a text box `width - 100` wide with 4 px
// inside, left aligned (FittingMultiLineTextWidget).
let box_w = w - 100.0;
let lines = wrapped(atlas, &message, box_w - 8.0);
self.message_lines.set(lines.len());
let top = warning_top(h, lines.len());
let header = Text::translate("multiplayerWarning.header", &[]).bold();
batch.text_styled(
atlas,
&header,
(w / 2.0).floor() - (atlas.font.width_text(&header) / 2.0).floor(),
top,
u32::MAX,
true,
);
let box_x = ((w - box_w) / 2.0).floor();
let box_y = top + 29.0;
let box_h = lines.len() as f32 * 9.0 + 8.0;
crate::ui::nine_slice(
batch,
atlas,
"gui/sprites/widget/text_field",
box_x,
box_y,
box_w,
box_h,
u32::MAX,
);
for (i, line) in lines.iter().enumerate() {
batch.text(
atlas,
line,
box_x + 4.0,
box_y + 4.0 + i as f32 * 9.0,
u32::MAX,
true,
);
}
// Checkbox: the box, its label right of it (as the dialogs draw theirs).
let label =
lang::get_or("multiplayerWarning.check", "Do not show this screen again");
let width = BOX + 4.0 + HudBatch::text_width(atlas, &label).ceil();
let x = (w / 2.0).floor() - (width / 2.0).floor();
let y = top + 57.0 + lines.len() as f32 * 9.0;
self.warning_check.set([x, y, width, BOX]);
let hover = (x..x + width).contains(&cursor.0) && (y..y + BOX).contains(&cursor.1);
let sprite = match (*check, hover) {
(true, true) => "gui/sprites/widget/checkbox_selected_highlighted",
(true, false) => "gui/sprites/widget/checkbox_selected",
(false, true) => "gui/sprites/widget/checkbox_highlighted",
(false, false) => "gui/sprites/widget/checkbox",
};
batch.sprite_scaled(atlas, sprite, x, y, BOX, BOX, u32::MAX);
batch.text(
atlas,
&label,
x + BOX + 4.0,
y + 4.0,
rgba(224, 224, 224, 255),
true,
);
}
Mode::Multiplayer(screen) => screen.draw(
atlas,
batch,
@@ -1454,6 +1580,14 @@ impl Title {
}
return (Action::None, changed);
}
// The SafetyScreen's box toggles where it was last drawn.
if let Mode::MultiplayerWarning { check } = &mut self.mode {
let [bx, by, bw, bh] = self.warning_check.get();
if (bx..bx + bw).contains(&x) && (by..by + bh).contains(&y) {
*check = !*check;
return (Action::None, true);
}
}
let hit = self
.buttons(w, h)
.into_iter()
@@ -1476,9 +1610,26 @@ impl Title {
}
(Mode::Main, Some(2)) => Action::Quit,
(Mode::Main, Some(4)) => {
// TitleScreen.init: SafetyScreen first, unless it was turned off.
self.mode = if self.skip_multiplayer_warning {
Mode::Multiplayer(crate::multiplayer::Screen::list(&self.saves))
} else {
Mode::MultiplayerWarning { check: false }
};
Action::None
}
(Mode::MultiplayerWarning { check }, Some(70)) => {
// SafetyScreen Proceed: the box saves the choice.
if *check {
self.skip_multiplayer_warning = true;
}
self.mode = Mode::Multiplayer(crate::multiplayer::Screen::list(&self.saves));
Action::None
}
(Mode::MultiplayerWarning { .. }, Some(71)) => {
self.mode = Mode::Main;
Action::None
}
(Mode::Multiplayer(_), hit) => match self.multiplayer_click(hit, x, y, (w, h)) {
crate::multiplayer::Outcome::Back => {
self.mode = Mode::Main;
@@ -1669,11 +1820,26 @@ impl Title {
creative, options, ..
},
Some(id),
) if id != 21 && id != 22 => {
) if !matches!(id, 21 | 22 | 31) => {
options.press(id, creative);
Action::None
}
(Mode::Create { .. }, Some(21)) => self.create_action(),
(Mode::Create { options, .. }, Some(31)) => {
if options.pack_dir.is_none() {
match crate::datapack::temp_folder() {
Ok(dir) => options.pack_dir = Some(dir),
Err(e) => {
log::warn!("Horizon: no folder for data packs: {e}");
return Action::None;
}
}
}
Action::DataPacks {
dir: options.pack_dir.clone().unwrap_or_default(),
selected: options.data_packs.clone(),
}
}
(Mode::Create { .. }, Some(22)) => {
self.cancel_create();
Action::None
@@ -38,6 +38,11 @@ pub struct WorldOptions {
pub bonus_chest: bool,
/// `getGameRules`: the Game Rules screen's values, saved with the world.
pub rules: crate::gamerules::GameRules,
/// The Data Packs screen's selection, lowest priority first.
pub data_packs: Vec<String>,
/// The folder of packs for the new world (vanilla's `mcworld-`
/// temporary folder), made when Data Packs first opens.
pub pack_dir: Option<std::path::PathBuf>,
}
impl Default for WorldOptions {
fn default() -> Self {
@@ -51,6 +56,8 @@ impl Default for WorldOptions {
structures: true,
bonus_chest: false,
rules: crate::gamerules::GameRules::default(),
data_packs: vec!["vanilla".into()],
pack_dir: None,
}
}
}
@@ -286,7 +293,7 @@ pub(super) fn buttons(w: f32, h: f32, creative: bool, o: &WorldOptions) -> Vec<B
28,
),
],
// Experiments and data packs have no screens yet.
// Experiments have no screen yet.
_ => [
"selectWorld.gameRules",
"selectWorld.experiments",
@@ -300,7 +307,7 @@ pub(super) fn buttons(w: f32, h: f32, creative: bool, o: &WorldOptions) -> Vec<B
gy + 28.0 * i as f32,
210.0,
tr(key),
i == 0,
i != 1,
29 + i as u8,
)
})
+25 -3
View File
@@ -88,6 +88,9 @@ fn direct_connection_remembers_the_address_on_cancel_escape_and_join() {
let mut f = Fixture::new();
f.title.last_server = "localhost:25566".into();
f.click("Multiplayer");
// SafetyScreen comes first while its box was never ticked.
assert!(matches!(f.title.mode, Mode::MultiplayerWarning { .. }));
f.click("Proceed");
f.click("Direct Connection");
assert_eq!(f.title.focused_field().unwrap().1, "localhost:25566");
@@ -100,6 +103,7 @@ fn direct_connection_remembers_the_address_on_cancel_escape_and_join() {
f.title.escape();
f.title.escape();
f.click("Multiplayer");
f.click("Proceed");
f.click("Direct Connection");
assert_eq!(f.title.focused_field().unwrap().1, "[::1]:25568");
@@ -122,6 +126,7 @@ fn direct_connection_remembers_the_address_on_cancel_escape_and_join() {
fn f5_reloads_the_server_list() {
let mut f = Fixture::new();
f.click("Multiplayer");
f.click("Proceed");
let file = crate::multiplayer::servers_file(&f.title.saves);
horizon_protocol::servers::save(
&file,
@@ -850,12 +855,29 @@ fn create_world_tabs_follow_vanilla_and_their_choices_reach_the_action() {
bonus_chest: true
}
);
// The More tab's Experiments and Data Packs screens don't exist yet.
// The More tab: Experiments has no screen yet; Data
// Packs opens on a new pack folder, and its selection reaches the action.
f.title.click(54.0 + 248.0 + 10.0, 10.0, size);
let more = labels(&f);
assert_eq!(
labels(&f)[..3].iter().map(|b| b.3).collect::<Vec<_>>(),
[true, false, false]
more[..3].iter().map(|b| b.3).collect::<Vec<_>>(),
[true, false, true]
);
let (action, sound) = f.title.click(more[2].1 + 10.0, more[2].2 + 10.0, size);
let Action::DataPacks { dir, selected } = action else {
panic!("{action:?}")
};
assert!(sound && dir.is_dir() && selected == ["vanilla"]);
f.title
.set_data_packs(vec!["vanilla".into(), "file/ttm.zip".into()]);
let Action::Create { options, .. } = f.title.create_action() else {
panic!()
};
assert_eq!(options.data_packs, ["vanilla", "file/ttm.zip"]);
assert_eq!(options.pack_dir.as_ref(), Some(&dir));
// Cancel removes the folder (removeTempDataPackDir).
f.title.escape();
assert!(!dir.exists());
}
#[test]
+1 -1
View File
@@ -641,7 +641,7 @@ impl ChunkGenerator for VanillaTerrain {
crate::structure_blocks::block_entities(&chunk, self.loot.as_deref());
out.block_entities = block_entities;
// The block entities Horizon does not model (decorated pots with their
// sherds and loot table, brushable blocks) stay as placed, like a
// sherds and loot table) stay as placed, like a
// loaded chunk's.
let mut unmodelled: Vec<Tag> = chunk
.block_entities
+5
View File
@@ -107,6 +107,8 @@ pub struct ItemInfo {
pub weapon_damage: Option<u32>,
/// `use_effects.speed_multiplier` (UseEffects.DEFAULT: 0.2).
pub use_speed: f32,
/// `use_effects.interact_vibrations` (default true).
pub interact_vibrations: bool,
/// `glider` (elytra).
pub glider: bool,
/// `equippable.swappable` and `equip_sound`.
@@ -663,6 +665,9 @@ impl Items {
use_speed: c["minecraft:use_effects"]["speed_multiplier"]
.as_f64()
.unwrap_or(0.2) as f32,
interact_vibrations: c["minecraft:use_effects"]["interact_vibrations"]
.as_bool()
.unwrap_or(true),
blocks_attacks: BlocksAttacks::parse(&c["minecraft:blocks_attacks"]),
disable_blocking_seconds: c["minecraft:weapon"]["disable_blocking_for_seconds"]
.as_f64()
+66
View File
@@ -504,6 +504,72 @@ impl<'r> BlockSection<'r> {
}
Ok(old)
}
/// Write `len` consecutive values at (`x`, `y_start..y_start+len`, `z`) with
/// `state`, all inside this section. Resolves the palette id once, then writes
/// the rest directly; returns how many previous blocks were `air` so the
/// caller can update its non-air count. The final palette and counts match
/// `len` calls to `set` in the same top-down order.
pub fn fill_run(
&mut self,
x: i32,
y_start: i32,
z: i32,
len: i32,
state: BlockStateId,
air: BlockStateId,
) -> io::Result<u16> {
if !(0..16).contains(&x)
|| !(0..16).contains(&z)
|| len <= 0
|| y_start < 0
|| y_start + len > 16
{
return Err(invalid("section fill outside its bounds"));
}
let index = |y: i32| ((y as usize) << 8) | ((z as usize) << 4) | x as usize;
let top = y_start + len - 1;
let mut added = 0u16;
// The first write takes the general path: it may add the state to the
// palette, allocate storage, or find the section already uniform.
let old = self.set(index(top), state)?;
if old == air {
added += 1;
}
let Some(id) = id_in(&self.palette, &self.counts, &mut self.last, state) else {
return Ok(added);
};
let Some(storage) = self.storage.as_mut() else {
return Ok(added);
};
for y in (y_start..top).rev() {
let i = index(y);
let old_id = storage.read(i);
let old_state = self.palette[old_id as usize];
if old_state == state {
continue;
}
storage.write(i, id);
self.counts[old_id as usize] -= 1;
self.counts[id as usize] += 1;
if old_state == air {
added += 1;
}
if self.counts[old_id as usize] == 0 {
self.free.push(old_id);
if self.last == Some((old_state, old_id)) {
self.last = None;
}
}
}
if self.counts[id as usize] == 4096 {
self.palette = vec![state];
self.last = Some((state, 0));
self.counts = vec![4096];
self.free.clear();
self.storage = None;
}
Ok(added)
}
pub fn compact(&mut self) -> io::Result<()> {
let values: Vec<_> = (0..4096).map(|i| self.get(i).unwrap()).collect();
self.palette.clear();
+1
View File
@@ -567,6 +567,7 @@ props! {
creaking_heart_state = "creaking_heart_state",
cracked = "cracked",
has_book = "has_book",
has_record = "has_record",
signal_fire = "signal_fire",
orientation = "orientation",
crafting = "crafting",
@@ -397,9 +397,11 @@ impl<L: LevelAccess + ?Sized> Sim<'_, L> {
| Class::BrewingStand
| Class::CartographyTable
| Class::Chest
| Class::CopperChest
| Class::Crafter
| Class::CraftingTable
| Class::Dispenser
| Class::Dropper
| Class::EnchantingTable
| Class::EnderChest
| Class::Grindstone
@@ -409,10 +411,16 @@ impl<L: LevelAccess + ?Sized> Sim<'_, L> {
| Class::Sign
| Class::SmithingTable
| Class::Stonecutter
| Class::TrappedChest
| Class::Lectern => {
self.player_effect(pos, state, PlayerEffect::OpenMenu);
Success
}
// DecoratedPotBlock.useWithoutItem: the wobble always succeeds.
Class::DecoratedPot => Success,
// JukeboxBlock.useWithoutItem: ejecting a disc is SUCCESS (the
// insert is useItemOn). An empty jukebox passes.
Class::Jukebox if table.bool(state, p.has_record) => Success,
Class::Command | Class::Structure | Class::Jigsaw => {
if player.game_master {
self.player_effect(pos, state, PlayerEffect::OpenMenu);
+38
View File
@@ -1474,6 +1474,44 @@ fn big_dripleaf_tilts_under_an_entity_standing_on_it() {
assert_eq!(w.prop(pos, "tilt"), "none");
}
#[test]
fn using_storage_and_interactable_blocks_succeeds() {
let mut w = world!();
let pos = BlockPos::new(0, 1, 0);
let cases: &[(&str, &[(&str, &str)])] = &[
("chest", &[("facing", "north"), ("type", "single")]),
("trapped_chest", &[("facing", "north"), ("type", "single")]),
("barrel", &[("facing", "up")]),
("ender_chest", &[("facing", "north")]),
("shulker_box", &[("facing", "up")]),
("dispenser", &[("facing", "north")]),
("dropper", &[("facing", "north")]),
("hopper", &[("facing", "down")]),
("crafter", &[("orientation", "north_up")]),
("furnace", &[("facing", "north")]),
("blast_furnace", &[("facing", "north")]),
("smoker", &[("facing", "north")]),
("brewing_stand", &[]),
("beacon", &[]),
("decorated_pot", &[]),
("jukebox", &[("has_record", "true")]),
];
for &(name, props) in cases {
w.put(pos, w.id(name, props));
assert_eq!(
w.use_block(pos),
InteractionResult::Success,
"{name} should succeed (client swing)"
);
}
w.put(pos, w.id("jukebox", &[("has_record", "false")]));
assert_eq!(
w.use_block(pos),
InteractionResult::Pass,
"an empty jukebox passes"
);
}
#[test]
fn creative_breaking_piston_head_does_not_drop_piston() {
for (piston_name, head_type) in [("piston", "normal"), ("sticky_piston", "sticky")] {
@@ -215,6 +215,22 @@ impl<P: FluidPicker, F: PositionalRandom, B: AquiferBlockStates> NoiseBasedAquif
pub fn skip_sampling_above_y(&self) -> i32 {
self.skip_above_y
}
/// The fill decided a block without this aquifer. Both old decisions
/// (positive density and air above the skip height) cleared the pending
/// fluid update, so the caller reproduces that side effect.
pub fn note_skipped(&mut self) {
self.schedule = false;
}
/// The y above which a non-positive density is the global fluid's air. The
/// vanilla fluid rules depend only on y; a picker that varies with x/z keeps
/// the per-block call by answering `None`.
pub fn air_above_y(&self) -> Option<i32> {
let center = self.picker.compute([0, i32::MAX, 0]);
let east = self.picker.compute([i32::MAX, i32::MAX, i32::MAX]);
let west = self.picker.compute([i32::MIN, i32::MAX, i32::MIN]);
(center.level == east.level && center.level == west.level)
.then(|| self.skip_above_y.max(center.level))
}
fn sample(
&self,
field: AquiferField,
+35 -14
View File
@@ -1,14 +1,19 @@
//! Apply ordered carving-mask intervals to pre-lighting terrain.
use super::{
material_condition::{MaterialRule, MaterialSurfaceQueries},
material_stage::{SurfaceError, TopMaterialInputs, top_material},
material_condition::{
MaterialConditions, MaterialDensitySources, MaterialRule, MaterialSurfaceQueries,
},
material_stage::{SurfaceError, TopMaterialInputs, top_material_cell},
terrain::{TerrainAquifer, TerrainBlockStates, TerrainChunk, TerrainError},
};
use crate::{
heightmap::HeightmapState,
registry::{BlockRegistry, BlockStateId},
};
use horizon_core::{carving::CarvingMask, position::BlockPos, random::RandomSource};
use horizon_core::{
carving::CarvingMask, density::SamplerContext, noise::DensityVolume, position::BlockPos,
random::RandomSource,
};
use std::collections::BTreeSet;
/// Per-state predicates resolved once from the world's block registry and
@@ -60,7 +65,7 @@ pub fn apply_carving_mask<R: RandomSource, S: MaterialSurfaceQueries, B: Terrain
chunk: &mut TerrainChunk<'_, B>,
mask: &CarvingMask,
rule: MaterialRule,
mut inputs: TopMaterialInputs<'_, R, S>,
inputs: TopMaterialInputs<'_, R, S>,
aquifer: &mut (impl TerrainAquifer + ?Sized),
blocks: &CarvingBlocks,
mut filter: impl FnMut([i32; 3]) -> bool,
@@ -68,6 +73,27 @@ pub fn apply_carving_mask<R: RandomSource, S: MaterialSurfaceQueries, B: Terrain
where
R::Positional: Clone,
{
// Restoring the dirt under a carved cell used to build a fresh material
// worker, compile the whole surface rule and allocate its bindings for every
// cell. One worker now serves the pass; only the 1x1x1 bindings move.
let TopMaterialInputs {
generation,
root,
surface,
preliminary_surface,
density_context,
} = inputs;
let volume =
DensityVolume::new([1; 3], [0; 3], [1; 3]).map_err(|_| SurfaceError::InvalidVolume)?;
let sources = MaterialDensitySources::new(
surface,
volume,
preliminary_surface,
SamplerContext::default(),
)?;
let mut worker =
MaterialConditions::<R, _>::with_possible_biomes(generation, root, sources, None);
let rule = worker.add_rule(rule)?;
let cx = chunk.position().x.wrapping_shl(4);
let cz = chunk.position().z.wrapping_shl(4);
for column in mask.columns() {
@@ -84,7 +110,7 @@ where
}
found_surface |= flags & 2 != 0;
let Some(state) = aquifer
.compute_substance(inputs.density_context, [x, y, z], 0.)
.compute_substance(density_context, [x, y, z], 0.)
.map_err(TerrainError::from)?
else {
continue;
@@ -96,16 +122,11 @@ where
let below = y.wrapping_sub(1);
if found_surface && blocks.flags(chunk.block(x, below, z))? & 4 != 0 {
let submerged = chunk.block_properties(state).has_fluid();
let replacement = top_material(
worker.retarget_surface_densities([x, below, z])?;
let replacement = top_material_cell(
&mut worker,
chunk,
rule.clone(),
TopMaterialInputs::<R, _> {
generation: inputs.generation,
root: inputs.root.clone(),
surface: &mut inputs.surface,
preliminary_surface: inputs.preliminary_surface.clone(),
density_context: inputs.density_context,
},
rule,
BlockPos::new(x, below, z),
submerged,
)?;
@@ -31,6 +31,36 @@ impl<S: MaterialSurfaceQueries> MaterialDensitySources<S> {
pub fn sampler_context_mut(&mut self) -> &mut SamplerContext {
&mut self.context
}
/// Re-target the per-cell bindings to one block. A carver reuses one worker
/// across every restored dirt block, so the 1×1×1 volumes the bindings and
/// the preliminary plane sample must follow the cell; the compiled rule is
/// kept.
pub fn retarget(&mut self, position: [i32; 3]) -> Result<(), DecodeError> {
let volume = DensityVolume::new([1; 3], position, [1; 3])
.map_err(|_| DecodeError::Field("material density volume"))?;
let plane = DensityVolume::new([1; 3], [position[0], 0, position[2]], [1; 3])
.map_err(|_| DecodeError::Field("material preliminary plane"))?;
self.expected = volume;
self.plane = plane;
// The plane is sampled lazily at the new x/z.
self.buffer = None;
let mut sampled = vec![false; self.buffers.len()];
let mut pending = Vec::new();
for bound in &self.densities {
let Some(buffer) = bound.buffer else { continue };
if sampled.get(buffer).copied().unwrap_or(true) {
continue;
}
sampled[buffer] = true;
pending.push((bound.sampler.clone(), buffer));
}
for (sampler, buffer) in pending {
let out = &mut self.buffers[buffer];
out.resize(volume.size(), 0.0);
sampler.sample_volume(&mut self.context, out, volume)?;
}
Ok(())
}
pub fn into_parts(self) -> (S, SamplerContext) {
(self.surface, self.context)
}
@@ -1,6 +1,7 @@
//! Compiled material rule composition, sharing the condition worker's context.
use super::{
Compiled, Context, Facts, MaterialCondition, MaterialConditions, MaterialSurfaceQueries,
density::MaterialDensitySources,
};
use crate::{registry::BlockStateId, worldgen::DecodeError};
use horizon_core::{
@@ -366,6 +367,12 @@ where
})
}
}
impl<R: RandomSource, T: MaterialSurfaceQueries> MaterialConditions<R, MaterialDensitySources<T>> {
/// Re-target the per-cell density bindings for a reused worker.
pub fn retarget_surface_densities(&mut self, position: [i32; 3]) -> Result<(), DecodeError> {
self.context.surface.retarget(position)
}
}
impl<R: RandomSource, S: MaterialSurfaceQueries> MaterialConditions<R, S> {
/// Compile all children in order, even after an unconditional block rule.
/// Failed compilation never adds a partial rule to this worker.
@@ -84,17 +84,65 @@ struct Column<'a, 'r, B: TerrainBlockStates> {
z: i32,
min: i32,
max: i32,
/// Resolved block ids for `low..=high`, reused across columns and updated by
/// `set_block`. The surface walk reads a column twice (top to bottom, then the
/// stone-depth look-behind); the palette decode is paid once per column.
cache: &'a mut Vec<BlockStateId>,
low: i32,
high: i32,
}
impl<'a, 'r, B: TerrainBlockStates> Column<'a, 'r, B> {
fn new(
chunk: &'a mut TerrainChunk<'r, B>,
x: i32,
z: i32,
min: i32,
max: i32,
top: i32,
cache: &'a mut Vec<BlockStateId>,
) -> Self {
let chunk_min = chunk.min_y();
let chunk_max = chunk_min.wrapping_add(chunk.height()).wrapping_sub(1);
let high = top.min(chunk_max);
let low = min.max(chunk_min);
cache.clear();
if high >= low {
cache.reserve((high - low + 1) as usize);
for y in low..=high {
cache.push(chunk.block(x, y, z));
}
}
Self {
chunk,
x,
z,
min,
max,
cache,
low,
high,
}
}
fn cache_index(&self, y: i32) -> Option<usize> {
(y >= self.low && y <= self.high).then(|| (y - self.low) as usize)
}
}
impl<B: TerrainBlockStates> MaterialColumn for Column<'_, '_, B> {
type Error = SurfaceError;
fn block(&mut self, y: i32) -> Result<BlockStateId, SurfaceError> {
Ok(self.chunk.block(self.x, y, self.z))
Ok(match self.cache_index(y) {
Some(index) => self.cache[index],
None => self.chunk.block(self.x, y, self.z),
})
}
fn set_block(&mut self, y: i32, state: BlockStateId) -> Result<(), SurfaceError> {
if y >= self.min && y <= self.max {
// Most of the Nether's rule writes netherrack over netherrack.
if self.chunk.block(self.x, y, self.z) != state {
if self.block(y)? != state {
self.chunk.set_block_worldgen(self.x, y, self.z, state)?;
if let Some(index) = self.cache_index(y) {
self.cache[index] = state;
}
}
if self.chunk.block_properties(state).has_fluid() {
self.chunk.mark_postprocessing(self.x, y, self.z);
@@ -132,6 +180,45 @@ fn tick(remaining: &mut usize) -> Result<(), SurfaceError> {
Ok(())
}
/// Apply a compiled top-material rule at one position with a worker the caller
/// built once. Carvers restore many cells per pass, so the rule is compiled and
/// the density bindings created once instead of per restored block.
pub(crate) fn top_material_cell<
R: RandomSource,
S: MaterialSurfaceQueries,
B: TerrainBlockStates,
>(
worker: &mut MaterialConditions<R, S>,
chunk: &mut TerrainChunk<'_, B>,
rule: usize,
position: BlockPos,
submerged: bool,
) -> Result<Option<BlockStateId>, SurfaceError> {
let (lx, lz) = (position.x & 15, position.z & 15);
let gx = first_available(chunk, (lx + 1).min(15), lz)?.wrapping_sub(first_available(
chunk,
(lx - 1).max(0),
lz,
)?);
let gz = first_available(chunk, lx, (lz + 1).min(15))?.wrapping_sub(first_available(
chunk,
lx,
(lz - 1).max(0),
)?);
worker.update_xz(position.x, position.z, gx, gz);
worker.update_y(
1,
1,
if submerged {
position.y.wrapping_add(1)
} else {
i32::MIN
},
position.y,
);
worker.try_apply(rule, position).map_err(SurfaceError::from)
}
/// Evaluate the replacement surface under a carved block. Each call binds a
/// fresh one-cell material context, without restricting possible biomes, and
/// uses one stone block above/below. The caller applies the returned state.
@@ -161,29 +248,7 @@ pub fn top_material<R: RandomSource, S: MaterialSurfaceQueries, B: TerrainBlockS
);
let result = (|| {
let rule = worker.add_rule(rule)?;
let (lx, lz) = (position.x & 15, position.z & 15);
let gx = first_available(chunk, (lx + 1).min(15), lz)?.wrapping_sub(first_available(
chunk,
(lx - 1).max(0),
lz,
)?);
let gz = first_available(chunk, lx, (lz + 1).min(15))?.wrapping_sub(first_available(
chunk,
lx,
(lz - 1).max(0),
)?);
worker.update_xz(position.x, position.z, gx, gz);
worker.update_y(
1,
1,
if submerged {
position.y.wrapping_add(1)
} else {
i32::MIN
},
position.y,
);
worker.try_apply(rule, position).map_err(SurfaceError::from)
top_material_cell(&mut worker, chunk, rule, position, submerged)
})();
let (_, mut context) = worker.into_surface().into_parts();
std::mem::swap(&mut context, inputs.density_context);
@@ -255,6 +320,8 @@ where
let variants = worker.surface_variants(rule)?;
let cx = chunk.position().x.wrapping_shl(4);
let cz = chunk.position().z.wrapping_shl(4);
// One block-id buffer, refilled per column and kept across columns.
let mut cache = Vec::new();
for lx in 0..16 {
for lz in 0..16 {
let x = cx.wrapping_add(lx);
@@ -265,13 +332,15 @@ where
.ok_or(MaterialRuleError::MissingBiome)?;
if biome.as_ref() == "minecraft:eroded_badlands" {
extensions.eroded_badlands(
&mut Column {
&mut Column::new(
chunk,
x,
z,
min: write_min_y,
max: write_max_y,
},
write_min_y,
write_max_y,
original_top,
&mut cache,
),
x,
z,
original_top,
@@ -295,13 +364,7 @@ where
let mut bottom = i32::MAX;
let mut y = top;
let mut budget = 1 << 20;
let mut column = Column {
chunk,
x,
z,
min: write_min_y,
max: write_max_y,
};
let mut column = Column::new(chunk, x, z, write_min_y, write_max_y, top, &mut cache);
while y >= min {
tick(&mut budget)?;
let state = column.block(y)?;
+112 -4
View File
@@ -31,6 +31,15 @@ pub trait TerrainAquifer {
density: f64,
) -> Result<Option<BlockStateId>, AquiferError>;
fn should_schedule_fluid_update(&self) -> bool;
/// The y above which every non-positive density is the aquifer's air. The
/// fill skips those blocks without asking the aquifer; `None` keeps the
/// per-block call for aquifers whose global fluid can vary with x/z.
fn air_above_y(&self) -> Option<i32> {
None
}
/// The fill decided this block without the aquifer (positive density or air
/// above its skip height). Both old paths cleared the pending fluid update.
fn note_skipped(&mut self) {}
}
impl<P: FluidPicker> TerrainAquifer for DisabledAquifer<P> {
fn compute_substance(
@@ -59,6 +68,12 @@ impl<P: FluidPicker, F: PositionalRandom, B: AquiferBlockStates> TerrainAquifer
fn should_schedule_fluid_update(&self) -> bool {
NoiseBasedAquifer::should_schedule_fluid_update(self)
}
fn air_above_y(&self) -> Option<i32> {
NoiseBasedAquifer::air_above_y(self)
}
fn note_skipped(&mut self) {
NoiseBasedAquifer::note_skipped(self);
}
}
#[derive(Debug)]
@@ -430,6 +445,44 @@ impl<'r, B: TerrainBlockStates> TerrainChunk<'r, B> {
}
Ok(old)
}
/// Write a vertical run of one non-air state from `y_top` downward, all
/// inside the chunk. Returns how many blocks changed from air; section
/// non-air counts are updated here and the caller owns the heightmaps.
pub fn fill_solid_run(
&mut self,
x: i32,
y_top: i32,
z: i32,
len: i32,
state: BlockStateId,
) -> Result<u16, TerrainError> {
let air = self.blocks.air;
let mut added = 0u16;
let mut top = y_top;
let mut left = len;
while left > 0 {
let section = self
.blocks
.section_index(top)
.ok_or(TerrainError::OutsideBuildHeight)?;
let local_top = top & 15;
let take = (local_top + 1).min(left);
let local_start = local_top - take + 1;
let now = self.blocks.sections[section].fill_run(
x & 15,
local_start,
z & 15,
take,
state,
air,
)?;
self.blocks.non_air[section] = self.blocks.non_air[section].saturating_add(now);
added = added.saturating_add(now);
top -= take;
left -= take;
}
Ok(added)
}
pub fn update_heightmap(
&mut self,
kind: HeightmapType,
@@ -517,6 +570,15 @@ pub fn fill_noise<B: TerrainBlockStates>(
chunk.ensure_heightmap(HeightmapType::WorldSurfaceWg);
let mut density = vec![0.; volume.size()];
final_density.sample_volume(context, &mut density, volume)?;
let air_above = aquifer.air_above_y();
// A non-air, non-fluid default block may be written as a run without asking
// the aquifer or touching the heightmap below the run's top.
let solid_runs = default_block != chunk.blocks.air
&& !chunk
.blocks
.properties
.heightmap_state(default_block)
.has_fluid();
const MAPS: [HeightmapType; 2] = [HeightmapType::OceanFloorWg, HeightmapType::WorldSurfaceWg];
for z in 0..sz {
let world_z = bz.wrapping_add(z as i32);
@@ -531,12 +593,58 @@ pub fn fill_noise<B: TerrainBlockStates>(
.first_available(x as i32, z as i32)
.map(|first| first.wrapping_sub(2))
});
for y in (0..sy).rev() {
let mut y = sy;
while y > 0 {
y -= 1;
let world_y = by.wrapping_add(y as i32);
let value = density[volume.index([x, y, z]).expect("valid density coordinates")];
let state = aquifer
.compute_substance(context, [world_x, world_y, world_z], f64::from(value))?
.unwrap_or(default_block);
// A positive-density run is entirely the default block. Write it
// through the section once instead of per block; the heightmap
// only changes at the run's top.
if solid_runs && value > 0.0 {
let mut run = 1usize;
while run <= y
&& density[volume
.index([x, y - run, z])
.expect("valid density coordinates")]
> 0.0
{
run += 1;
}
aquifer.note_skipped();
chunk.fill_solid_run(x as i32, world_y, z as i32, run as i32, default_block)?;
for (kind, settled) in MAPS.into_iter().zip(&mut settled) {
if matches!(settled, Ok(bound) if world_y <= *bound) {
continue;
}
chunk.update_heightmap(kind, x as i32, world_y, z as i32, default_block)?;
*settled = chunk.heightmaps[kind as usize]
.as_ref()
.expect("ensured heightmap")
.first_available(x as i32, z as i32)
.map(|first| first.wrapping_sub(2));
}
y -= run - 1;
continue;
}
// The aquifer answers `None` for positive density, which the fill
// writes as the default block, and air above its skip/fluid level.
// Both are decided here so the per-block call is not made at all,
// with the same pending-update side effect the call had.
let solid = value > 0.0;
if solid {
aquifer.note_skipped();
}
let state = if solid {
default_block
} else if air_above.is_some_and(|limit| world_y > limit) {
aquifer.note_skipped();
continue;
} else {
aquifer
.compute_substance(context, [world_x, world_y, world_z], f64::from(value))?
.unwrap_or(default_block)
};
if state == chunk.blocks.air {
continue;
}
+1 -1
View File
@@ -125,7 +125,7 @@ Every command `horizon-ctl` takes, its MCP tool in `horizon-ctl mcp` (the launch
| `potion ITEM POTION` | `potion` | Give a potion item | `item` (potion, splash_potion, lingering_potion, tipped_arrow, required): which item<br>`potion` (string, required): potion id |
| `fill X1 Y1 Z1 X2 Y2 Z2 BLOCK` | `fill` (destructive) | Set a box of loaded blocks | `x1` (integer, required): corner X<br>`y1` (integer, required): corner Y<br>`z1` (integer, required): corner Z<br>`x2` (integer, required): opposite X<br>`y2` (integer, required): opposite Y<br>`z2` (integer, required): opposite Z<br>`block` (string, required): block state |
| `container X Y Z [ITEM COUNT]` | `container` | List a container's items, or add items to it | `x` (integer, required): block X<br>`y` (integer, required): block Y<br>`z` (integer, required): block Z<br>`item` (string): item to add<br>`count` (integer): how many |
| `render-distance N` | CLI only | Chunks, 2..64 | `chunks` (integer, required): render distance |
| `render-distance N` | CLI only | Chunks, 2..128 | `chunks` (integer, required): render distance |
| `wait TICKS` | `wait` | Wait until TICKS game ticks have passed (20 per second) | `ticks` (integer, required): game ticks |
## Scripting and benchmarks
+1 -1
View File
@@ -48,7 +48,7 @@ Development builds that link quickly: `cargo build --profile fast -p horizon-cli
| `--world NAME` | World folder under `saves/` (default "New World"); reopened if it exists |
| `--seed N` | Seed for a new world (numbers or text, like vanilla) |
| `--creative` | Creative mode (instant breaking, pick block) |
| `--render-distance N` | Chunks, 2..64 (default 12) |
| `--render-distance N` | Chunks, 2..128 (default 12) |
| `--resources PATH` | Prepared resource directory |
| Control | Action |
+10
View File
@@ -123,6 +123,16 @@ at a time, with each class's Java source, home files, and Rust functions in them
for whoever (or whichever agent) writes the next batch file. Set `PORT_LEDGER_OUT` to build into another
directory, so several people can check their own rows at once.
## Parity harness coverage
A mapped method says where the port is, not that it behaves like vanilla; the parity harnesses check that
(`tools/test_*_parity.py`: a vanilla oracle in `mods/horizon/src/test/java/dev/horizonlab/parity/` and a Rust
fixture or probe under `crates/*/examples/` run on the same inputs). The ledger links them: a harness covers a
ported method when its fixture reaches the port and the vanilla side is in reach (the oracle calls into the
method, or the harness or oracle names its class). `where` lists a method's harnesses, and
`gaps --kind untested [--package world/entity]` lists the sure pairs (cited or mapped) with behaviour of their
own that no harness covers, most-called first: where a new harness would catch the most drift.
## Bug reports and branches
`issue N` reads a GitHub issue (`gh issue view`), or takes the report's text (`-` reads stdin), drops the
@@ -309,7 +309,7 @@ public final class VanillaPackScreenOracle {
List<String> initial = new ArrayList<>();
for (var s : c.getAsJsonArray("selected")) initial.add(s.getAsString());
repository.setSelected(initial);
var screen = new PackSelectionScreen(repository, r -> { }, Path.of(c.get("dir").getAsString()), Component.translatable("resourcePack.title"));
var screen = new PackSelectionScreen(repository, r -> { }, Path.of(c.get("dir").getAsString()), Component.translatable(c.get("title").getAsString()));
gui.setScreen(screen);
// PackSelectionScreen.loadPackIcon: a pack with a pack.png gets its own texture.
@SuppressWarnings("unchecked")
+2
View File
@@ -102,6 +102,8 @@ impl Game {
self.audio.play("hit", None, 1.0, 1.0);
}
}
// Tutorial.onDestroyBlock (tutorial.rs): the hints play no part in mining.
fn tutorial_destroy<T>(&mut self, _: T, _: f32) {}
METHOD
}
fn main() {
+1 -1
View File
@@ -80,7 +80,7 @@ class RepositoryRoadmap(unittest.TestCase):
def test_generated_files_match_the_toml(self):
for path, text in roadmap.outputs(roadmap.load()).items():
self.assertEqual(path.read_text(), text, f"{path.name} is out of date: run `python3 tools/roadmap.py build`")
self.assertEqual(path.read_text(encoding="utf-8"), text, f"{path.name} is out of date: run `python3 tools/roadmap.py build`")
def test_site_data_has_every_item_in_one_line_text(self):
data = json.loads(roadmap.site_data(tomllib.loads(SAMPLE)))
+92 -2
View File
@@ -1031,6 +1031,70 @@ def registry_aliases(sources, van):
return out
ORACLE_DIR = ROOT / "mods" / "horizon" / "src" / "test" / "java" / "dev" / "horizonlab" / "parity"
def harness_coverage(van, methods, fns, edges, known):
"""The parity harnesses that cover each ported method. A harness (tools/test_*_parity.py) runs a vanilla oracle
(mods/horizon/src/test/java/.../parity/*.java) and a Rust fixture (crates/*/examples/**/*_fixture.rs) on the same
inputs. It covers a method when its fixture reaches the method's port and the vanilla side is in reach too: the
oracle calls into the method, or the harness or oracle names the method's class (oracles often reach vanilla
through an interface, a block state for the block, which a call graph can't follow)."""
oracles = {p.stem: p for p in ORACLE_DIR.glob("*.java")} if ORACLE_DIR.is_dir() else {}
fixture_fns = defaultdict(list) # the probes' example files: *_fixture.rs, *_probe.rs and the like
for fn in fns:
if "/examples/" in fn["file"]:
fixture_fns[fn["file"].rsplit("/", 1)[-1][:-3]].append(fn["id"])
def java_reach(names, depth=3):
keys = set()
for name in names:
text = oracles[name].read_text(encoding="utf-8", errors="replace")
imported = {m.group(2): m.group(1).replace(".", "/") + "/" + m.group(2)
for m in re.finditer(r"^import\s+((?:net|com)\.minecraft[\w.]*|com\.mojang[\w.]*)\.([A-Z]\w*);", text, re.M)}
called = set(re.findall(r"\.(\w+)\s*\(", text)) | {m for _, m in re.findall(r"\b([A-Z]\w*)::(\w+)", text)}
for cp in imported.values():
if cp not in van.classes:
continue
for meth in called:
decl, _ = van.find_method(cp, meth)
if decl:
keys.add(key(decl, meth))
frontier = set(keys)
for _ in range(depth):
frontier = {c for k in frontier for c in methods.get(k, {}).get("callees", ())} - keys
keys |= frontier
return keys
def rust_reach(starts, depth=5):
seen = set(starts)
frontier = set(starts)
for _ in range(depth):
frontier = {c for f in frontier for c in edges.get(f, ())} - seen
seen |= frontier
return seen
covered = defaultdict(list)
for path in sorted((ROOT / "tools").glob("test_*_parity.py")):
text = path.read_text(encoding="utf-8", errors="replace")
tokens = set(re.findall(r"\w+", text))
names = tokens & oracles.keys()
fixtures = {n for n in tokens & fixture_fns.keys() if n.endswith(("_fixture", "_probe"))}
if not names or not fixtures:
continue
vkeys = java_reach(names)
rfns = rust_reach([f for n in fixtures for f in fixture_fns[n]])
words = set(re.findall(r"\b[A-Z]\w+", text + "".join(oracles[n].read_text(encoding="utf-8", errors="replace") for n in names)))
harness_name = path.stem.removeprefix("test_").removesuffix("_parity")
for k, fids in known.items():
if not fids & rfns:
continue
simple = methods[k]["class"].rsplit("/", 1)[-1] if k in methods else ""
if k in vkeys or simple.split("$")[0] in words:
covered[k].append(harness_name)
return dict(covered)
def build(sources, jars, jobs):
if not sources and not jars:
sys.exit("No vanilla code: run `python3 tools/lab.py decompile`, or pass --sources DIR / --jar JAR.")
@@ -1616,6 +1680,8 @@ def build(sources, jars, jobs):
for k, v in structural.items():
known.setdefault(k, set()).add(v["fn"])
harness = harness_coverage(van, methods, fns, edges, known)
def reach(fid, depth=5):
"""Names of the fns `fid` reaches within `depth` calls, and of the calls left unresolved."""
seen, frontier = {fid}, {fid}
@@ -1807,6 +1873,7 @@ def build(sources, jars, jobs):
"absent": absent,
"homes": homes,
"aliases": aliases,
"harness": harness,
"inferred": inferred,
"class_cites": {k: sorted(set(v)) for k, v in class_cites.items()},
"file_class_cites": {k: sorted(v) for k, v in file_class_cites.items()},
@@ -1924,6 +1991,7 @@ def method_view(led, k):
[f"skip:{led['skipped'][k]['reason']} {led['skipped'][k]['note']} ({led['skipped'][k]['src']})"] if k in led.get("skipped", {}) else
[f"missing {led['absent'][k]['note']} ({led['absent'][k]['src']})"] if k in led.get("absent", {}) else []),
"class_home": led.get("homes", {}).get(m["class"]) or led.get("homes", {}).get(m["class"].split("$")[0], []),
"parity_harnesses": led.get("harness", {}).get(k, []),
"inferred": [f"{fn_ref(led, i['fn'])} (score {i['score']}, shares {', '.join(i['shared'])})" for i in led["inferred"].get(k, [])],
"client_effect": m["client"],
"calls": [f"{short(led['methods'][c]['class'], led['methods'][c]['name'])} [{status_of(led, c)}]" for c in m["callees"] if c in led["methods"]][:40],
@@ -2061,6 +2129,24 @@ def gap_rank(g):
g.get("vanilla") or g.get("vanilla_class") or g.get("file", ""))
def untested(led, package=None, limit=50):
"""Ported methods no parity harness covers, most-called first: where a harness would catch the most drift."""
harness = led.get("harness", {})
rows = []
for k, m in led["methods"].items():
if m["class"].startswith(SKIP_PACKAGES) or k in harness or m["name"].startswith("<"):
continue
if package and not m["class"].startswith("net/minecraft/" + package):
continue
# Sure pairs only (cited, or answered in the map), and methods with behaviour of their own.
if status_of(led, k) not in ("ported", "mapped") or m.get("accessor") or m.get("size", 0) <= 8:
continue
rows.append((len(led["callers"].get(k, [])), k))
rows.sort(reverse=True)
return [{"vanilla": short(led["methods"][k]["class"], led["methods"][k]["name"]), "callers": n,
"port": fn_ref(led, port_of(led, k)[0]) if port_of(led, k) else ""} for n, k in rows[:limit]]
def unported(led, package=None, limit=50):
rows = []
for k, m in led["methods"].items():
@@ -2084,6 +2170,9 @@ def cmd_gaps(led, kind, package, limit, as_json):
if kind == "unported":
emit(unported(led, package, limit), as_json, "Nothing unported there.")
return
if kind == "untested":
emit(untested(led, package, limit), as_json, "Every port there has a parity harness.")
return
gaps = [g for g in led["gaps"] if (not kind or g["kind"] == kind)]
if package:
gaps = [g for g in gaps if (g.get("vanilla") or g.get("vanilla_class") or "").startswith("net/minecraft/" + package)
@@ -2670,7 +2759,7 @@ def main():
c.add_argument("--package")
c.add_argument("--depth", type=int, default=2)
g = sub.add_parser("gaps")
g.add_argument("--kind", choices=["seam", "client", "drift", "class", "callee", "stale", "map", "unported"])
g.add_argument("--kind", choices=["seam", "client", "drift", "class", "callee", "stale", "map", "unported", "untested"])
g.add_argument("--package")
g.add_argument("--limit", type=int, default=50)
sub.add_parser("report")
@@ -2697,7 +2786,8 @@ def main():
tot.update(r)
print(f"{len(led['methods'])} vanilla methods, {len(led['fns'])} Rust functions; of {tot['total']} outside the "
f"skipped packages: " + ", ".join(f"{tot[k]} {k}" for k in COVERAGE_COLS)
+ f" ({found_pct(tot):.0f}% of those worth porting found, {classified_pct(tot):.0f}% of all answered); gaps: "
+ f" ({found_pct(tot):.0f}% of those worth porting found, {classified_pct(tot):.0f}% of all answered;"
f" {len(led.get('harness', {}))} covered by a parity harness); gaps: "
+ ", ".join(f"{k} {v}" for k, v in Counter(gg['kind'] for gg in led['gaps']).most_common())
+ f" -> {LEDGER}")
return
+3 -3
View File
@@ -2,7 +2,7 @@ AgeableWaterCreature.handleAirSupply inline crates/horizon-client/src/mobs/ai.rs
AgeableWaterCreature.checkSurfaceAgeableWaterCreatureSpawnRules port crates/horizon-client/src/mobs/spawn_rules.rs::surface_water
Animal.readAdditionalSaveData port crates/horizon-client/src/entity_nbt.rs::mob_from_nbt InLove is read; LoveCause is not kept
Animal.canMate port crates/horizon-client/src/mobs/animal_brain.rs::can_mate_with brain breeding; the Breed goal in goals.rs does the same for goal-driven animals
Animal.handleEntityEvent port crates/horizon-client/src/particles.rs::entity_event_burst event 18 love hearts
Animal.handleEntityEvent port crates/horizon-client-render/src/particles.rs::entity_event_burst event 18 love hearts
Animal.getDismountLocationForPassenger port crates/horizon-client/src/game/mounts.rs::Game::dismount_mount gap: tries both sides by the mob's yaw, then on top; not DismountHelper's offsets and pose boxes
Allay.createAttributes skip:data attributes come from entity-types.json
Allay.createNavigation port crates/horizon-client/src/mobs/allay.rs::register flying navigation, required path length 48
@@ -21,8 +21,8 @@ Allay.readAdditionalSaveData port crates/horizon-client/src/entity_nbt.rs::mob_f
Allay.updateDuplicationCooldown inline crates/horizon-client/src/mobs/allay.rs::ai_step egg_time counts down
Allay.setDuplicationCooldown inline crates/horizon-client/src/game/allays.rs::Game::interact_allay 6000 set here; can_duplicate is derived from egg_time in mob_meta
Allay.getLeashOffset missing lead hangs at the default offset (eye height), not 0.6 of it; leash::leash_offset only special-cases llamas
Allay.handleEntityEvent port crates/horizon-client/src/particles.rs::entity_event_burst event 18, three hearts
Allay.spawnHeartParticle port crates/horizon-client/src/particles.rs::around_self one heart's random placement
Allay.handleEntityEvent port crates/horizon-client-render/src/particles.rs::entity_event_burst event 18, three hearts
Allay.spawnHeartParticle port crates/horizon-client-render/src/particles.rs::around_self one heart's random placement
Allay.VibrationUser.canReceiveVibration missing allays never listen for vibrations: a note block played near one is not remembered
AllayAi.initCoreActivity inline crates/horizon-client/src/mobs/allay.rs::register panic goal; the cooldown countdowns are plain ints
AllayAi.initIdleActivity inline crates/horizon-client/src/mobs/allay.rs::register fetch, deliver, stay close, stroll and look as goals instead of a brain
1 AgeableWaterCreature.handleAirSupply inline crates/horizon-client/src/mobs/ai.rs::base_tick the needs_water branch of base_tick; dolphins override it to nothing and refill air in aquatic.rs
2 AgeableWaterCreature.checkSurfaceAgeableWaterCreatureSpawnRules port crates/horizon-client/src/mobs/spawn_rules.rs::surface_water
3 Animal.readAdditionalSaveData port crates/horizon-client/src/entity_nbt.rs::mob_from_nbt InLove is read; LoveCause is not kept
4 Animal.canMate port crates/horizon-client/src/mobs/animal_brain.rs::can_mate_with brain breeding; the Breed goal in goals.rs does the same for goal-driven animals
5 Animal.handleEntityEvent port crates/horizon-client/src/particles.rs::entity_event_burst crates/horizon-client-render/src/particles.rs::entity_event_burst event 18 love hearts
6 Animal.getDismountLocationForPassenger port crates/horizon-client/src/game/mounts.rs::Game::dismount_mount gap: tries both sides by the mob's yaw, then on top; not DismountHelper's offsets and pose boxes
7 Allay.createAttributes skip:data attributes come from entity-types.json
8 Allay.createNavigation port crates/horizon-client/src/mobs/allay.rs::register flying navigation, required path length 48
21 Allay.updateDuplicationCooldown inline crates/horizon-client/src/mobs/allay.rs::ai_step egg_time counts down
22 Allay.setDuplicationCooldown inline crates/horizon-client/src/game/allays.rs::Game::interact_allay 6000 set here; can_duplicate is derived from egg_time in mob_meta
23 Allay.getLeashOffset missing lead hangs at the default offset (eye height), not 0.6 of it; leash::leash_offset only special-cases llamas
24 Allay.handleEntityEvent port crates/horizon-client/src/particles.rs::entity_event_burst crates/horizon-client-render/src/particles.rs::entity_event_burst event 18, three hearts
25 Allay.spawnHeartParticle port crates/horizon-client/src/particles.rs::around_self crates/horizon-client-render/src/particles.rs::around_self one heart's random placement
26 Allay.VibrationUser.canReceiveVibration missing allays never listen for vibrations: a note block played near one is not remembered
27 AllayAi.initCoreActivity inline crates/horizon-client/src/mobs/allay.rs::register panic goal; the cooldown countdowns are plain ints
28 AllayAi.initIdleActivity inline crates/horizon-client/src/mobs/allay.rs::register fetch, deliver, stay close, stroll and look as goals instead of a brain
+1 -1
View File
@@ -50,7 +50,7 @@ BannerDuplicateRecipe.getRemainingItems port crates/horizon-client/src/crafting.
BannerDuplicateRecipe.matches port crates/horizon-client/src/crafting.rs::Special::matches
BlastingRecipe.recipeBookCategory skip:data book category comes from the recipe JSON (Recipes::load keeps recipes.meta)
BrewingInput.getItem skip:java
BrewingRecipe.matches port crates/horizon-client/src/brewing.rs::Brewing::find input and reagent both tested
BrewingRecipe.matches port crates/horizon-client-render/src/brewing.rs::Brewing::find input and reagent both tested
CraftingRecipe.recipeBookCategory skip:java
DecoratedPotRecipe.assemble port crates/horizon-client/src/crafting.rs::Special::assemble
DecoratedPotRecipe.matches port crates/horizon-client/src/crafting.rs::Special::matches four sherds or bricks in the four pattern cells
Can't render this file because it contains an unexpected character in line 1 and column 84.
+3 -3
View File
@@ -4,9 +4,9 @@ VillagerTrades skip:data trade definitions are data; read from data/minecraft/t
BlockCollisions.<init> port crates/horizon-world/src/block_collision_scan.rs::BlockCollisionScan::new scan set-up over the box
BlockCollisions.computeNext port crates/horizon-world/src/block_collision_scan.rs::BlockCollisionScan::find_next next block shape along the box
BlockCollisions.getChunk inline crates/horizon-world/src/block_collision_scan.rs::BlockCollisionScan::find_next chunk fetch through collision_chunk inside find_next
CardinalLighting.byFace port crates/horizon-client/src/mesher/lighting.rs::cardinal per-face directional shade; nether flag handled in the same fn
CardinalLighting.byFace port crates/horizon-client-render/src/mesher/lighting.rs::cardinal per-face directional shade; nether flag handled in the same fn
ClipContext.getFluidShape inline crates/horizon-world/src/world_ray.rs::clip_world pick_fluid decides canPick; the shape is clipped in clip_world
ColorMapColorUtil.get port crates/horizon-client/src/biome.rs::sample colormap lookup by temperature and downfall
ColorMapColorUtil.get port crates/horizon-client-render/src/biome.rs::sample colormap lookup by temperature and downfall
EntityBasedExplosionDamageCalculator.getBlockExplosionResistance missing unsure: source-entity overrides (wither skull, minecart TNT, primed TNT keeping nether portals) are not read; explosion_hit_block uses the block's own resistance
ExplosionDamageCalculator.getEntityDamageAmount inline crates/horizon-client/src/game/explosion.rs::Game::explosion_hurt_entities damage formula inline; the player copy is in explosion_hurt_player
LevelSettings.copy skip:java immutable record copy; Horizon keeps level fields on its own struct
@@ -103,7 +103,7 @@ BlastFurnaceBlock.openContainer port crates/horizon-world/src/level/interact.rs:
BonemealableFeaturePlacerBlock.performBonemeal port crates/horizon-world/src/level/bonemeal.rs::Behaviours::place_feature places the configured feature
BrewingStandBlock.animateTick port crates/horizon-client/src/animate_tick.rs::block_animate_tick brewing bubbles
BrewingStandBlock.createBlockStateDefinition skip:data block state definition is data (blocks table in horizon-items)
BrewingStandBlock.getTicker port crates/horizon-client/src/brewing.rs::BrewingStand::brew the stand's brewing step
BrewingStandBlock.getTicker port crates/horizon-client-render/src/brewing.rs::BrewingStand::brew the stand's brewing step
BuddingAmethystBlock.randomTick port crates/horizon-world/src/level/tick.rs::Sim::budding_amethyst_tick
BushBlock.performBonemeal port crates/horizon-world/src/level/bonemeal.rs::Sim::perform_bonemeal
CactusFlowerBlock.mayPlaceOn port crates/horizon-world/src/level/survive.rs::Sim::may_place_on
1 TradeRebalanceVillagerTrades skip:data rebalanced villager trade definitions are data; Horizon reads trade_set JSON (merchant.rs Trades::load)
4 BlockCollisions.<init> port crates/horizon-world/src/block_collision_scan.rs::BlockCollisionScan::new scan set-up over the box
5 BlockCollisions.computeNext port crates/horizon-world/src/block_collision_scan.rs::BlockCollisionScan::find_next next block shape along the box
6 BlockCollisions.getChunk inline crates/horizon-world/src/block_collision_scan.rs::BlockCollisionScan::find_next chunk fetch through collision_chunk inside find_next
7 CardinalLighting.byFace port crates/horizon-client/src/mesher/lighting.rs::cardinal crates/horizon-client-render/src/mesher/lighting.rs::cardinal per-face directional shade; nether flag handled in the same fn
8 ClipContext.getFluidShape inline crates/horizon-world/src/world_ray.rs::clip_world pick_fluid decides canPick; the shape is clipped in clip_world
9 ColorMapColorUtil.get port crates/horizon-client/src/biome.rs::sample crates/horizon-client-render/src/biome.rs::sample colormap lookup by temperature and downfall
10 EntityBasedExplosionDamageCalculator.getBlockExplosionResistance missing unsure: source-entity overrides (wither skull, minecart TNT, primed TNT keeping nether portals) are not read; explosion_hit_block uses the block's own resistance
11 ExplosionDamageCalculator.getEntityDamageAmount inline crates/horizon-client/src/game/explosion.rs::Game::explosion_hurt_entities damage formula inline; the player copy is in explosion_hurt_player
12 LevelSettings.copy skip:java immutable record copy; Horizon keeps level fields on its own struct
103 BonemealableFeaturePlacerBlock.performBonemeal port crates/horizon-world/src/level/bonemeal.rs::Behaviours::place_feature places the configured feature
104 BrewingStandBlock.animateTick port crates/horizon-client/src/animate_tick.rs::block_animate_tick brewing bubbles
105 BrewingStandBlock.createBlockStateDefinition skip:data block state definition is data (blocks table in horizon-items)
106 BrewingStandBlock.getTicker port crates/horizon-client/src/brewing.rs::BrewingStand::brew crates/horizon-client-render/src/brewing.rs::BrewingStand::brew the stand's brewing step
107 BuddingAmethystBlock.randomTick port crates/horizon-world/src/level/tick.rs::Sim::budding_amethyst_tick
108 BushBlock.performBonemeal port crates/horizon-world/src/level/bonemeal.rs::Sim::perform_bonemeal
109 CactusFlowerBlock.mayPlaceOn port crates/horizon-world/src/level/survive.rs::Sim::may_place_on
+10 -10
View File
@@ -145,7 +145,7 @@ CopperGolemStatueBlockEntity.createStatue port crates/horizon-client/src/game/co
CopperGolemStatueBlockEntity.getItem port crates/horizon-client/src/game/block_items.rs::Game::picked_stack statue pose on the picked item
CopperGolemStatueBlockEntity.initCopperGolem port crates/horizon-client/src/game/copper_golems.rs::Game::use_golem_statue axe on an unaffected statue brings the golem back
DecoratedPotPatterns skip:data bootstrap and asset registration
EnchantingTableBlockEntity.bookAnimationTick port crates/horizon-client/src/block_entity_anim.rs::EnchantingBook::tick
EnchantingTableBlockEntity.bookAnimationTick port crates/horizon-client-render/src/block_entity_anim.rs::EnchantingBook::tick
ListBackedContainer skip:java slot helpers over a plain list
PotDecorations.addSideDetailsToTooltip port crates/horizon-client/src/item_tooltip.rs::TooltipDisplay::detail_lines sherd lines of the decorated pot tooltip
PotDecorations.allBrick skip:data constant brick decoration set
@@ -165,10 +165,10 @@ RandomizableContainerBlockEntity.applyImplicitComponents missing minor: a chest
RandomizableContainerBlockEntity.canOpen missing unsure: minor: the spectator and loot-table open checks were not found
RandomizableContainerBlockEntity.collectImplicitComponents missing minor: a container does not save its loot table onto the item it drops
RandomizableContainerBlockEntity.createMenu port crates/horizon-client/src/game.rs::Game::open_menu gap: minor: the spectator and loot-table checks are not ported here
SculkSensorBlockEntity.loadAdditional port crates/horizon-client/src/sculk.rs::SculkEntity::load
SculkSensorBlockEntity.saveAdditional port crates/horizon-client/src/sculk.rs::SculkEntity::to_nbt
SculkSensorBlockEntity.VibrationUser.canReceiveVibration port crates/horizon-client/src/sculk.rs::valid_vibration
SculkSensorBlockEntity.VibrationUser.onReceiveVibration port crates/horizon-client/src/sculk.rs::Data::schedule
SculkSensorBlockEntity.loadAdditional port crates/horizon-client-render/src/sculk.rs::SculkEntity::load
SculkSensorBlockEntity.saveAdditional port crates/horizon-client-render/src/sculk.rs::SculkEntity::to_nbt
SculkSensorBlockEntity.VibrationUser.canReceiveVibration port crates/horizon-client-render/src/sculk.rs::valid_vibration
SculkSensorBlockEntity.VibrationUser.onReceiveVibration port crates/horizon-client-render/src/sculk.rs::Data::schedule
TestBlockEntity missing minor: game-test block entity; reset, trigger and logging are not ported, NBT only
TestInstanceBlockEntity missing minor: game-test structure tooling; export and chunk forcing are not ported
TrialSpawnerConfig.calculateTargetSimultaneousMobs port crates/horizon-client/src/mobs/trial_spawner.rs::TrialConfig::target_simultaneous_mobs
@@ -204,7 +204,7 @@ LinearPalette skip:java palette storage; Horizon's chunk.rs keeps block ids in
PalettedContainerFactory skip:java factory for palette storage; Horizon's chunk.rs keeps block ids in plain arrays
SingleValuePalette skip:java palette storage; Horizon's chunk.rs keeps block ids in plain arrays
UpgradeData missing unsure: minor: block upgrades of old chunks on load are not ported
ChunkDependencies.getRadiusOf inline crates/horizon-client/src/streaming.rs::Ranges::margins fixed margins instead of a per-status radius
ChunkDependencies.getRadiusOf inline crates/horizon-client-render/src/streaming.rs::Ranges::margins fixed margins instead of a per-status radius
ChunkPyramid.Builder skip:java builder for the status pyramid; Horizon uses fixed margins
ChunkStatusTasks.buildTerrain inline crates/horizon-world/src/worldgen/generator.rs::Pipeline::generate_with_context terrain pass
ChunkStatusTasks.collectPossibleBiomes inline crates/horizon-world/src/worldgen/generator.rs::Pipeline::biome_chunk biome set folded into the biome pass
@@ -214,11 +214,11 @@ ChunkStatusTasks.generateFeatures port crates/horizon-world/src/worldgen/generat
ChunkStatusTasks.generateSpawn port crates/horizon-world/src/worldgen/spawn_finder.rs::find_spawn_position
ChunkStatusTasks.generateStructureReferences port crates/horizon-world/src/worldgen/generator_structures.rs::StructureState::references
ChunkStatusTasks.generateStructureStarts port crates/horizon-world/src/worldgen/generator_structures.rs::StructureState::starts_at
ChunkStatusTasks.initializeLight port crates/horizon-client/src/light.rs::light_chunk
ChunkStatusTasks.initializeLight port crates/horizon-client-render/src/light.rs::light_chunk
ChunkStatusTasks.isLighted skip:other status check; streaming tracks which chunks are lit
ChunkStep.apply inline crates/horizon-client/src/streaming.rs::Streaming::update stage advance
ChunkStep.completeChunkGeneration inline crates/horizon-client/src/streaming.rs::Streaming::update final stage hand-over
ChunkStep.getAccumulatedRadiusOf inline crates/horizon-client/src/streaming.rs::Ranges::margins fixed margins
ChunkStep.apply inline crates/horizon-client-render/src/streaming.rs::Streaming::update stage advance
ChunkStep.completeChunkGeneration inline crates/horizon-client-render/src/streaming.rs::Streaming::update final stage hand-over
ChunkStep.getAccumulatedRadiusOf inline crates/horizon-client-render/src/streaming.rs::Ranges::margins fixed margins
ChunkStep.Builder skip:java builder for chunk steps
ChunkIOErrorReporter.createMisplacedChunkReport skip:other report text for a chunk saved at another position; Horizon logs its own load error
RecreatingSimpleRegionStorage skip:java close: Rust closes the file on drop
1 RodBlock.mirror port crates/horizon-world/src/worldgen/structure.rs::StateTransforms::mirror rod facing mirrored through the state table
145 CopperGolemStatueBlockEntity.getItem port crates/horizon-client/src/game/block_items.rs::Game::picked_stack statue pose on the picked item
146 CopperGolemStatueBlockEntity.initCopperGolem port crates/horizon-client/src/game/copper_golems.rs::Game::use_golem_statue axe on an unaffected statue brings the golem back
147 DecoratedPotPatterns skip:data bootstrap and asset registration
148 EnchantingTableBlockEntity.bookAnimationTick port crates/horizon-client/src/block_entity_anim.rs::EnchantingBook::tick crates/horizon-client-render/src/block_entity_anim.rs::EnchantingBook::tick
149 ListBackedContainer skip:java slot helpers over a plain list
150 PotDecorations.addSideDetailsToTooltip port crates/horizon-client/src/item_tooltip.rs::TooltipDisplay::detail_lines sherd lines of the decorated pot tooltip
151 PotDecorations.allBrick skip:data constant brick decoration set
165 RandomizableContainerBlockEntity.canOpen missing unsure: minor: the spectator and loot-table open checks were not found
166 RandomizableContainerBlockEntity.collectImplicitComponents missing minor: a container does not save its loot table onto the item it drops
167 RandomizableContainerBlockEntity.createMenu port crates/horizon-client/src/game.rs::Game::open_menu gap: minor: the spectator and loot-table checks are not ported here
168 SculkSensorBlockEntity.loadAdditional port crates/horizon-client/src/sculk.rs::SculkEntity::load crates/horizon-client-render/src/sculk.rs::SculkEntity::load
169 SculkSensorBlockEntity.saveAdditional port crates/horizon-client/src/sculk.rs::SculkEntity::to_nbt crates/horizon-client-render/src/sculk.rs::SculkEntity::to_nbt
170 SculkSensorBlockEntity.VibrationUser.canReceiveVibration port crates/horizon-client/src/sculk.rs::valid_vibration crates/horizon-client-render/src/sculk.rs::valid_vibration
171 SculkSensorBlockEntity.VibrationUser.onReceiveVibration port crates/horizon-client/src/sculk.rs::Data::schedule crates/horizon-client-render/src/sculk.rs::Data::schedule
172 TestBlockEntity missing minor: game-test block entity; reset, trigger and logging are not ported, NBT only
173 TestInstanceBlockEntity missing minor: game-test structure tooling; export and chunk forcing are not ported
174 TrialSpawnerConfig.calculateTargetSimultaneousMobs port crates/horizon-client/src/mobs/trial_spawner.rs::TrialConfig::target_simultaneous_mobs
204 PalettedContainerFactory skip:java factory for palette storage; Horizon's chunk.rs keeps block ids in plain arrays
205 SingleValuePalette skip:java palette storage; Horizon's chunk.rs keeps block ids in plain arrays
206 UpgradeData missing unsure: minor: block upgrades of old chunks on load are not ported
207 ChunkDependencies.getRadiusOf inline crates/horizon-client/src/streaming.rs::Ranges::margins crates/horizon-client-render/src/streaming.rs::Ranges::margins fixed margins instead of a per-status radius
208 ChunkPyramid.Builder skip:java builder for the status pyramid; Horizon uses fixed margins
209 ChunkStatusTasks.buildTerrain inline crates/horizon-world/src/worldgen/generator.rs::Pipeline::generate_with_context terrain pass
210 ChunkStatusTasks.collectPossibleBiomes inline crates/horizon-world/src/worldgen/generator.rs::Pipeline::biome_chunk biome set folded into the biome pass
214 ChunkStatusTasks.generateSpawn port crates/horizon-world/src/worldgen/spawn_finder.rs::find_spawn_position
215 ChunkStatusTasks.generateStructureReferences port crates/horizon-world/src/worldgen/generator_structures.rs::StructureState::references
216 ChunkStatusTasks.generateStructureStarts port crates/horizon-world/src/worldgen/generator_structures.rs::StructureState::starts_at
217 ChunkStatusTasks.initializeLight port crates/horizon-client/src/light.rs::light_chunk crates/horizon-client-render/src/light.rs::light_chunk
218 ChunkStatusTasks.isLighted skip:other status check; streaming tracks which chunks are lit
219 ChunkStep.apply inline crates/horizon-client/src/streaming.rs::Streaming::update crates/horizon-client-render/src/streaming.rs::Streaming::update stage advance
220 ChunkStep.completeChunkGeneration inline crates/horizon-client/src/streaming.rs::Streaming::update crates/horizon-client-render/src/streaming.rs::Streaming::update final stage hand-over
221 ChunkStep.getAccumulatedRadiusOf inline crates/horizon-client/src/streaming.rs::Ranges::margins crates/horizon-client-render/src/streaming.rs::Ranges::margins fixed margins
222 ChunkStep.Builder skip:java builder for chunk steps
223 ChunkIOErrorReporter.createMisplacedChunkReport skip:other report text for a chunk saved at another position; Horizon logs its own load error
224 RecreatingSimpleRegionStorage skip:java close: Rust closes the file on drop
+3 -3
View File
@@ -44,9 +44,9 @@ EuclideanGameEventListenerRegistry.unregister port crates/horizon-client/src/gam
EuclideanGameEventListenerRegistry.visitInRangeListeners port crates/horizon-client/src/game/sculk.rs::Game::post_game_event walks the index for listeners in range, then the wardens
VibrationInfo.getEntity port crates/horizon-client/src/game/sculk.rs::Game::sculk_receive the source is held as a Who and read there
VibrationInfo.getProjectileOwner port crates/horizon-client/src/game/sculk.rs::Game::sculk_receive the projectile owner is captured when posted (info.owner) and read there
VibrationSelector.addCandidate port crates/horizon-client/src/sculk.rs::Selector::add_candidate
VibrationSelector.chosenCandidate port crates/horizon-client/src/sculk.rs::Selector::chosen_candidate
VibrationSelector.shouldReplaceVibration port crates/horizon-client/src/sculk.rs::Selector::should_replace
VibrationSelector.addCandidate port crates/horizon-client-render/src/sculk.rs::Selector::add_candidate
VibrationSelector.chosenCandidate port crates/horizon-client-render/src/sculk.rs::Selector::chosen_candidate
VibrationSelector.shouldReplaceVibration port crates/horizon-client-render/src/sculk.rs::Selector::should_replace
GameRuleCategory.register skip:data static category table; Horizon's rule categories are static strings (gamerules.rs)
GameRuleMap.equals skip:java value equality of the map
GameRuleMap.of port crates/horizon-client-core/src/gamerules.rs::GameRules::get no stored map: a rule that was never set reads its table default
1 RegionFileVersion.configure missing minor: region-file-compression is read from server.properties (horizon-server-files properties.rs) but nothing applies it; chunk saves always write zlib (save.rs compress_records)
44 EuclideanGameEventListenerRegistry.visitInRangeListeners port crates/horizon-client/src/game/sculk.rs::Game::post_game_event walks the index for listeners in range, then the wardens
45 VibrationInfo.getEntity port crates/horizon-client/src/game/sculk.rs::Game::sculk_receive the source is held as a Who and read there
46 VibrationInfo.getProjectileOwner port crates/horizon-client/src/game/sculk.rs::Game::sculk_receive the projectile owner is captured when posted (info.owner) and read there
47 VibrationSelector.addCandidate port crates/horizon-client/src/sculk.rs::Selector::add_candidate crates/horizon-client-render/src/sculk.rs::Selector::add_candidate
48 VibrationSelector.chosenCandidate port crates/horizon-client/src/sculk.rs::Selector::chosen_candidate crates/horizon-client-render/src/sculk.rs::Selector::chosen_candidate
49 VibrationSelector.shouldReplaceVibration port crates/horizon-client/src/sculk.rs::Selector::should_replace crates/horizon-client-render/src/sculk.rs::Selector::should_replace
50 GameRuleCategory.register skip:data static category table; Horizon's rule categories are static strings (gamerules.rs)
51 GameRuleMap.equals skip:java value equality of the map
52 GameRuleMap.of port crates/horizon-client-core/src/gamerules.rs::GameRules::get no stored map: a rule that was never set reads its table default
+18 -18
View File
@@ -132,32 +132,32 @@ GradientNoise.Gradient.dotXz inline crates/horizon-core/src/noise/perlin.rs::Sme
LegacyFbmInitializer.createForLegacyNetherBiome port crates/horizon-core/src/noise/normal.rs::create_legacy_fbm
NoiseUtils.biasTowardsExtreme skip:other no caller in the vanilla 26.3 sources
NoiseUtils.parityNoiseOctaveConfigString skip:debug debug text
BlockLightEngine.checkNode inline crates/horizon-client/src/light.rs::relight_layer neighbour checks in both passes
BlockLightEngine.getEmission port crates/horizon-client/src/light.rs::LightTables::emission
BlockLightEngine.propagateDecrease port crates/horizon-client/src/light.rs::relight_layer decrease pass, sky false
BlockLightEngine.propagateIncrease port crates/horizon-client/src/light.rs::relight_layer increase pass, sky false
BlockLightEngine.propagateLightSources inline crates/horizon-client/src/light.rs::relight_layer emission seeds for cleared cells
BlockLightSectionStorage.getLightValue port crates/horizon-client/src/light.rs::level
BlockLightEngine.checkNode inline crates/horizon-client-render/src/light.rs::relight_layer neighbour checks in both passes
BlockLightEngine.getEmission port crates/horizon-client-render/src/light.rs::LightTables::emission
BlockLightEngine.propagateDecrease port crates/horizon-client-render/src/light.rs::relight_layer decrease pass, sky false
BlockLightEngine.propagateIncrease port crates/horizon-client-render/src/light.rs::relight_layer increase pass, sky false
BlockLightEngine.propagateLightSources inline crates/horizon-client-render/src/light.rs::relight_layer emission seeds for cleared cells
BlockLightSectionStorage.getLightValue port crates/horizon-client-render/src/light.rs::level
DataLayerStorageMap skip:java cache of light data layers keyed by section
DynamicGraphMinFixedPoint.checkEdge inline crates/horizon-client/src/light.rs::relight_layer edge test inside the passes
DynamicGraphMinFixedPoint.checkNeighbor inline crates/horizon-client/src/light.rs::relight_layer neighbour test inside the passes
DynamicGraphMinFixedPoint.checkEdge inline crates/horizon-client-render/src/light.rs::relight_layer edge test inside the passes
DynamicGraphMinFixedPoint.checkNeighbor inline crates/horizon-client-render/src/light.rs::relight_layer neighbour test inside the passes
DynamicGraphMinFixedPoint.removeFromQueue skip:java queue bookkeeping; the passes never remove queued entries
DynamicGraphMinFixedPoint.removeIf skip:java queue bookkeeping
DynamicGraphMinFixedPoint.runUpdates port crates/horizon-client/src/light.rs::relight_layer runs the decrease and increase passes
DynamicGraphMinFixedPoint.runUpdates port crates/horizon-client-render/src/light.rs::relight_layer runs the decrease and increase passes
LayerLightSectionStorage skip:other per-section light data bookkeeping; Horizon keeps light in chunk sections (light.rs apply_lighting, light_chunk)
LayerLightSectionStorage.SectionState skip:other section state flags of the light storage; no Horizon equivalent needed
LeveledPriorityQueue skip:java priority queue of light levels; relight_layer runs two FIFO passes
SkyLightEngine.addSourcesAbove inline crates/horizon-client/src/light.rs::relight_region column sources loop
SkyLightEngine.checkNode inline crates/horizon-client/src/light.rs::relight_layer neighbour checks in the sky passes
SkyLightEngine.addSourcesAbove inline crates/horizon-client-render/src/light.rs::relight_region column sources loop
SkyLightEngine.checkNode inline crates/horizon-client-render/src/light.rs::relight_layer neighbour checks in the sky passes
SkyLightEngine.countEmptySectionsBelowIfAtBorder skip:java shortcut over empty sections; Horizon relights a region directly
SkyLightEngine.crossedSectionEdge port crates/horizon-client/src/light.rs::LightChanges::class edge flags of a changed cell
SkyLightEngine.crossedSectionEdge port crates/horizon-client-render/src/light.rs::LightChanges::class edge flags of a changed cell
SkyLightEngine.getChunkSources skip:java per-chunk source cache; lowest_sky_source computes each column on demand
SkyLightEngine.getLowestSourceY port crates/horizon-client/src/light.rs::lowest_sky_source
SkyLightEngine.propagateDecrease port crates/horizon-client/src/light.rs::relight_layer decrease pass, sky true
SkyLightEngine.propagateFromEmptySections inline crates/horizon-client/src/light.rs::relight_region sky seeds below the source in each column
SkyLightEngine.propagateIncrease port crates/horizon-client/src/light.rs::relight_layer increase pass, sky true
SkyLightEngine.propagateLightSources inline crates/horizon-client/src/light.rs::relight_layer sky sources inside the cleared area
SkyLightEngine.removeSourcesBelow inline crates/horizon-client/src/light.rs::relight_region column sources loop
SkyLightEngine.getLowestSourceY port crates/horizon-client-render/src/light.rs::lowest_sky_source
SkyLightEngine.propagateDecrease port crates/horizon-client-render/src/light.rs::relight_layer decrease pass, sky true
SkyLightEngine.propagateFromEmptySections inline crates/horizon-client-render/src/light.rs::relight_region sky seeds below the source in each column
SkyLightEngine.propagateIncrease port crates/horizon-client-render/src/light.rs::relight_layer increase pass, sky true
SkyLightEngine.propagateLightSources inline crates/horizon-client-render/src/light.rs::relight_layer sky sources inside the cleared area
SkyLightEngine.removeSourcesBelow inline crates/horizon-client-render/src/light.rs::relight_region column sources loop
SkyLightEngine.setLightEnabled skip:other light is computed when a chunk loads (light_chunk); no per-chunk enable flag
SkyLightSectionStorage skip:other sky data layer bookkeeping per section; Horizon keeps light in chunk sections
SkyLightSectionStorage.SkyDataLayerStorageMap skip:java copy of sky data layers; collection plumbing
1 RepeatingPlacement.modify port crates/horizon-world/src/worldgen/placement.rs::PlacementModifier::modify_inner repeat arm for Count and the noise counts emits the count
132 LegacyFbmInitializer.createForLegacyNetherBiome port crates/horizon-core/src/noise/normal.rs::create_legacy_fbm
133 NoiseUtils.biasTowardsExtreme skip:other no caller in the vanilla 26.3 sources
134 NoiseUtils.parityNoiseOctaveConfigString skip:debug debug text
135 BlockLightEngine.checkNode inline crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer neighbour checks in both passes
136 BlockLightEngine.getEmission port crates/horizon-client/src/light.rs::LightTables::emission crates/horizon-client-render/src/light.rs::LightTables::emission
137 BlockLightEngine.propagateDecrease port crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer decrease pass, sky false
138 BlockLightEngine.propagateIncrease port crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer increase pass, sky false
139 BlockLightEngine.propagateLightSources inline crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer emission seeds for cleared cells
140 BlockLightSectionStorage.getLightValue port crates/horizon-client/src/light.rs::level crates/horizon-client-render/src/light.rs::level
141 DataLayerStorageMap skip:java cache of light data layers keyed by section
142 DynamicGraphMinFixedPoint.checkEdge inline crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer edge test inside the passes
143 DynamicGraphMinFixedPoint.checkNeighbor inline crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer neighbour test inside the passes
144 DynamicGraphMinFixedPoint.removeFromQueue skip:java queue bookkeeping; the passes never remove queued entries
145 DynamicGraphMinFixedPoint.removeIf skip:java queue bookkeeping
146 DynamicGraphMinFixedPoint.runUpdates port crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer runs the decrease and increase passes
147 LayerLightSectionStorage skip:other per-section light data bookkeeping; Horizon keeps light in chunk sections (light.rs apply_lighting, light_chunk)
148 LayerLightSectionStorage.SectionState skip:other section state flags of the light storage; no Horizon equivalent needed
149 LeveledPriorityQueue skip:java priority queue of light levels; relight_layer runs two FIFO passes
150 SkyLightEngine.addSourcesAbove inline crates/horizon-client/src/light.rs::relight_region crates/horizon-client-render/src/light.rs::relight_region column sources loop
151 SkyLightEngine.checkNode inline crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer neighbour checks in the sky passes
152 SkyLightEngine.countEmptySectionsBelowIfAtBorder skip:java shortcut over empty sections; Horizon relights a region directly
153 SkyLightEngine.crossedSectionEdge port crates/horizon-client/src/light.rs::LightChanges::class crates/horizon-client-render/src/light.rs::LightChanges::class edge flags of a changed cell
154 SkyLightEngine.getChunkSources skip:java per-chunk source cache; lowest_sky_source computes each column on demand
155 SkyLightEngine.getLowestSourceY port crates/horizon-client/src/light.rs::lowest_sky_source crates/horizon-client-render/src/light.rs::lowest_sky_source
156 SkyLightEngine.propagateDecrease port crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer decrease pass, sky true
157 SkyLightEngine.propagateFromEmptySections inline crates/horizon-client/src/light.rs::relight_region crates/horizon-client-render/src/light.rs::relight_region sky seeds below the source in each column
158 SkyLightEngine.propagateIncrease port crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer increase pass, sky true
159 SkyLightEngine.propagateLightSources inline crates/horizon-client/src/light.rs::relight_layer crates/horizon-client-render/src/light.rs::relight_layer sky sources inside the cleared area
160 SkyLightEngine.removeSourcesBelow inline crates/horizon-client/src/light.rs::relight_region crates/horizon-client-render/src/light.rs::relight_region column sources loop
161 SkyLightEngine.setLightEnabled skip:other light is computed when a chunk loads (light_chunk); no per-chunk enable flag
162 SkyLightSectionStorage skip:other sky data layer bookkeeping per section; Horizon keeps light in chunk sections
163 SkyLightSectionStorage.SkyDataLayerStorageMap skip:java copy of sky data layers; collection plumbing
+3 -3
View File
@@ -71,7 +71,7 @@ floats/Minimum.getFloatUnsafe port crates/horizon-client/src/game/commands/compu
floats/Modulus.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float mod arm
floats/Product.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float mul arm
floats/Quotient.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float div arm
ResolvableFloat.getFromItem port crates/horizon-client/src/providers.rs::Providers::speed furnace fuel speed multiplier (COOKING_FUEL); gap: minor: only the furnace fuel component is read
ResolvableFloat.getFromItem port crates/horizon-client-render/src/providers.rs::Providers::speed furnace fuel speed multiplier (COOKING_FUEL); gap: minor: only the furnace fuel component is read
ResolvableFloat.wrap skip:java codec helper
floats/StorageValue missing minor: no vanilla data uses storage providers
floats/Sum.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float add arm
@@ -83,7 +83,7 @@ ints/BinomialDistributionGenerator.getIntUnsafe port crates/horizon-world/src/lo
ints/BinomialDistributionGenerator.validate skip:data datapack validation
ints/ContextIntProviders.bootstrap skip:data registry bootstrap
ints/ContextIntProviders.compostable port crates/horizon-client/src/game/composter.rs::Game::compostable the item's compostable layer provider; evaluated when the composter takes it (Game::composter_add)
ints/ContextIntProviders.cooking port crates/horizon-client/src/providers.rs::Providers::burn_time fuel burn times (the cooking/time_* providers)
ints/ContextIntProviders.cooking port crates/horizon-client-render/src/providers.rs::Providers::burn_time fuel burn times (the cooking/time_* providers)
ints/Difference.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int sub arm
ints/EnvironmentAttributeValue missing minor: no vanilla data uses environment_attribute providers
ints/FloorModulus.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int floor_mod arm
@@ -93,7 +93,7 @@ ints/Minimum.getIntUnsafe port crates/horizon-client/src/game/commands/compute.r
ints/Modulus.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int mod arm
ints/Product.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int mul arm
ints/Quotient.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int div arm
ResolvableInt.getFromItem port crates/horizon-client/src/providers.rs::Providers::burn_time furnace fuel burn time (COOKING_FUEL); gap: minor: only the furnace fuel component is read
ResolvableInt.getFromItem port crates/horizon-client-render/src/providers.rs::Providers::burn_time furnace fuel burn time (COOKING_FUEL); gap: minor: only the furnace fuel component is read
ResolvableInt.wrap skip:java codec helper
ints/ScoreboardValue.getIntUnsafe missing minor: no vanilla data uses score providers
ints/ScoreboardValue.getScoreInfo missing minor: no vanilla data uses score providers
1 SetStewEffectFunction.Builder skip:java builder for the stew effect list; Horizon keeps the effects in loot.rs Context::run (set_stew_effect)
71 floats/Modulus.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float mod arm
72 floats/Product.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float mul arm
73 floats/Quotient.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float div arm
74 ResolvableFloat.getFromItem port crates/horizon-client/src/providers.rs::Providers::speed crates/horizon-client-render/src/providers.rs::Providers::speed furnace fuel speed multiplier (COOKING_FUEL); gap: minor: only the furnace fuel component is read
75 ResolvableFloat.wrap skip:java codec helper
76 floats/StorageValue missing minor: no vanilla data uses storage providers
77 floats/Sum.getFloatUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_float add arm
83 ints/BinomialDistributionGenerator.validate skip:data datapack validation
84 ints/ContextIntProviders.bootstrap skip:data registry bootstrap
85 ints/ContextIntProviders.compostable port crates/horizon-client/src/game/composter.rs::Game::compostable the item's compostable layer provider; evaluated when the composter takes it (Game::composter_add)
86 ints/ContextIntProviders.cooking port crates/horizon-client/src/providers.rs::Providers::burn_time crates/horizon-client-render/src/providers.rs::Providers::burn_time fuel burn times (the cooking/time_* providers)
87 ints/Difference.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int sub arm
88 ints/EnvironmentAttributeValue missing minor: no vanilla data uses environment_attribute providers
89 ints/FloorModulus.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int floor_mod arm
93 ints/Modulus.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int mod arm
94 ints/Product.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int mul arm
95 ints/Quotient.getIntUnsafe port crates/horizon-client/src/game/commands/compute.rs::Game::provider_int div arm
96 ResolvableInt.getFromItem port crates/horizon-client/src/providers.rs::Providers::burn_time crates/horizon-client-render/src/providers.rs::Providers::burn_time furnace fuel burn time (COOKING_FUEL); gap: minor: only the furnace fuel component is read
97 ResolvableInt.wrap skip:java codec helper
98 ints/ScoreboardValue.getIntUnsafe missing minor: no vanilla data uses score providers
99 ints/ScoreboardValue.getScoreInfo missing minor: no vanilla data uses score providers
+2 -2
View File
@@ -10,9 +10,9 @@ LevelChunkTicks.poll port crates/horizon-core/src/ticks/mod.rs::ChunkTicks::poll
LevelChunkTicks.removeIf port crates/horizon-core/src/ticks/mod.rs::ChunkTicks::remove_if
LevelChunkTicks.scheduleUnchecked inline crates/horizon-core/src/ticks/mod.rs::ChunkTicks::schedule gap: minor: push only, no duplicate check (the unpack path is in ChunkTicks::unpack); the onTickAdded deadline update is in LevelTicks::schedule
LevelChunkTicks.unpack port crates/horizon-core/src/ticks/mod.rs::ChunkTicks::unpack gap: minor: the deadline refresh is in LevelTicks::unpack_chunk
AttributeTrack.bakeSampler inline crates/horizon-client/src/environment.rs::Environment::load_dimension gap: minor: builds the day timeline's tracks only (keyframes, easing, multiply); the clock holder is implicit
AttributeTrack.bakeSampler inline crates/horizon-client-render/src/environment.rs::Environment::load_dimension gap: minor: builds the day timeline's tracks only (keyframes, easing, multiply); the clock holder is implicit
AttributeTrack.createCodec skip:java codec; Horizon parses the timeline JSON in Environment::load_dimension and patrol.rs GameplayAttributes::load
AttributeTrack.createCodecWithModifier skip:java codec; same parsing as createCodec
AttributeTrack.validatePeriod skip:data load-time check of keyframes against period_ticks; Horizon reads the vanilla timeline files without it
AttributeTrackSampler.applyTimeBased port crates/horizon-client/src/environment.rs::Environment::value gap: minor: multiply and override only; star_brightness 'maximum' reads as override (same value at base 0); booleans are in patrol.rs BoolTrack or hardcoded per consumer; no per-tick cache
AttributeTrackSampler.applyTimeBased port crates/horizon-client-render/src/environment.rs::Environment::value gap: minor: multiply and override only; star_brightness 'maximum' reads as override (same value at base 0); booleans are in patrol.rs BoolTrack or hardcoded per consumer; no per-tick cache
Timelines.bootstrap skip:data registers the timelines in code; Horizon reads data/minecraft/timeline/*.json, and the few day-cycle numbers it needs are in level/timeline.rs
1 SubShape.clampToShape inline crates/horizon-core/src/geometry/shape/face.rs::VoxelShape::calculate_face clamps the parent's discrete extrema to the slice (face.rs:43-46)
10 LevelChunkTicks.removeIf port crates/horizon-core/src/ticks/mod.rs::ChunkTicks::remove_if
11 LevelChunkTicks.scheduleUnchecked inline crates/horizon-core/src/ticks/mod.rs::ChunkTicks::schedule gap: minor: push only, no duplicate check (the unpack path is in ChunkTicks::unpack); the onTickAdded deadline update is in LevelTicks::schedule
12 LevelChunkTicks.unpack port crates/horizon-core/src/ticks/mod.rs::ChunkTicks::unpack gap: minor: the deadline refresh is in LevelTicks::unpack_chunk
13 AttributeTrack.bakeSampler inline crates/horizon-client/src/environment.rs::Environment::load_dimension crates/horizon-client-render/src/environment.rs::Environment::load_dimension gap: minor: builds the day timeline's tracks only (keyframes, easing, multiply); the clock holder is implicit
14 AttributeTrack.createCodec skip:java codec; Horizon parses the timeline JSON in Environment::load_dimension and patrol.rs GameplayAttributes::load
15 AttributeTrack.createCodecWithModifier skip:java codec; same parsing as createCodec
16 AttributeTrack.validatePeriod skip:data load-time check of keyframes against period_ticks; Horizon reads the vanilla timeline files without it
17 AttributeTrackSampler.applyTimeBased port crates/horizon-client/src/environment.rs::Environment::value crates/horizon-client-render/src/environment.rs::Environment::value gap: minor: multiply and override only; star_brightness 'maximum' reads as override (same value at base 0); booleans are in patrol.rs BoolTrack or hardcoded per consumer; no per-tick cache
18 Timelines.bootstrap skip:data registers the timelines in code; Horizon reads data/minecraft/timeline/*.json, and the few day-cycle numbers it needs are in level/timeline.rs
+7 -7
View File
@@ -11,13 +11,13 @@ ClientAdvancements.setSelectedTab port crates/horizon-client/src/game/advancemen
ClientAdvancements.setListener skip:ui listener plumbing for the advancements screen; Horizon's screen reads its state each frame
ClientAdvancements.get port crates/horizon-client/src/advancements.rs::Tree::get returns the advancement by id; holder wrapper is not needed
ClientChunkCache.isValidChunk skip:other chunks are stored by position, so there is no ring slot to check
ClientChunkCache.drop port crates/horizon-client/src/streaming.rs::Streaming::forget gap: minor: no ChunkEvent unload hook; block entities and renderer columns are cleared in Game::handle_packet
ClientChunkCache.drop port crates/horizon-client-render/src/streaming.rs::Streaming::forget gap: minor: no ChunkEvent unload hook; block entities and renderer columns are cleared in Game::handle_packet
ClientChunkCache.getChunk skip:java lookup of a loaded chunk; Horizon reads world.chunks directly
ClientChunkCache.replaceBiomes missing minor: ChunksBiomes (id 13) has no arm in Game::handle_packet, so server biome changes (e.g. /fillbiome) do not reach the client until the chunk is resent
ClientChunkCache.flipUpdateTrackingSets skip:other double-buffered change lists for LevelRenderer; Horizon hands changed columns to the renderer directly
ClientChunkCache.Storage.getIndex skip:java ring-buffer index into the view range; Horizon keys chunks by position
ClientChunkCache.Storage.replace port crates/horizon-client/src/game/remote_chunks.rs::Game::remote_chunk gap: minor: old chunk unload is in Streaming::forget, not here
ClientChunkCache.Storage.drop port crates/horizon-client/src/streaming.rs::Streaming::forget forgets the chunk at the index
ClientChunkCache.Storage.drop port crates/horizon-client-render/src/streaming.rs::Streaming::forget forgets the chunk at the index
ClientChunkCache.Storage.onSectionEmptinessChanged skip:java empty-section sets for the renderer's culling; Horizon's mesher works from block data
ClientChunkCache.Storage.onChunkRemoved skip:java empty-section bookkeeping when a chunk leaves; see Storage.onSectionEmptinessChanged
ClientChunkCache.Storage.onChunkAdded skip:java empty-section bookkeeping when a chunk arrives; see Storage.onSectionEmptinessChanged
@@ -71,8 +71,8 @@ ClientDebugSubscriber.ValueMap.forEach skip:java iteration helper
ClientDebugSubscriber.ValueMaps.purgeExpired missing minor: expiry of server debug values; none are received
ClientDebugSubscriber.ValueMaps.dropChunkAndBlocks missing minor: drops server debug values per chunk; none are received
ClientDebugSubscriber.ValueWrapper.hasExpired skip:java timestamp check on a debug value wrapper
ClientExplosionTracker.track inline crates/horizon-client/src/particles.rs::ParticleEngine::explosion gap: minor: the debris is thrown at once instead of queued for later ticks
ClientExplosionTracker.addParticle port crates/horizon-client/src/particles.rs::ParticleEngine::explosion_blocks gap: minor: always the default poof and smoke list; the explode packet's own block particle list is not read
ClientExplosionTracker.track inline crates/horizon-client-render/src/particles.rs::ParticleEngine::explosion gap: minor: the debris is thrown at once instead of queued for later ticks
ClientExplosionTracker.addParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::explosion_blocks gap: minor: always the default poof and smoke list; the explode packet's own block particle list is not read
ClientHandshakePacketListenerImpl.switchState inline crates/horizon-client/src/net.rs::run login steps run in packet order in run(); no state machine
ClientHandshakePacketListenerImpl.handleHello port crates/horizon-client/src/net.rs::run gap: minor: the session join and server check are in auth.rs (join_server); the encryption setup is in run
ClientHandshakePacketListenerImpl.setEncryption port crates/horizon-client/src/net.rs::run enables the connection cipher
@@ -107,10 +107,10 @@ ClientLevel.playPlayerSound skip:other no caller in the 26.3 client sources
ClientLevel.playSound missing player: distance-delayed sounds (over 10 blocks, sqrt(distance)/40 s) play at once, so far fireworks and similar sounds arrive early; audio.rs has no delay
ClientLevel.getRelativeTickSpeed skip:other no caller in the 26.3 client sources
ClientLevel.destroyBlockProgress port crates/horizon-client/src/game.rs::Game::destroy_block_progress sets or clears another player's crack on a block
ClientLevel.addAlwaysVisibleParticle port crates/horizon-client/src/particles.rs::ParticleEngine::add_with always-show flag set
ClientLevel.doAddParticle port crates/horizon-client/src/particles.rs::ParticleEngine::add_with drops particles beyond 32 blocks and at minimal particle level
ClientLevel.addAlwaysVisibleParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::add_with always-show flag set
ClientLevel.doAddParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::add_with drops particles beyond 32 blocks and at minimal particle level
ClientLevel.getSkyFlashTime inline crates/horizon-client/src/game.rs::Game::render the flash check with the hideLightningFlashes option
ClientLevel.calculateBlockTint port crates/horizon-client/src/mesher.rs::MeshTables::terrain_particle_tint gap: minor: returns none for grass-block tints
ClientLevel.calculateBlockTint port crates/horizon-client-render/src/mesher.rs::MeshTables::terrain_particle_tint gap: minor: returns none for grass-block tints
ClientLevel.playBreakingSound port crates/horizon-client/src/game/level_particles.rs::Game::breaking_block_effects the block's hit sound while digging
ClientLevel.getClientLeafTintColor port crates/horizon-client/src/animate_tick.rs::AnimateContext::foliage leaf tint for tinted leaves particles; the caller is TintedParticleLeavesBlock
ClientLevel.EntityCallbacks.onTrackingStart inline crates/horizon-client/src/game/remote.rs::Game::spawn_entity minor: ender dragon parts are placed by the dragon module, with no tracked parts list
1 AccountProfileKeyPairManager.prepareKeyPair skip:service Mojang profile key pair for chat signing; Horizon fetches none
11 ClientAdvancements.setListener skip:ui listener plumbing for the advancements screen; Horizon's screen reads its state each frame
12 ClientAdvancements.get port crates/horizon-client/src/advancements.rs::Tree::get returns the advancement by id; holder wrapper is not needed
13 ClientChunkCache.isValidChunk skip:other chunks are stored by position, so there is no ring slot to check
14 ClientChunkCache.drop port crates/horizon-client/src/streaming.rs::Streaming::forget crates/horizon-client-render/src/streaming.rs::Streaming::forget gap: minor: no ChunkEvent unload hook; block entities and renderer columns are cleared in Game::handle_packet
15 ClientChunkCache.getChunk skip:java lookup of a loaded chunk; Horizon reads world.chunks directly
16 ClientChunkCache.replaceBiomes missing minor: ChunksBiomes (id 13) has no arm in Game::handle_packet, so server biome changes (e.g. /fillbiome) do not reach the client until the chunk is resent
17 ClientChunkCache.flipUpdateTrackingSets skip:other double-buffered change lists for LevelRenderer; Horizon hands changed columns to the renderer directly
18 ClientChunkCache.Storage.getIndex skip:java ring-buffer index into the view range; Horizon keys chunks by position
19 ClientChunkCache.Storage.replace port crates/horizon-client/src/game/remote_chunks.rs::Game::remote_chunk gap: minor: old chunk unload is in Streaming::forget, not here
20 ClientChunkCache.Storage.drop port crates/horizon-client/src/streaming.rs::Streaming::forget crates/horizon-client-render/src/streaming.rs::Streaming::forget forgets the chunk at the index
21 ClientChunkCache.Storage.onSectionEmptinessChanged skip:java empty-section sets for the renderer's culling; Horizon's mesher works from block data
22 ClientChunkCache.Storage.onChunkRemoved skip:java empty-section bookkeeping when a chunk leaves; see Storage.onSectionEmptinessChanged
23 ClientChunkCache.Storage.onChunkAdded skip:java empty-section bookkeeping when a chunk arrives; see Storage.onSectionEmptinessChanged
71 ClientDebugSubscriber.ValueMaps.purgeExpired missing minor: expiry of server debug values; none are received
72 ClientDebugSubscriber.ValueMaps.dropChunkAndBlocks missing minor: drops server debug values per chunk; none are received
73 ClientDebugSubscriber.ValueWrapper.hasExpired skip:java timestamp check on a debug value wrapper
74 ClientExplosionTracker.track inline crates/horizon-client/src/particles.rs::ParticleEngine::explosion crates/horizon-client-render/src/particles.rs::ParticleEngine::explosion gap: minor: the debris is thrown at once instead of queued for later ticks
75 ClientExplosionTracker.addParticle port crates/horizon-client/src/particles.rs::ParticleEngine::explosion_blocks crates/horizon-client-render/src/particles.rs::ParticleEngine::explosion_blocks gap: minor: always the default poof and smoke list; the explode packet's own block particle list is not read
76 ClientHandshakePacketListenerImpl.switchState inline crates/horizon-client/src/net.rs::run login steps run in packet order in run(); no state machine
77 ClientHandshakePacketListenerImpl.handleHello port crates/horizon-client/src/net.rs::run gap: minor: the session join and server check are in auth.rs (join_server); the encryption setup is in run
78 ClientHandshakePacketListenerImpl.setEncryption port crates/horizon-client/src/net.rs::run enables the connection cipher
107 ClientLevel.playSound missing player: distance-delayed sounds (over 10 blocks, sqrt(distance)/40 s) play at once, so far fireworks and similar sounds arrive early; audio.rs has no delay
108 ClientLevel.getRelativeTickSpeed skip:other no caller in the 26.3 client sources
109 ClientLevel.destroyBlockProgress port crates/horizon-client/src/game.rs::Game::destroy_block_progress sets or clears another player's crack on a block
110 ClientLevel.addAlwaysVisibleParticle port crates/horizon-client/src/particles.rs::ParticleEngine::add_with crates/horizon-client-render/src/particles.rs::ParticleEngine::add_with always-show flag set
111 ClientLevel.doAddParticle port crates/horizon-client/src/particles.rs::ParticleEngine::add_with crates/horizon-client-render/src/particles.rs::ParticleEngine::add_with drops particles beyond 32 blocks and at minimal particle level
112 ClientLevel.getSkyFlashTime inline crates/horizon-client/src/game.rs::Game::render the flash check with the hideLightningFlashes option
113 ClientLevel.calculateBlockTint port crates/horizon-client/src/mesher.rs::MeshTables::terrain_particle_tint crates/horizon-client-render/src/mesher.rs::MeshTables::terrain_particle_tint gap: minor: returns none for grass-block tints
114 ClientLevel.playBreakingSound port crates/horizon-client/src/game/level_particles.rs::Game::breaking_block_effects the block's hit sound while digging
115 ClientLevel.getClientLeafTintColor port crates/horizon-client/src/animate_tick.rs::AnimateContext::foliage leaf tint for tinted leaves particles; the caller is TintedParticleLeavesBlock
116 ClientLevel.EntityCallbacks.onTrackingStart inline crates/horizon-client/src/game/remote.rs::Game::spawn_entity minor: ender dragon parts are placed by the dragon module, with no tracked parts list
+2 -2
View File
@@ -14,9 +14,9 @@ ClientPacketListener.setValuesFromPositionPacket port crates/horizon-client/src/
ClientPacketListener.handleRotatePlayer port crates/horizon-client/src/game/remote.rs::Game::handle_packet PlayerRotation arm; gap: minor: no ServerboundMovePlayerPacket.Rot reply is sent
ClientPacketListener.handleChunkBlocksUpdate port crates/horizon-client/src/game/remote.rs::Game::handle_packet SectionBlocksUpdate arm: each change through the block update
ClientPacketListener.handleChunksBiomes missing player: biome updates for loaded chunks are dropped, so grass, leaves and water keep the old biome colour
ClientPacketListener.enableChunkLight inline crates/horizon-client/src/streaming.rs::Streaming::insert_remote gap: minor: the air-only section status is not set; every section of the 3x3 columns is marked dirty
ClientPacketListener.enableChunkLight inline crates/horizon-client-render/src/streaming.rs::Streaming::insert_remote gap: minor: the air-only section status is not set; every section of the 3x3 columns is marked dirty
ClientPacketListener.handleForgetLevelChunk port crates/horizon-client/src/game/remote.rs::Game::handle_packet ForgetLevelChunk arm: Streaming::forget, block entities and renderer columns dropped
ClientPacketListener.queueLightRemoval inline crates/horizon-client/src/streaming.rs::Streaming::forget gap: minor: the column's light state is dropped with the column; no per-section light clearing
ClientPacketListener.queueLightRemoval inline crates/horizon-client-render/src/streaming.rs::Streaming::forget gap: minor: the column's light state is dropped with the column; no per-section light clearing
ClientPacketListener.handleBlockUpdate port crates/horizon-client/src/game/remote.rs::Game::server_block
ClientPacketListener.handleConfigurationStart port crates/horizon-client/src/net.rs::receive_play gap: player: no reconfiguring screen is shown and the chat state is not stored
ClientPacketListener.handleSystemChat port crates/horizon-client/src/game/remote.rs::Game::handle_packet SystemChat arm: overlay to the action bar, otherwise the chat
1 ClientPacketListener.<init> port crates/horizon-client/src/game/remote.rs::Game::join_server gap: minor: clears the chat on join; vanilla restores chat state kept across a reconfiguration
14 ClientPacketListener.handleRotatePlayer port crates/horizon-client/src/game/remote.rs::Game::handle_packet PlayerRotation arm; gap: minor: no ServerboundMovePlayerPacket.Rot reply is sent
15 ClientPacketListener.handleChunkBlocksUpdate port crates/horizon-client/src/game/remote.rs::Game::handle_packet SectionBlocksUpdate arm: each change through the block update
16 ClientPacketListener.handleChunksBiomes missing player: biome updates for loaded chunks are dropped, so grass, leaves and water keep the old biome colour
17 ClientPacketListener.enableChunkLight inline crates/horizon-client/src/streaming.rs::Streaming::insert_remote crates/horizon-client-render/src/streaming.rs::Streaming::insert_remote gap: minor: the air-only section status is not set; every section of the 3x3 columns is marked dirty
18 ClientPacketListener.handleForgetLevelChunk port crates/horizon-client/src/game/remote.rs::Game::handle_packet ForgetLevelChunk arm: Streaming::forget, block entities and renderer columns dropped
19 ClientPacketListener.queueLightRemoval inline crates/horizon-client/src/streaming.rs::Streaming::forget crates/horizon-client-render/src/streaming.rs::Streaming::forget gap: minor: the column's light state is dropped with the column; no per-section light clearing
20 ClientPacketListener.handleBlockUpdate port crates/horizon-client/src/game/remote.rs::Game::server_block
21 ClientPacketListener.handleConfigurationStart port crates/horizon-client/src/net.rs::receive_play gap: player: no reconfiguring screen is shown and the chat state is not stored
22 ClientPacketListener.handleSystemChat port crates/horizon-client/src/game/remote.rs::Game::handle_packet SystemChat arm: overlay to the action bar, otherwise the chat
+4 -4
View File
@@ -18,8 +18,8 @@ SessionSearchTrees.rebuildAfterLanguageChange skip:java creative search reads n
SessionSearchTrees.getTooltipLines inline crates/horizon-client/src/creative.rs::Creative::from_json search lines come pre-stripped from the export and are read here
SessionSearchTrees.updateCreativeTags inline crates/horizon-client/src/creative.rs::Creative::from_json tag index comes from the export's tag lists
SessionSearchTrees.updateCreativeTooltips inline crates/horizon-client/src/creative.rs::Creative::from_json name index comes from the export's tooltip lines
ChatAbilities.selectVisibleMessages port crates/horizon-client/src/chat.rs::ChatAbilities::shows source filter: client lines always, player and server lines per the abilities
ChatAbilities.Builder.build inline crates/horizon-client/src/chat.rs::ChatAbilities::new restrictions come from the Chat option alone; new() maps the visibility to them
ChatAbilities.selectVisibleMessages port crates/horizon-client-render/src/chat.rs::ChatAbilities::shows source filter: client lines always, player and server lines per the abilities
ChatAbilities.Builder.build inline crates/horizon-client-render/src/chat.rs::ChatAbilities::new restrictions come from the Chat option alone; new() maps the visibility to them
ChatListener.tick missing player: the Chat Delay option does nothing; lines show at once instead of after the delay
ChatListener.setMessageDelay missing player: no delayed-message queue, so Chat Delay has no effect
ChatListener.flushQueue missing player: no queue to flush (part of Chat Delay)
@@ -43,7 +43,7 @@ ChatTrustLevel.evaluate missing player: no Not Secure or Modified marking on ch
ChatTrustLevel.isModified missing minor: only feeds the Modified marking
ChatTrustLevel.containsModifiedStyle missing minor: only feeds the Modified marking
ChatTrustLevel.createTag missing player: no grey Not Secure bar or Modified tag on player chat lines
GuiMessage.splitLines port crates/horizon-client/src/chat.rs::Chat::add_lines gap: minor: no width reserved for a tag icon; Horizon draws no icon tags
GuiMessage.splitLines port crates/horizon-client-render/src/chat.rs::Chat::add_lines gap: minor: no width reserved for a tag icon; Horizon draws no icon tags
GuiMessageTag.chatModified missing minor: no Modified tag text or icon (needs the trust check)
GuiMessageTag.Icon.extractRenderState missing minor: the chat_modified icon is never drawn
LoggedChatMessage.Player.toContentComponent skip:service chat report view of a logged line
@@ -133,7 +133,7 @@ CowRenderer.getTextureLocation port crates/horizon-client/src/mobs/render.rs::bo
CowRenderer.extractRenderState port crates/horizon-client/src/mobs/render.rs::body variant is read there
CowRenderer.submit port crates/horizon-client/src/mobs/render.rs::body model per variant and age
CreakingRenderer.extractRenderState port crates/horizon-client/src/mobs/creaking.rs::animate attack, invulnerability and death clocks
CreeperRenderer.extractRenderState port crates/horizon-client/src/overlay.rs::creeper_progress white flash from swelling; the charged layer is in render.rs (energy swirl)
CreeperRenderer.extractRenderState port crates/horizon-client-render/src/overlay.rs::creeper_progress white flash from swelling; the charged layer is in render.rs (energy swirl)
CushionRenderer.extractRenderState port crates/horizon-client/src/game/cushions.rs::Game::cushion_geometry yaw and colour texture are read there
CushionRenderer.submit port crates/horizon-client/src/game/cushions.rs::Game::cushion_geometry turned to its facing and drawn
DisplayRenderer.getSkyLightLevel port crates/horizon-client/src/game/text_displays.rs::Game::text_display_geometry brightness override
1 ServerData.write port crates/horizon-protocol/src/servers.rs::ServerEntry::to_tag gap: minor: no acceptedCodeOfConduct entry (Horizon never stores code of conduct acceptance)
18 SessionSearchTrees.getTooltipLines inline crates/horizon-client/src/creative.rs::Creative::from_json search lines come pre-stripped from the export and are read here
19 SessionSearchTrees.updateCreativeTags inline crates/horizon-client/src/creative.rs::Creative::from_json tag index comes from the export's tag lists
20 SessionSearchTrees.updateCreativeTooltips inline crates/horizon-client/src/creative.rs::Creative::from_json name index comes from the export's tooltip lines
21 ChatAbilities.selectVisibleMessages port crates/horizon-client/src/chat.rs::ChatAbilities::shows crates/horizon-client-render/src/chat.rs::ChatAbilities::shows source filter: client lines always, player and server lines per the abilities
22 ChatAbilities.Builder.build inline crates/horizon-client/src/chat.rs::ChatAbilities::new crates/horizon-client-render/src/chat.rs::ChatAbilities::new restrictions come from the Chat option alone; new() maps the visibility to them
23 ChatListener.tick missing player: the Chat Delay option does nothing; lines show at once instead of after the delay
24 ChatListener.setMessageDelay missing player: no delayed-message queue, so Chat Delay has no effect
25 ChatListener.flushQueue missing player: no queue to flush (part of Chat Delay)
43 ChatTrustLevel.isModified missing minor: only feeds the Modified marking
44 ChatTrustLevel.containsModifiedStyle missing minor: only feeds the Modified marking
45 ChatTrustLevel.createTag missing player: no grey Not Secure bar or Modified tag on player chat lines
46 GuiMessage.splitLines port crates/horizon-client/src/chat.rs::Chat::add_lines crates/horizon-client-render/src/chat.rs::Chat::add_lines gap: minor: no width reserved for a tag icon; Horizon draws no icon tags
47 GuiMessageTag.chatModified missing minor: no Modified tag text or icon (needs the trust check)
48 GuiMessageTag.Icon.extractRenderState missing minor: the chat_modified icon is never drawn
49 LoggedChatMessage.Player.toContentComponent skip:service chat report view of a logged line
133 CowRenderer.extractRenderState port crates/horizon-client/src/mobs/render.rs::body variant is read there
134 CowRenderer.submit port crates/horizon-client/src/mobs/render.rs::body model per variant and age
135 CreakingRenderer.extractRenderState port crates/horizon-client/src/mobs/creaking.rs::animate attack, invulnerability and death clocks
136 CreeperRenderer.extractRenderState port crates/horizon-client/src/overlay.rs::creeper_progress crates/horizon-client-render/src/overlay.rs::creeper_progress white flash from swelling; the charged layer is in render.rs (energy swirl)
137 CushionRenderer.extractRenderState port crates/horizon-client/src/game/cushions.rs::Game::cushion_geometry yaw and colour texture are read there
138 CushionRenderer.submit port crates/horizon-client/src/game/cushions.rs::Game::cushion_geometry turned to its facing and drawn
139 DisplayRenderer.getSkyLightLevel port crates/horizon-client/src/game/text_displays.rs::Game::text_display_geometry brightness override
+1 -1
View File
@@ -72,7 +72,7 @@ ItemFrameRenderer.submit port crates/horizon-client/src/game/frames.rs::Game::fr
ItemFrameRenderer.getRenderOffset inline crates/horizon-client/src/game/frames.rs::Game::frame_geometry offset in front of the wall
ItemFrameRenderer.extractRenderState inline crates/horizon-client/src/game/frames.rs::Game::frame_geometry direction, item, rotation, glow and map read there
LeashKnotRenderer.submit port crates/horizon-client/src/game/leads.rs::Game::leash_geometry knot drawn with the rope pass
LightningBoltRenderer.quad inline crates/horizon-client/src/gfx/lightning.rs::geometry quad built inline
LightningBoltRenderer.quad inline crates/horizon-client-render/src/gfx/lightning.rs::geometry quad built inline
LivingEntityRenderer.getBoundingBoxForCulling skip:other culling box only (dragon-head inflate)
LivingEntityRenderer.isEntityUpsideDown port crates/horizon-client/src/mobs/render.rs::base_transform_at upside-down flip for Dinnerbone and Grumm
LivingEntityRenderer.isUpsideDownName inline crates/horizon-client/src/mobs/render.rs::base_transform_at name check folded into the flip
1 DolphinRenderer.extractRenderState port crates/horizon-client/src/game/mob_blocks.rs::Game::held_item_geometry gap: minor: isMoving (dolphin motion flag) is not read
72 ItemFrameRenderer.getRenderOffset inline crates/horizon-client/src/game/frames.rs::Game::frame_geometry offset in front of the wall
73 ItemFrameRenderer.extractRenderState inline crates/horizon-client/src/game/frames.rs::Game::frame_geometry direction, item, rotation, glow and map read there
74 LeashKnotRenderer.submit port crates/horizon-client/src/game/leads.rs::Game::leash_geometry knot drawn with the rope pass
75 LightningBoltRenderer.quad inline crates/horizon-client/src/gfx/lightning.rs::geometry crates/horizon-client-render/src/gfx/lightning.rs::geometry quad built inline
76 LivingEntityRenderer.getBoundingBoxForCulling skip:other culling box only (dragon-head inflate)
77 LivingEntityRenderer.isEntityUpsideDown port crates/horizon-client/src/mobs/render.rs::base_transform_at upside-down flip for Dinnerbone and Grumm
78 LivingEntityRenderer.isUpsideDownName inline crates/horizon-client/src/mobs/render.rs::base_transform_at name check folded into the flip
+1 -1
View File
@@ -35,7 +35,7 @@ DrownedOuterLayer.submit port crates/horizon-client/src/mobs/render.rs::layers d
EnergySwirlLayer.submit port crates/horizon-client/src/mobs/render.rs::energy_swirl charged creeper and powered wither swirl, drawn in render_visible
EquipmentLayerRenderer.renderLayers port crates/horizon-client/src/game/armor_stands.rs::Game::armor_layers gap: player: the leather overlay (layer 1 of the equipment asset) is never drawn, only layer 0
EquipmentLayerRenderer.getColorForLayer port crates/horizon-client/src/game/armor_stands.rs::Game::armor_layers gap: player: a dyed leather piece is drawn in the undyed brown; the stack's dyed colour is not read
EquipmentLayerRenderer.TrimTextureKey.createTextureWithNoPalette port crates/horizon-client/src/trims.rs::TrimTexture::generate a trim with no palette is used as its own texture
EquipmentLayerRenderer.TrimTextureKey.createTextureWithNoPalette port crates/horizon-client-render/src/trims.rs::TrimTexture::generate a trim with no palette is used as its own texture
EyesLayer.submit port crates/horizon-client/src/mobs/render.rs::layers spider, enderman and phantom eyes
FoxHeldItemLayer.submit missing player: a fox's food in its mouth (berries, fish) is not drawn; the fox model has no arm bones for the hand lookup
HorseMarkingLayer.submit port crates/horizon-client/src/mobs/render.rs::layers horse markings layer
1 VillagerRenderer.getShadowRadius missing minor: baby villagers keep the full shadow radius; shadows.rs shadow_params takes no baby flag
35 EnergySwirlLayer.submit port crates/horizon-client/src/mobs/render.rs::energy_swirl charged creeper and powered wither swirl, drawn in render_visible
36 EquipmentLayerRenderer.renderLayers port crates/horizon-client/src/game/armor_stands.rs::Game::armor_layers gap: player: the leather overlay (layer 1 of the equipment asset) is never drawn, only layer 0
37 EquipmentLayerRenderer.getColorForLayer port crates/horizon-client/src/game/armor_stands.rs::Game::armor_layers gap: player: a dyed leather piece is drawn in the undyed brown; the stack's dyed colour is not read
38 EquipmentLayerRenderer.TrimTextureKey.createTextureWithNoPalette port crates/horizon-client/src/trims.rs::TrimTexture::generate crates/horizon-client-render/src/trims.rs::TrimTexture::generate a trim with no palette is used as its own texture
39 EyesLayer.submit port crates/horizon-client/src/mobs/render.rs::layers spider, enderman and phantom eyes
40 FoxHeldItemLayer.submit missing player: a fox's food in its mouth (berries, fish) is not drawn; the fox model has no arm bones for the hand lookup
41 HorseMarkingLayer.submit port crates/horizon-client/src/mobs/render.rs::layers horse markings layer
+1 -1
View File
@@ -93,7 +93,7 @@ ModelLayers.register skip:data layer id registry; Horizon uses string keys
ModelLayers.registerArmorSet skip:data layer id registry; Horizon uses string keys
ModelPart.storePose skip:other no callers in vanilla; a snapshot of the current pose that nothing reads
ModelPart.loadPose port crates/horizon-client/src/mobs.rs::Part::parse reads the pose from the model data; the reset per frame is Poses::reset
ModelPart.getChild port crates/horizon-client/src/block_entity_render.rs::ModelPart::child named child lookup (Option instead of a throw)
ModelPart.getChild port crates/horizon-client-render/src/block_entity_render.rs::ModelPart::child named child lookup (Option instead of a throw)
ModelPart.compile port crates/horizon-client/src/mobs/render.rs::draw_normals emits each polygon with the posed transform; skipDraw gating
ModelPart.offsetRotation port crates/horizon-client/src/mobs/keyframes.rs::Animation::apply Target::Rotation channel adds to xRot/yRot/zRot
ModelPart.offsetScale port crates/horizon-client/src/mobs/keyframes.rs::Animation::apply Target::Scale channel adds to the scale
1 EquineSaddleModel.createSaddleLayer skip:data geometry baked into entity-models.json, which Horizon loads as a resource
93 ModelLayers.registerArmorSet skip:data layer id registry; Horizon uses string keys
94 ModelPart.storePose skip:other no callers in vanilla; a snapshot of the current pose that nothing reads
95 ModelPart.loadPose port crates/horizon-client/src/mobs.rs::Part::parse reads the pose from the model data; the reset per frame is Poses::reset
96 ModelPart.getChild port crates/horizon-client/src/block_entity_render.rs::ModelPart::child crates/horizon-client-render/src/block_entity_render.rs::ModelPart::child named child lookup (Option instead of a throw)
97 ModelPart.compile port crates/horizon-client/src/mobs/render.rs::draw_normals emits each polygon with the posed transform; skipDraw gating
98 ModelPart.offsetRotation port crates/horizon-client/src/mobs/keyframes.rs::Animation::apply Target::Rotation channel adds to xRot/yRot/zRot
99 ModelPart.offsetScale port crates/horizon-client/src/mobs/keyframes.rs::Animation::apply Target::Scale channel adds to the scale
+43 -43
View File
@@ -59,7 +59,7 @@ BoatModel.createChestBoatModel skip:data layer baked into entity-models.json, l
BoatModel.createWaterPatch skip:data layer baked into entity-models.json, loaded by key
RaftModel.createRaftModel skip:data bamboo raft is boat/bamboo#main in entity-models.json
RaftModel.createChestRaftModel skip:data bamboo chest raft is chest_boat/bamboo#main in entity-models.json
BookModel.State.forAnimation port crates/horizon-client/src/block_entity_anim.rs::EnchantingBook::render openness and page flips computed in EnchantingBook::render
BookModel.State.forAnimation port crates/horizon-client-render/src/block_entity_anim.rs::EnchantingBook::render openness and page flips computed in EnchantingBook::render
MinecartModel.createBodyLayer skip:data layer baked into entity-models.json, loaded by key
ChestModel.createSingleBodyLayer skip:data layer baked into entity-models.json, loaded by key
ChestModel.createDoubleBodyRightLayer skip:data layer baked into entity-models.json, loaded by key
@@ -77,11 +77,11 @@ TridentModel.createLayer skip:data layer baked into entity-models.json, loaded
WindChargeModel.createBodyLayer skip:data layer baked into entity-models.json, loaded by key
WindChargeModel.setupAnim port crates/horizon-client/src/game/wind.rs::Game::wind_charge_geometry wind and wind_charge parts spin in opposite directions
DragonHeadModel.createHeadLayer skip:data layer baked into entity-models.json, loaded by key
DragonHeadModel.setupAnim inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one jaw animation in the skull branch of render_one
PiglinHeadModel.setupAnim inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one ear flap in the skull branch of render_one
DragonHeadModel.setupAnim inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one jaw animation in the skull branch of render_one
PiglinHeadModel.setupAnim inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one ear flap in the skull branch of render_one
SkullModel.createHeadModel skip:data layer baked into entity-models.json, loaded by key
SkullModel.createHumanoidHeadLayer skip:data layer baked into entity-models.json, loaded by key
SkullModel.setupAnim inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one head yaw and pitch in the skull branch of render_one
SkullModel.setupAnim inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one head yaw and pitch in the skull branch of render_one
PlayerCapeModel.createCapeLayer missing player: capes never draw; skins.rs downloads the cape texture but nothing draws the cape layer
PlayerCapeModel.setupAnim missing player: the cape does not lean or flap with movement, since no cape is drawn
PlayerEarsModel.createEarsLayer missing minor: extra ears (showExtraEars accounts) are not drawn
@@ -89,12 +89,12 @@ PlayerModel.createMesh skip:data layer baked into entity-models.json, loaded by
PlayerModel.createArmorMeshSet skip:data layer baked into entity-models.json, loaded by key
PlayerModel.setupAnim port crates/horizon-client/src/mobs/anim.rs::setup gap: player: hat, jacket, sleeve and pant toggles (modelPart options) are not read, so a hidden layer still draws; humanoid pose is in the Humanoid branch
PlayerModel.translateToHand port crates/horizon-client/src/mobs/render.rs::hand_base gap: minor: slim-arm 0.5 pixel hand offset not applied
BlockModelLighter.prepareQuadAmbientOcclusion port crates/horizon-client/src/mesher/lighting.rs::ambient_occlusion per-vertex AO brightness and smooth light from the corner samples
BlockModelLighter.prepareQuadFlat port crates/horizon-client/src/mesher/lighting.rs::flat light only; the directional colour is applied in Mesher::face
BlockModelLighter.prepareQuadShape port crates/horizon-client/src/mesher/lighting.rs::shape face bounds, partial and cubic flags
BlockModelLighter.getDirectionalBrightness port crates/horizon-client/src/mesher/lighting.rs::cardinal face shade; the shade direction override is read in Mesher::face
BlockModelLighter.Cache.getLightCoords port crates/horizon-client/src/mesher/lighting.rs::coords packed light for a position
BlockModelLighter.Cache.getShadeBrightness port crates/horizon-client/src/mesher.rs::MeshTables::new shade per block state (Info.shade), not cached per position
BlockModelLighter.prepareQuadAmbientOcclusion port crates/horizon-client-render/src/mesher/lighting.rs::ambient_occlusion per-vertex AO brightness and smooth light from the corner samples
BlockModelLighter.prepareQuadFlat port crates/horizon-client-render/src/mesher/lighting.rs::flat light only; the directional colour is applied in Mesher::face
BlockModelLighter.prepareQuadShape port crates/horizon-client-render/src/mesher/lighting.rs::shape face bounds, partial and cubic flags
BlockModelLighter.getDirectionalBrightness port crates/horizon-client-render/src/mesher/lighting.rs::cardinal face shade; the shade direction override is read in Mesher::face
BlockModelLighter.Cache.getLightCoords port crates/horizon-client-render/src/mesher/lighting.rs::coords packed light for a position
BlockModelLighter.Cache.getShadeBrightness port crates/horizon-client-render/src/mesher.rs::MeshTables::new shade per block state (Info.shade), not cached per position
BlockModelRenderState.clear skip:java reuse of a pooled render state object
BlockModelRenderState.tintLayers port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices gap: minor: the caller tints every face with one sprite tint, not per tint index
BlockModelRenderState.setupModel port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices model parts with the transform matrix
@@ -102,43 +102,43 @@ BlockModelRenderState.submit port crates/horizon-client/src/game/minecarts.rs::G
BlockModelRenderState.submitModel port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices faces written to the vertex list
BlockModelRenderState.scratchRandomSource port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices seeded variant choice through collect_seeded
BlockModelResolver.update port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices resolves the seeded model for a block state; light is passed in by the caller
BlockModelSet.createFallbackModel port crates/horizon-client/src/mesher.rs::MeshTables::new per-state tint sources (Info.tints) and the plain model
BuiltInBlockModels.special port crates/horizon-client/src/block_entity_render.rs::classify special model name to Kind
BuiltInBlockModels.createMobHead port crates/horizon-client/src/block_entity_render.rs::classify Skull kind for mob heads
BuiltInBlockModels.createMobWallHead port crates/horizon-client/src/block_entity_render.rs::classify Skull kind for wall mob heads
BuiltInBlockModels.createMobHeads port crates/horizon-client/src/block_entity_render.rs::classify Skull kind for the head set
BuiltInBlockModels.createPlayerHead port crates/horizon-client/src/block_entity_render.rs::classify Skull kind for player heads
BuiltInBlockModels.createPlayerWallHead port crates/horizon-client/src/block_entity_render.rs::classify Skull kind for wall player heads
BuiltInBlockModels.createBanner port crates/horizon-client/src/block_entity_render.rs::classify Banner kind
BuiltInBlockModels.createWallBanner port crates/horizon-client/src/block_entity_render.rs::classify Banner kind for wall banners
BuiltInBlockModels.createDyedShulkerBox port crates/horizon-client/src/block_entity_render.rs::classify Shulker kind for dyed boxes
BuiltInBlockModels.createChest port crates/horizon-client/src/block_entity_render.rs::classify Chest kind
BuiltInBlockModels.createSingletonChest port crates/horizon-client/src/block_entity_render.rs::classify Chest kind, single chest
BuiltInBlockModels.createXmasChest port crates/horizon-client/src/block_entity_render.rs::classify Chest kind with the Christmas texture
BuiltInBlockModels.createCopperGolem port crates/horizon-client/src/block_entity_render.rs::classify CopperGolem kind
BlockModelSet.createFallbackModel port crates/horizon-client-render/src/mesher.rs::MeshTables::new per-state tint sources (Info.tints) and the plain model
BuiltInBlockModels.special port crates/horizon-client-render/src/block_entity_render.rs::classify special model name to Kind
BuiltInBlockModels.createMobHead port crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for mob heads
BuiltInBlockModels.createMobWallHead port crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for wall mob heads
BuiltInBlockModels.createMobHeads port crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for the head set
BuiltInBlockModels.createPlayerHead port crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for player heads
BuiltInBlockModels.createPlayerWallHead port crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for wall player heads
BuiltInBlockModels.createBanner port crates/horizon-client-render/src/block_entity_render.rs::classify Banner kind
BuiltInBlockModels.createWallBanner port crates/horizon-client-render/src/block_entity_render.rs::classify Banner kind for wall banners
BuiltInBlockModels.createDyedShulkerBox port crates/horizon-client-render/src/block_entity_render.rs::classify Shulker kind for dyed boxes
BuiltInBlockModels.createChest port crates/horizon-client-render/src/block_entity_render.rs::classify Chest kind
BuiltInBlockModels.createSingletonChest port crates/horizon-client-render/src/block_entity_render.rs::classify Chest kind, single chest
BuiltInBlockModels.createXmasChest port crates/horizon-client-render/src/block_entity_render.rs::classify Chest kind with the Christmas texture
BuiltInBlockModels.createCopperGolem port crates/horizon-client-render/src/block_entity_render.rs::classify CopperGolem kind
BuiltInBlockModels.createFlowerBedModel missing minor: the 0.25 block shift for a flower bed shown by a copper golem is not applied
BuiltInBlockModels.createEnchantingTable port crates/horizon-client/src/block_entity_render.rs::classify EnchantingTable kind
BuiltInBlockModels.specialModelWithPropertyDispatch port crates/horizon-client/src/block_entity_render.rs::classify property dispatch by block state values
BuiltInBlockModels.createEnchantingTable port crates/horizon-client-render/src/block_entity_render.rs::classify EnchantingTable kind
BuiltInBlockModels.specialModelWithPropertyDispatch port crates/horizon-client-render/src/block_entity_render.rs::classify property dispatch by block state values
BuiltInBlockModels.Builder.put skip:java builder map of special models
FluidModel.Unbaked.bake port crates/horizon-client/src/mesher.rs::MeshTables::new gap: minor: water and lava layers hard-wired; translucency picked in fluid tesselate
FluidModel.Unbaked.getAndValidateMaterial port crates/horizon-client/src/mesher.rs::MeshTables::new sprite lookup through layer(); no separate atlas check
FluidRenderer.isFaceOccludedByState port crates/horizon-client/src/mesher/fluid.rs::occluded_by fluid face occlusion by the neighbour's face shape
FluidRenderer.shouldRenderFace port crates/horizon-client/src/mesher/fluid.rs::tesselate render_up, render_down and side checks, neighbour-same-fluid and self occlusion
FluidRenderer.addFace inline crates/horizon-client/src/mesher/fluid.rs::tesselate quad closure in tesselate
FluidRenderer.calculateAverageHeight inline crates/horizon-client/src/mesher/fluid.rs::tesselate average closure in tesselate
FluidRenderer.addWeightedHeight inline crates/horizon-client/src/mesher/fluid.rs::tesselate weighted sum inside the average closure
FluidRenderer.vertex inline crates/horizon-client/src/mesher/fluid.rs::tesselate vertex built in the quad closure
FluidStateModelSet.bake port crates/horizon-client/src/mesher.rs::MeshTables::new fluid layers and tints baked per fluid
FluidModel.Unbaked.bake port crates/horizon-client-render/src/mesher.rs::MeshTables::new gap: minor: water and lava layers hard-wired; translucency picked in fluid tesselate
FluidModel.Unbaked.getAndValidateMaterial port crates/horizon-client-render/src/mesher.rs::MeshTables::new sprite lookup through layer(); no separate atlas check
FluidRenderer.isFaceOccludedByState port crates/horizon-client-render/src/mesher/fluid.rs::occluded_by fluid face occlusion by the neighbour's face shape
FluidRenderer.shouldRenderFace port crates/horizon-client-render/src/mesher/fluid.rs::tesselate render_up, render_down and side checks, neighbour-same-fluid and self occlusion
FluidRenderer.addFace inline crates/horizon-client-render/src/mesher/fluid.rs::tesselate quad closure in tesselate
FluidRenderer.calculateAverageHeight inline crates/horizon-client-render/src/mesher/fluid.rs::tesselate average closure in tesselate
FluidRenderer.addWeightedHeight inline crates/horizon-client-render/src/mesher/fluid.rs::tesselate weighted sum inside the average closure
FluidRenderer.vertex inline crates/horizon-client-render/src/mesher/fluid.rs::tesselate vertex built in the quad closure
FluidStateModelSet.bake port crates/horizon-client-render/src/mesher.rs::MeshTables::new fluid layers and tints baked per fluid
LoadedBlockModels.bake port crates/horizon-assets/src/bake.rs::bake_block_model bakes each block model; the loop over the set is the caller's
ModelBlockRenderer.tesselateBlock port crates/horizon-client/src/mesher.rs::Mesher::mesh per block: fluids, models, smooth-light choice
ModelBlockRenderer.configureTintCache port crates/horizon-client/src/mesher.rs::Tints::new per section tint tables
ModelBlockRenderer.resetTintCache inline crates/horizon-client/src/mesher.rs::Tints::new tables are built fresh per section, no reset
ModelBlockRenderer.tesselateAmbientOcclusion port crates/horizon-client/src/mesher.rs::Mesher::face AO branch of face
ModelBlockRenderer.tesselateFlat port crates/horizon-client/src/mesher.rs::Mesher::face flat branch of face
ModelBlockRenderer.tesselateBlock port crates/horizon-client-render/src/mesher.rs::Mesher::mesh per block: fluids, models, smooth-light choice
ModelBlockRenderer.configureTintCache port crates/horizon-client-render/src/mesher.rs::Tints::new per section tint tables
ModelBlockRenderer.resetTintCache inline crates/horizon-client-render/src/mesher.rs::Tints::new tables are built fresh per section, no reset
ModelBlockRenderer.tesselateAmbientOcclusion port crates/horizon-client-render/src/mesher.rs::Mesher::face AO branch of face
ModelBlockRenderer.tesselateFlat port crates/horizon-client-render/src/mesher.rs::Mesher::face flat branch of face
ModelBlockRenderer.shouldRenderFace port crates/horizon-world/src/block_render.rs::FaceVisibility::should_render_face per face visibility, called from Mesher::mesh
ModelBlockRenderer.putQuadWithTint port crates/horizon-client/src/mesher.rs::Mesher::face tinted vertex write
ModelBlockRenderer.getTintColor port crates/horizon-client/src/mesher.rs::Mesher::tint tint source index to colour
ModelBlockRenderer.computeTintColor port crates/horizon-client/src/mesher.rs::Tints::get biome colour average over the blend radius
ModelBlockRenderer.putQuadWithTint port crates/horizon-client-render/src/mesher.rs::Mesher::face tinted vertex write
ModelBlockRenderer.getTintColor port crates/horizon-client-render/src/mesher.rs::Mesher::tint tint source index to colour
ModelBlockRenderer.computeTintColor port crates/horizon-client-render/src/mesher.rs::Tints::get biome colour average over the blend radius
MovingBlockRenderState.getBlockTint port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_block_vertices gap: minor: tint is the particle colour at the source position, not the biome tint at the moved spot
MovingBlockRenderState.getBlockState port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_blocks moved block and piston base
SelectBlockModel.update missing minor: display-context switch (copper golem hand, flower bed) is not applied; block items use the normal transform
1 PiglinModel.setupAttackAnimation port crates/horizon-client/src/mobs/anim.rs::humanoid melee swing branch via weapon_swing, which piglin_pose sets
59 BoatModel.createWaterPatch skip:data layer baked into entity-models.json, loaded by key
60 RaftModel.createRaftModel skip:data bamboo raft is boat/bamboo#main in entity-models.json
61 RaftModel.createChestRaftModel skip:data bamboo chest raft is chest_boat/bamboo#main in entity-models.json
62 BookModel.State.forAnimation port crates/horizon-client/src/block_entity_anim.rs::EnchantingBook::render crates/horizon-client-render/src/block_entity_anim.rs::EnchantingBook::render openness and page flips computed in EnchantingBook::render
63 MinecartModel.createBodyLayer skip:data layer baked into entity-models.json, loaded by key
64 ChestModel.createSingleBodyLayer skip:data layer baked into entity-models.json, loaded by key
65 ChestModel.createDoubleBodyRightLayer skip:data layer baked into entity-models.json, loaded by key
77 WindChargeModel.createBodyLayer skip:data layer baked into entity-models.json, loaded by key
78 WindChargeModel.setupAnim port crates/horizon-client/src/game/wind.rs::Game::wind_charge_geometry wind and wind_charge parts spin in opposite directions
79 DragonHeadModel.createHeadLayer skip:data layer baked into entity-models.json, loaded by key
80 DragonHeadModel.setupAnim inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one jaw animation in the skull branch of render_one
81 PiglinHeadModel.setupAnim inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one ear flap in the skull branch of render_one
82 SkullModel.createHeadModel skip:data layer baked into entity-models.json, loaded by key
83 SkullModel.createHumanoidHeadLayer skip:data layer baked into entity-models.json, loaded by key
84 SkullModel.setupAnim inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one head yaw and pitch in the skull branch of render_one
85 PlayerCapeModel.createCapeLayer missing player: capes never draw; skins.rs downloads the cape texture but nothing draws the cape layer
86 PlayerCapeModel.setupAnim missing player: the cape does not lean or flap with movement, since no cape is drawn
87 PlayerEarsModel.createEarsLayer missing minor: extra ears (showExtraEars accounts) are not drawn
89 PlayerModel.createArmorMeshSet skip:data layer baked into entity-models.json, loaded by key
90 PlayerModel.setupAnim port crates/horizon-client/src/mobs/anim.rs::setup gap: player: hat, jacket, sleeve and pant toggles (modelPart options) are not read, so a hidden layer still draws; humanoid pose is in the Humanoid branch
91 PlayerModel.translateToHand port crates/horizon-client/src/mobs/render.rs::hand_base gap: minor: slim-arm 0.5 pixel hand offset not applied
92 BlockModelLighter.prepareQuadAmbientOcclusion port crates/horizon-client/src/mesher/lighting.rs::ambient_occlusion crates/horizon-client-render/src/mesher/lighting.rs::ambient_occlusion per-vertex AO brightness and smooth light from the corner samples
93 BlockModelLighter.prepareQuadFlat port crates/horizon-client/src/mesher/lighting.rs::flat crates/horizon-client-render/src/mesher/lighting.rs::flat light only; the directional colour is applied in Mesher::face
94 BlockModelLighter.prepareQuadShape port crates/horizon-client/src/mesher/lighting.rs::shape crates/horizon-client-render/src/mesher/lighting.rs::shape face bounds, partial and cubic flags
95 BlockModelLighter.getDirectionalBrightness port crates/horizon-client/src/mesher/lighting.rs::cardinal crates/horizon-client-render/src/mesher/lighting.rs::cardinal face shade; the shade direction override is read in Mesher::face
96 BlockModelLighter.Cache.getLightCoords port crates/horizon-client/src/mesher/lighting.rs::coords crates/horizon-client-render/src/mesher/lighting.rs::coords packed light for a position
97 BlockModelLighter.Cache.getShadeBrightness port crates/horizon-client/src/mesher.rs::MeshTables::new crates/horizon-client-render/src/mesher.rs::MeshTables::new shade per block state (Info.shade), not cached per position
98 BlockModelRenderState.clear skip:java reuse of a pooled render state object
99 BlockModelRenderState.tintLayers port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices gap: minor: the caller tints every face with one sprite tint, not per tint index
100 BlockModelRenderState.setupModel port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices model parts with the transform matrix
102 BlockModelRenderState.submitModel port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices faces written to the vertex list
103 BlockModelRenderState.scratchRandomSource port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices seeded variant choice through collect_seeded
104 BlockModelResolver.update port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices resolves the seeded model for a block state; light is passed in by the caller
105 BlockModelSet.createFallbackModel port crates/horizon-client/src/mesher.rs::MeshTables::new crates/horizon-client-render/src/mesher.rs::MeshTables::new per-state tint sources (Info.tints) and the plain model
106 BuiltInBlockModels.special port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify special model name to Kind
107 BuiltInBlockModels.createMobHead port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for mob heads
108 BuiltInBlockModels.createMobWallHead port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for wall mob heads
109 BuiltInBlockModels.createMobHeads port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for the head set
110 BuiltInBlockModels.createPlayerHead port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for player heads
111 BuiltInBlockModels.createPlayerWallHead port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Skull kind for wall player heads
112 BuiltInBlockModels.createBanner port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Banner kind
113 BuiltInBlockModels.createWallBanner port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Banner kind for wall banners
114 BuiltInBlockModels.createDyedShulkerBox port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Shulker kind for dyed boxes
115 BuiltInBlockModels.createChest port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Chest kind
116 BuiltInBlockModels.createSingletonChest port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Chest kind, single chest
117 BuiltInBlockModels.createXmasChest port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify Chest kind with the Christmas texture
118 BuiltInBlockModels.createCopperGolem port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify CopperGolem kind
119 BuiltInBlockModels.createFlowerBedModel missing minor: the 0.25 block shift for a flower bed shown by a copper golem is not applied
120 BuiltInBlockModels.createEnchantingTable port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify EnchantingTable kind
121 BuiltInBlockModels.specialModelWithPropertyDispatch port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify property dispatch by block state values
122 BuiltInBlockModels.Builder.put skip:java builder map of special models
123 FluidModel.Unbaked.bake port crates/horizon-client/src/mesher.rs::MeshTables::new crates/horizon-client-render/src/mesher.rs::MeshTables::new gap: minor: water and lava layers hard-wired; translucency picked in fluid tesselate
124 FluidModel.Unbaked.getAndValidateMaterial port crates/horizon-client/src/mesher.rs::MeshTables::new crates/horizon-client-render/src/mesher.rs::MeshTables::new sprite lookup through layer(); no separate atlas check
125 FluidRenderer.isFaceOccludedByState port crates/horizon-client/src/mesher/fluid.rs::occluded_by crates/horizon-client-render/src/mesher/fluid.rs::occluded_by fluid face occlusion by the neighbour's face shape
126 FluidRenderer.shouldRenderFace port crates/horizon-client/src/mesher/fluid.rs::tesselate crates/horizon-client-render/src/mesher/fluid.rs::tesselate render_up, render_down and side checks, neighbour-same-fluid and self occlusion
127 FluidRenderer.addFace inline crates/horizon-client/src/mesher/fluid.rs::tesselate crates/horizon-client-render/src/mesher/fluid.rs::tesselate quad closure in tesselate
128 FluidRenderer.calculateAverageHeight inline crates/horizon-client/src/mesher/fluid.rs::tesselate crates/horizon-client-render/src/mesher/fluid.rs::tesselate average closure in tesselate
129 FluidRenderer.addWeightedHeight inline crates/horizon-client/src/mesher/fluid.rs::tesselate crates/horizon-client-render/src/mesher/fluid.rs::tesselate weighted sum inside the average closure
130 FluidRenderer.vertex inline crates/horizon-client/src/mesher/fluid.rs::tesselate crates/horizon-client-render/src/mesher/fluid.rs::tesselate vertex built in the quad closure
131 FluidStateModelSet.bake port crates/horizon-client/src/mesher.rs::MeshTables::new crates/horizon-client-render/src/mesher.rs::MeshTables::new fluid layers and tints baked per fluid
132 LoadedBlockModels.bake port crates/horizon-assets/src/bake.rs::bake_block_model bakes each block model; the loop over the set is the caller's
133 ModelBlockRenderer.tesselateBlock port crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh per block: fluids, models, smooth-light choice
134 ModelBlockRenderer.configureTintCache port crates/horizon-client/src/mesher.rs::Tints::new crates/horizon-client-render/src/mesher.rs::Tints::new per section tint tables
135 ModelBlockRenderer.resetTintCache inline crates/horizon-client/src/mesher.rs::Tints::new crates/horizon-client-render/src/mesher.rs::Tints::new tables are built fresh per section, no reset
136 ModelBlockRenderer.tesselateAmbientOcclusion port crates/horizon-client/src/mesher.rs::Mesher::face crates/horizon-client-render/src/mesher.rs::Mesher::face AO branch of face
137 ModelBlockRenderer.tesselateFlat port crates/horizon-client/src/mesher.rs::Mesher::face crates/horizon-client-render/src/mesher.rs::Mesher::face flat branch of face
138 ModelBlockRenderer.shouldRenderFace port crates/horizon-world/src/block_render.rs::FaceVisibility::should_render_face per face visibility, called from Mesher::mesh
139 ModelBlockRenderer.putQuadWithTint port crates/horizon-client/src/mesher.rs::Mesher::face crates/horizon-client-render/src/mesher.rs::Mesher::face tinted vertex write
140 ModelBlockRenderer.getTintColor port crates/horizon-client/src/mesher.rs::Mesher::tint crates/horizon-client-render/src/mesher.rs::Mesher::tint tint source index to colour
141 ModelBlockRenderer.computeTintColor port crates/horizon-client/src/mesher.rs::Tints::get crates/horizon-client-render/src/mesher.rs::Tints::get biome colour average over the blend radius
142 MovingBlockRenderState.getBlockTint port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_block_vertices gap: minor: tint is the particle colour at the source position, not the biome tint at the moved spot
143 MovingBlockRenderState.getBlockState port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_blocks moved block and piston base
144 SelectBlockModel.update missing minor: display-context switch (copper golem hand, flower bed) is not applied; block items use the normal transform
+46 -46
View File
@@ -6,8 +6,8 @@ Variant.SimpleModelState.withUvLock skip:java copy-with setter of an immutable
VariantMutator.then skip:java composes JSON field setters; Variant::decode reads all fields in one pass
VariantSelector.predicate port crates/horizon-assets/src/blockstate/bind.rs::variant_predicate parses the property clauses; matching against states is in BlockStateDefinition::bind
WeightedVariants.computeMaterialFlags skip:java OR of per-model render flags; Horizon keeps translucency per face (BakedFace in models/catalog.rs)
WeightedVariants.Unbaked.bake inline crates/horizon-client/src/models/catalog.rs::StateModels::load each weighted variant baked once with its transform; the choice is kept in CompiledChoices
WeightedVariants.Unbaked.resolveDependencies inline crates/horizon-client/src/models/catalog.rs::StateModels::load model names gathered from all definitions before the block library loads
WeightedVariants.Unbaked.bake inline crates/horizon-client-render/src/models/catalog.rs::StateModels::load each weighted variant baked once with its transform; the choice is kept in CompiledChoices
WeightedVariants.Unbaked.resolveDependencies inline crates/horizon-client-render/src/models/catalog.rs::StateModels::load model names gathered from all definitions before the block library loads
CombinedCondition.instantiate port crates/horizon-assets/src/blockstate/bind.rs::BoundCondition::bind AND and OR branches; the test itself is BoundCondition::matches
KeyValueCondition.instantiate port crates/horizon-assets/src/blockstate/bind.rs::BoundCondition::bind property lookup per key and the properties branch
KeyValueCondition.Term.parse port crates/horizon-assets/src/blockstate.rs::Condition::decode reads the leading "!" as negation
@@ -19,37 +19,37 @@ MultiPartModel.SharedBakedState.getFirstModel port crates/horizon-assets/src/blo
MultiPartModel.SharedBakedState.computeMaterialFlags skip:java same OR of render flags as WeightedVariants; translucency is kept per face
MultiPartModel.SharedBakedState.selectModels port crates/horizon-assets/src/blockstate/bind.rs::BlockStateDefinition::bind selected selector indices per state, computed once at load
MultiPartModel.Unbaked.visualEqualityGroup skip:java key for sharing identical visual states; Horizon keys block states by id
MultiPartModel.Unbaked.resolveDependencies inline crates/horizon-client/src/models/catalog.rs::StateModels::load model names gathered from every multipart selector
MultiPartModel.Unbaked.bake inline crates/horizon-client/src/models/catalog.rs::StateModels::load shared bake per definition; per-state selection stored in states
MultiPartModel.Unbaked.resolveDependencies inline crates/horizon-client-render/src/models/catalog.rs::StateModels::load model names gathered from every multipart selector
MultiPartModel.Unbaked.bake inline crates/horizon-client-render/src/models/catalog.rs::StateModels::load shared bake per definition; per-state selection stored in states
Selector.instantiate port crates/horizon-assets/src/blockstate/bind.rs::BlockStateDefinition::bind a selector without a condition applies to every state
BlockStateModelWrapper.update port crates/horizon-client/src/game/minecarts.rs::Game::block_model_vertices gap: player: no tint layers, so carried or cart blocks with tint sources (grass, leaves) are drawn untinted
BlockStateModelWrapper.updateTints missing player: carried and cart blocks with tint sources (grass, leaves, water) show untinted; Horizon's block_model_vertices has no tint step
BlockStateModelWrapper.Unbaked.bake skip:java builds the wrapper object; Horizon passes the transform straight to block_model_vertices
CompositeBlockModel.update missing player: only block display entities reach this and Horizon draws none, so a special block (chest and similar) shown that way never appears
CompositeBlockModel.Unbaked.bake skip:java builds the composite object; no separate step in Horizon
ConditionalBlockModel.update inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one Christmas chest texture chosen in the chest branch by extended_christmas()
ConditionalBlockModel.update inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one Christmas chest texture chosen in the chest branch by extended_christmas()
ConditionalBlockModel.Unbaked.bake skip:java builds the conditional object; the chest branch picks the texture when drawing
SpecialBlockModelWrapper.Unbaked.bake skip:data special models come from exported model data in BlockEntityRenderer::load; no baking step
AbstractEndPortalRenderer.submitSpecial port crates/horizon-client/src/block_entity_render.rs::portal_cube gap: minor: no outline pass (outlineColor) for the portal faces
AbstractSignRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one front and back text drawn in the sign branch via sign_text_calls
AbstractSignRenderer.isOutlineVisible port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: only the 16-block distance is tested; spyglass scoping in first person does not turn the outline on
AbstractSignRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: the text filtering option is not read; filtered sign lines are not shown
BannerRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one flutter phase from position, game time and partial tick; standing or wall placement
BannerRenderer.bannerModel inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one wall or standing banner model chosen in the banner branch
BannerRenderer.flagModel inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one wall or standing flag model chosen in the banner branch
AbstractEndPortalRenderer.submitSpecial port crates/horizon-client-render/src/block_entity_render.rs::portal_cube gap: minor: no outline pass (outlineColor) for the portal faces
AbstractSignRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one front and back text drawn in the sign branch via sign_text_calls
AbstractSignRenderer.isOutlineVisible port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: only the 16-block distance is tested; spyglass scoping in first person does not turn the outline on
AbstractSignRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: the text filtering option is not read; filtered sign lines are not shown
BannerRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one flutter phase from position, game time and partial tick; standing or wall placement
BannerRenderer.bannerModel inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one wall or standing banner model chosen in the banner branch
BannerRenderer.flagModel inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one wall or standing flag model chosen in the banner branch
BannerRenderer.submitSpecial port crates/horizon-client/src/item_render/special.rs::submit banner as a special item model: base, flag and pattern layers
BannerRenderer.submitBanner port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one base model, flag and pattern layers; the crumbling overlay is drawn by render_breaking
BannerRenderer.submitPatternLayer inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one loop over up to 16 pattern layers in the banner branch
BannerRenderer.modelTransformation inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one translate, turn by angle, scale in the banner branch
BannerRenderer.submitBanner port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one base model, flag and pattern layers; the crumbling overlay is drawn by render_breaking
BannerRenderer.submitPatternLayer inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one loop over up to 16 pattern layers in the banner branch
BannerRenderer.modelTransformation inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one translate, turn by angle, scale in the banner branch
BeaconRenderer.extractRenderState inline crates/horizon-client/src/game/beacon.rs::Game::beacon_geometry animation time and beam radius scale computed there
BeaconRenderer.extract inline crates/horizon-client/src/game/beacon.rs::Game::beacon_geometry same time and scale rules, from distance and scoping
BeaconRenderer.renderQuad port crates/horizon-client/src/block_entity_render.rs::beam solid beam and glow quads per section
BeaconRenderer.addVertex port crates/horizon-client/src/block_entity_render.rs::beam vertex with colour and full light, emitted by beam's inner emit
BellRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one bell ticks and shake direction read in the bell branch
BellRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay while a bell is broken (render_breaking draws only banners and chests)
BlockEntityRenderDispatcher.getRenderer port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::kind renderer chosen from the block state
BlockEntityRenderDispatcher.tryExtractRenderState port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render gap: minor: distance cull only (256 for gateways); no frustum, type-validity or off-screen test here
BlockEntityRenderDispatcher.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one draws each kind; no crash report wrapper
BeaconRenderer.renderQuad port crates/horizon-client-render/src/block_entity_render.rs::beam solid beam and glow quads per section
BeaconRenderer.addVertex port crates/horizon-client-render/src/block_entity_render.rs::beam vertex with colour and full light, emitted by beam's inner emit
BellRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one bell ticks and shake direction read in the bell branch
BellRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay while a bell is broken (render_breaking draws only banners and chests)
BlockEntityRenderDispatcher.getRenderer port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::kind renderer chosen from the block state
BlockEntityRenderDispatcher.tryExtractRenderState port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render gap: minor: distance cull only (256 for gateways); no frustum, type-validity or off-screen test here
BlockEntityRenderDispatcher.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one draws each kind; no crash report wrapper
BlockEntityRenderDispatcher.onResourceManagerReload missing minor: block entity models load once in BlockEntityRenderer::load; no reload path found
BlockEntityRenderers.createEntityRenderers skip:data renderer registration table; Horizon's classify table replaces it
BlockEntityWithBoundingBoxRenderer.extractRenderState missing player: game-master players (creative or op) see no structure box, invisible-block or structure-void markers
@@ -57,56 +57,56 @@ BlockEntityWithBoundingBoxRenderer.extract missing player: game-master players
BlockEntityWithBoundingBoxRenderer.submit missing player: game-master players (creative or op) see no structure box, invisible-block or structure-void markers
BlockEntityWithBoundingBoxRenderer.renderInvisibleBlocks missing player: game-master players (creative or op) see no barrier, light or air block markers
BlockEntityWithBoundingBoxRenderer.renderStructureVoids missing player: game-master players (creative or op) see no structure void markers
BrightnessCombiner.acceptDouble inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one brighter of the two chest halves per channel, in the chest branch
BrightnessCombiner.acceptDouble inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one brighter of the two chest halves per channel, in the chest branch
BrushableBlockRenderer.extractRenderState missing player: brushing a suspicious block shows no item on its face; the hit side and dust stage are not read
BrushableBlockRenderer.submit missing player: the brushed item never slides out of the block while it is brushed
BrushableBlockRenderer.translations missing player: the per-side slide offset for each dust stage is not computed
CampfireRenderer.extractRenderState inline crates/horizon-client/src/game/campfire.rs::Game::campfire_geometry facing and per-slot item seed read there
CampfireRenderer.submit port crates/horizon-client/src/game/campfire.rs::Game::campfire_geometry items on the four sides, drawn within 64 blocks
ChestRenderer.createModelTransformation inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one chest turn about its centre in the chest branch
ChestRenderer.createModelTransformation inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one chest turn about its centre in the chest branch
ConduitRenderer.createEyeLayer skip:data model layer; Horizon loads the conduit parts from exported model data in BlockEntityRenderer::load
ConduitRenderer.createWindLayer skip:data model layer; Horizon loads the conduit parts from exported model data in BlockEntityRenderer::load
ConduitRenderer.createShellLayer skip:data model layer; Horizon loads the conduit parts from exported model data in BlockEntityRenderer::load
ConduitRenderer.createCageLayer skip:data model layer; Horizon loads the conduit parts from exported model data in BlockEntityRenderer::load
ConduitRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on the conduit (render_breaking draws only banners and chests)
CopperGolemStatueBlockRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one facing, pose and oxidation texture read in the golem branch
CopperGolemStatueBlockRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on the statue (render_breaking draws only banners and chests)
CopperGolemStatueBlockRenderer.createModelTransformation inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one rotation from the opposite facing in the golem branch
ConduitRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on the conduit (render_breaking draws only banners and chests)
CopperGolemStatueBlockRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one facing, pose and oxidation texture read in the golem branch
CopperGolemStatueBlockRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on the statue (render_breaking draws only banners and chests)
CopperGolemStatueBlockRenderer.createModelTransformation inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one rotation from the opposite facing in the golem branch
DecoratedPotRenderer.createBaseLayer skip:data pot base model; Horizon loads it from exported model data in BlockEntityRenderer::load
DecoratedPotRenderer.createSidesLayer skip:data pot side models; Horizon loads them from exported model data in BlockEntityRenderer::load
DecoratedPotRenderer.getSideSprite inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one sherd pattern texture per side from pot_patterns, blank side otherwise
DecoratedPotRenderer.createModelTransformation inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one pot turn about its centre in the decorated pot branch
DecoratedPotRenderer.getSideSprite inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one sherd pattern texture per side from pot_patterns, blank side otherwise
DecoratedPotRenderer.createModelTransformation inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one pot turn about its centre in the decorated pot branch
DecoratedPotRenderer.getExtents port crates/horizon-client/src/item_render/special.rs::extents decorated pot part extents for the item model bounds
HangingSignRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: the text filtering option is not read
LecternRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one book drawn only when has_book is set, turned by facing
LecternRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on the lectern book (render_breaking draws only banners and chests)
HangingSignRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: the text filtering option is not read
LecternRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one book drawn only when has_book is set, turned by facing
LecternRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on the lectern book (render_breaking draws only banners and chests)
PistonHeadRenderer.submit port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_geometry head and base blocks drawn at their offsets
PistonHeadRenderer.createMovingBlock port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_block_vertices gap: minor: the tint is the particle sprite colour, not the block's tint sources
ShelfRenderer.extractRenderState missing player: items placed on shelf blocks are not kept for drawing; only the comparator signal is handled (game/machines.rs::shelf_signal)
ShelfRenderer.submit missing player: items on shelves are invisible
ShelfRenderer.submitItem missing player: shelf item slots, offsets and scale are not drawn
ShulkerBoxRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one facing, colour texture and lid progress read in the shulker branch
ShulkerBoxRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on shulker boxes (render_breaking draws only banners and chests)
ShulkerBoxRenderer.createModelTransform inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one facing transform in the shulker branch
ShulkerBoxRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one facing, colour texture and lid progress read in the shulker branch
ShulkerBoxRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on shulker boxes (render_breaking draws only banners and chests)
ShulkerBoxRenderer.createModelTransform inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one facing transform in the shulker branch
ShulkerBoxRenderer.getExtents port crates/horizon-client/src/item_render/special.rs::extents shulker lid pose extents for the item model bounds
SkullBlockRenderer.createModel skip:data skull models; Horizon loads them from exported model data in BlockEntityRenderer::load
SkullBlockRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one type, wall facing and turn read from the skull kind; player skin via scene.skull
SkullBlockRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on skulls and heads (render_breaking draws only banners and chests)
SkullBlockRenderer.submitSkull port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on skulls and heads (render_breaking draws only banners and chests)
SkullBlockRenderer.resolveSkullRenderType inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one player head skin via scene.skull, otherwise the type's texture
SkullBlockRenderer.createWallTransformation inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one wall skull offset and turn in the skull branch
SkullBlockRenderer.createGroundTransformation inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one ground skull turn by segment in the skull branch
SkullBlockRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one type, wall facing and turn read from the skull kind; player skin via scene.skull
SkullBlockRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on skulls and heads (render_breaking draws only banners and chests)
SkullBlockRenderer.submitSkull port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: player: no crack overlay on skulls and heads (render_breaking draws only banners and chests)
SkullBlockRenderer.resolveSkullRenderType inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one player head skin via scene.skull, otherwise the type's texture
SkullBlockRenderer.createWallTransformation inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one wall skull offset and turn in the skull branch
SkullBlockRenderer.createGroundTransformation inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one ground skull turn by segment in the skull branch
SpawnerRenderer.extractRenderState port crates/horizon-client/src/mobs/spawner.rs::display_pose spin and scale of the display mob
SpawnerRenderer.submit port crates/horizon-client/src/game/spawner.rs::Game::spawner_geometry display mob at the spawner's centre with spin, tilt and scale
StandingSignRenderer.extractRenderState inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: the text filtering option is not read
StandingSignRenderer.createTransformations inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one front and back text transforms per attachment
StandingSignRenderer.extractRenderState inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one gap: minor: the text filtering option is not read
StandingSignRenderer.createTransformations inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one front and back text transforms per attachment
TestInstanceRenderer.extractRenderState missing player: creative players placing a test instance block see no beacon beam, box or error markers
TestInstanceRenderer.submit missing player: creative players placing a test instance block see no beacon beam or box
TestInstanceRenderer.submitErrorMarker missing player: red error markers and their text are not drawn
TestInstanceRenderer.shouldRenderOffScreen missing minor: culling policy of a renderer Horizon lacks
TestInstanceRenderer.shouldRender missing minor: culling policy of a renderer Horizon lacks
TheEndGatewayRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one beam and visible cube faces in the end gateway branch
TheEndPortalRenderer.submit port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one portal slab in the end portal branch
TheEndGatewayRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one beam and visible cube faces in the end gateway branch
TheEndPortalRenderer.submit port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one portal slab in the end portal branch
TrialSpawnerRenderer.extractRenderState port crates/horizon-client/src/mobs/spawner.rs::display_pose same spin and scale rule as spawners
TrialSpawnerRenderer.submit port crates/horizon-client/src/game/spawner.rs::Game::spawner_geometry trial spawner display mob drawn in the same pass
VaultRenderer.extractRenderState inline crates/horizon-client/src/game/vault.rs::Game::vault_geometry display item and spin read there
Can't render this file because it contains an unexpected character in line 13 and column 112.
+46 -46
View File
@@ -1,24 +1,24 @@
CloudRenderer.getSizeForCloudDistance skip:java GPU ring-buffer capacity for the cloud face buffer; Horizon sizes its vertex buffer from the built mesh
CloudRenderer.packCellData inline crates/horizon-client/src/clouds.rs::Mesh::prepare cell presence is a bool test on the texture grid; no packed long
CloudRenderer.isNorthEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.isEastEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.isSouthEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.isWestEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.render port crates/horizon-client/src/gfx.rs::Renderer::draw_frame gap: minor: one cloud pipeline; fancy vs flat is chosen by the mesh fast flag, not by pipeline
CloudRenderer.packCellData inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare cell presence is a bool test on the texture grid; no packed long
CloudRenderer.isNorthEmpty inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.isEastEmpty inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.isSouthEmpty inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.isWestEmpty inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
CloudRenderer.render port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: one cloud pipeline; fancy vs flat is chosen by the mesh fast flag, not by pipeline
CloudRenderer.renderOit missing player: with Improved transparency on, clouds keep the classic blend; no OIT pass exists and the option is only saved
CloudRenderer.buildMesh port crates/horizon-client/src/clouds.rs::Mesh::prepare cell ring walk via cells(radius), nearest first
CloudRenderer.tryBuildCell inline crates/horizon-client/src/clouds.rs::Mesh::prepare skip empty cells, then build the cell's faces
CloudRenderer.encodeFace inline crates/horizon-client/src/clouds.rs::Mesh::prepare 3-byte face records replaced by vertex quads
CloudRenderer.buildExtrudedCell port crates/horizon-client/src/clouds.rs::face_mask top, bottom and side visibility; quads emitted in Mesh::prepare via faces()
CubeMap.initializeVertices port crates/horizon-client/src/gfx/panorama.rs::Panorama::new 24-corner cube; Horizon draws 36 vertices from the shader in the pipeline built here
CloudRenderer.buildMesh port crates/horizon-client-render/src/clouds.rs::Mesh::prepare cell ring walk via cells(radius), nearest first
CloudRenderer.tryBuildCell inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare skip empty cells, then build the cell's faces
CloudRenderer.encodeFace inline crates/horizon-client-render/src/clouds.rs::Mesh::prepare 3-byte face records replaced by vertex quads
CloudRenderer.buildExtrudedCell port crates/horizon-client-render/src/clouds.rs::face_mask top, bottom and side visibility; quads emitted in Mesh::prepare via faces()
CubeMap.initializeVertices port crates/horizon-client-render/src/gfx/panorama.rs::Panorama::new 24-corner cube; Horizon draws 36 vertices from the shader in the pipeline built here
DebugCrosshairRenderer.<init> skip:debug F3 3D axis gizmo at the view; Horizon has no debug crosshair
DynamicGpuData.reset skip:other GPU per-frame ring reset; wgpu staging in Horizon's Uploads belt
DynamicGpuData.close skip:other GPU buffer release; Rust drops the wgpu buffers
DynamicGpuData.writeTransform skip:other per-draw uniform staging; Horizon writes its uniforms directly with queue writes
DynamicGpuData.writeChunkSections port crates/horizon-client/src/gfx.rs::section_instance gap: player: section fade-in (vanilla default 0.75 s) is not sent; Horizon writes a fixed fourth value
DynamicGpuData.writeChunkSectionsInstanced port crates/horizon-client/src/gfx.rs::section_instance gap: player: section fade-in (vanilla default 0.75 s) is not sent; same instance record as writeChunkSections
DynamicGpuData.writeChunkSectionCommands port crates/horizon-client/src/gfx.rs::Renderer::draw_frame IndexedDraw records built and uploaded into the indirect buffer
DynamicGpuData.ChunkSectionInfo.write port crates/horizon-client/src/gfx.rs::section_instance gap: player: packs origin only; the fade-in visibility float (default 0.75 s) is not in the record
DynamicGpuData.writeChunkSections port crates/horizon-client-render/src/gfx.rs::section_instance gap: player: section fade-in (vanilla default 0.75 s) is not sent; Horizon writes a fixed fourth value
DynamicGpuData.writeChunkSectionsInstanced port crates/horizon-client-render/src/gfx.rs::section_instance gap: player: section fade-in (vanilla default 0.75 s) is not sent; same instance record as writeChunkSections
DynamicGpuData.writeChunkSectionCommands port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame IndexedDraw records built and uploaded into the indirect buffer
DynamicGpuData.ChunkSectionInfo.write port crates/horizon-client-render/src/gfx.rs::section_instance gap: player: packs origin only; the fade-in visibility float (default 0.75 s) is not in the record
DynamicGpuData.IndexedDraw.write skip:other indirect draw args; Horizon keeps them as [u32;5] words uploaded in one copy
DynamicGpuData.TerrainTransform.write skip:other terrain UBO layout; Horizon's terrain pass uses its own uniforms
DynamicGpuData.Transform.write skip:other std140 layout of the transform UBO; wgpu bindings in Horizon
@@ -50,12 +50,12 @@ FirstPersonHandsAndItemsRenderer.applyItemArmAttackTransform port crates/horizon
FirstPersonHandsAndItemsRenderer.applyItemArmTransform port crates/horizon-client/src/first_person.rs::item_pose base item-in-arm translation
FirstPersonHandsAndItemsRenderer.submitHandsWithItems port crates/horizon-client/src/game.rs::Game::hand_geometry sway, both hands, empty-hand arm and item pose
FirstPersonHandsAndItemsRenderer.swingArm port crates/horizon-client/src/first_person.rs::item_pose attack swing translation and arm rotation
GameRenderer.<init> port crates/horizon-client/src/gfx.rs::Renderer::new lightmap, hand target, debug crosshair and screen effects are built here
GameRenderer.<init> port crates/horizon-client-render/src/gfx.rs::Renderer::new lightmap, hand target, debug crosshair and screen effects are built here
GameRenderer.close skip:other GPU resource teardown; wgpu drops the renderer's objects
GameRenderer.checkEntityPostEffect missing player: spectating a creeper, spider or enderman does not put their overlay shader on the screen
GameRenderer.processBlurEffect port crates/horizon-client/src/menu_blur.rs::MenuBlur::apply menu background blur pass
GameRenderer.processBlurEffect port crates/horizon-client-render/src/menu_blur.rs::MenuBlur::apply menu background blur pass
GameRenderer.preloadUiShader skip:other GPU pipeline precompile at load; Horizon builds its pipelines in Renderer::new
GameRenderer.update port crates/horizon-client/src/camera.rs::AvatarBob::update_bob gap: minor: the requested post-effect list (from /postEffect) is not built
GameRenderer.update port crates/horizon-client-render/src/camera.rs::AvatarBob::update_bob gap: minor: the requested post-effect list (from /postEffect) is not built
GameRenderer.extract skip:other render-state copy for the vanilla render thread; Horizon renders from game state
GameRenderer.preparePostEffects missing minor: vanilla post chains from requested effects are not applied; shader packs use pack_post
GameRenderer.applyPostEffects missing minor: vanilla post chains are not run; shader packs use pack_post
@@ -75,37 +75,37 @@ GpuWarnlistManager.parseJson missing minor: no GPU driver warnlist JSON
GpuWarnlistManager.Preparations.matchAny missing minor: no GPU driver warnlist matching
LevelEventHandler.playJukeboxSong port crates/horizon-client/src/game/jukebox.rs::Game::start_song song starts and the now-playing overlay is shown
LevelEventHandler.stopJukeboxSong port crates/horizon-client/src/game/jukebox.rs::Game::stop_song song sound stops for that jukebox
LevelRenderer.<init> port crates/horizon-client/src/gfx.rs::Renderer::new targets, pipelines and buffers built once
LevelRenderer.submitFeatures port crates/horizon-client/src/gfx.rs::Renderer::draw_frame entities, block entities, crumbling, particles, outline and gizmos are submitted and drawn in the frame
LevelRenderer.repositionCamera port crates/horizon-client/src/gfx/resident.rs::camera_column camera section column that the section grid is centred on; gap: minor: world border invalidation is not part of it
LevelRenderer.addMainPass port crates/horizon-client/src/gfx.rs::Renderer::draw_frame gap: minor: the Improved transparency targets (depth bounds, transmittance, accumulate) are not created
LevelRenderer.<init> port crates/horizon-client-render/src/gfx.rs::Renderer::new targets, pipelines and buffers built once
LevelRenderer.submitFeatures port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame entities, block entities, crumbling, particles, outline and gizmos are submitted and drawn in the frame
LevelRenderer.repositionCamera port crates/horizon-client-render/src/gfx/resident.rs::camera_column camera section column that the section grid is centred on; gap: minor: world border invalidation is not part of it
LevelRenderer.addMainPass port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: the Improved transparency targets (depth bounds, transmittance, accumulate) are not created
LevelRenderer.executeAlwaysOnTop port crates/horizon-client/src/game.rs::Game::render always-on-top debug lines and crosshair drawn over the world
LevelRenderer.executeSolid port crates/horizon-client/src/gfx.rs::Renderer::draw_sections solid section draws in arena page order
LevelRenderer.prepareTranslucents port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort translucent quads sorted from the camera each frame
LevelRenderer.executeSolid port crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections solid section draws in arena page order
LevelRenderer.prepareTranslucents port crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort translucent quads sorted from the camera each frame
LevelRenderer.executeOit missing player: with Improved transparency on, translucent blocks and water blend order-independently; Horizon has no OIT pass and the option does nothing
LevelRenderer.executeDepthBoundsCull missing player: part of Improved transparency's pass; no depth-bounds cull exists in Horizon
LevelRenderer.executeOitWaterMask missing player: part of Improved transparency; no water mask pass exists in Horizon
LevelRenderer.extractSectionDrawGroups port crates/horizon-client/src/gfx.rs::Renderer::draw_frame section draws grouped per layer and arena page from the visible sections
LevelRenderer.prepareChunkRenders port crates/horizon-client/src/gfx.rs::Renderer::draw_frame per-layer draw list built for the frame, reversed for translucent layers
LevelRenderer.extractSectionDrawGroups port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame section draws grouped per layer and arena page from the visible sections
LevelRenderer.prepareChunkRenders port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame per-layer draw list built for the frame, reversed for translucent layers
LevelRenderer.performTransientBlockRemovals missing minor: removes transient blocks when their section recompiles; Horizon has no transient blocks
LevelRenderer.prepareChunkRendersIndirect port crates/horizon-client/src/gfx.rs::Renderer::draw_frame indirect draw arguments written and multi-draw issued
LevelRenderer.compileSections port crates/horizon-client/src/streaming.rs::Streaming::update section meshing jobs queued for dirty sections nearest the camera
LevelRenderer.submitEntities port crates/horizon-client/src/gfx.rs::Renderer::draw_frame entity models drawn with their batches
LevelRenderer.submitBlockEntities port crates/horizon-client/src/gfx.rs::Renderer::block_entities block entity list submitted for drawing
LevelRenderer.submitBlockDestroyAnimation port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crumbling overlay drawn on the block being broken
LevelRenderer.prepareChunkRendersIndirect port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame indirect draw arguments written and multi-draw issued
LevelRenderer.compileSections port crates/horizon-client-render/src/streaming.rs::Streaming::update section meshing jobs queued for dirty sections nearest the camera
LevelRenderer.submitEntities port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame entity models drawn with their batches
LevelRenderer.submitBlockEntities port crates/horizon-client-render/src/gfx.rs::Renderer::block_entities block entity list submitted for drawing
LevelRenderer.submitBlockDestroyAnimation port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame crumbling overlay drawn on the block being broken
LevelRenderer.submitTransientBlocks missing player: a block the server sends as temporary (ClientboundAddTransientBlockPacket) does not appear; the packet is not handled
LevelRenderer.submitHitOutline port crates/horizon-client/src/game.rs::Game::outline_boxes outline of the block under the crosshair
LevelRenderer.close skip:other GPU resource teardown
LevelRenderer.invalidateCompiledGeometry port crates/horizon-client/src/gfx.rs::Renderer::clear_sections all section meshes dropped and rebuilt when settings are applied
LevelRenderer.scheduleTranslucentSectionResort port crates/horizon-client/src/gfx/translucency.rs::SortState::update resort scheduled when the camera point of view changes
LevelRenderer.scheduleResort port crates/horizon-client/src/gfx/translucency.rs::SortState::update per-section resort gated by point-of-view change and translucent geometry
LevelRenderer.resetLevelRenderData port crates/horizon-client/src/gfx.rs::Renderer::clear_sections section data released when a level is left
LevelRenderer.invalidateCompiledGeometry port crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections all section meshes dropped and rebuilt when settings are applied
LevelRenderer.scheduleTranslucentSectionResort port crates/horizon-client-render/src/gfx/translucency.rs::SortState::update resort scheduled when the camera point of view changes
LevelRenderer.scheduleResort port crates/horizon-client-render/src/gfx/translucency.rs::SortState::update per-section resort gated by point-of-view change and translucent geometry
LevelRenderer.resetLevelRenderData port crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections section data released when a level is left
LevelRenderer.hasRenderedAllSections missing minor: only the world icon screenshot asks this, and that screenshot is missing
LevelRenderer.isSectionCompiledAndVisible port crates/horizon-client/src/gfx/resident.rs::Resident::contains gap: minor: no section fade-in, so the 0.3 visibility threshold is not checked
LevelRenderer.isSectionCompiledAndVisible port crates/horizon-client-render/src/gfx/resident.rs::Resident::contains gap: minor: no section fade-in, so the 0.3 visibility threshold is not checked
LevelRenderer.finalizeGizmoCollection port crates/horizon-client/src/game/debug_keys.rs::Game::debug_gizmos debug gizmos collected for the frame
LevelTargetBundle.replace skip:other render-target bundle for post chains; Horizon has no frame graph
LevelTargetBundle.get skip:other render-target bundle for post chains; Horizon has no frame graph
Lightmap.render port crates/horizon-client/src/gfx.rs::Renderer::update_lightmap lightmap pass from sky, block, darkness, gamma, night vision, flicker and boss darkening
Lightmap.render port crates/horizon-client-render/src/gfx.rs::Renderer::update_lightmap lightmap pass from sky, block, darkness, gamma, night vision, flicker and boss darkening
LightmapRenderStateExtractor.calculateDarknessScale port crates/horizon-client/src/game/sculk.rs::Game::darkness_lighting pulsing darkness scale from the darkness blend and the option
LightmapRenderStateExtractor.extract port crates/horizon-client/src/game.rs::Game::render lightmap inputs gathered into the frame; the end flash is added to sky_light_factor in end.rs::end_flash_sky
MapRenderer.extractRenderState port crates/horizon-client/src/game/maps.rs::Game::map_vertices map texture and decorations gathered for drawing
@@ -113,7 +113,7 @@ MapRenderer.extractDecorationRenderState port crates/horizon-client/src/game/map
MappableRingBuffer.currentBuffer skip:other GPU ring buffer bookkeeping
MappableRingBuffer.rotate skip:other GPU ring buffer bookkeeping
MappableRingBuffer.close skip:other GPU buffer release
MultiblockChestResources.select inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one single, left and right chest sprite chosen by ChestPart
MultiblockChestResources.select inline crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one single, left and right chest sprite chosen by ChestPart
MultiblockChestResources.map skip:java record mapping of the three sprites
Octree.isClose missing unsure: vanilla flags sections next to the camera so the occlusion walk keeps them; not traced in Horizon's occlusion path
Octree.AxisSorting.getAxisSorting skip:java traversal-order helper; Resident::visible sorts visible sections by distance
@@ -121,14 +121,14 @@ Octree.Branch.<init> skip:other octree node; Horizon keeps sections in a reside
Octree.Branch.add skip:other octree insert; Horizon keeps sections in a resident grid instead
Octree.Branch.getNodeIndex skip:other octree child index; Horizon keeps sections in a resident grid instead
Octree.Branch.createChildBoundingBox skip:other octree child bounds; Horizon keeps sections in a resident grid instead
Octree.Branch.visitNodes port crates/horizon-client/src/gfx/resident.rs::Resident::visible frustum and distance visit of sections, nearest first
Octree.Branch.visitNodes port crates/horizon-client-render/src/gfx/resident.rs::Resident::visible frustum and distance visit of sections, nearest first
Octree.Branch.getAABB skip:java no callers in vanilla 26.3
Octree.Leaf.visitNodes port crates/horizon-client/src/gfx/resident.rs::Resident::visible leaf sections visited in the same frustum and distance walk
Octree.Leaf.visitNodes port crates/horizon-client-render/src/gfx/resident.rs::Resident::visible leaf sections visited in the same frustum and distance walk
OrderedSubmitNodeCollector.submitModel skip:other submit queue of vanilla's render thread; Horizon draws each model in place
OrderedSubmitNodeCollector.submitCrumblingOverlay port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crumbling overlay drawn on the block being broken
OrderedSubmitNodeCollector.submitCrumblingOverlay port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame crumbling overlay drawn on the block being broken
OrderedSubmitNodeCollector.submitModelPart skip:other submit queue of vanilla's render thread; Horizon draws each model part in place
Panorama.extractRenderState port crates/horizon-client/src/gfx/panorama.rs::Rotation::update spin accumulated from the panorama speed option; overlay blit is drawn by the title screen
PlayerSkinRenderCache.createLookup port crates/horizon-client/src/skins.rs::lookup skin texture chosen from the profile, falling back to the default skin
Panorama.extractRenderState port crates/horizon-client-render/src/gfx/panorama.rs::Rotation::update spin accumulated from the panorama speed option; overlay blit is drawn by the title screen
PlayerSkinRenderCache.createLookup port crates/horizon-client-render/src/skins.rs::lookup skin texture chosen from the profile, falling back to the default skin
PlayerSkinRenderCache.RenderInfo.renderType port crates/horizon-client/src/game/item_draw.rs::Host::player_skin skin texture path a head is drawn with; no separate render type in Horizon
PlayerSkinRenderCache.RenderInfo.textureView skip:other GPU texture view cache; Horizon binds skin textures by atlas name
PlayerSkinRenderCache.RenderInfo.glyphRenderTypes skip:other font render types for name tags; Horizon's text uses its own glyph pipeline
@@ -137,14 +137,14 @@ PlayerSkinRenderCache.RenderInfo.hashCode skip:java hash for a cache key
PostChain.load missing minor: no data-driven post chain loader; only the blur and entity outline chains exist, hard-coded
PostChain.getReferencedExternalTargets skip:other config validation for data-driven post chains
PostChain.createPass missing minor: no data-driven post pass creation; the outline and blur passes are fixed
PostChain.addToFrame port crates/horizon-client/src/gfx/entity_outline.rs::EntityOutline::draw gap: minor: runs the entity outline chain only; other chains are not built
PostChain.process port crates/horizon-client/src/menu_blur.rs::MenuBlur::apply gap: minor: runs the menu blur only; other chains are not run
PostChain.addToFrame port crates/horizon-client-render/src/gfx/entity_outline.rs::EntityOutline::draw gap: minor: runs the entity outline chain only; other chains are not built
PostChain.process port crates/horizon-client-render/src/menu_blur.rs::MenuBlur::apply gap: minor: runs the menu blur only; other chains are not run
PostChain.getOrCreatePersistentTarget skip:other GPU persistent target cache
PostChain.close skip:other GPU resource teardown
PostChain.TargetBundle.getOrThrow skip:other frame-graph target lookup; Horizon has no frame graph
PostChainConfig.Pass.referencedTargets skip:data config accessor for post chain JSON
PostPass.<init> skip:other GPU pipeline creation for a post pass
PostPass.addToFrame port crates/horizon-client/src/gfx/entity_outline.rs::EntityOutline::draw gap: minor: the pass runs inside the entity outline draw only
PostPass.addToFrame port crates/horizon-client-render/src/gfx/entity_outline.rs::EntityOutline::draw gap: minor: the pass runs inside the entity outline draw only
PostPass.close skip:other GPU resource teardown
PostPass.TargetInput.getHandle skip:other frame-graph input handle
PostPass.TargetInput.texture skip:other frame-graph input texture view
1 CloudRenderer.getSizeForCloudDistance skip:java GPU ring-buffer capacity for the cloud face buffer; Horizon sizes its vertex buffer from the built mesh
2 CloudRenderer.packCellData inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare cell presence is a bool test on the texture grid; no packed long
3 CloudRenderer.isNorthEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
4 CloudRenderer.isEastEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
5 CloudRenderer.isSouthEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
6 CloudRenderer.isWestEmpty inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare neighbour-empty flags passed to face_mask in N,E,S,W order
7 CloudRenderer.render port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: one cloud pipeline; fancy vs flat is chosen by the mesh fast flag, not by pipeline
8 CloudRenderer.renderOit missing player: with Improved transparency on, clouds keep the classic blend; no OIT pass exists and the option is only saved
9 CloudRenderer.buildMesh port crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare cell ring walk via cells(radius), nearest first
10 CloudRenderer.tryBuildCell inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare skip empty cells, then build the cell's faces
11 CloudRenderer.encodeFace inline crates/horizon-client/src/clouds.rs::Mesh::prepare crates/horizon-client-render/src/clouds.rs::Mesh::prepare 3-byte face records replaced by vertex quads
12 CloudRenderer.buildExtrudedCell port crates/horizon-client/src/clouds.rs::face_mask crates/horizon-client-render/src/clouds.rs::face_mask top, bottom and side visibility; quads emitted in Mesh::prepare via faces()
13 CubeMap.initializeVertices port crates/horizon-client/src/gfx/panorama.rs::Panorama::new crates/horizon-client-render/src/gfx/panorama.rs::Panorama::new 24-corner cube; Horizon draws 36 vertices from the shader in the pipeline built here
14 DebugCrosshairRenderer.<init> skip:debug F3 3D axis gizmo at the view; Horizon has no debug crosshair
15 DynamicGpuData.reset skip:other GPU per-frame ring reset; wgpu staging in Horizon's Uploads belt
16 DynamicGpuData.close skip:other GPU buffer release; Rust drops the wgpu buffers
17 DynamicGpuData.writeTransform skip:other per-draw uniform staging; Horizon writes its uniforms directly with queue writes
18 DynamicGpuData.writeChunkSections port crates/horizon-client/src/gfx.rs::section_instance crates/horizon-client-render/src/gfx.rs::section_instance gap: player: section fade-in (vanilla default 0.75 s) is not sent; Horizon writes a fixed fourth value
19 DynamicGpuData.writeChunkSectionsInstanced port crates/horizon-client/src/gfx.rs::section_instance crates/horizon-client-render/src/gfx.rs::section_instance gap: player: section fade-in (vanilla default 0.75 s) is not sent; same instance record as writeChunkSections
20 DynamicGpuData.writeChunkSectionCommands port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame IndexedDraw records built and uploaded into the indirect buffer
21 DynamicGpuData.ChunkSectionInfo.write port crates/horizon-client/src/gfx.rs::section_instance crates/horizon-client-render/src/gfx.rs::section_instance gap: player: packs origin only; the fade-in visibility float (default 0.75 s) is not in the record
22 DynamicGpuData.IndexedDraw.write skip:other indirect draw args; Horizon keeps them as [u32;5] words uploaded in one copy
23 DynamicGpuData.TerrainTransform.write skip:other terrain UBO layout; Horizon's terrain pass uses its own uniforms
24 DynamicGpuData.Transform.write skip:other std140 layout of the transform UBO; wgpu bindings in Horizon
50 FirstPersonHandsAndItemsRenderer.applyItemArmTransform port crates/horizon-client/src/first_person.rs::item_pose base item-in-arm translation
51 FirstPersonHandsAndItemsRenderer.submitHandsWithItems port crates/horizon-client/src/game.rs::Game::hand_geometry sway, both hands, empty-hand arm and item pose
52 FirstPersonHandsAndItemsRenderer.swingArm port crates/horizon-client/src/first_person.rs::item_pose attack swing translation and arm rotation
53 GameRenderer.<init> port crates/horizon-client/src/gfx.rs::Renderer::new crates/horizon-client-render/src/gfx.rs::Renderer::new lightmap, hand target, debug crosshair and screen effects are built here
54 GameRenderer.close skip:other GPU resource teardown; wgpu drops the renderer's objects
55 GameRenderer.checkEntityPostEffect missing player: spectating a creeper, spider or enderman does not put their overlay shader on the screen
56 GameRenderer.processBlurEffect port crates/horizon-client/src/menu_blur.rs::MenuBlur::apply crates/horizon-client-render/src/menu_blur.rs::MenuBlur::apply menu background blur pass
57 GameRenderer.preloadUiShader skip:other GPU pipeline precompile at load; Horizon builds its pipelines in Renderer::new
58 GameRenderer.update port crates/horizon-client/src/camera.rs::AvatarBob::update_bob crates/horizon-client-render/src/camera.rs::AvatarBob::update_bob gap: minor: the requested post-effect list (from /postEffect) is not built
59 GameRenderer.extract skip:other render-state copy for the vanilla render thread; Horizon renders from game state
60 GameRenderer.preparePostEffects missing minor: vanilla post chains from requested effects are not applied; shader packs use pack_post
61 GameRenderer.applyPostEffects missing minor: vanilla post chains are not run; shader packs use pack_post
75 GpuWarnlistManager.Preparations.matchAny missing minor: no GPU driver warnlist matching
76 LevelEventHandler.playJukeboxSong port crates/horizon-client/src/game/jukebox.rs::Game::start_song song starts and the now-playing overlay is shown
77 LevelEventHandler.stopJukeboxSong port crates/horizon-client/src/game/jukebox.rs::Game::stop_song song sound stops for that jukebox
78 LevelRenderer.<init> port crates/horizon-client/src/gfx.rs::Renderer::new crates/horizon-client-render/src/gfx.rs::Renderer::new targets, pipelines and buffers built once
79 LevelRenderer.submitFeatures port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame entities, block entities, crumbling, particles, outline and gizmos are submitted and drawn in the frame
80 LevelRenderer.repositionCamera port crates/horizon-client/src/gfx/resident.rs::camera_column crates/horizon-client-render/src/gfx/resident.rs::camera_column camera section column that the section grid is centred on; gap: minor: world border invalidation is not part of it
81 LevelRenderer.addMainPass port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: the Improved transparency targets (depth bounds, transmittance, accumulate) are not created
82 LevelRenderer.executeAlwaysOnTop port crates/horizon-client/src/game.rs::Game::render always-on-top debug lines and crosshair drawn over the world
83 LevelRenderer.executeSolid port crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections solid section draws in arena page order
84 LevelRenderer.prepareTranslucents port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort translucent quads sorted from the camera each frame
85 LevelRenderer.executeOit missing player: with Improved transparency on, translucent blocks and water blend order-independently; Horizon has no OIT pass and the option does nothing
86 LevelRenderer.executeDepthBoundsCull missing player: part of Improved transparency's pass; no depth-bounds cull exists in Horizon
87 LevelRenderer.executeOitWaterMask missing player: part of Improved transparency; no water mask pass exists in Horizon
88 LevelRenderer.extractSectionDrawGroups port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame section draws grouped per layer and arena page from the visible sections
89 LevelRenderer.prepareChunkRenders port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame per-layer draw list built for the frame, reversed for translucent layers
90 LevelRenderer.performTransientBlockRemovals missing minor: removes transient blocks when their section recompiles; Horizon has no transient blocks
91 LevelRenderer.prepareChunkRendersIndirect port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame indirect draw arguments written and multi-draw issued
92 LevelRenderer.compileSections port crates/horizon-client/src/streaming.rs::Streaming::update crates/horizon-client-render/src/streaming.rs::Streaming::update section meshing jobs queued for dirty sections nearest the camera
93 LevelRenderer.submitEntities port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame entity models drawn with their batches
94 LevelRenderer.submitBlockEntities port crates/horizon-client/src/gfx.rs::Renderer::block_entities crates/horizon-client-render/src/gfx.rs::Renderer::block_entities block entity list submitted for drawing
95 LevelRenderer.submitBlockDestroyAnimation port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame crumbling overlay drawn on the block being broken
96 LevelRenderer.submitTransientBlocks missing player: a block the server sends as temporary (ClientboundAddTransientBlockPacket) does not appear; the packet is not handled
97 LevelRenderer.submitHitOutline port crates/horizon-client/src/game.rs::Game::outline_boxes outline of the block under the crosshair
98 LevelRenderer.close skip:other GPU resource teardown
99 LevelRenderer.invalidateCompiledGeometry port crates/horizon-client/src/gfx.rs::Renderer::clear_sections crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections all section meshes dropped and rebuilt when settings are applied
100 LevelRenderer.scheduleTranslucentSectionResort port crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update resort scheduled when the camera point of view changes
101 LevelRenderer.scheduleResort port crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update per-section resort gated by point-of-view change and translucent geometry
102 LevelRenderer.resetLevelRenderData port crates/horizon-client/src/gfx.rs::Renderer::clear_sections crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections section data released when a level is left
103 LevelRenderer.hasRenderedAllSections missing minor: only the world icon screenshot asks this, and that screenshot is missing
104 LevelRenderer.isSectionCompiledAndVisible port crates/horizon-client/src/gfx/resident.rs::Resident::contains crates/horizon-client-render/src/gfx/resident.rs::Resident::contains gap: minor: no section fade-in, so the 0.3 visibility threshold is not checked
105 LevelRenderer.finalizeGizmoCollection port crates/horizon-client/src/game/debug_keys.rs::Game::debug_gizmos debug gizmos collected for the frame
106 LevelTargetBundle.replace skip:other render-target bundle for post chains; Horizon has no frame graph
107 LevelTargetBundle.get skip:other render-target bundle for post chains; Horizon has no frame graph
108 Lightmap.render port crates/horizon-client/src/gfx.rs::Renderer::update_lightmap crates/horizon-client-render/src/gfx.rs::Renderer::update_lightmap lightmap pass from sky, block, darkness, gamma, night vision, flicker and boss darkening
109 LightmapRenderStateExtractor.calculateDarknessScale port crates/horizon-client/src/game/sculk.rs::Game::darkness_lighting pulsing darkness scale from the darkness blend and the option
110 LightmapRenderStateExtractor.extract port crates/horizon-client/src/game.rs::Game::render lightmap inputs gathered into the frame; the end flash is added to sky_light_factor in end.rs::end_flash_sky
111 MapRenderer.extractRenderState port crates/horizon-client/src/game/maps.rs::Game::map_vertices map texture and decorations gathered for drawing
113 MappableRingBuffer.currentBuffer skip:other GPU ring buffer bookkeeping
114 MappableRingBuffer.rotate skip:other GPU ring buffer bookkeeping
115 MappableRingBuffer.close skip:other GPU buffer release
116 MultiblockChestResources.select inline crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_one crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_one single, left and right chest sprite chosen by ChestPart
117 MultiblockChestResources.map skip:java record mapping of the three sprites
118 Octree.isClose missing unsure: vanilla flags sections next to the camera so the occlusion walk keeps them; not traced in Horizon's occlusion path
119 Octree.AxisSorting.getAxisSorting skip:java traversal-order helper; Resident::visible sorts visible sections by distance
121 Octree.Branch.add skip:other octree insert; Horizon keeps sections in a resident grid instead
122 Octree.Branch.getNodeIndex skip:other octree child index; Horizon keeps sections in a resident grid instead
123 Octree.Branch.createChildBoundingBox skip:other octree child bounds; Horizon keeps sections in a resident grid instead
124 Octree.Branch.visitNodes port crates/horizon-client/src/gfx/resident.rs::Resident::visible crates/horizon-client-render/src/gfx/resident.rs::Resident::visible frustum and distance visit of sections, nearest first
125 Octree.Branch.getAABB skip:java no callers in vanilla 26.3
126 Octree.Leaf.visitNodes port crates/horizon-client/src/gfx/resident.rs::Resident::visible crates/horizon-client-render/src/gfx/resident.rs::Resident::visible leaf sections visited in the same frustum and distance walk
127 OrderedSubmitNodeCollector.submitModel skip:other submit queue of vanilla's render thread; Horizon draws each model in place
128 OrderedSubmitNodeCollector.submitCrumblingOverlay port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame crumbling overlay drawn on the block being broken
129 OrderedSubmitNodeCollector.submitModelPart skip:other submit queue of vanilla's render thread; Horizon draws each model part in place
130 Panorama.extractRenderState port crates/horizon-client/src/gfx/panorama.rs::Rotation::update crates/horizon-client-render/src/gfx/panorama.rs::Rotation::update spin accumulated from the panorama speed option; overlay blit is drawn by the title screen
131 PlayerSkinRenderCache.createLookup port crates/horizon-client/src/skins.rs::lookup crates/horizon-client-render/src/skins.rs::lookup skin texture chosen from the profile, falling back to the default skin
132 PlayerSkinRenderCache.RenderInfo.renderType port crates/horizon-client/src/game/item_draw.rs::Host::player_skin skin texture path a head is drawn with; no separate render type in Horizon
133 PlayerSkinRenderCache.RenderInfo.textureView skip:other GPU texture view cache; Horizon binds skin textures by atlas name
134 PlayerSkinRenderCache.RenderInfo.glyphRenderTypes skip:other font render types for name tags; Horizon's text uses its own glyph pipeline
137 PostChain.load missing minor: no data-driven post chain loader; only the blur and entity outline chains exist, hard-coded
138 PostChain.getReferencedExternalTargets skip:other config validation for data-driven post chains
139 PostChain.createPass missing minor: no data-driven post pass creation; the outline and blur passes are fixed
140 PostChain.addToFrame port crates/horizon-client/src/gfx/entity_outline.rs::EntityOutline::draw crates/horizon-client-render/src/gfx/entity_outline.rs::EntityOutline::draw gap: minor: runs the entity outline chain only; other chains are not built
141 PostChain.process port crates/horizon-client/src/menu_blur.rs::MenuBlur::apply crates/horizon-client-render/src/menu_blur.rs::MenuBlur::apply gap: minor: runs the menu blur only; other chains are not run
142 PostChain.getOrCreatePersistentTarget skip:other GPU persistent target cache
143 PostChain.close skip:other GPU resource teardown
144 PostChain.TargetBundle.getOrThrow skip:other frame-graph target lookup; Horizon has no frame graph
145 PostChainConfig.Pass.referencedTargets skip:data config accessor for post chain JSON
146 PostPass.<init> skip:other GPU pipeline creation for a post pass
147 PostPass.addToFrame port crates/horizon-client/src/gfx/entity_outline.rs::EntityOutline::draw crates/horizon-client-render/src/gfx/entity_outline.rs::EntityOutline::draw gap: minor: the pass runs inside the entity outline draw only
148 PostPass.close skip:other GPU resource teardown
149 PostPass.TargetInput.getHandle skip:other frame-graph input handle
150 PostPass.TargetInput.texture skip:other frame-graph input texture view
+70 -70
View File
@@ -1,38 +1,38 @@
Projection.setupPerspective inline crates/horizon-client/src/camera.rs::perspective gap: minor: the dirty-flag cache and the stored fov/near/far are not kept; the matrix is built from the arguments per call
Projection.setupPerspective inline crates/horizon-client-render/src/camera.rs::perspective gap: minor: the dirty-flag cache and the stored fov/near/far are not kept; the matrix is built from the arguments per call
Projection.setupOrtho skip:ui GUI draws in pixels through Horizon's own HUD pipeline; no ortho projection state of its own
Projection.getMatrixVersion skip:java matrix version counter for the dirty-check cache
ProjectionMatrixBuffer.getBuffer skip:other GPU buffer handle getter; Horizon owns its uniform buffers in gfx.rs
ProjectionMatrixBuffer.writeBuffer port crates/horizon-client/src/gfx/upload.rs::Uploads::buffer gap: minor: the caller decides which uniform receives the projection
ProjectionMatrixBuffer.writeBuffer port crates/horizon-client-render/src/gfx/upload.rs::Uploads::buffer gap: minor: the caller decides which uniform receives the projection
Rect2i.intersect skip:ui GUI clip rectangle math; Horizon clips each draw in hud.rs (clip_since), no rectangle type
Rect2i.contains skip:ui GUI hit test on a rectangle; Horizon's widgets hit-test in their own UI code
RenderPipelines.register skip:data pipeline registry; Horizon creates its pipelines in gfx.rs
RunningTrimmedMean.registerValueAndGetMean skip:debug frame-time smoothing helper; no vanilla caller in this source tree
ScreenEffectRenderer.submit port crates/horizon-client/src/screen_effects.rs::ScreenEffects::build gap: minor: the item activation is not built here (see renderItemActivationAnimation)
ScreenEffectRenderer.submit port crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build gap: minor: the item activation is not built here (see renderItemActivationAnimation)
ScreenEffectRenderer.renderItemActivationAnimation missing player: when a totem of undying saves the player, the totem does not pop up in front of the screen; Horizon only plays the totem particles and sound (game/totem.rs totem_event)
ScreenEffectRenderer.submitWater inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build underwater overlay branch (misc/underwater)
ScreenEffectRenderer.submitFire inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build first-person fire overlay branch (block/fire_1, two quads)
ScreenEffectRenderer.buildFireQuad inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build the two fire quads' corners and offsets
ScreenEffectRenderer.buildSpriteQuad inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build hand_quad closure: sprite rect and uv for overlay quads
ScreenEffectRenderer.buildQuad inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build hand_quad closure: corners, uv and colour of one overlay quad
ScreenEffectRenderer.submitWater inline crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build underwater overlay branch (misc/underwater)
ScreenEffectRenderer.submitFire inline crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build first-person fire overlay branch (block/fire_1, two quads)
ScreenEffectRenderer.buildFireQuad inline crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build the two fire quads' corners and offsets
ScreenEffectRenderer.buildSpriteQuad inline crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build hand_quad closure: sprite rect and uv for overlay quads
ScreenEffectRenderer.buildQuad inline crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build hand_quad closure: corners, uv and colour of one overlay quad
SectionBufferBuilderPool.allocate skip:java heap-sized pool of section builders; Horizon's mesher uses its own worker threads
SectionOcclusionGraph.waitAndReset port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::clear gap: minor: clear discards a running search instead of waiting for it
SectionOcclusionGraph.waitAndReset port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::clear gap: minor: clear discards a running search instead of waiting for it
SectionOcclusionGraph.expectedChunks missing unsure: Horizon's occlusion graph keeps no list of sections waiting on chunk loads (streaming.rs has its own waiting set)
SectionOcclusionGraph.invalidateIfNeeded port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::update gap: minor: the search is keyed on camera section and radius only; fov and smart-cull changes do not restart it
SectionOcclusionGraph.addSectionsInFrustum port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::contains gap: minor: the frustum test is not here; the caller builds the visible list
SectionOcclusionGraph.schedulePropagationFrom port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::changed queues the changed section; propagation runs in propagate_changes
SectionOcclusionGraph.scheduleFullUpdate port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::start gap: minor: the full search goes to a worker and is collected later (collect), not to a background executor
SectionOcclusionGraph.runPartialUpdate port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::propagate_changes gap: minor: chunk-load waiting is not handled here (see expectedChunks)
SectionOcclusionGraph.initializeQueueForFullUpdate port crates/horizon-client/src/gfx/occlusion.rs::Graph::seed_outside gap: minor: seeds the sections around a camera outside the world; the camera-inside seed is in Graph::search
SectionOcclusionGraph.runUpdates port crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate gap: minor: BFS over face directions; vanilla's distant-section ray check for smart cull is not checked here
SectionOcclusionGraph.getRelativeFrom inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate neighbour lookup inside the BFS
SectionOcclusionGraph.updateEmptySections port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::set gap: minor: empty sections are not kept in a separate set; their visibility arrives through set
SectionOcclusionGraph.invalidateIfNeeded port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::update gap: minor: the search is keyed on camera section and radius only; fov and smart-cull changes do not restart it
SectionOcclusionGraph.addSectionsInFrustum port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::contains gap: minor: the frustum test is not here; the caller builds the visible list
SectionOcclusionGraph.schedulePropagationFrom port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::changed queues the changed section; propagation runs in propagate_changes
SectionOcclusionGraph.scheduleFullUpdate port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::start gap: minor: the full search goes to a worker and is collected later (collect), not to a background executor
SectionOcclusionGraph.runPartialUpdate port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::propagate_changes gap: minor: chunk-load waiting is not handled here (see expectedChunks)
SectionOcclusionGraph.initializeQueueForFullUpdate port crates/horizon-client-render/src/gfx/occlusion.rs::Graph::seed_outside gap: minor: seeds the sections around a camera outside the world; the camera-inside seed is in Graph::search
SectionOcclusionGraph.runUpdates port crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate gap: minor: BFS over face directions; vanilla's distant-section ray check for smart cull is not checked here
SectionOcclusionGraph.getRelativeFrom inline crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate neighbour lookup inside the BFS
SectionOcclusionGraph.updateEmptySections port crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::set gap: minor: empty sections are not kept in a separate set; their visibility arrives through set
SectionOcclusionGraph.updateLoadedChunks missing unsure: no loaded-chunk set for the occlusion graph found in gfx/occlusion.rs
SectionOcclusionGraph.Node.setDirections inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate face direction bits kept per section in directions[]
SectionOcclusionGraph.Node.hasDirection inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate face direction bit test inside the BFS
SectionOcclusionGraph.Node.addSourceDirection inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate entered-face bits kept per section in entered[]
SectionOcclusionGraph.Node.hasSourceDirection inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate entered-face bit test inside the BFS
SectionOcclusionGraph.Node.setDirections inline crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate face direction bits kept per section in directions[]
SectionOcclusionGraph.Node.hasDirection inline crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate face direction bit test inside the BFS
SectionOcclusionGraph.Node.addSourceDirection inline crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate entered-face bits kept per section in entered[]
SectionOcclusionGraph.Node.hasSourceDirection inline crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate entered-face bit test inside the BFS
SectionOcclusionGraph.Node.equals skip:java node equality for vanilla's hash sets; Horizon indexes sections by position
SectionOcclusionGraph.SectionToNodeMap.get port crates/horizon-client/src/gfx/occlusion.rs::Graph::index gap: minor: a per-section array index instead of a map
SectionOcclusionGraph.SectionToNodeMap.get port crates/horizon-client-render/src/gfx/occlusion.rs::Graph::index gap: minor: a per-section array index instead of a map
ShaderDefines.withOverrides skip:other merges GLSL #define sets; Horizon's WGSL uses override constants
ShaderDefines.asSourceDirectives skip:other emits GLSL #define text; Horizon has no GLSL source
ShaderDefines.isEmpty skip:other helper for the define set; see ShaderDefines
@@ -51,22 +51,22 @@ ShaderManager.getPostChain missing minor: spectator entity post effects (creepe
ShaderManager.PostChainCache.getOrLoadPostChain missing minor: cache for the spectator entity post effects Horizon lacks
ShaderManager.PostChainCache.loadPostChain missing minor: loads the spectator entity post effects Horizon lacks
ShaderManager.PostChainCache.close skip:other releases post chains; Horizon has none
Sheets.chooseSprite port crates/horizon-client/src/block_entity_render.rs::classify gap: minor: the Christmas chest texture is picked outside this fn (block_entity_render.rs extended_christmas)
SkyRenderer.<init> inline crates/horizon-client/src/gfx/pack_sky.rs::PackSky::new gap: minor: builds the disc, sunset fan, stars and void up front; sun and moon quads are built per frame in game.rs celestial_geometry
SkyRenderer.extractRenderState port crates/horizon-client/src/environment.rs::Environment::sample gap: minor: the End flash state is read in game/end.rs (end_flash_sky)
SkyRenderer.render port crates/horizon-client/src/gfx.rs::Renderer::draw_frame sky pass; the frame's sky and dark-disc flags come from Game::render
SkyRenderer.renderSkyDisc port crates/horizon-client/src/gfx/pack_sky.rs::disc top sky disc fan, sky colour from PackSky::prepare
SkyRenderer.renderDarkDisc inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame dark disc pipeline (fs_dark_disc) drawn when frame.dark_disc is set
Sheets.chooseSprite port crates/horizon-client-render/src/block_entity_render.rs::classify gap: minor: the Christmas chest texture is picked outside this fn (block_entity_render.rs extended_christmas)
SkyRenderer.<init> inline crates/horizon-client-render/src/gfx/pack_sky.rs::PackSky::new gap: minor: builds the disc, sunset fan, stars and void up front; sun and moon quads are built per frame in game.rs celestial_geometry
SkyRenderer.extractRenderState port crates/horizon-client-render/src/environment.rs::Environment::sample gap: minor: the End flash state is read in game/end.rs (end_flash_sky)
SkyRenderer.render port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame sky pass; the frame's sky and dark-disc flags come from Game::render
SkyRenderer.renderSkyDisc port crates/horizon-client-render/src/gfx/pack_sky.rs::disc top sky disc fan, sky colour from PackSky::prepare
SkyRenderer.renderDarkDisc inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame dark disc pipeline (fs_dark_disc) drawn when frame.dark_disc is set
SkyRenderer.renderSun port crates/horizon-client/src/game.rs::Game::celestial_geometry sun quad 100 blocks out, half-size 30, faded by rain
SkyRenderer.renderMoon port crates/horizon-client/src/game.rs::Game::celestial_geometry moon quad 100 blocks out, half-size 20, faded by rain
SkyRenderer.applyCelestialBodyTransform inline crates/horizon-client/src/game.rs::Game::celestial_geometry the body frame: rotate Y -90, then X by the body's angle
SkyRenderer.drawCelestialBody inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame draws the body quads with the celestial pipeline
SkyRenderer.renderSunriseAndSunset port crates/horizon-client/src/gfx/pack_sky.rs::PackSky::prepare sunset fan turned to the sun's horizon and its alpha uploaded as sunrise
SkyRenderer.renderEndSky port crates/horizon-client/src/gfx/end_sky.rs::EndSky::draw End sky cube
SkyRenderer.buildSunriseFan port crates/horizon-client/src/gfx/pack_sky.rs::PackSky::new gap: minor: a unit 16-segment fan; the 120 and -40 block shape is not built here
SkyRenderer.drawCelestialBody inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame draws the body quads with the celestial pipeline
SkyRenderer.renderSunriseAndSunset port crates/horizon-client-render/src/gfx/pack_sky.rs::PackSky::prepare sunset fan turned to the sun's horizon and its alpha uploaded as sunrise
SkyRenderer.renderEndSky port crates/horizon-client-render/src/gfx/end_sky.rs::EndSky::draw End sky cube
SkyRenderer.buildSunriseFan port crates/horizon-client-render/src/gfx/pack_sky.rs::PackSky::new gap: minor: a unit 16-segment fan; the 120 and -40 block shape is not built here
SkyRenderer.buildCelestialQuad port crates/horizon-client/src/game.rs::Game::celestial_geometry sprite quad for the sun and moon (body closure)
SkyRenderer.buildMoonPhases port crates/horizon-client/src/game.rs::Game::celestial_geometry gap: minor: picks the phase from day time (day_time / 24000), not from the environment's moon phase value
SkyRenderer.buildSkyDisc port crates/horizon-client/src/gfx/pack_sky.rs::disc 16-block disc fan (top and bottom)
SkyRenderer.buildSkyDisc port crates/horizon-client-render/src/gfx/pack_sky.rs::disc 16-block disc fan (top and bottom)
SkyRenderer.close skip:other releases sky buffers; Rust drops the wgpu buffers
SpriteCoordinateExpander.addVertex skip:other no callers in this vanilla tree; UV wrapper for sprite quads
SpriteCoordinateExpander.setColor skip:other no callers in this vanilla tree; see addVertex
@@ -75,18 +75,18 @@ SpriteMapper.apply skip:other atlas id plumbing; Horizon looks sprites up by na
StagedVertexBuffer.appendDraw skip:other staging draw object; Horizon's arena allocates vertex ranges directly
StagedVertexBuffer.getVertexBuilder skip:other builder for the next mesh; Horizon's mesher writes straight into the section mesh
StagedVertexBuffer.finishLastVertexBuilder skip:other closes the last mesh builder; see getVertexBuilder
StagedVertexBuffer.upload port crates/horizon-client/src/gfx/arena.rs::Arena::alloc gap: minor: vertex ranges come from the arena; the copy is Uploads::buffer
StagedVertexBuffer.uploadDrawsToBuffers inline crates/horizon-client/src/gfx/upload.rs::Uploads::buffer copies the staged vertex data into the buffers
StagedVertexBuffer.decodeSortingPoints port crates/horizon-client/src/gfx/translucency.rs::quad_center gap: minor: the centre of one quad from two corners; reading the vertex buffer itself is not here
StagedVertexBuffer.upload port crates/horizon-client-render/src/gfx/arena.rs::Arena::alloc gap: minor: vertex ranges come from the arena; the copy is Uploads::buffer
StagedVertexBuffer.uploadDrawsToBuffers inline crates/horizon-client-render/src/gfx/upload.rs::Uploads::buffer copies the staged vertex data into the buffers
StagedVertexBuffer.decodeSortingPoints port crates/horizon-client-render/src/gfx/translucency.rs::quad_center gap: minor: the centre of one quad from two corners; reading the vertex buffer itself is not here
StagedVertexBuffer.getExecuteInfo skip:other describes a draw for execution; Horizon issues draws in gfx.rs::Renderer::draw_sections
StagedVertexBuffer.requestIndexCount port crates/horizon-client/src/gfx/arena.rs::Arena::indices gap: minor: the index buffer is sized when created, not requested per draw
StagedVertexBuffer.endFrame port crates/horizon-client/src/gfx/arena.rs::Arena::trim gap: minor: releases unused pages; no fence-based recycling
StagedVertexBuffer.requestIndexCount port crates/horizon-client-render/src/gfx/arena.rs::Arena::indices gap: minor: the index buffer is sized when created, not requested per draw
StagedVertexBuffer.endFrame port crates/horizon-client-render/src/gfx/arena.rs::Arena::trim gap: minor: releases unused pages; no fence-based recycling
StagedVertexBuffer.close skip:other releases buffers; Rust drops them
StagedVertexBuffer.Draw.append skip:other accumulates mesh counts for one draw; Horizon counts vertices in the arena
StagedVertexBuffer.ExecuteInfo.indexBuffer skip:other picks the index buffer for a draw; Horizon keeps its own index buffers
StagedVertexBuffer.GpuBufferPool.tryRecycleBuffers port crates/horizon-client/src/gfx/arena.rs::FreeList::give_all gap: minor: freed ranges return to the free list at once; no fence wait
StagedVertexBuffer.GpuBufferPool.acquire port crates/horizon-client/src/gfx/arena.rs::Arena::alloc gap: minor: allocates a range in an existing page instead of a new buffer per size
StagedVertexBuffer.GpuBufferPool.takeBestAvailable port crates/horizon-client/src/gfx/arena.rs::FreeList::take gap: minor: first fit, where vanilla takes the smallest buffer that fits
StagedVertexBuffer.GpuBufferPool.tryRecycleBuffers port crates/horizon-client-render/src/gfx/arena.rs::FreeList::give_all gap: minor: freed ranges return to the free list at once; no fence wait
StagedVertexBuffer.GpuBufferPool.acquire port crates/horizon-client-render/src/gfx/arena.rs::Arena::alloc gap: minor: allocates a range in an existing page instead of a new buffer per size
StagedVertexBuffer.GpuBufferPool.takeBestAvailable port crates/horizon-client-render/src/gfx/arena.rs::FreeList::take gap: minor: first fit, where vanilla takes the smallest buffer that fits
StagedVertexBuffer.GpuBufferPool.endFrame skip:other fence bookkeeping for GPU reuse; Horizon's arena releases ranges directly
StagedVertexBuffer.GpuBufferPool.close skip:other releases buffers; Rust drops them
StagedVertexBuffer.GpuBufferPool.PendingRecycle.tryRecycle skip:other fence wait for GPU reuse; Horizon has no fence here
@@ -103,10 +103,10 @@ SubmitNodeCollection.submitLeash port crates/horizon-client/src/game/leads.rs::G
SubmitNodeCollection.submitModel port crates/horizon-client/src/game/creatures.rs::Game::mob_geometry mob models
SubmitNodeCollection.submitCrumblingOverlay port crates/horizon-client/src/game.rs::Game::cracks block break cracks (destroy_stage sprites) over a block
SubmitNodeCollection.submitMovingBlock port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_geometry moving piston blocks
SubmitNodeCollection.submitBlockModel port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_block gap: minor: block models driven by block entities only
SubmitNodeCollection.getOutlineRenderType inline crates/horizon-client/src/gfx.rs::Renderer::draw_outline one outline pass; the render type choice is folded into it
SubmitNodeCollection.submitBlockModel port crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_block gap: minor: block models driven by block entities only
SubmitNodeCollection.getOutlineRenderType inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_outline one outline pass; the render type choice is folded into it
SubmitNodeCollection.submitBreakingBlockModel port crates/horizon-client/src/game.rs::Game::cracks gap: minor: drawn as cracks; the block model itself is not redrawn
SubmitNodeCollection.submitShapeOutline port crates/horizon-client/src/gfx.rs::Renderer::draw_outline block shape outline (selection box)
SubmitNodeCollection.submitShapeOutline port crates/horizon-client-render/src/gfx.rs::Renderer::draw_outline block shape outline (selection box)
SubmitNodeCollection.submitItem port crates/horizon-client/src/game/item_draw.rs::Game::dropped_item_geometry dropped item entities
SubmitNodeCollection.submitCustomGeometry port crates/horizon-client/src/mobs/guardian.rs::beam_geometry gap: minor: the guardian beam only; screen overlay quads are built in ScreenEffects::build
SubmitNodeCollection.submitGizmoPrimitives skip:debug debug gizmo overlay
@@ -120,31 +120,31 @@ SubmitNodeStorage.submitCrumblingOverlay skip:other submit wrapper; see SubmitN
SubmitNodeStorage.submitBlockModel skip:other submit wrapper; see SubmitNodeCollection.submitBlockModel
SubmitNodeStorage.submitShapeOutline skip:other submit wrapper; see SubmitNodeCollection.submitShapeOutline
SubmitNodeStorage.submitItem skip:other submit wrapper; see SubmitNodeCollection.submitItem
SubmitNodeStorage.drainPhases inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame the pass order that draws each phase
ViewArea.releaseAllBuffers port crates/horizon-client/src/gfx.rs::Renderer::clear_sections drops every section's buffers
ViewArea.repositionCamera inline crates/horizon-client/src/gfx/occlusion.rs::Occlusion::update gap: minor: the occlusion graph restarts on a camera section change; sections are keyed by absolute position, nothing is re-centred
WeatherEffectRenderer.renderWeather inline crates/horizon-client/src/gfx/weather.rs::Weather::draw draws the rain and snow column ranges
WeatherEffectRenderer.uploadVertexBuffer port crates/horizon-client/src/gfx/weather.rs::Weather::prepare gap: minor: the buffer grows to the next power of two
WeatherEffectRenderer.prepare port crates/horizon-client/src/weather.rs::column_quad gap: minor: the column list comes from rain_column and snow_column; this fn builds the quads
WeatherEffectRenderer.render port crates/horizon-client/src/gfx/weather.rs::Weather::draw draws the rain and snow columns
WeatherEffectRenderer.createSnowColumnInstance port crates/horizon-client/src/weather.rs::snow_column snow drift and brightened light
WeatherEffectRenderer.prepareInstances port crates/horizon-client/src/weather.rs::column_quad gap: minor: one column per call; the loop over columns is in the caller
WorldBorderRenderer.renderOit inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame border wall draw when frame.border is set
WorldBorderRenderer.prepareRenderPass inline crates/horizon-client/src/border_render.rs::BorderRenderer::transforms the uniforms (colour, offset, texture scroll) for the wall
WorldBorderRenderer.shouldRebuildWorldBorderBuffer port crates/horizon-client/src/border_render.rs::BorderRenderer::prepare rebuilds when the border moved or was invalidated
FluidRenderer.getHeight inline crates/horizon-client/src/mesher/fluid.rs::tesselate corner heights from own_height and the neighbour average
ChunkSectionLayer.byTransparency inline crates/horizon-client/src/mesher.rs::Mesher::face a face goes to the translucent list when it is translucent
ChunkSectionsToRender.renderGroup port crates/horizon-client/src/gfx.rs::Renderer::draw_sections gap: minor: draws the given page runs; the terrain uniforms are bound by the caller
ChunkSectionsToRender.renderOit port crates/horizon-client/src/gfx.rs::Renderer::draw_sections gap: minor: the OIT pass set-up is not in this fn
ChunkSectionsToRender.renderLayers inline crates/horizon-client/src/gfx.rs::Renderer::draw_sections per-layer loop over the page runs
ChunkSectionsToRender.DrawIndirect.render port crates/horizon-client/src/gfx.rs::Renderer::draw_sections multi-draw indirect branch
ChunkSectionsToRender.DrawSeparate.render port crates/horizon-client/src/gfx.rs::Renderer::draw_sections per-draw branch without multi-draw
RenderRegionCache.createRegion inline crates/horizon-client/src/mesher.rs::borrow gap: minor: borrows the 3x3 chunk columns around the section; nothing is copied
SubmitNodeStorage.drainPhases inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame the pass order that draws each phase
ViewArea.releaseAllBuffers port crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections drops every section's buffers
ViewArea.repositionCamera inline crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::update gap: minor: the occlusion graph restarts on a camera section change; sections are keyed by absolute position, nothing is re-centred
WeatherEffectRenderer.renderWeather inline crates/horizon-client-render/src/gfx/weather.rs::Weather::draw draws the rain and snow column ranges
WeatherEffectRenderer.uploadVertexBuffer port crates/horizon-client-render/src/gfx/weather.rs::Weather::prepare gap: minor: the buffer grows to the next power of two
WeatherEffectRenderer.prepare port crates/horizon-client-render/src/weather.rs::column_quad gap: minor: the column list comes from rain_column and snow_column; this fn builds the quads
WeatherEffectRenderer.render port crates/horizon-client-render/src/gfx/weather.rs::Weather::draw draws the rain and snow columns
WeatherEffectRenderer.createSnowColumnInstance port crates/horizon-client-render/src/weather.rs::snow_column snow drift and brightened light
WeatherEffectRenderer.prepareInstances port crates/horizon-client-render/src/weather.rs::column_quad gap: minor: one column per call; the loop over columns is in the caller
WorldBorderRenderer.renderOit inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame border wall draw when frame.border is set
WorldBorderRenderer.prepareRenderPass inline crates/horizon-client-render/src/border_render.rs::BorderRenderer::transforms the uniforms (colour, offset, texture scroll) for the wall
WorldBorderRenderer.shouldRebuildWorldBorderBuffer port crates/horizon-client-render/src/border_render.rs::BorderRenderer::prepare rebuilds when the border moved or was invalidated
FluidRenderer.getHeight inline crates/horizon-client-render/src/mesher/fluid.rs::tesselate corner heights from own_height and the neighbour average
ChunkSectionLayer.byTransparency inline crates/horizon-client-render/src/mesher.rs::Mesher::face a face goes to the translucent list when it is translucent
ChunkSectionsToRender.renderGroup port crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections gap: minor: draws the given page runs; the terrain uniforms are bound by the caller
ChunkSectionsToRender.renderOit port crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections gap: minor: the OIT pass set-up is not in this fn
ChunkSectionsToRender.renderLayers inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections per-layer loop over the page runs
ChunkSectionsToRender.DrawIndirect.render port crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections multi-draw indirect branch
ChunkSectionsToRender.DrawSeparate.render port crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections per-draw branch without multi-draw
RenderRegionCache.createRegion inline crates/horizon-client-render/src/mesher.rs::borrow gap: minor: borrows the 3x3 chunk columns around the section; nothing is copied
RenderRegionCache.getSectionDataCopy skip:java per-thread copy cache; Horizon borrows the chunks
RenderSectionRegion.getBlockState inline crates/horizon-client/src/mesher.rs::Mesher::mesh block reads of the mesh loop
RenderSectionRegion.getFluidState port crates/horizon-client/src/mesher/fluid.rs::FlowView::fluid fluid read used by the fluid mesher
RenderSectionRegion.getBlockState inline crates/horizon-client-render/src/mesher.rs::Mesher::mesh block reads of the mesh loop
RenderSectionRegion.getFluidState port crates/horizon-client-render/src/mesher/fluid.rs::FlowView::fluid fluid read used by the fluid mesher
RenderSectionRegion.getBlockEntity skip:other block entities are drawn from the world's list, not from the section region
RenderSectionRegion.getSection skip:java section copy objects; Horizon borrows chunks
RenderSectionRegion.index inline crates/horizon-client/src/mesher.rs::Mesher::mesh gap: minor: Horizon indexes 3x3 chunk columns, the section is picked by sy
SectionCompiler.compile port crates/horizon-client/src/mesher.rs::Mesher::mesh gap: minor: block-entity tiles are not built here; they are drawn by block_entity_render
SectionCompiler.getOrBeginLayer inline crates/horizon-client/src/mesher.rs::Mesher::mesh per-layer builders created on first use
RenderSectionRegion.index inline crates/horizon-client-render/src/mesher.rs::Mesher::mesh gap: minor: Horizon indexes 3x3 chunk columns, the section is picked by sy
SectionCompiler.compile port crates/horizon-client-render/src/mesher.rs::Mesher::mesh gap: minor: block-entity tiles are not built here; they are drawn by block_entity_render
SectionCompiler.getOrBeginLayer inline crates/horizon-client-render/src/mesher.rs::Mesher::mesh per-layer builders created on first use
1 Projection.setupPerspective inline crates/horizon-client/src/camera.rs::perspective crates/horizon-client-render/src/camera.rs::perspective gap: minor: the dirty-flag cache and the stored fov/near/far are not kept; the matrix is built from the arguments per call
2 Projection.setupOrtho skip:ui GUI draws in pixels through Horizon's own HUD pipeline; no ortho projection state of its own
3 Projection.getMatrixVersion skip:java matrix version counter for the dirty-check cache
4 ProjectionMatrixBuffer.getBuffer skip:other GPU buffer handle getter; Horizon owns its uniform buffers in gfx.rs
5 ProjectionMatrixBuffer.writeBuffer port crates/horizon-client/src/gfx/upload.rs::Uploads::buffer crates/horizon-client-render/src/gfx/upload.rs::Uploads::buffer gap: minor: the caller decides which uniform receives the projection
6 Rect2i.intersect skip:ui GUI clip rectangle math; Horizon clips each draw in hud.rs (clip_since), no rectangle type
7 Rect2i.contains skip:ui GUI hit test on a rectangle; Horizon's widgets hit-test in their own UI code
8 RenderPipelines.register skip:data pipeline registry; Horizon creates its pipelines in gfx.rs
9 RunningTrimmedMean.registerValueAndGetMean skip:debug frame-time smoothing helper; no vanilla caller in this source tree
10 ScreenEffectRenderer.submit port crates/horizon-client/src/screen_effects.rs::ScreenEffects::build crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build gap: minor: the item activation is not built here (see renderItemActivationAnimation)
11 ScreenEffectRenderer.renderItemActivationAnimation missing player: when a totem of undying saves the player, the totem does not pop up in front of the screen; Horizon only plays the totem particles and sound (game/totem.rs totem_event)
12 ScreenEffectRenderer.submitWater inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build underwater overlay branch (misc/underwater)
13 ScreenEffectRenderer.submitFire inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build first-person fire overlay branch (block/fire_1, two quads)
14 ScreenEffectRenderer.buildFireQuad inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build the two fire quads' corners and offsets
15 ScreenEffectRenderer.buildSpriteQuad inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build hand_quad closure: sprite rect and uv for overlay quads
16 ScreenEffectRenderer.buildQuad inline crates/horizon-client/src/screen_effects.rs::ScreenEffects::build crates/horizon-client-render/src/screen_effects.rs::ScreenEffects::build hand_quad closure: corners, uv and colour of one overlay quad
17 SectionBufferBuilderPool.allocate skip:java heap-sized pool of section builders; Horizon's mesher uses its own worker threads
18 SectionOcclusionGraph.waitAndReset port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::clear crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::clear gap: minor: clear discards a running search instead of waiting for it
19 SectionOcclusionGraph.expectedChunks missing unsure: Horizon's occlusion graph keeps no list of sections waiting on chunk loads (streaming.rs has its own waiting set)
20 SectionOcclusionGraph.invalidateIfNeeded port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::update crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::update gap: minor: the search is keyed on camera section and radius only; fov and smart-cull changes do not restart it
21 SectionOcclusionGraph.addSectionsInFrustum port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::contains crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::contains gap: minor: the frustum test is not here; the caller builds the visible list
22 SectionOcclusionGraph.schedulePropagationFrom port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::changed crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::changed queues the changed section; propagation runs in propagate_changes
23 SectionOcclusionGraph.scheduleFullUpdate port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::start crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::start gap: minor: the full search goes to a worker and is collected later (collect), not to a background executor
24 SectionOcclusionGraph.runPartialUpdate port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::propagate_changes crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::propagate_changes gap: minor: chunk-load waiting is not handled here (see expectedChunks)
25 SectionOcclusionGraph.initializeQueueForFullUpdate port crates/horizon-client/src/gfx/occlusion.rs::Graph::seed_outside crates/horizon-client-render/src/gfx/occlusion.rs::Graph::seed_outside gap: minor: seeds the sections around a camera outside the world; the camera-inside seed is in Graph::search
26 SectionOcclusionGraph.runUpdates port crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate gap: minor: BFS over face directions; vanilla's distant-section ray check for smart cull is not checked here
27 SectionOcclusionGraph.getRelativeFrom inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate neighbour lookup inside the BFS
28 SectionOcclusionGraph.updateEmptySections port crates/horizon-client/src/gfx/occlusion.rs::Occlusion::set crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::set gap: minor: empty sections are not kept in a separate set; their visibility arrives through set
29 SectionOcclusionGraph.updateLoadedChunks missing unsure: no loaded-chunk set for the occlusion graph found in gfx/occlusion.rs
30 SectionOcclusionGraph.Node.setDirections inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate face direction bits kept per section in directions[]
31 SectionOcclusionGraph.Node.hasDirection inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate face direction bit test inside the BFS
32 SectionOcclusionGraph.Node.addSourceDirection inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate entered-face bits kept per section in entered[]
33 SectionOcclusionGraph.Node.hasSourceDirection inline crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate entered-face bit test inside the BFS
34 SectionOcclusionGraph.Node.equals skip:java node equality for vanilla's hash sets; Horizon indexes sections by position
35 SectionOcclusionGraph.SectionToNodeMap.get port crates/horizon-client/src/gfx/occlusion.rs::Graph::index crates/horizon-client-render/src/gfx/occlusion.rs::Graph::index gap: minor: a per-section array index instead of a map
36 ShaderDefines.withOverrides skip:other merges GLSL #define sets; Horizon's WGSL uses override constants
37 ShaderDefines.asSourceDirectives skip:other emits GLSL #define text; Horizon has no GLSL source
38 ShaderDefines.isEmpty skip:other helper for the define set; see ShaderDefines
51 ShaderManager.PostChainCache.getOrLoadPostChain missing minor: cache for the spectator entity post effects Horizon lacks
52 ShaderManager.PostChainCache.loadPostChain missing minor: loads the spectator entity post effects Horizon lacks
53 ShaderManager.PostChainCache.close skip:other releases post chains; Horizon has none
54 Sheets.chooseSprite port crates/horizon-client/src/block_entity_render.rs::classify crates/horizon-client-render/src/block_entity_render.rs::classify gap: minor: the Christmas chest texture is picked outside this fn (block_entity_render.rs extended_christmas)
55 SkyRenderer.<init> inline crates/horizon-client/src/gfx/pack_sky.rs::PackSky::new crates/horizon-client-render/src/gfx/pack_sky.rs::PackSky::new gap: minor: builds the disc, sunset fan, stars and void up front; sun and moon quads are built per frame in game.rs celestial_geometry
56 SkyRenderer.extractRenderState port crates/horizon-client/src/environment.rs::Environment::sample crates/horizon-client-render/src/environment.rs::Environment::sample gap: minor: the End flash state is read in game/end.rs (end_flash_sky)
57 SkyRenderer.render port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame sky pass; the frame's sky and dark-disc flags come from Game::render
58 SkyRenderer.renderSkyDisc port crates/horizon-client/src/gfx/pack_sky.rs::disc crates/horizon-client-render/src/gfx/pack_sky.rs::disc top sky disc fan, sky colour from PackSky::prepare
59 SkyRenderer.renderDarkDisc inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame dark disc pipeline (fs_dark_disc) drawn when frame.dark_disc is set
60 SkyRenderer.renderSun port crates/horizon-client/src/game.rs::Game::celestial_geometry crates/horizon-client/src/game.rs::Game::celestial_geometry sun quad 100 blocks out, half-size 30, faded by rain
61 SkyRenderer.renderMoon port crates/horizon-client/src/game.rs::Game::celestial_geometry crates/horizon-client/src/game.rs::Game::celestial_geometry moon quad 100 blocks out, half-size 20, faded by rain
62 SkyRenderer.applyCelestialBodyTransform inline crates/horizon-client/src/game.rs::Game::celestial_geometry crates/horizon-client/src/game.rs::Game::celestial_geometry the body frame: rotate Y -90, then X by the body's angle
63 SkyRenderer.drawCelestialBody inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame draws the body quads with the celestial pipeline
64 SkyRenderer.renderSunriseAndSunset port crates/horizon-client/src/gfx/pack_sky.rs::PackSky::prepare crates/horizon-client-render/src/gfx/pack_sky.rs::PackSky::prepare sunset fan turned to the sun's horizon and its alpha uploaded as sunrise
65 SkyRenderer.renderEndSky port crates/horizon-client/src/gfx/end_sky.rs::EndSky::draw crates/horizon-client-render/src/gfx/end_sky.rs::EndSky::draw End sky cube
66 SkyRenderer.buildSunriseFan port crates/horizon-client/src/gfx/pack_sky.rs::PackSky::new crates/horizon-client-render/src/gfx/pack_sky.rs::PackSky::new gap: minor: a unit 16-segment fan; the 120 and -40 block shape is not built here
67 SkyRenderer.buildCelestialQuad port crates/horizon-client/src/game.rs::Game::celestial_geometry crates/horizon-client/src/game.rs::Game::celestial_geometry sprite quad for the sun and moon (body closure)
68 SkyRenderer.buildMoonPhases port crates/horizon-client/src/game.rs::Game::celestial_geometry crates/horizon-client/src/game.rs::Game::celestial_geometry gap: minor: picks the phase from day time (day_time / 24000), not from the environment's moon phase value
69 SkyRenderer.buildSkyDisc port crates/horizon-client/src/gfx/pack_sky.rs::disc crates/horizon-client-render/src/gfx/pack_sky.rs::disc 16-block disc fan (top and bottom)
70 SkyRenderer.close skip:other releases sky buffers; Rust drops the wgpu buffers
71 SpriteCoordinateExpander.addVertex skip:other no callers in this vanilla tree; UV wrapper for sprite quads
72 SpriteCoordinateExpander.setColor skip:other no callers in this vanilla tree; see addVertex
75 StagedVertexBuffer.appendDraw skip:other staging draw object; Horizon's arena allocates vertex ranges directly
76 StagedVertexBuffer.getVertexBuilder skip:other builder for the next mesh; Horizon's mesher writes straight into the section mesh
77 StagedVertexBuffer.finishLastVertexBuilder skip:other closes the last mesh builder; see getVertexBuilder
78 StagedVertexBuffer.upload port crates/horizon-client/src/gfx/arena.rs::Arena::alloc crates/horizon-client-render/src/gfx/arena.rs::Arena::alloc gap: minor: vertex ranges come from the arena; the copy is Uploads::buffer
79 StagedVertexBuffer.uploadDrawsToBuffers inline crates/horizon-client/src/gfx/upload.rs::Uploads::buffer crates/horizon-client-render/src/gfx/upload.rs::Uploads::buffer copies the staged vertex data into the buffers
80 StagedVertexBuffer.decodeSortingPoints port crates/horizon-client/src/gfx/translucency.rs::quad_center crates/horizon-client-render/src/gfx/translucency.rs::quad_center gap: minor: the centre of one quad from two corners; reading the vertex buffer itself is not here
81 StagedVertexBuffer.getExecuteInfo skip:other describes a draw for execution; Horizon issues draws in gfx.rs::Renderer::draw_sections
82 StagedVertexBuffer.requestIndexCount port crates/horizon-client/src/gfx/arena.rs::Arena::indices crates/horizon-client-render/src/gfx/arena.rs::Arena::indices gap: minor: the index buffer is sized when created, not requested per draw
83 StagedVertexBuffer.endFrame port crates/horizon-client/src/gfx/arena.rs::Arena::trim crates/horizon-client-render/src/gfx/arena.rs::Arena::trim gap: minor: releases unused pages; no fence-based recycling
84 StagedVertexBuffer.close skip:other releases buffers; Rust drops them
85 StagedVertexBuffer.Draw.append skip:other accumulates mesh counts for one draw; Horizon counts vertices in the arena
86 StagedVertexBuffer.ExecuteInfo.indexBuffer skip:other picks the index buffer for a draw; Horizon keeps its own index buffers
87 StagedVertexBuffer.GpuBufferPool.tryRecycleBuffers port crates/horizon-client/src/gfx/arena.rs::FreeList::give_all crates/horizon-client-render/src/gfx/arena.rs::FreeList::give_all gap: minor: freed ranges return to the free list at once; no fence wait
88 StagedVertexBuffer.GpuBufferPool.acquire port crates/horizon-client/src/gfx/arena.rs::Arena::alloc crates/horizon-client-render/src/gfx/arena.rs::Arena::alloc gap: minor: allocates a range in an existing page instead of a new buffer per size
89 StagedVertexBuffer.GpuBufferPool.takeBestAvailable port crates/horizon-client/src/gfx/arena.rs::FreeList::take crates/horizon-client-render/src/gfx/arena.rs::FreeList::take gap: minor: first fit, where vanilla takes the smallest buffer that fits
90 StagedVertexBuffer.GpuBufferPool.endFrame skip:other fence bookkeeping for GPU reuse; Horizon's arena releases ranges directly
91 StagedVertexBuffer.GpuBufferPool.close skip:other releases buffers; Rust drops them
92 StagedVertexBuffer.GpuBufferPool.PendingRecycle.tryRecycle skip:other fence wait for GPU reuse; Horizon has no fence here
103 SubmitNodeCollection.submitModel port crates/horizon-client/src/game/creatures.rs::Game::mob_geometry crates/horizon-client/src/game/creatures.rs::Game::mob_geometry mob models
104 SubmitNodeCollection.submitCrumblingOverlay port crates/horizon-client/src/game.rs::Game::cracks crates/horizon-client/src/game.rs::Game::cracks block break cracks (destroy_stage sprites) over a block
105 SubmitNodeCollection.submitMovingBlock port crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_geometry crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_geometry moving piston blocks
106 SubmitNodeCollection.submitBlockModel port crates/horizon-client/src/block_entity_render.rs::BlockEntityRenderer::render_block crates/horizon-client-render/src/block_entity_render.rs::BlockEntityRenderer::render_block gap: minor: block models driven by block entities only
107 SubmitNodeCollection.getOutlineRenderType inline crates/horizon-client/src/gfx.rs::Renderer::draw_outline crates/horizon-client-render/src/gfx.rs::Renderer::draw_outline one outline pass; the render type choice is folded into it
108 SubmitNodeCollection.submitBreakingBlockModel port crates/horizon-client/src/game.rs::Game::cracks crates/horizon-client/src/game.rs::Game::cracks gap: minor: drawn as cracks; the block model itself is not redrawn
109 SubmitNodeCollection.submitShapeOutline port crates/horizon-client/src/gfx.rs::Renderer::draw_outline crates/horizon-client-render/src/gfx.rs::Renderer::draw_outline block shape outline (selection box)
110 SubmitNodeCollection.submitItem port crates/horizon-client/src/game/item_draw.rs::Game::dropped_item_geometry crates/horizon-client/src/game/item_draw.rs::Game::dropped_item_geometry dropped item entities
111 SubmitNodeCollection.submitCustomGeometry port crates/horizon-client/src/mobs/guardian.rs::beam_geometry crates/horizon-client/src/mobs/guardian.rs::beam_geometry gap: minor: the guardian beam only; screen overlay quads are built in ScreenEffects::build
112 SubmitNodeCollection.submitGizmoPrimitives skip:debug debug gizmo overlay
120 SubmitNodeStorage.submitBlockModel skip:other submit wrapper; see SubmitNodeCollection.submitBlockModel
121 SubmitNodeStorage.submitShapeOutline skip:other submit wrapper; see SubmitNodeCollection.submitShapeOutline
122 SubmitNodeStorage.submitItem skip:other submit wrapper; see SubmitNodeCollection.submitItem
123 SubmitNodeStorage.drainPhases inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame the pass order that draws each phase
124 ViewArea.releaseAllBuffers port crates/horizon-client/src/gfx.rs::Renderer::clear_sections crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections drops every section's buffers
125 ViewArea.repositionCamera inline crates/horizon-client/src/gfx/occlusion.rs::Occlusion::update crates/horizon-client-render/src/gfx/occlusion.rs::Occlusion::update gap: minor: the occlusion graph restarts on a camera section change; sections are keyed by absolute position, nothing is re-centred
126 WeatherEffectRenderer.renderWeather inline crates/horizon-client/src/gfx/weather.rs::Weather::draw crates/horizon-client-render/src/gfx/weather.rs::Weather::draw draws the rain and snow column ranges
127 WeatherEffectRenderer.uploadVertexBuffer port crates/horizon-client/src/gfx/weather.rs::Weather::prepare crates/horizon-client-render/src/gfx/weather.rs::Weather::prepare gap: minor: the buffer grows to the next power of two
128 WeatherEffectRenderer.prepare port crates/horizon-client/src/weather.rs::column_quad crates/horizon-client-render/src/weather.rs::column_quad gap: minor: the column list comes from rain_column and snow_column; this fn builds the quads
129 WeatherEffectRenderer.render port crates/horizon-client/src/gfx/weather.rs::Weather::draw crates/horizon-client-render/src/gfx/weather.rs::Weather::draw draws the rain and snow columns
130 WeatherEffectRenderer.createSnowColumnInstance port crates/horizon-client/src/weather.rs::snow_column crates/horizon-client-render/src/weather.rs::snow_column snow drift and brightened light
131 WeatherEffectRenderer.prepareInstances port crates/horizon-client/src/weather.rs::column_quad crates/horizon-client-render/src/weather.rs::column_quad gap: minor: one column per call; the loop over columns is in the caller
132 WorldBorderRenderer.renderOit inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame border wall draw when frame.border is set
133 WorldBorderRenderer.prepareRenderPass inline crates/horizon-client/src/border_render.rs::BorderRenderer::transforms crates/horizon-client-render/src/border_render.rs::BorderRenderer::transforms the uniforms (colour, offset, texture scroll) for the wall
134 WorldBorderRenderer.shouldRebuildWorldBorderBuffer port crates/horizon-client/src/border_render.rs::BorderRenderer::prepare crates/horizon-client-render/src/border_render.rs::BorderRenderer::prepare rebuilds when the border moved or was invalidated
135 FluidRenderer.getHeight inline crates/horizon-client/src/mesher/fluid.rs::tesselate crates/horizon-client-render/src/mesher/fluid.rs::tesselate corner heights from own_height and the neighbour average
136 ChunkSectionLayer.byTransparency inline crates/horizon-client/src/mesher.rs::Mesher::face crates/horizon-client-render/src/mesher.rs::Mesher::face a face goes to the translucent list when it is translucent
137 ChunkSectionsToRender.renderGroup port crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections gap: minor: draws the given page runs; the terrain uniforms are bound by the caller
138 ChunkSectionsToRender.renderOit port crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections gap: minor: the OIT pass set-up is not in this fn
139 ChunkSectionsToRender.renderLayers inline crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections per-layer loop over the page runs
140 ChunkSectionsToRender.DrawIndirect.render port crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections multi-draw indirect branch
141 ChunkSectionsToRender.DrawSeparate.render port crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections per-draw branch without multi-draw
142 RenderRegionCache.createRegion inline crates/horizon-client/src/mesher.rs::borrow crates/horizon-client-render/src/mesher.rs::borrow gap: minor: borrows the 3x3 chunk columns around the section; nothing is copied
143 RenderRegionCache.getSectionDataCopy skip:java per-thread copy cache; Horizon borrows the chunks
144 RenderSectionRegion.getBlockState inline crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh block reads of the mesh loop
145 RenderSectionRegion.getFluidState port crates/horizon-client/src/mesher/fluid.rs::FlowView::fluid crates/horizon-client-render/src/mesher/fluid.rs::FlowView::fluid fluid read used by the fluid mesher
146 RenderSectionRegion.getBlockEntity skip:other block entities are drawn from the world's list, not from the section region
147 RenderSectionRegion.getSection skip:java section copy objects; Horizon borrows chunks
148 RenderSectionRegion.index inline crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh gap: minor: Horizon indexes 3x3 chunk columns, the section is picked by sy
149 SectionCompiler.compile port crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh gap: minor: block-entity tiles are not built here; they are drawn by block_entity_render
150 SectionCompiler.getOrBeginLayer inline crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh per-layer builders created on first use
+43 -43
View File
@@ -1,47 +1,47 @@
SectionCopy.getBlockState inline crates/horizon-client/src/mesher.rs::Padded::new the copy is Padded's block array; no debug-world barrier or DebugLevelSource blocks
SectionCopy.getBlockState inline crates/horizon-client-render/src/mesher.rs::Padded::new the copy is Padded's block array; no debug-world barrier or DebugLevelSource blocks
SectionRenderDispatcher.<init> skip:other builds the GPU arena and staging for chunk upload; Horizon creates its arena and uploads in gfx.rs with the renderer
SectionRenderDispatcher.runTask port crates/horizon-client/src/streaming.rs::Streaming::new the worker loop pops the nearest queued job and runs it
SectionRenderDispatcher.getRenderSectionSlice port crates/horizon-client/src/gfx.rs::Renderer::draw_sections the per-layer vertex and index slices of a section are read when drawing
SectionRenderDispatcher.uploadTerrainBuffersToGpu port crates/horizon-client/src/gfx/upload.rs::Uploads::finish closes the frame's staging belt after the terrain copies
SectionRenderDispatcher.schedule port crates/horizon-client/src/streaming.rs::Streaming::submit the mesh job goes into the priority queue by distance
SectionRenderDispatcher.dispose port crates/horizon-client/src/gfx.rs::Renderer::clear_sections frees every section's GPU buffers
SectionRenderDispatcher.runTask port crates/horizon-client-render/src/streaming.rs::Streaming::new the worker loop pops the nearest queued job and runs it
SectionRenderDispatcher.getRenderSectionSlice port crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections the per-layer vertex and index slices of a section are read when drawing
SectionRenderDispatcher.uploadTerrainBuffersToGpu port crates/horizon-client-render/src/gfx/upload.rs::Uploads::finish closes the frame's staging belt after the terrain copies
SectionRenderDispatcher.schedule port crates/horizon-client-render/src/streaming.rs::Streaming::submit the mesh job goes into the priority queue by distance
SectionRenderDispatcher.dispose port crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections frees every section's GPU buffers
SectionRenderDispatcher.getStats skip:debug F3 text: compile queue size and free buffers
SectionRenderDispatcher.RenderSection.getVisibility missing player: newly meshed terrain appears at full strength; vanilla fades each section in over the chunkSectionFadeInTime option, and block entities wait for 0.3
SectionRenderDispatcher.RenderSection.setSectionNode port crates/horizon-client/src/gfx.rs::section_instance the section's render origin; its 16-block bounds are derived from the origin
SectionRenderDispatcher.RenderSection.reset port crates/horizon-client/src/gfx.rs::Renderer::release_section drops the section's mesh and GPU slices
SectionRenderDispatcher.RenderSection.resortTransparency port crates/horizon-client/src/gfx/translucency.rs::SortState::update translucent quads re-sorted for the camera; gap: minor: the new order goes to the next draw, not a newly uploaded index buffer
SectionRenderDispatcher.RenderSection.setSectionNode port crates/horizon-client-render/src/gfx.rs::section_instance the section's render origin; its 16-block bounds are derived from the origin
SectionRenderDispatcher.RenderSection.reset port crates/horizon-client-render/src/gfx.rs::Renderer::release_section drops the section's mesh and GPU slices
SectionRenderDispatcher.RenderSection.resortTransparency port crates/horizon-client-render/src/gfx/translucency.rs::SortState::update translucent quads re-sorted for the camera; gap: minor: the new order goes to the next draw, not a newly uploaded index buffer
SectionRenderDispatcher.RenderSection.transparencyResortingScheduled skip:other Horizon sorts during the frame, so there is no pending resort task to report
SectionRenderDispatcher.RenderSection.cancelTasks inline crates/horizon-client/src/streaming.rs::Streaming::update a finished job whose seq no longer matches is dropped on arrival; queued jobs are not removed
SectionRenderDispatcher.RenderSection.createCompileTask port crates/horizon-client/src/streaming.rs::Streaming::submit the mesh job is queued; the recompile flag is not kept
SectionRenderDispatcher.RenderSection.compileSync port crates/horizon-client/src/mesher.rs::Mesher::mesh meshes on the calling thread with no queue
SectionRenderDispatcher.RenderSection.setSectionMesh port crates/horizon-client/src/gfx.rs::Renderer::upload stores the new mesh for the section and hands back the old one
SectionRenderDispatcher.RenderSection.releaseSectionMesh port crates/horizon-client/src/gfx.rs::Renderer::release_mesh frees the old mesh's GPU slices
SectionRenderDispatcher.RenderSection.createVertexSorting port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort sort by squared distance from the camera to each quad centre
SectionRenderDispatcher.RenderSection.checkSectionMesh inline crates/horizon-client/src/gfx.rs::Renderer::upload uploads are synchronous, so there is no wait for every layer to land before publishing
SectionRenderDispatcher.RenderSection.addSectionBuffersToUberBuffer port crates/horizon-client/src/gfx.rs::Renderer::upload_mesh copies a layer's vertex and index bytes into arena pages
SectionRenderDispatcher.RenderSection.CompileTask.doTask port crates/horizon-client/src/mesher.rs::Mesher::mesh meshes the section; the empty result and upload are handled in streaming and Renderer::upload
SectionRenderDispatcher.RenderSection.ResortTransparencyTask.doTask port crates/horizon-client/src/gfx/translucency.rs::SortState::update re-sorts translucent quads when the camera's point of view changes
SectionTaskDynamicQueue.poll port crates/horizon-client/src/streaming.rs::Queued::cmp nearest job first; gap: minor: no recompile quota, new and remesh jobs share one priority
SectionRenderDispatcher.RenderSection.cancelTasks inline crates/horizon-client-render/src/streaming.rs::Streaming::update a finished job whose seq no longer matches is dropped on arrival; queued jobs are not removed
SectionRenderDispatcher.RenderSection.createCompileTask port crates/horizon-client-render/src/streaming.rs::Streaming::submit the mesh job is queued; the recompile flag is not kept
SectionRenderDispatcher.RenderSection.compileSync port crates/horizon-client-render/src/mesher.rs::Mesher::mesh meshes on the calling thread with no queue
SectionRenderDispatcher.RenderSection.setSectionMesh port crates/horizon-client-render/src/gfx.rs::Renderer::upload stores the new mesh for the section and hands back the old one
SectionRenderDispatcher.RenderSection.releaseSectionMesh port crates/horizon-client-render/src/gfx.rs::Renderer::release_mesh frees the old mesh's GPU slices
SectionRenderDispatcher.RenderSection.createVertexSorting port crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort sort by squared distance from the camera to each quad centre
SectionRenderDispatcher.RenderSection.checkSectionMesh inline crates/horizon-client-render/src/gfx.rs::Renderer::upload uploads are synchronous, so there is no wait for every layer to land before publishing
SectionRenderDispatcher.RenderSection.addSectionBuffersToUberBuffer port crates/horizon-client-render/src/gfx.rs::Renderer::upload_mesh copies a layer's vertex and index bytes into arena pages
SectionRenderDispatcher.RenderSection.CompileTask.doTask port crates/horizon-client-render/src/mesher.rs::Mesher::mesh meshes the section; the empty result and upload are handled in streaming and Renderer::upload
SectionRenderDispatcher.RenderSection.ResortTransparencyTask.doTask port crates/horizon-client-render/src/gfx/translucency.rs::SortState::update re-sorts translucent quads when the camera's point of view changes
SectionTaskDynamicQueue.poll port crates/horizon-client-render/src/streaming.rs::Queued::cmp nearest job first; gap: minor: no recompile quota, new and remesh jobs share one priority
SectionTaskDynamicQueue.clear skip:other Horizon has no queue clear; stale results are dropped by seq in Streaming::update
TranslucencyPointOfView.set inline crates/horizon-client/src/gfx/translucency.rs::SortState::update the point of view: camera block minus section, clamped to -1..1 per axis
TranslucencyPointOfView.isAxisAligned inline crates/horizon-client/src/gfx/translucency.rs::SortState::update the axis-aligned test: a zero component in the point of view
TranslucencyPointOfView.equals inline crates/horizon-client/src/gfx/translucency.rs::SortState::update compares the last point of view with the new one
TranslucencyPointOfView.set inline crates/horizon-client-render/src/gfx/translucency.rs::SortState::update the point of view: camera block minus section, clamped to -1..1 per axis
TranslucencyPointOfView.isAxisAligned inline crates/horizon-client-render/src/gfx/translucency.rs::SortState::update the axis-aligned test: a zero component in the point of view
TranslucencyPointOfView.equals inline crates/horizon-client-render/src/gfx/translucency.rs::SortState::update compares the last point of view with the new one
TranslucencyPointOfView.hashCode skip:java hash for a map key
VisGraph.setOpaque inline crates/horizon-client/src/mesher.rs::visibility opaque cells are marked in the seen map before the flood fill
VisGraph.getIndex inline crates/horizon-client/src/mesher.rs::visibility cell index y<<8 | z<<4 | x in the seen map
VisGraph.floodFill inline crates/horizon-client/src/mesher.rs::visibility flood fill from each open cell; gap: minor: no shortcut for sections with fewer than 256 opaque cells, which vanilla marks fully visible
VisGraph.addEdges inline crates/horizon-client/src/mesher.rs::visibility the faces of the section a cell touches
VisGraph.getNeighborIndexAtFace inline crates/horizon-client/src/mesher.rs::visibility the neighbour index inside the section, -1 at its border
VisibilitySet.add inline crates/horizon-client/src/mesher.rs::visibility sets the bit for each pair of faces an open region touches (bit a*6+b)
VisibilitySet.set inline crates/horizon-client/src/mesher.rs::visibility sets both bits of a face pair
VisibilitySet.visibilityBetween port crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate the faces a section connects are read from its visibility bits when the search moves on
VisGraph.setOpaque inline crates/horizon-client-render/src/mesher.rs::visibility opaque cells are marked in the seen map before the flood fill
VisGraph.getIndex inline crates/horizon-client-render/src/mesher.rs::visibility cell index y<<8 | z<<4 | x in the seen map
VisGraph.floodFill inline crates/horizon-client-render/src/mesher.rs::visibility flood fill from each open cell; gap: minor: no shortcut for sections with fewer than 256 opaque cells, which vanilla marks fully visible
VisGraph.addEdges inline crates/horizon-client-render/src/mesher.rs::visibility the faces of the section a cell touches
VisGraph.getNeighborIndexAtFace inline crates/horizon-client-render/src/mesher.rs::visibility the neighbour index inside the section, -1 at its border
VisibilitySet.add inline crates/horizon-client-render/src/mesher.rs::visibility sets the bit for each pair of faces an open region touches (bit a*6+b)
VisibilitySet.set inline crates/horizon-client-render/src/mesher.rs::visibility sets both bits of a face pair
VisibilitySet.visibilityBetween port crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate the faces a section connects are read from its visibility bits when the search moves on
VisibilitySet.toString skip:debug debug text
Frustum.set skip:java copies the frustum; Horizon passes the Frustum value
Frustum.offset missing minor: particles are not culled against a frustum pulled back 3 blocks (ParticleEngine.extract); Horizon has no particle frustum test
Frustum.offsetToFullyIncludeCameraCube port crates/horizon-client/src/gfx/occlusion.rs::Graph::search the occlusion search starts in the camera's own section, so its cube is always included; gap: minor: no frustum offset
Frustum.calculateFrustum port crates/horizon-client/src/gfx.rs::frustum the six planes from projection times view
Frustum.isVisible port crates/horizon-client/src/gfx.rs::Frustum::intersects box against the planes; gap: minor: infinite bounds are not special-cased
Frustum.cubeInFrustum port crates/horizon-client/src/gfx.rs::Frustum::intersects box test on camera-relative bounds
Frustum.offsetToFullyIncludeCameraCube port crates/horizon-client-render/src/gfx/occlusion.rs::Graph::search the occlusion search starts in the camera's own section, so its cube is always included; gap: minor: no frustum offset
Frustum.calculateFrustum port crates/horizon-client-render/src/gfx.rs::frustum the six planes from projection times view
Frustum.isVisible port crates/horizon-client-render/src/gfx.rs::Frustum::intersects box against the planes; gap: minor: infinite bounds are not special-cased
Frustum.cubeInFrustum port crates/horizon-client-render/src/gfx.rs::Frustum::intersects box test on camera-relative bounds
Frustum.pointInFrustum missing minor: only particle culling uses it (QuadParticleGroup), and Horizon has no particle frustum test
Frustum.getFrustumPoints skip:debug the eight frustum corners, for debug drawing only
Frustum.getNearPlaneBounds missing player: the block texture overlay drawn when your eye is inside a block (view-blocking block) is never shown; ScreenEffectRenderer's block_overlay is never set outside tests
@@ -84,14 +84,14 @@ LevelExtractor.extractVisibleBlockEntities inline crates/horizon-client/src/game
LevelExtractor.extractBlockDestroyAnimation port crates/horizon-client/src/game.rs::Game::destroy_block_progress keeps the crumbling progress per breaker for 400 ticks; gap: minor: no 32-block distance cut here
LevelExtractor.extractGizmos port crates/horizon-client/src/game/debug_keys.rs::Game::debug_gizmos the frame's debug gizmos
LevelExtractor.extractPlayerState inline crates/horizon-client/src/game.rs::Game::render player and hands read from the game state at draw time; gap: minor: the view-blocking block is missing, see Frustum.getNearPlaneBounds
LevelExtractor.applyFrustum port crates/horizon-client/src/gfx/resident.rs::Resident::visible the frustum decides which sections are visible
LevelExtractor.applyFrustum port crates/horizon-client-render/src/gfx/resident.rs::Resident::visible the frustum decides which sections are visible
LevelExtractor.setLevel inline crates/horizon-client/src/game.rs::Game::all_sections_changed a new level rebuilds every loaded section (allChanged); the null-level branch is not separate
LevelExtractor.blockChanged port crates/horizon-client/src/world.rs::World::set a block edit marks its 3x3x3 neighbourhood; gap: minor: the player-changed flag (update bit 8) is not kept
LevelExtractor.setBlockDirty port crates/horizon-client/src/world.rs::World::set marks the 3x3x3 section neighbourhood of an edited block
LevelExtractor.setBlocksDirty inline crates/horizon-client/src/world.rs::World::set each block of the range goes through the same 3x3x3 marking
LevelExtractor.setSectionDirtyWithNeighbors port crates/horizon-client/src/streaming.rs::Streaming::light_updated the section and its neighbours remesh
LevelExtractor.setSectionRangeDirty inline crates/horizon-client/src/streaming.rs::Streaming::light_updated section range marked in world.dirty_sections
LevelExtractor.setSectionDirty port crates/horizon-client/src/world.rs::DirtySections::insert marks one section for remesh
LevelExtractor.blockChanged port crates/horizon-client-render/src/world.rs::World::set a block edit marks its 3x3x3 neighbourhood; gap: minor: the player-changed flag (update bit 8) is not kept
LevelExtractor.setBlockDirty port crates/horizon-client-render/src/world.rs::World::set marks the 3x3x3 section neighbourhood of an edited block
LevelExtractor.setBlocksDirty inline crates/horizon-client-render/src/world.rs::World::set each block of the range goes through the same 3x3x3 marking
LevelExtractor.setSectionDirtyWithNeighbors port crates/horizon-client-render/src/streaming.rs::Streaming::light_updated the section and its neighbours remesh
LevelExtractor.setSectionRangeDirty inline crates/horizon-client-render/src/streaming.rs::Streaming::light_updated section range marked in world.dirty_sections
LevelExtractor.setSectionDirty port crates/horizon-client-render/src/world.rs::DirtySections::insert marks one section for remesh
LevelExtractor.countRenderedSections skip:debug F3 count of sections with renderable layers; Horizon reports Renderer::section_count
LevelExtractor.sectionStatistics skip:debug F3 text
LevelExtractor.entityStatistics skip:debug F3 text
@@ -100,5 +100,5 @@ CustomFeatureRenderer.buildGroup skip:other feature pass plumbing; Horizon has
FeatureRenderDispatcher.<init> skip:other feature dispatcher set-up; Horizon has no feature dispatcher
FeatureRenderDispatcher.prepareFrame skip:other feature dispatcher; the frame's draw order is fixed in Renderer::draw_frame
FeatureRenderDispatcher.prepareFrameWithContext skip:other feature dispatcher; the frame's draw order is fixed in Renderer::draw_frame
FeatureRenderDispatcher.renderAllFeatures port crates/horizon-client/src/gfx.rs::Renderer::draw_frame draws the frame's passes; gap: minor: the order is fixed, not taken from a feature list
FeatureRenderDispatcher.renderAllFeatures port crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame draws the frame's passes; gap: minor: the order is fixed, not taken from a feature list
FeatureRenderDispatcher.PhaseSubmitGrouper skip:other groups feature submissions per phase for vanilla's dispatcher; Horizon submits in fixed passes
1 SectionCopy.getBlockState inline crates/horizon-client/src/mesher.rs::Padded::new crates/horizon-client-render/src/mesher.rs::Padded::new the copy is Padded's block array; no debug-world barrier or DebugLevelSource blocks
2 SectionRenderDispatcher.<init> skip:other builds the GPU arena and staging for chunk upload; Horizon creates its arena and uploads in gfx.rs with the renderer
3 SectionRenderDispatcher.runTask port crates/horizon-client/src/streaming.rs::Streaming::new crates/horizon-client-render/src/streaming.rs::Streaming::new the worker loop pops the nearest queued job and runs it
4 SectionRenderDispatcher.getRenderSectionSlice port crates/horizon-client/src/gfx.rs::Renderer::draw_sections crates/horizon-client-render/src/gfx.rs::Renderer::draw_sections the per-layer vertex and index slices of a section are read when drawing
5 SectionRenderDispatcher.uploadTerrainBuffersToGpu port crates/horizon-client/src/gfx/upload.rs::Uploads::finish crates/horizon-client-render/src/gfx/upload.rs::Uploads::finish closes the frame's staging belt after the terrain copies
6 SectionRenderDispatcher.schedule port crates/horizon-client/src/streaming.rs::Streaming::submit crates/horizon-client-render/src/streaming.rs::Streaming::submit the mesh job goes into the priority queue by distance
7 SectionRenderDispatcher.dispose port crates/horizon-client/src/gfx.rs::Renderer::clear_sections crates/horizon-client-render/src/gfx.rs::Renderer::clear_sections frees every section's GPU buffers
8 SectionRenderDispatcher.getStats skip:debug F3 text: compile queue size and free buffers
9 SectionRenderDispatcher.RenderSection.getVisibility missing player: newly meshed terrain appears at full strength; vanilla fades each section in over the chunkSectionFadeInTime option, and block entities wait for 0.3
10 SectionRenderDispatcher.RenderSection.setSectionNode port crates/horizon-client/src/gfx.rs::section_instance crates/horizon-client-render/src/gfx.rs::section_instance the section's render origin; its 16-block bounds are derived from the origin
11 SectionRenderDispatcher.RenderSection.reset port crates/horizon-client/src/gfx.rs::Renderer::release_section crates/horizon-client-render/src/gfx.rs::Renderer::release_section drops the section's mesh and GPU slices
12 SectionRenderDispatcher.RenderSection.resortTransparency port crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update translucent quads re-sorted for the camera; gap: minor: the new order goes to the next draw, not a newly uploaded index buffer
13 SectionRenderDispatcher.RenderSection.transparencyResortingScheduled skip:other Horizon sorts during the frame, so there is no pending resort task to report
14 SectionRenderDispatcher.RenderSection.cancelTasks inline crates/horizon-client/src/streaming.rs::Streaming::update crates/horizon-client-render/src/streaming.rs::Streaming::update a finished job whose seq no longer matches is dropped on arrival; queued jobs are not removed
15 SectionRenderDispatcher.RenderSection.createCompileTask port crates/horizon-client/src/streaming.rs::Streaming::submit crates/horizon-client-render/src/streaming.rs::Streaming::submit the mesh job is queued; the recompile flag is not kept
16 SectionRenderDispatcher.RenderSection.compileSync port crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh meshes on the calling thread with no queue
17 SectionRenderDispatcher.RenderSection.setSectionMesh port crates/horizon-client/src/gfx.rs::Renderer::upload crates/horizon-client-render/src/gfx.rs::Renderer::upload stores the new mesh for the section and hands back the old one
18 SectionRenderDispatcher.RenderSection.releaseSectionMesh port crates/horizon-client/src/gfx.rs::Renderer::release_mesh crates/horizon-client-render/src/gfx.rs::Renderer::release_mesh frees the old mesh's GPU slices
19 SectionRenderDispatcher.RenderSection.createVertexSorting port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort sort by squared distance from the camera to each quad centre
20 SectionRenderDispatcher.RenderSection.checkSectionMesh inline crates/horizon-client/src/gfx.rs::Renderer::upload crates/horizon-client-render/src/gfx.rs::Renderer::upload uploads are synchronous, so there is no wait for every layer to land before publishing
21 SectionRenderDispatcher.RenderSection.addSectionBuffersToUberBuffer port crates/horizon-client/src/gfx.rs::Renderer::upload_mesh crates/horizon-client-render/src/gfx.rs::Renderer::upload_mesh copies a layer's vertex and index bytes into arena pages
22 SectionRenderDispatcher.RenderSection.CompileTask.doTask port crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh meshes the section; the empty result and upload are handled in streaming and Renderer::upload
23 SectionRenderDispatcher.RenderSection.ResortTransparencyTask.doTask port crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update re-sorts translucent quads when the camera's point of view changes
24 SectionTaskDynamicQueue.poll port crates/horizon-client/src/streaming.rs::Queued::cmp crates/horizon-client-render/src/streaming.rs::Queued::cmp nearest job first; gap: minor: no recompile quota, new and remesh jobs share one priority
25 SectionTaskDynamicQueue.clear skip:other Horizon has no queue clear; stale results are dropped by seq in Streaming::update
26 TranslucencyPointOfView.set inline crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update the point of view: camera block minus section, clamped to -1..1 per axis
27 TranslucencyPointOfView.isAxisAligned inline crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update the axis-aligned test: a zero component in the point of view
28 TranslucencyPointOfView.equals inline crates/horizon-client/src/gfx/translucency.rs::SortState::update crates/horizon-client-render/src/gfx/translucency.rs::SortState::update compares the last point of view with the new one
29 TranslucencyPointOfView.hashCode skip:java hash for a map key
30 VisGraph.setOpaque inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility opaque cells are marked in the seen map before the flood fill
31 VisGraph.getIndex inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility cell index y<<8 | z<<4 | x in the seen map
32 VisGraph.floodFill inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility flood fill from each open cell; gap: minor: no shortcut for sections with fewer than 256 opaque cells, which vanilla marks fully visible
33 VisGraph.addEdges inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility the faces of the section a cell touches
34 VisGraph.getNeighborIndexAtFace inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility the neighbour index inside the section, -1 at its border
35 VisibilitySet.add inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility sets the bit for each pair of faces an open region touches (bit a*6+b)
36 VisibilitySet.set inline crates/horizon-client/src/mesher.rs::visibility crates/horizon-client-render/src/mesher.rs::visibility sets both bits of a face pair
37 VisibilitySet.visibilityBetween port crates/horizon-client/src/gfx/occlusion.rs::Graph::propagate crates/horizon-client-render/src/gfx/occlusion.rs::Graph::propagate the faces a section connects are read from its visibility bits when the search moves on
38 VisibilitySet.toString skip:debug debug text
39 Frustum.set skip:java copies the frustum; Horizon passes the Frustum value
40 Frustum.offset missing minor: particles are not culled against a frustum pulled back 3 blocks (ParticleEngine.extract); Horizon has no particle frustum test
41 Frustum.offsetToFullyIncludeCameraCube port crates/horizon-client/src/gfx/occlusion.rs::Graph::search crates/horizon-client-render/src/gfx/occlusion.rs::Graph::search the occlusion search starts in the camera's own section, so its cube is always included; gap: minor: no frustum offset
42 Frustum.calculateFrustum port crates/horizon-client/src/gfx.rs::frustum crates/horizon-client-render/src/gfx.rs::frustum the six planes from projection times view
43 Frustum.isVisible port crates/horizon-client/src/gfx.rs::Frustum::intersects crates/horizon-client-render/src/gfx.rs::Frustum::intersects box against the planes; gap: minor: infinite bounds are not special-cased
44 Frustum.cubeInFrustum port crates/horizon-client/src/gfx.rs::Frustum::intersects crates/horizon-client-render/src/gfx.rs::Frustum::intersects box test on camera-relative bounds
45 Frustum.pointInFrustum missing minor: only particle culling uses it (QuadParticleGroup), and Horizon has no particle frustum test
46 Frustum.getFrustumPoints skip:debug the eight frustum corners, for debug drawing only
47 Frustum.getNearPlaneBounds missing player: the block texture overlay drawn when your eye is inside a block (view-blocking block) is never shown; ScreenEffectRenderer's block_overlay is never set outside tests
84 LevelExtractor.extractBlockDestroyAnimation port crates/horizon-client/src/game.rs::Game::destroy_block_progress crates/horizon-client/src/game.rs::Game::destroy_block_progress keeps the crumbling progress per breaker for 400 ticks; gap: minor: no 32-block distance cut here
85 LevelExtractor.extractGizmos port crates/horizon-client/src/game/debug_keys.rs::Game::debug_gizmos crates/horizon-client/src/game/debug_keys.rs::Game::debug_gizmos the frame's debug gizmos
86 LevelExtractor.extractPlayerState inline crates/horizon-client/src/game.rs::Game::render crates/horizon-client/src/game.rs::Game::render player and hands read from the game state at draw time; gap: minor: the view-blocking block is missing, see Frustum.getNearPlaneBounds
87 LevelExtractor.applyFrustum port crates/horizon-client/src/gfx/resident.rs::Resident::visible crates/horizon-client-render/src/gfx/resident.rs::Resident::visible the frustum decides which sections are visible
88 LevelExtractor.setLevel inline crates/horizon-client/src/game.rs::Game::all_sections_changed crates/horizon-client/src/game.rs::Game::all_sections_changed a new level rebuilds every loaded section (allChanged); the null-level branch is not separate
89 LevelExtractor.blockChanged port crates/horizon-client/src/world.rs::World::set crates/horizon-client-render/src/world.rs::World::set a block edit marks its 3x3x3 neighbourhood; gap: minor: the player-changed flag (update bit 8) is not kept
90 LevelExtractor.setBlockDirty port crates/horizon-client/src/world.rs::World::set crates/horizon-client-render/src/world.rs::World::set marks the 3x3x3 section neighbourhood of an edited block
91 LevelExtractor.setBlocksDirty inline crates/horizon-client/src/world.rs::World::set crates/horizon-client-render/src/world.rs::World::set each block of the range goes through the same 3x3x3 marking
92 LevelExtractor.setSectionDirtyWithNeighbors port crates/horizon-client/src/streaming.rs::Streaming::light_updated crates/horizon-client-render/src/streaming.rs::Streaming::light_updated the section and its neighbours remesh
93 LevelExtractor.setSectionRangeDirty inline crates/horizon-client/src/streaming.rs::Streaming::light_updated crates/horizon-client-render/src/streaming.rs::Streaming::light_updated section range marked in world.dirty_sections
94 LevelExtractor.setSectionDirty port crates/horizon-client/src/world.rs::DirtySections::insert crates/horizon-client-render/src/world.rs::DirtySections::insert marks one section for remesh
95 LevelExtractor.countRenderedSections skip:debug F3 count of sections with renderable layers; Horizon reports Renderer::section_count
96 LevelExtractor.sectionStatistics skip:debug F3 text
97 LevelExtractor.entityStatistics skip:debug F3 text
100 FeatureRenderDispatcher.<init> skip:other feature dispatcher set-up; Horizon has no feature dispatcher
101 FeatureRenderDispatcher.prepareFrame skip:other feature dispatcher; the frame's draw order is fixed in Renderer::draw_frame
102 FeatureRenderDispatcher.prepareFrameWithContext skip:other feature dispatcher; the frame's draw order is fixed in Renderer::draw_frame
103 FeatureRenderDispatcher.renderAllFeatures port crates/horizon-client/src/gfx.rs::Renderer::draw_frame crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame draws the frame's passes; gap: minor: the order is fixed, not taken from a feature list
104 FeatureRenderDispatcher.PhaseSubmitGrouper skip:other groups feature submissions per phase for vanilla's dispatcher; Horizon submits in fixed passes
+12 -12
View File
@@ -27,27 +27,27 @@ RenderTypeFeatureRenderer.Group skip:other GPU render-type batching, as above
ShadowFeatureRenderer.buildGroup port crates/horizon-client/src/shadows.rs::shadow loop over shadow submits
ShadowFeatureRenderer.prepare port crates/horizon-client/src/shadows.rs::shadow shadow quads per piece, clamped by the block below
ShadowFeatureRenderer.shadowVertex inline crates/horizon-client/src/shadows.rs::shadow vertex push folded into shadow
ShapeOutlineFeatureRenderer.buildGroup port crates/horizon-client/src/gfx.rs::outline_vertices block selection outline edges as line vertices
ShapeOutlineFeatureRenderer.buildGroup port crates/horizon-client-render/src/gfx.rs::outline_vertices block selection outline edges as line vertices
TextFeatureRenderer.buildGroup skip:other dispatch over text and background submits; each kind is covered below or by Horizon's text draw
TextFeatureRenderer.renderText missing minor: unsure: no outlined-text path found (font.rs, hud.rs, names.rs); the outline colour of a text submit is not drawn
TextFeatureRenderer.GlyphRenderer.acceptRenderable skip:other glyph sink for the text pass; Horizon's font pass draws the glyphs
FeatureRenderPhase.Output.acceptFeatureGroup skip:other phase plumbing: hands sorted groups to the renderer pass
SimpleFeatureRenderPhase skip:other submit, sort, shuffle (debug only) and clear of feature submits; Horizon sorts its own draws
SimpleFeatureRenderPhase.FeatureSubmits skip:other batching bookkeeping of feature submits
TranslucentFeatureRenderPhase.submit inline crates/horizon-client/src/gfx/translucency.rs::Sorter::sort collects submits; distances are taken in sort
TranslucentFeatureRenderPhase.sortInto port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort back-to-front by distance, equal distances keep submit order
TranslucentFeatureRenderPhase.sortIndices port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort far to near, stable on ties
TranslucentSubmit.computeDistanceToCameraSq inline crates/horizon-client/src/gfx/translucency.rs::Sorter::sort distance from the quad centre to the camera, computed inside sort
TranslucentFeatureRenderPhase.submit inline crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort collects submits; distances are taken in sort
TranslucentFeatureRenderPhase.sortInto port crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort back-to-front by distance, equal distances keep submit order
TranslucentFeatureRenderPhase.sortIndices port crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort far to near, stable on ties
TranslucentSubmit.computeDistanceToCameraSq inline crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort distance from the quad centre to the camera, computed inside sort
FogRenderer.getBuffer skip:other selects the fog uniform slice; Horizon hands its fog values to its own shader per frame
FogRenderer.updateBuffer skip:other writes the fog uniform buffer; Horizon's frame_fog passes FogData to its own shader
AtmosphericFogEnvironment.getBaseColor port crates/horizon-client/src/fog.rs::setup_fog gap: minor: sky fog end uses constant 512 instead of the SKY_FOG_END_DISTANCE attribute
AtmosphericFogEnvironment.applyWeatherDarken inline crates/horizon-client/src/fog.rs::setup_fog rain and thunder darkening folded into the atmospheric colour
BlindnessFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog blindness distance and sky/cloud ends
BlindnessFogEnvironment.getModifiedDarkness inline crates/horizon-client/src/fog.rs::setup_fog blindness darkness folded into setup_fog
LavaFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog gap: player: spectator (-8 start, half render distance) and fire resistance (0 to 5) are not applied in lava
AtmosphericFogEnvironment.getBaseColor port crates/horizon-client-render/src/fog.rs::setup_fog gap: minor: sky fog end uses constant 512 instead of the SKY_FOG_END_DISTANCE attribute
AtmosphericFogEnvironment.applyWeatherDarken inline crates/horizon-client-render/src/fog.rs::setup_fog rain and thunder darkening folded into the atmospheric colour
BlindnessFogEnvironment.setupFog port crates/horizon-client-render/src/fog.rs::setup_fog blindness distance and sky/cloud ends
BlindnessFogEnvironment.getModifiedDarkness inline crates/horizon-client-render/src/fog.rs::setup_fog blindness darkness folded into setup_fog
LavaFogEnvironment.setupFog port crates/horizon-client-render/src/fog.rs::setup_fog gap: player: spectator (-8 start, half render distance) and fire resistance (0 to 5) are not applied in lava
MobEffectFogEnvironment.isApplicable inline crates/horizon-client/src/game/render_tick.rs::Game::frame_fog effect gate is where frame_fog builds the blindness and darkness inputs
PowderedSnowFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog gap: player: spectator case (-8 start, half render distance) is not applied
WaterFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog gap: minor: water fog start is fixed at -8; vanilla reads the WATER_FOG_START_DISTANCE attribute
PowderedSnowFogEnvironment.setupFog port crates/horizon-client-render/src/fog.rs::setup_fog gap: player: spectator case (-8 start, half render distance) is not applied
WaterFogEnvironment.setupFog port crates/horizon-client-render/src/fog.rs::setup_fog gap: minor: water fog start is fixed at -8; vanilla reads the WATER_FOG_START_DISTANCE attribute
DrawableGizmoPrimitives.addPoint missing minor: debug points are not drawn; Gizmos has no point kind
DrawableGizmoPrimitives.addLine port crates/horizon-client/src/gizmos.rs::Gizmos::line
DrawableGizmoPrimitives.addTriangleFan missing minor: debug triangle fans are not drawn
1 FeatureRenderDispatcher.PreparedFrame skip:other render-pass order and draw-group plumbing of vanilla's feature renderer; Horizon orders its own passes
27 ShadowFeatureRenderer.buildGroup port crates/horizon-client/src/shadows.rs::shadow loop over shadow submits
28 ShadowFeatureRenderer.prepare port crates/horizon-client/src/shadows.rs::shadow shadow quads per piece, clamped by the block below
29 ShadowFeatureRenderer.shadowVertex inline crates/horizon-client/src/shadows.rs::shadow vertex push folded into shadow
30 ShapeOutlineFeatureRenderer.buildGroup port crates/horizon-client/src/gfx.rs::outline_vertices crates/horizon-client-render/src/gfx.rs::outline_vertices block selection outline edges as line vertices
31 TextFeatureRenderer.buildGroup skip:other dispatch over text and background submits; each kind is covered below or by Horizon's text draw
32 TextFeatureRenderer.renderText missing minor: unsure: no outlined-text path found (font.rs, hud.rs, names.rs); the outline colour of a text submit is not drawn
33 TextFeatureRenderer.GlyphRenderer.acceptRenderable skip:other glyph sink for the text pass; Horizon's font pass draws the glyphs
34 FeatureRenderPhase.Output.acceptFeatureGroup skip:other phase plumbing: hands sorted groups to the renderer pass
35 SimpleFeatureRenderPhase skip:other submit, sort, shuffle (debug only) and clear of feature submits; Horizon sorts its own draws
36 SimpleFeatureRenderPhase.FeatureSubmits skip:other batching bookkeeping of feature submits
37 TranslucentFeatureRenderPhase.submit inline crates/horizon-client/src/gfx/translucency.rs::Sorter::sort crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort collects submits; distances are taken in sort
38 TranslucentFeatureRenderPhase.sortInto port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort back-to-front by distance, equal distances keep submit order
39 TranslucentFeatureRenderPhase.sortIndices port crates/horizon-client/src/gfx/translucency.rs::Sorter::sort crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort far to near, stable on ties
40 TranslucentSubmit.computeDistanceToCameraSq inline crates/horizon-client/src/gfx/translucency.rs::Sorter::sort crates/horizon-client-render/src/gfx/translucency.rs::Sorter::sort distance from the quad centre to the camera, computed inside sort
41 FogRenderer.getBuffer skip:other selects the fog uniform slice; Horizon hands its fog values to its own shader per frame
42 FogRenderer.updateBuffer skip:other writes the fog uniform buffer; Horizon's frame_fog passes FogData to its own shader
43 AtmosphericFogEnvironment.getBaseColor port crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog gap: minor: sky fog end uses constant 512 instead of the SKY_FOG_END_DISTANCE attribute
44 AtmosphericFogEnvironment.applyWeatherDarken inline crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog rain and thunder darkening folded into the atmospheric colour
45 BlindnessFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog blindness distance and sky/cloud ends
46 BlindnessFogEnvironment.getModifiedDarkness inline crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog blindness darkness folded into setup_fog
47 LavaFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog gap: player: spectator (-8 start, half render distance) and fire resistance (0 to 5) are not applied in lava
48 MobEffectFogEnvironment.isApplicable inline crates/horizon-client/src/game/render_tick.rs::Game::frame_fog effect gate is where frame_fog builds the blindness and darkness inputs
49 PowderedSnowFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog gap: player: spectator case (-8 start, half render distance) is not applied
50 WaterFogEnvironment.setupFog port crates/horizon-client/src/fog.rs::setup_fog crates/horizon-client-render/src/fog.rs::setup_fog gap: minor: water fog start is fixed at -8; vanilla reads the WATER_FOG_START_DISTANCE attribute
51 DrawableGizmoPrimitives.addPoint missing minor: debug points are not drawn; Gizmos has no point kind
52 DrawableGizmoPrimitives.addLine port crates/horizon-client/src/gizmos.rs::Gizmos::line
53 DrawableGizmoPrimitives.addTriangleFan missing minor: debug triangle fans are not drawn
+33 -33
View File
@@ -9,15 +9,15 @@ OitRenderPassProvider.createDepthBoundsPass missing minor: opt-in Improved Tran
OitRenderPassProvider.createTransmittancePass missing minor: opt-in Improved Transparency (off by default), no OIT pipelines or passes in Horizon
OitRenderPassProvider.createAccumulatePass missing minor: opt-in Improved Transparency (off by default), no OIT pipelines or passes in Horizon
PreparedRenderType.drawFromBufferOit missing minor: opt-in Improved Transparency (off by default), no OIT pipelines or passes in Horizon
PreparedRenderType.draw inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame gap: minor: the indexed draw runs in the gfx/ pass modules that draw_frame calls; RenderSetup scissor not seen
PreparedRenderType.draw inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: the indexed draw runs in the gfx/ pass modules that draw_frame calls; RenderSetup scissor not seen
RenderSetup.toString skip:debug
RenderSetup.prepareTextures inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame overlay and lightmap samplers are bound per pass in gfx/
RenderSetup.prepareTextures inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame overlay and lightmap samplers are bound per pass in gfx/
RenderSetup.RenderSetupBuilder.withTexture skip:java builder
RenderSetup.RenderSetupBuilder.setOutline skip:java builder setter; outline behaviour is in gfx/entity_outline.rs
RenderSetup.RenderSetupBuilder.createRenderSetup skip:java builder
RenderType.calculateHasBlending skip:other blend flag from the pipeline colour targets; Horizon picks blend per pipeline in gfx.rs
RenderType.prepare inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame gap: minor: texture and overlay/lightmap binding folded into the frame passes
RenderType.writeDynamicTransforms inline crates/horizon-client/src/gfx.rs::Renderer::draw_frame gap: minor: no per-render-type layering offset found (only perspective layering scale)
RenderType.prepare inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: texture and overlay/lightmap binding folded into the frame passes
RenderType.writeDynamicTransforms inline crates/horizon-client-render/src/gfx.rs::Renderer::draw_frame gap: minor: no per-render-type layering offset found (only perspective layering scale)
RenderTypes.createMovingBlockSetup inline crates/horizon-client/src/game/moving_pistons.rs::Game::moving_piston_geometry block atlas and lightmap for moving blocks; gap: minor: crumbling and outline flags not checked here
RenderTypes.breezeWind inline crates/horizon-client/src/mobs/render.rs::layers gap: player: the breeze wind layer does not scroll; the UV offset is not applied (render.rs comment)
BannerSpecialRenderer.submit port crates/horizon-client/src/item_render/special.rs::submit Banner arm: flag, base and up to 16 pattern layers
@@ -41,7 +41,7 @@ DecoratedPotSpecialRenderer.submit port crates/horizon-client/src/item_render/sp
EndCubeSpecialRenderer.Unbaked.bake missing minor: no bundled item uses the end cube model (special.rs notes it), so no end portal or gateway effect in hand
PlayerHeadSpecialRenderer.submit port crates/horizon-client/src/item_render/special.rs::submit PlayerHead arm
PlayerHeadSpecialRenderer.getExtents port crates/horizon-client/src/item_render/special.rs::extents PlayerHead arm
PlayerHeadSpecialRenderer.extractArgument port crates/horizon-client/src/skins.rs::head_skin profile to skin lookup
PlayerHeadSpecialRenderer.extractArgument port crates/horizon-client-render/src/skins.rs::head_skin profile to skin lookup
PlayerHeadSpecialRenderer.Unbaked.bake inline crates/horizon-client/src/item_render/special.rs::load_parts models are baked once from entity-models.json
ShieldSpecialRenderer.getExtents port crates/horizon-client/src/item_render/special.rs::extents Shield arm
ShieldSpecialRenderer.Unbaked.bake inline crates/horizon-client/src/item_render/special.rs::load_parts models are baked once from entity-models.json
@@ -89,50 +89,50 @@ TiledBlitRenderState.buildVertices skip:ui GUI tiled draw geometry
TiledBlitRenderState.getBounds skip:ui GUI draw bounds
PictureInPictureRenderState.getBounds skip:ui GUI draw bounds
LevelRenderState.reset skip:java per-frame state clear
ParticlesRenderState.submit inline crates/horizon-client/src/particles.rs::ParticleEngine::render submits particle groups; draws in render
ParticlesRenderState.submit inline crates/horizon-client-render/src/particles.rs::ParticleEngine::render submits particle groups; draws in render
PlayerRenderState.reset skip:java per-frame state clear
QuadParticleRenderState.add port crates/horizon-client/src/particles.rs::ParticleEngine::add quad particle queued per layer
QuadParticleRenderState.buildLayer port crates/horizon-client/src/particles.rs::ParticleEngine::render per-layer quad build and draw
QuadParticleRenderState.renderVertex inline crates/horizon-client/src/particles.rs::ParticleEngine::render vertex math inside the render rotated quad
QuadParticleRenderState.Storage.add port crates/horizon-client/src/particles.rs::ParticleEngine::push store one quad particle
QuadParticleRenderState.Storage.forEachParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::render iterates stored particles in render
QuadParticleRenderState.add port crates/horizon-client-render/src/particles.rs::ParticleEngine::add quad particle queued per layer
QuadParticleRenderState.buildLayer port crates/horizon-client-render/src/particles.rs::ParticleEngine::render per-layer quad build and draw
QuadParticleRenderState.renderVertex inline crates/horizon-client-render/src/particles.rs::ParticleEngine::render vertex math inside the render rotated quad
QuadParticleRenderState.Storage.add port crates/horizon-client-render/src/particles.rs::ParticleEngine::push store one quad particle
QuadParticleRenderState.Storage.forEachParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::render iterates stored particles in render
QuadParticleRenderState.Storage.grow skip:java array capacity growth
WeatherRenderState.reset skip:java per-frame state clear
AbstractTexture.releaseTextures skip:java GPU handle release; Rust drop
AbstractTexture.getTexture skip:java accessor
AbstractTexture.getTextureView skip:java accessor
CubeMapTexture.loadContents port crates/horizon-client/src/gfx/panorama.rs::Faces::try_load six faces read, flipped and stacked
CubeMapTexture.doLoad port crates/horizon-client/src/gfx/panorama.rs::Panorama::new cube texture creation and upload
CubeMapTexture.loadContents port crates/horizon-client-render/src/gfx/panorama.rs::Faces::try_load six faces read, flipped and stacked
CubeMapTexture.doLoad port crates/horizon-client-render/src/gfx/panorama.rs::Panorama::new cube texture creation and upload
DynamicAtlasTree.insertInner skip:other dynamic atlas packing; Horizon uses texture-array layers, not a rectangle packer
DynamicTexture.createTexture skip:other GPU texture creation for CPU pixels; Horizon has no DynamicTexture class
DynamicTexture.upload port crates/horizon-client/src/gfx.rs::Renderer::update_lightmap gap: minor: only the lightmap upload goes through here
DynamicTexture.upload port crates/horizon-client-render/src/gfx.rs::Renderer::update_lightmap gap: minor: only the lightmap upload goes through here
DynamicTexture.dumpContents skip:debug dump debug action
MipmappedTexture.setSampler port crates/horizon-client/src/screen_effects.rs::sampling gap: minor: only blur and clamp bits; filters fixed in gfx
MipmappedTexture.doLoad port crates/horizon-client/src/mipmap.rs::generate mip chain generation
MipmappedTexture.clampMipLevel port crates/horizon-client/src/sprites.rs::sprite_mipmap_limit mip level cap from texture size
MissingTextureAtlasSprite.create port crates/horizon-client/src/sprites.rs::Sprites::insert generated magenta and black missing texture
MipmappedTexture.setSampler port crates/horizon-client-render/src/screen_effects.rs::sampling gap: minor: only blur and clamp bits; filters fixed in gfx
MipmappedTexture.doLoad port crates/horizon-client-render/src/mipmap.rs::generate mip chain generation
MipmappedTexture.clampMipLevel port crates/horizon-client-render/src/sprites.rs::sprite_mipmap_limit mip level cap from texture size
MissingTextureAtlasSprite.create port crates/horizon-client-render/src/sprites.rs::Sprites::insert generated magenta and black missing texture
OverlayTexture.pack skip:other packs u and v into one int for vertex data; overlay.rs::living uses one code
ReloadableTexture.apply inline crates/horizon-client/src/sprites.rs::Sprites::load gap: minor: sampler flags read from the texture section; upload happens later in gfx
ReloadableTexture.doLoad inline crates/horizon-client/src/sprites.rs::Sprites::finish gap: minor: lays out layers; the GPU upload is in gfx
SkinTextureDownloader.downloadAndRegisterSkin port crates/horizon-client/src/skins.rs::Downloader::state starts the skin download and decode
SkinTextureDownloader.downloadSkin port crates/horizon-client/src/skins.rs::Downloader::state disk cache read or HTTP fetch with cache write, in the spawned thread
SkinTextureDownloader.registerTextureInManager inline crates/horizon-client/src/skins.rs::Downloader::queue ready skin queued for the atlas upload
SkinTextureDownloader.doNotchTransparencyHack inline crates/horizon-client/src/skins.rs::process_legacy_skin hat layer cleared when fully opaque
SkinTextureDownloader.setNoAlpha inline crates/horizon-client/src/skins.rs::process_legacy_skin legacy skin regions made opaque
SpriteContents.increaseMipLevel port crates/horizon-client/src/mipmap.rs::generate mip chain generation
SpriteContents.createAnimatedTexture port crates/horizon-client/src/sprites.rs::Sprites::load animation frames from mcmeta
SpriteContents.createAnimationState inline crates/horizon-client/src/sprites.rs::Sprites::finish animation frames laid out per layer
ReloadableTexture.apply inline crates/horizon-client-render/src/sprites.rs::Sprites::load gap: minor: sampler flags read from the texture section; upload happens later in gfx
ReloadableTexture.doLoad inline crates/horizon-client-render/src/sprites.rs::Sprites::finish gap: minor: lays out layers; the GPU upload is in gfx
SkinTextureDownloader.downloadAndRegisterSkin port crates/horizon-client-render/src/skins.rs::Downloader::state starts the skin download and decode
SkinTextureDownloader.downloadSkin port crates/horizon-client-render/src/skins.rs::Downloader::state disk cache read or HTTP fetch with cache write, in the spawned thread
SkinTextureDownloader.registerTextureInManager inline crates/horizon-client-render/src/skins.rs::Downloader::queue ready skin queued for the atlas upload
SkinTextureDownloader.doNotchTransparencyHack inline crates/horizon-client-render/src/skins.rs::process_legacy_skin hat layer cleared when fully opaque
SkinTextureDownloader.setNoAlpha inline crates/horizon-client-render/src/skins.rs::process_legacy_skin legacy skin regions made opaque
SpriteContents.increaseMipLevel port crates/horizon-client-render/src/mipmap.rs::generate mip chain generation
SpriteContents.createAnimatedTexture port crates/horizon-client-render/src/sprites.rs::Sprites::load animation frames from mcmeta
SpriteContents.createAnimationState inline crates/horizon-client-render/src/sprites.rs::Sprites::finish animation frames laid out per layer
SpriteContents.getAdditionalMetadata skip:java generic metadata lookup
SpriteContents.close skip:java image release; Rust drop
SpriteContents.toString skip:debug
SpriteContents.isTransparent inline crates/horizon-client/src/sprites.rs::Sprites::region_opaque gap: minor: single-texel alpha query is not kept; region_opaque tests alpha 255 over a UV box
SpriteContents.uploadFirstFrame inline crates/horizon-client/src/sprites.rs::Sprites::finish first frame copied into the layer pixels
SpriteContents.AnimatedTexture.createAnimationState inline crates/horizon-client/src/sprites.rs::Sprites::finish animation frames laid out per layer
SpriteContents.isTransparent inline crates/horizon-client-render/src/sprites.rs::Sprites::region_opaque gap: minor: single-texel alpha query is not kept; region_opaque tests alpha 255 over a UV box
SpriteContents.uploadFirstFrame inline crates/horizon-client-render/src/sprites.rs::Sprites::finish first frame copied into the layer pixels
SpriteContents.AnimatedTexture.createAnimationState inline crates/horizon-client-render/src/sprites.rs::Sprites::finish animation frames laid out per layer
SpriteContents.AnimationState.needsToDraw skip:java redraw skip optimisation
SpriteContents.AnimationState.close skip:java frame texture release; Rust drop
SpriteLoader.stitch port crates/horizon-client/src/sprites.rs::sprite_mipmap_limit gap: minor: atlas stitching replaced by one texture-array layer per sprite
SpriteLoader.stitch port crates/horizon-client-render/src/sprites.rs::sprite_mipmap_limit gap: minor: atlas stitching replaced by one texture-array layer per sprite
SpriteLoader.runSpriteSuppliers skip:java parallel sprite loading
SpriteLoader.loadAndStitch inline crates/horizon-client/src/sprites.rs::Sprites::insert gap: minor: sprites are read on first use, not as one batch
SpriteLoader.loadAndStitch inline crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: sprites are read on first use, not as one batch
SpriteLoader.getStitchedSprites skip:other maps sprites to atlas rectangles; Horizon uses array layers
Stitcher.registerSprite skip:other atlas rectangle packing; Horizon uses one texture-array layer per sprite
Stitcher.stitch skip:other atlas rectangle packing; Horizon uses one texture-array layer per sprite
Can't render this file because it contains an unexpected character in line 31 and column 151.
+128 -128
View File
@@ -1,150 +1,150 @@
TextureAtlas.createTexture inline crates/horizon-client/src/sprites.rs::Sprites::finish gap: minor: no GPU texture objects or mip views; array size and mip count are set in finish
TextureAtlas.upload inline crates/horizon-client/src/sprites.rs::Sprites::finish gap: minor: no GPU upload or animated UBOs; sprites are inserted before finish
TextureAtlas.uploadInitialContents inline crates/horizon-client/src/sprites.rs::Sprites::finish static frames copied into the array pixels
TextureAtlas.createTexture inline crates/horizon-client-render/src/sprites.rs::Sprites::finish gap: minor: no GPU texture objects or mip views; array size and mip count are set in finish
TextureAtlas.upload inline crates/horizon-client-render/src/sprites.rs::Sprites::finish gap: minor: no GPU upload or animated UBOs; sprites are inserted before finish
TextureAtlas.uploadInitialContents inline crates/horizon-client-render/src/sprites.rs::Sprites::finish static frames copied into the array pixels
TextureAtlas.dumpContents skip:debug DEBUG_DUMP_TEXTURE_ATLAS PNG dump
TextureAtlas.dumpSpriteNames skip:debug DEBUG_DUMP_TEXTURE_ATLAS name list
TextureAtlas.cycleAnimationFrames port crates/horizon-client/src/gfx/animate.rs::SpriteAnimator::animate advances every animated layer to the frame for the tick
TextureAtlas.uploadAnimationFrames port crates/horizon-client/src/gfx/animate.rs::mix_level per mip level frame mix (drawToAtlas)
TextureAtlas.getSprite port crates/horizon-client/src/sprites.rs::Sprites::insert gap: minor: loads a texture on first lookup; vanilla returns the missing sprite for names not in the atlas
TextureAtlas.cycleAnimationFrames port crates/horizon-client-render/src/gfx/animate.rs::SpriteAnimator::animate advances every animated layer to the frame for the tick
TextureAtlas.uploadAnimationFrames port crates/horizon-client-render/src/gfx/animate.rs::mix_level per mip level frame mix (drawToAtlas)
TextureAtlas.getSprite port crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: loads a texture on first lookup; vanilla returns the missing sprite for names not in the atlas
TextureAtlas.clearTextureData skip:java frees sprite and UBO memory; Rust ownership
TextureAtlas.releaseTextures skip:java frees GPU mip views; Rust ownership
TextureAtlasSprite.getV inline crates/horizon-client/src/particles.rs::ParticleEngine::render gap: minor: only the particle quad V lerp is here; other getV callers keep their own lerp
TextureAtlasSprite.getV inline crates/horizon-client-render/src/particles.rs::ParticleEngine::render gap: minor: only the particle quad V lerp is here; other getV callers keep their own lerp
TextureAtlasSprite.toString skip:debug debug string
TextureAtlasSprite.uploadSpriteUbo skip:other GPU uniform block for the atlas blit; Horizon samples its layer array and SpriteAnimator computes frames, so no UBO is needed
TextureContents.load port crates/horizon-client/src/sprites.rs::Sprites::load reads the PNG and the .mcmeta animation section
TextureManager.registerAndLoad port crates/horizon-client/src/sprites.rs::Sprites::insert loads the texture into a layer and registers it by name
TextureManager.loadContentsSafe inline crates/horizon-client/src/sprites.rs::Sprites::insert missing texture fallback when a texture does not load
TextureManager.register inline crates/horizon-client/src/sprites.rs::Sprites::insert adds the layer under its name
TextureContents.load port crates/horizon-client-render/src/sprites.rs::Sprites::load reads the PNG and the .mcmeta animation section
TextureManager.registerAndLoad port crates/horizon-client-render/src/sprites.rs::Sprites::insert loads the texture into a layer and registers it by name
TextureManager.loadContentsSafe inline crates/horizon-client-render/src/sprites.rs::Sprites::insert missing texture fallback when a texture does not load
TextureManager.register inline crates/horizon-client-render/src/sprites.rs::Sprites::insert adds the layer under its name
TextureManager.safeClose skip:java closes a texture object; Rust ownership
TextureManager.getTexture port crates/horizon-client/src/sprites.rs::Sprites::insert loads on first use, as SimpleTexture does
TextureManager.tick port crates/horizon-client/src/gfx/animate.rs::SpriteAnimator::animate gap: minor: animated layers advance in the per frame animate pass; there is no tickable texture list
TextureManager.getTexture port crates/horizon-client-render/src/sprites.rs::Sprites::insert loads on first use, as SimpleTexture does
TextureManager.tick port crates/horizon-client-render/src/gfx/animate.rs::SpriteAnimator::animate gap: minor: animated layers advance in the per frame animate pass; there is no tickable texture list
TextureManager.release skip:java drops one texture object; Rust ownership
TextureManager.close skip:java drops all texture objects; Rust ownership
TextureManager.reload port crates/horizon-client/src/assets.rs::Assets::reload gap: minor: rebuilds every render asset synchronously; no pending futures
TextureManager.reload port crates/horizon-client-render/src/assets.rs::Assets::reload gap: minor: rebuilds every render asset synchronously; no pending futures
TextureManager.dumpAllSheets skip:debug debug dump of every atlas
TextureManager.scheduleLoad skip:other asynchronous texture preparation; Horizon loads each texture on the calling thread in Sprites::insert
SpriteSource.Output.add port crates/horizon-client/src/atlas_sources.rs::list records a sprite id and its origin; a later source with the same id replaces it
SpriteSourceList.load port crates/horizon-client/src/atlas_sources.rs::atlases gap: minor: reads one resource root's atlases/*.json, not every pack's stacked definitions
DirectoryLister.run port crates/horizon-client/src/atlas_sources.rs::list Directory arm: textures under source/ get the prefix
SpriteSource.Output.add port crates/horizon-client-render/src/atlas_sources.rs::list records a sprite id and its origin; a later source with the same id replaces it
SpriteSourceList.load port crates/horizon-client-render/src/atlas_sources.rs::atlases gap: minor: reads one resource root's atlases/*.json, not every pack's stacked definitions
DirectoryLister.run port crates/horizon-client-render/src/atlas_sources.rs::list Directory arm: textures under source/ get the prefix
LazyLoadedImage.get skip:java shared image cache; generate reads the source texture each time it builds a sprite
LazyLoadedImage.release skip:java releases the shared image cache
PalettedPermutations.loadPaletteEntryFromImage inline crates/horizon-client/src/atlas_sources.rs::generate palette images are loaded inside the Paletted arm of generate
PalettedPermutations.PalettedSpriteSupplier.get port crates/horizon-client/src/atlas_sources.rs::generate Paletted arm: base colours mapped through the palette pair (apply_palette)
SingleFile.run port crates/horizon-client/src/atlas_sources.rs::list Single arm: the sprite named by the resource, or its sprite id
Unstitcher.run port crates/horizon-client/src/atlas_sources.rs::list Unstitch arm: one sprite per region of the texture
Unstitcher.RegionInstance.get port crates/horizon-client/src/atlas_sources.rs::generate Region arm: the region cut out of the texture
AshParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Ash arm
AttackSweepParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle SweepAttack uses the HugeExplosion behaviour: age, then sprite from age
AttackSweepParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make SweepAttack arm: size from xAux
BaseAshSmokeParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make Smoke, Ash, WhiteAsh and DustPlume arms: motion, GrowIn size, lifetime
BreakingItemParticle.CobwebProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make ItemCobweb arm; the layer comes from item_sprites (game/item_particles.rs)
BreakingItemParticle.ItemParticleProvider.getSprite port crates/horizon-client/src/particles.rs::ParticleEngine::make Item arms pick a layer with the engine random; ItemCobweb, ItemSlime and ItemSnowball read item_sprites
BreakingItemParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Item arm
BreakingItemParticle.SlimeProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make ItemSlime arm
BreakingItemParticle.SnowballProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make ItemSnowball arm
BreakingItemParticle.SulfurCubeProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make SulfurCubeGoo arm: the first sprite of its set
BubbleColumnUpParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle BubbleColumnUp arm: removed once it leaves water
BubbleColumnUpParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make BubbleColumnUp arm
BubbleParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Bubble arm: rises, drag 0.85, removed out of water
BubbleParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Bubble arm
BubblePopParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle BubblePop arm
BubblePopParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make BubblePop arm
CampfireSmokeParticle.CosyProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make CampfireCosySmoke arm, alpha 0.9
CampfireSmokeParticle.SignalProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make CampfireSignalSmoke arm, alpha 0.95
CritParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make Crit arm; the constructor tick runs on the next engine tick (pre_tick)
CritParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Crit arm: green and blue fade
CritParticle.DamageIndicatorProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DamageIndicator arm; lifetime 20 from after_constructor_tick
CritParticle.MagicProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make EnchantedHit arm; red and green scaled by after_constructor_tick
CritParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Crit arm
DragonBreathParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle DragonBreath arm: hit-ground flag and friction
DragonBreathParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size GrowIn size curve
DragonBreathParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DragonBreath arm; power through set_power
DripParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords Block15 for the glowing tears; World for the rest
DripParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Drip: pre move, gravity and move, post move, fluid check
DripParticle.preMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Drip: lifetime countdown and removal
DripParticle.CoolingDripHangParticle.preMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Drip CoolingHang stage: red, green and blue fade
DripParticle.DripHangParticle.preMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Drip Hang stage: spawns the falling drip when the countdown ends
DripParticle.DripHangParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Drip Hang stage: velocity times 0.02
DripParticle.DripstoneFallAndLandParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle FallAndLand stage with the dripstone land sound
DripParticle.DripstoneLavaFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make FallingDripstoneLava arm
DripParticle.DripstoneLavaHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DrippingDripstoneLava arm
DripParticle.DripstoneWaterFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make FallingDripstoneWater arm
DripParticle.DripstoneWaterHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DrippingDripstoneWater arm
DripParticle.FallAndLandParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle FallAndLand stage: removed on the ground, spawns the land particle
DripParticle.HoneyFallAndLandParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle FallAndLand for FallingHoney: beehive drip sound
DripParticle.LavaFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make FallingLava arm
DripParticle.LavaHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DrippingLava arm
DripParticle.LavaLandProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make LandingLava arm
DripParticle.ObsidianTearFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make FallingObsidianTear arm
DripParticle.ObsidianTearHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DrippingObsidianTear arm
DripParticle.ObsidianTearLandProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make LandingObsidianTear arm
DripParticle.SporeBlossomFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make FallingSporeBlossom arm
DripParticle.WaterFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make FallingWater arm
DripParticle.WaterHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DrippingWater arm
DustColorTransitionParticle.randomizeColor port crates/horizon-client/src/particles.rs::ParticleEngine::make DustColorTransition arm: the randomize closure for from and to colours
DustColorTransitionParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DustColorTransition arm
DustParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Dust arm
DustParticleBase.randomizeColor port crates/horizon-client/src/particles.rs::ParticleEngine::make Dust and DustColorTransition arms: the randomize closure
DustParticleBase.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size GrowIn size curve
DustPlumeParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make DustPlume arm, base 1.0
PalettedPermutations.loadPaletteEntryFromImage inline crates/horizon-client-render/src/atlas_sources.rs::generate palette images are loaded inside the Paletted arm of generate
PalettedPermutations.PalettedSpriteSupplier.get port crates/horizon-client-render/src/atlas_sources.rs::generate Paletted arm: base colours mapped through the palette pair (apply_palette)
SingleFile.run port crates/horizon-client-render/src/atlas_sources.rs::list Single arm: the sprite named by the resource, or its sprite id
Unstitcher.run port crates/horizon-client-render/src/atlas_sources.rs::list Unstitch arm: one sprite per region of the texture
Unstitcher.RegionInstance.get port crates/horizon-client-render/src/atlas_sources.rs::generate Region arm: the region cut out of the texture
AshParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Ash arm
AttackSweepParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle SweepAttack uses the HugeExplosion behaviour: age, then sprite from age
AttackSweepParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make SweepAttack arm: size from xAux
BaseAshSmokeParticle.<init> port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke, Ash, WhiteAsh and DustPlume arms: motion, GrowIn size, lifetime
BreakingItemParticle.CobwebProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make ItemCobweb arm; the layer comes from item_sprites (game/item_particles.rs)
BreakingItemParticle.ItemParticleProvider.getSprite port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Item arms pick a layer with the engine random; ItemCobweb, ItemSlime and ItemSnowball read item_sprites
BreakingItemParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Item arm
BreakingItemParticle.SlimeProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make ItemSlime arm
BreakingItemParticle.SnowballProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make ItemSnowball arm
BreakingItemParticle.SulfurCubeProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make SulfurCubeGoo arm: the first sprite of its set
BubbleColumnUpParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle BubbleColumnUp arm: removed once it leaves water
BubbleColumnUpParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make BubbleColumnUp arm
BubbleParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Bubble arm: rises, drag 0.85, removed out of water
BubbleParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Bubble arm
BubblePopParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle BubblePop arm
BubblePopParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make BubblePop arm
CampfireSmokeParticle.CosyProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make CampfireCosySmoke arm, alpha 0.9
CampfireSmokeParticle.SignalProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make CampfireSignalSmoke arm, alpha 0.95
CritParticle.<init> port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Crit arm; the constructor tick runs on the next engine tick (pre_tick)
CritParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Crit arm: green and blue fade
CritParticle.DamageIndicatorProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DamageIndicator arm; lifetime 20 from after_constructor_tick
CritParticle.MagicProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make EnchantedHit arm; red and green scaled by after_constructor_tick
CritParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Crit arm
DragonBreathParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle DragonBreath arm: hit-ground flag and friction
DragonBreathParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
DragonBreathParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DragonBreath arm; power through set_power
DripParticle.getLightCoords port crates/horizon-client-render/src/particles.rs::Particle::light_coords Block15 for the glowing tears; World for the rest
DripParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Drip: pre move, gravity and move, post move, fluid check
DripParticle.preMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip: lifetime countdown and removal
DripParticle.CoolingDripHangParticle.preMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip CoolingHang stage: red, green and blue fade
DripParticle.DripHangParticle.preMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip Hang stage: spawns the falling drip when the countdown ends
DripParticle.DripHangParticle.postMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip Hang stage: velocity times 0.02
DripParticle.DripstoneFallAndLandParticle.postMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallAndLand stage with the dripstone land sound
DripParticle.DripstoneLavaFallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingDripstoneLava arm
DripParticle.DripstoneLavaHangProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingDripstoneLava arm
DripParticle.DripstoneWaterFallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingDripstoneWater arm
DripParticle.DripstoneWaterHangProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingDripstoneWater arm
DripParticle.FallAndLandParticle.postMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallAndLand stage: removed on the ground, spawns the land particle
DripParticle.HoneyFallAndLandParticle.postMoveUpdate port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallAndLand for FallingHoney: beehive drip sound
DripParticle.LavaFallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingLava arm
DripParticle.LavaHangProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingLava arm
DripParticle.LavaLandProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make LandingLava arm
DripParticle.ObsidianTearFallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingObsidianTear arm
DripParticle.ObsidianTearHangProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingObsidianTear arm
DripParticle.ObsidianTearLandProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make LandingObsidianTear arm
DripParticle.SporeBlossomFallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingSporeBlossom arm
DripParticle.WaterFallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingWater arm
DripParticle.WaterHangProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingWater arm
DustColorTransitionParticle.randomizeColor port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustColorTransition arm: the randomize closure for from and to colours
DustColorTransitionParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustColorTransition arm
DustParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Dust arm
DustParticleBase.randomizeColor port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Dust and DustColorTransition arms: the randomize closure
DustParticleBase.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
DustPlumeParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustPlume arm, base 1.0
ElderGuardianParticleGroup.extractRenderState port crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry gap: minor: one apparition timer that a new curse resets, so two curses show one ghost
ElderGuardianParticleGroup.ElderGuardianParticleRenderState.fromParticle port crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry fade, camera pose and offsets
ElderGuardianParticleGroup.State.submit port crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry draws the guardian model
EmissiveRisingParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords Block15 for sculk soul only (the SculkSoul arm)
EmissiveRisingParticle.EmissiveProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make SculkSoul arm of the Soul arms
EmissiveRisingParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Soul arm
EndRodParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by free_move: moves the box without collision
EndRodParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make EndRod arm
ExplodeParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make Poof and Spit arms: puff motion, size and lifetime
ExplodeParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Poof arm
FallingDustParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size GrowIn size curve
FallingDustParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle FallingDust arm: roll and gravity clamp
FallingDustParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make gap: minor: the invisible-block skip and the tint lookup happen in animate_tick (Animate::Falling), not here
FallingLeavesParticle.CherryProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make CherryLeaves arm
FallingLeavesParticle.PaleOakProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make PaleOakLeaves arm
FallingLeavesParticle.PoplarProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make RedPoplarLeaves, OrangePoplarLeaves and YellowPoplarLeaves arms
FallingLeavesParticle.TintedLeavesProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make TintedLeaves arm with the option colour
FallingParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make Leaves arm: size, gravity, start velocity, flow and swirl
FallingParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Leaves arm: wind, spin and removal on the ground
FireflyParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Firefly arm: removed in a solid block, fade, random drift
FireflyParticle.FireflyProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Firefly arm
FireworkParticles.FlashProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Flash arm
FireworkParticles.SparkProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Firework arm, alpha 0.99
FireworkParticles.Starter.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_starters launch sound, a burst every 2 ticks, flash, twinkle sound at the end
FireworkParticles.Starter.isFarAwayFromCamera inline crates/horizon-client/src/particles.rs::ParticleEngine::fireworks gap: minor: the distance is taken when the rocket is launched, not on each tick
FireworkParticles.Starter.createParticleBall port crates/horizon-client/src/particles.rs::ParticleEngine::spark_ball
FireworkParticles.Starter.createParticleShape port crates/horizon-client/src/particles.rs::ParticleEngine::spark_shape
FireworkParticles.Starter.createParticleBurst inline crates/horizon-client/src/particles.rs::ParticleEngine::tick_starters Burst shape arm of tick_starters
FlameParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by free_move: moves the box without collision
FlameParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Flame size curve
FlameParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords AgeEmission light
FlameParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Flame arm (also copper and soul fire flame)
FlameParticle.SmallFlameProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make SmallFlame arm, scaled 0.5
FlyStraightTowardsParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle FlyStraight arm: position and colour lerp
FlyStraightTowardsParticle.OminousSpawnProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make OminousSpawning arm
FlyTowardsPositionParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make Enchant, Nautilus and VaultConnection arms
FlyTowardsPositionParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by free_move: moves the box without collision
FlyTowardsPositionParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords AgeEmission4 for enchant and nautilus; Block15 for vault connection
FlyTowardsPositionParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle FlyTowards arm
FlyTowardsPositionParticle.extract port crates/horizon-client/src/particles.rs::ParticleEngine::render alpha from the lifetime curve at draw time
FlyTowardsPositionParticle.EnchantProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Enchant arm
FlyTowardsPositionParticle.NautilusProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Nautilus arm
FlyTowardsPositionParticle.VaultConnectionProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make VaultConnection arm: block light, lifetime alpha, scale 1.5
EmissiveRisingParticle.getLightCoords port crates/horizon-client-render/src/particles.rs::Particle::light_coords Block15 for sculk soul only (the SculkSoul arm)
EmissiveRisingParticle.EmissiveProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make SculkSoul arm of the Soul arms
EmissiveRisingParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Soul arm
EndRodParticle.move port crates/horizon-client-render/src/particles.rs::Particle::move_by free_move: moves the box without collision
EndRodParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make EndRod arm
ExplodeParticle.<init> port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof and Spit arms: puff motion, size and lifetime
ExplodeParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof arm
FallingDustParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
FallingDustParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallingDust arm: roll and gravity clamp
FallingDustParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: the invisible-block skip and the tint lookup happen in animate_tick (Animate::Falling), not here
FallingLeavesParticle.CherryProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make CherryLeaves arm
FallingLeavesParticle.PaleOakProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make PaleOakLeaves arm
FallingLeavesParticle.PoplarProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make RedPoplarLeaves, OrangePoplarLeaves and YellowPoplarLeaves arms
FallingLeavesParticle.TintedLeavesProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make TintedLeaves arm with the option colour
FallingParticle.<init> port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Leaves arm: size, gravity, start velocity, flow and swirl
FallingParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Leaves arm: wind, spin and removal on the ground
FireflyParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Firefly arm: removed in a solid block, fade, random drift
FireflyParticle.FireflyProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Firefly arm
FireworkParticles.FlashProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Flash arm
FireworkParticles.SparkProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Firework arm, alpha 0.99
FireworkParticles.Starter.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_starters launch sound, a burst every 2 ticks, flash, twinkle sound at the end
FireworkParticles.Starter.isFarAwayFromCamera inline crates/horizon-client-render/src/particles.rs::ParticleEngine::fireworks gap: minor: the distance is taken when the rocket is launched, not on each tick
FireworkParticles.Starter.createParticleBall port crates/horizon-client-render/src/particles.rs::ParticleEngine::spark_ball
FireworkParticles.Starter.createParticleShape port crates/horizon-client-render/src/particles.rs::ParticleEngine::spark_shape
FireworkParticles.Starter.createParticleBurst inline crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_starters Burst shape arm of tick_starters
FlameParticle.move port crates/horizon-client-render/src/particles.rs::Particle::move_by free_move: moves the box without collision
FlameParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Flame size curve
FlameParticle.getLightCoords port crates/horizon-client-render/src/particles.rs::Particle::light_coords AgeEmission light
FlameParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Flame arm (also copper and soul fire flame)
FlameParticle.SmallFlameProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make SmallFlame arm, scaled 0.5
FlyStraightTowardsParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FlyStraight arm: position and colour lerp
FlyStraightTowardsParticle.OminousSpawnProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make OminousSpawning arm
FlyTowardsPositionParticle.<init> port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Enchant, Nautilus and VaultConnection arms
FlyTowardsPositionParticle.move port crates/horizon-client-render/src/particles.rs::Particle::move_by free_move: moves the box without collision
FlyTowardsPositionParticle.getLightCoords port crates/horizon-client-render/src/particles.rs::Particle::light_coords AgeEmission4 for enchant and nautilus; Block15 for vault connection
FlyTowardsPositionParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FlyTowards arm
FlyTowardsPositionParticle.extract port crates/horizon-client-render/src/particles.rs::ParticleEngine::render alpha from the lifetime curve at draw time
FlyTowardsPositionParticle.EnchantProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Enchant arm
FlyTowardsPositionParticle.NautilusProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Nautilus arm
FlyTowardsPositionParticle.VaultConnectionProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make VaultConnection arm: block light, lifetime alpha, scale 1.5
GeyserBaseParticle.Provider.createParticle missing player: sulfur geysers do not erupt here: no water column, base puff or eruption sound (only the potent sulfur block state exists), and the geyser particle types are not in ParticleType
GeyserEruptionParticle.tick missing player: the water column of a geyser eruption is not drawn; no geyser particle types exist here
GeyserEruptionParticle.Provider.createParticle missing player: no geyser eruption particle is made
GeyserPlumeParticle.<init> missing player: no water plume is made when a sulfur geyser erupts
GeyserPlumeParticle.tick missing player: the plume does not rise, spray or fall back
GeyserPlumeParticle.Provider.createParticle missing player: no water plume is made when a sulfur geyser erupts
GlowParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords AgeEmission light (glow, wax, electric spark)
GlowParticle.ElectricSparkProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make ElectricSpark arm
GlowParticle.GlowSquidProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Glow arm
GlowParticle.WaxOffProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make WaxOff arm
GlowParticle.WaxOnProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make WaxOn arm
GustParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle HugeExplosion behaviour: age, then sprite from age
GustParticle.SmallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make SmallGust arm, scaled 0.15
GustSeedParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle GustSeed arm: a gust every tick or two, then removal
GustSeedParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make GustEmitterLarge and GustEmitterSmall arms: scale, lifetime, delay
HeartParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size GrowIn size curve
HeartParticle.AngryVillagerProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make AngryVillager arm, raised 0.5; the default colour is already white
HeartParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make Heart arm
GlowParticle.getLightCoords port crates/horizon-client-render/src/particles.rs::Particle::light_coords AgeEmission light (glow, wax, electric spark)
GlowParticle.ElectricSparkProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make ElectricSpark arm
GlowParticle.GlowSquidProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Glow arm
GlowParticle.WaxOffProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make WaxOff arm
GlowParticle.WaxOnProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make WaxOn arm
GustParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle HugeExplosion behaviour: age, then sprite from age
GustParticle.SmallProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make SmallGust arm, scaled 0.15
GustSeedParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle GustSeed arm: a gust every tick or two, then removal
GustSeedParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make GustEmitterLarge and GustEmitterSmall arms: scale, lifetime, delay
HeartParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
HeartParticle.AngryVillagerProvider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make AngryVillager arm, raised 0.5; the default colour is already white
HeartParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make Heart arm
1 TextureAtlas.createTexture inline crates/horizon-client/src/sprites.rs::Sprites::finish crates/horizon-client-render/src/sprites.rs::Sprites::finish gap: minor: no GPU texture objects or mip views; array size and mip count are set in finish
2 TextureAtlas.upload inline crates/horizon-client/src/sprites.rs::Sprites::finish crates/horizon-client-render/src/sprites.rs::Sprites::finish gap: minor: no GPU upload or animated UBOs; sprites are inserted before finish
3 TextureAtlas.uploadInitialContents inline crates/horizon-client/src/sprites.rs::Sprites::finish crates/horizon-client-render/src/sprites.rs::Sprites::finish static frames copied into the array pixels
4 TextureAtlas.dumpContents skip:debug DEBUG_DUMP_TEXTURE_ATLAS PNG dump
5 TextureAtlas.dumpSpriteNames skip:debug DEBUG_DUMP_TEXTURE_ATLAS name list
6 TextureAtlas.cycleAnimationFrames port crates/horizon-client/src/gfx/animate.rs::SpriteAnimator::animate crates/horizon-client-render/src/gfx/animate.rs::SpriteAnimator::animate advances every animated layer to the frame for the tick
7 TextureAtlas.uploadAnimationFrames port crates/horizon-client/src/gfx/animate.rs::mix_level crates/horizon-client-render/src/gfx/animate.rs::mix_level per mip level frame mix (drawToAtlas)
8 TextureAtlas.getSprite port crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: loads a texture on first lookup; vanilla returns the missing sprite for names not in the atlas
9 TextureAtlas.clearTextureData skip:java frees sprite and UBO memory; Rust ownership
10 TextureAtlas.releaseTextures skip:java frees GPU mip views; Rust ownership
11 TextureAtlasSprite.getV inline crates/horizon-client/src/particles.rs::ParticleEngine::render crates/horizon-client-render/src/particles.rs::ParticleEngine::render gap: minor: only the particle quad V lerp is here; other getV callers keep their own lerp
12 TextureAtlasSprite.toString skip:debug debug string
13 TextureAtlasSprite.uploadSpriteUbo skip:other GPU uniform block for the atlas blit; Horizon samples its layer array and SpriteAnimator computes frames, so no UBO is needed
14 TextureContents.load port crates/horizon-client/src/sprites.rs::Sprites::load crates/horizon-client-render/src/sprites.rs::Sprites::load reads the PNG and the .mcmeta animation section
15 TextureManager.registerAndLoad port crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert loads the texture into a layer and registers it by name
16 TextureManager.loadContentsSafe inline crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert missing texture fallback when a texture does not load
17 TextureManager.register inline crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert adds the layer under its name
18 TextureManager.safeClose skip:java closes a texture object; Rust ownership
19 TextureManager.getTexture port crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert loads on first use, as SimpleTexture does
20 TextureManager.tick port crates/horizon-client/src/gfx/animate.rs::SpriteAnimator::animate crates/horizon-client-render/src/gfx/animate.rs::SpriteAnimator::animate gap: minor: animated layers advance in the per frame animate pass; there is no tickable texture list
21 TextureManager.release skip:java drops one texture object; Rust ownership
22 TextureManager.close skip:java drops all texture objects; Rust ownership
23 TextureManager.reload port crates/horizon-client/src/assets.rs::Assets::reload crates/horizon-client-render/src/assets.rs::Assets::reload gap: minor: rebuilds every render asset synchronously; no pending futures
24 TextureManager.dumpAllSheets skip:debug debug dump of every atlas
25 TextureManager.scheduleLoad skip:other asynchronous texture preparation; Horizon loads each texture on the calling thread in Sprites::insert
26 SpriteSource.Output.add port crates/horizon-client/src/atlas_sources.rs::list crates/horizon-client-render/src/atlas_sources.rs::list records a sprite id and its origin; a later source with the same id replaces it
27 SpriteSourceList.load port crates/horizon-client/src/atlas_sources.rs::atlases crates/horizon-client-render/src/atlas_sources.rs::atlases gap: minor: reads one resource root's atlases/*.json, not every pack's stacked definitions
28 DirectoryLister.run port crates/horizon-client/src/atlas_sources.rs::list crates/horizon-client-render/src/atlas_sources.rs::list Directory arm: textures under source/ get the prefix
29 LazyLoadedImage.get skip:java shared image cache; generate reads the source texture each time it builds a sprite
30 LazyLoadedImage.release skip:java releases the shared image cache
31 PalettedPermutations.loadPaletteEntryFromImage inline crates/horizon-client/src/atlas_sources.rs::generate crates/horizon-client-render/src/atlas_sources.rs::generate palette images are loaded inside the Paletted arm of generate
32 PalettedPermutations.PalettedSpriteSupplier.get port crates/horizon-client/src/atlas_sources.rs::generate crates/horizon-client-render/src/atlas_sources.rs::generate Paletted arm: base colours mapped through the palette pair (apply_palette)
33 SingleFile.run port crates/horizon-client/src/atlas_sources.rs::list crates/horizon-client-render/src/atlas_sources.rs::list Single arm: the sprite named by the resource, or its sprite id
34 Unstitcher.run port crates/horizon-client/src/atlas_sources.rs::list crates/horizon-client-render/src/atlas_sources.rs::list Unstitch arm: one sprite per region of the texture
35 Unstitcher.RegionInstance.get port crates/horizon-client/src/atlas_sources.rs::generate crates/horizon-client-render/src/atlas_sources.rs::generate Region arm: the region cut out of the texture
36 AshParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Ash arm
37 AttackSweepParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle SweepAttack uses the HugeExplosion behaviour: age, then sprite from age
38 AttackSweepParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SweepAttack arm: size from xAux
39 BaseAshSmokeParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke, Ash, WhiteAsh and DustPlume arms: motion, GrowIn size, lifetime
40 BreakingItemParticle.CobwebProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make ItemCobweb arm; the layer comes from item_sprites (game/item_particles.rs)
41 BreakingItemParticle.ItemParticleProvider.getSprite port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Item arms pick a layer with the engine random; ItemCobweb, ItemSlime and ItemSnowball read item_sprites
42 BreakingItemParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Item arm
43 BreakingItemParticle.SlimeProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make ItemSlime arm
44 BreakingItemParticle.SnowballProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make ItemSnowball arm
45 BreakingItemParticle.SulfurCubeProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SulfurCubeGoo arm: the first sprite of its set
46 BubbleColumnUpParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle BubbleColumnUp arm: removed once it leaves water
47 BubbleColumnUpParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make BubbleColumnUp arm
48 BubbleParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Bubble arm: rises, drag 0.85, removed out of water
49 BubbleParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Bubble arm
50 BubblePopParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle BubblePop arm
51 BubblePopParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make BubblePop arm
52 CampfireSmokeParticle.CosyProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make CampfireCosySmoke arm, alpha 0.9
53 CampfireSmokeParticle.SignalProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make CampfireSignalSmoke arm, alpha 0.95
54 CritParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Crit arm; the constructor tick runs on the next engine tick (pre_tick)
55 CritParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Crit arm: green and blue fade
56 CritParticle.DamageIndicatorProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DamageIndicator arm; lifetime 20 from after_constructor_tick
57 CritParticle.MagicProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make EnchantedHit arm; red and green scaled by after_constructor_tick
58 CritParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Crit arm
59 DragonBreathParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle DragonBreath arm: hit-ground flag and friction
60 DragonBreathParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
61 DragonBreathParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DragonBreath arm; power through set_power
62 DripParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords crates/horizon-client-render/src/particles.rs::Particle::light_coords Block15 for the glowing tears; World for the rest
63 DripParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Drip: pre move, gravity and move, post move, fluid check
64 DripParticle.preMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip: lifetime countdown and removal
65 DripParticle.CoolingDripHangParticle.preMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip CoolingHang stage: red, green and blue fade
66 DripParticle.DripHangParticle.preMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip Hang stage: spawns the falling drip when the countdown ends
67 DripParticle.DripHangParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Drip Hang stage: velocity times 0.02
68 DripParticle.DripstoneFallAndLandParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallAndLand stage with the dripstone land sound
69 DripParticle.DripstoneLavaFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingDripstoneLava arm
70 DripParticle.DripstoneLavaHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingDripstoneLava arm
71 DripParticle.DripstoneWaterFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingDripstoneWater arm
72 DripParticle.DripstoneWaterHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingDripstoneWater arm
73 DripParticle.FallAndLandParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallAndLand stage: removed on the ground, spawns the land particle
74 DripParticle.HoneyFallAndLandParticle.postMoveUpdate port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallAndLand for FallingHoney: beehive drip sound
75 DripParticle.LavaFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingLava arm
76 DripParticle.LavaHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingLava arm
77 DripParticle.LavaLandProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make LandingLava arm
78 DripParticle.ObsidianTearFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingObsidianTear arm
79 DripParticle.ObsidianTearHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingObsidianTear arm
80 DripParticle.ObsidianTearLandProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make LandingObsidianTear arm
81 DripParticle.SporeBlossomFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingSporeBlossom arm
82 DripParticle.WaterFallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make FallingWater arm
83 DripParticle.WaterHangProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DrippingWater arm
84 DustColorTransitionParticle.randomizeColor port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustColorTransition arm: the randomize closure for from and to colours
85 DustColorTransitionParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustColorTransition arm
86 DustParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Dust arm
87 DustParticleBase.randomizeColor port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Dust and DustColorTransition arms: the randomize closure
88 DustParticleBase.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
89 DustPlumeParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustPlume arm, base 1.0
90 ElderGuardianParticleGroup.extractRenderState port crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry gap: minor: one apparition timer that a new curse resets, so two curses show one ghost
91 ElderGuardianParticleGroup.ElderGuardianParticleRenderState.fromParticle port crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry fade, camera pose and offsets
92 ElderGuardianParticleGroup.State.submit port crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry crates/horizon-client/src/game/mob_blocks.rs::Game::elder_apparition_geometry draws the guardian model
93 EmissiveRisingParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords crates/horizon-client-render/src/particles.rs::Particle::light_coords Block15 for sculk soul only (the SculkSoul arm)
94 EmissiveRisingParticle.EmissiveProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SculkSoul arm of the Soul arms
95 EmissiveRisingParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Soul arm
96 EndRodParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by crates/horizon-client-render/src/particles.rs::Particle::move_by free_move: moves the box without collision
97 EndRodParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make EndRod arm
98 ExplodeParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof and Spit arms: puff motion, size and lifetime
99 ExplodeParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof arm
100 FallingDustParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
101 FallingDustParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FallingDust arm: roll and gravity clamp
102 FallingDustParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: the invisible-block skip and the tint lookup happen in animate_tick (Animate::Falling), not here
103 FallingLeavesParticle.CherryProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make CherryLeaves arm
104 FallingLeavesParticle.PaleOakProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make PaleOakLeaves arm
105 FallingLeavesParticle.PoplarProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make RedPoplarLeaves, OrangePoplarLeaves and YellowPoplarLeaves arms
106 FallingLeavesParticle.TintedLeavesProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make TintedLeaves arm with the option colour
107 FallingParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Leaves arm: size, gravity, start velocity, flow and swirl
108 FallingParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Leaves arm: wind, spin and removal on the ground
109 FireflyParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Firefly arm: removed in a solid block, fade, random drift
110 FireflyParticle.FireflyProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Firefly arm
111 FireworkParticles.FlashProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Flash arm
112 FireworkParticles.SparkProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Firework arm, alpha 0.99
113 FireworkParticles.Starter.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_starters crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_starters launch sound, a burst every 2 ticks, flash, twinkle sound at the end
114 FireworkParticles.Starter.isFarAwayFromCamera inline crates/horizon-client/src/particles.rs::ParticleEngine::fireworks crates/horizon-client-render/src/particles.rs::ParticleEngine::fireworks gap: minor: the distance is taken when the rocket is launched, not on each tick
115 FireworkParticles.Starter.createParticleBall port crates/horizon-client/src/particles.rs::ParticleEngine::spark_ball crates/horizon-client-render/src/particles.rs::ParticleEngine::spark_ball
116 FireworkParticles.Starter.createParticleShape port crates/horizon-client/src/particles.rs::ParticleEngine::spark_shape crates/horizon-client-render/src/particles.rs::ParticleEngine::spark_shape
117 FireworkParticles.Starter.createParticleBurst inline crates/horizon-client/src/particles.rs::ParticleEngine::tick_starters crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_starters Burst shape arm of tick_starters
118 FlameParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by crates/horizon-client-render/src/particles.rs::Particle::move_by free_move: moves the box without collision
119 FlameParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Flame size curve
120 FlameParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords crates/horizon-client-render/src/particles.rs::Particle::light_coords AgeEmission light
121 FlameParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Flame arm (also copper and soul fire flame)
122 FlameParticle.SmallFlameProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SmallFlame arm, scaled 0.5
123 FlyStraightTowardsParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FlyStraight arm: position and colour lerp
124 FlyStraightTowardsParticle.OminousSpawnProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make OminousSpawning arm
125 FlyTowardsPositionParticle.<init> port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Enchant, Nautilus and VaultConnection arms
126 FlyTowardsPositionParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by crates/horizon-client-render/src/particles.rs::Particle::move_by free_move: moves the box without collision
127 FlyTowardsPositionParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords crates/horizon-client-render/src/particles.rs::Particle::light_coords AgeEmission4 for enchant and nautilus; Block15 for vault connection
128 FlyTowardsPositionParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle FlyTowards arm
129 FlyTowardsPositionParticle.extract port crates/horizon-client/src/particles.rs::ParticleEngine::render crates/horizon-client-render/src/particles.rs::ParticleEngine::render alpha from the lifetime curve at draw time
130 FlyTowardsPositionParticle.EnchantProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Enchant arm
131 FlyTowardsPositionParticle.NautilusProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Nautilus arm
132 FlyTowardsPositionParticle.VaultConnectionProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make VaultConnection arm: block light, lifetime alpha, scale 1.5
133 GeyserBaseParticle.Provider.createParticle missing player: sulfur geysers do not erupt here: no water column, base puff or eruption sound (only the potent sulfur block state exists), and the geyser particle types are not in ParticleType
134 GeyserEruptionParticle.tick missing player: the water column of a geyser eruption is not drawn; no geyser particle types exist here
135 GeyserEruptionParticle.Provider.createParticle missing player: no geyser eruption particle is made
136 GeyserPlumeParticle.<init> missing player: no water plume is made when a sulfur geyser erupts
137 GeyserPlumeParticle.tick missing player: the plume does not rise, spray or fall back
138 GeyserPlumeParticle.Provider.createParticle missing player: no water plume is made when a sulfur geyser erupts
139 GlowParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords crates/horizon-client-render/src/particles.rs::Particle::light_coords AgeEmission light (glow, wax, electric spark)
140 GlowParticle.ElectricSparkProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make ElectricSpark arm
141 GlowParticle.GlowSquidProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Glow arm
142 GlowParticle.WaxOffProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make WaxOff arm
143 GlowParticle.WaxOnProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make WaxOn arm
144 GustParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle HugeExplosion behaviour: age, then sprite from age
145 GustParticle.SmallProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SmallGust arm, scaled 0.15
146 GustSeedParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle GustSeed arm: a gust every tick or two, then removal
147 GustSeedParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make GustEmitterLarge and GustEmitterSmall arms: scale, lifetime, delay
148 HeartParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size GrowIn size curve
149 HeartParticle.AngryVillagerProvider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make AngryVillager arm, raised 0.5; the default colour is already white
150 HeartParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Heart arm
+100 -100
View File
@@ -1,131 +1,131 @@
HugeExplosionParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::HugeExplosion: age, sprite from age, removed at lifetime
HugeExplosionParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Explosion arm (SonicBoom shares it): quad size from xAux, full bright
HugeExplosionSeedParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::ExplosionSeed: six EXPLOSION particles per tick, removed at lifetime
HugeExplosionParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::HugeExplosion: age, sprite from age, removed at lifetime
HugeExplosionParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Explosion arm (SonicBoom shares it): quad size from xAux, full bright
HugeExplosionSeedParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::ExplosionSeed: six EXPLOSION particles per tick, removed at lifetime
ItemPickupParticle.tick port crates/horizon-client/src/game/pickups.rs::Game::tick_pickups life to LIFE_TIME (3) then removed; follows the collector
ItemPickupParticle.saveOldPosition inline crates/horizon-client/src/game/pickups.rs::Game::tick_pickups target_old = target, done inside tick_pickups
ItemPickupParticleGroup.extractRenderState port crates/horizon-client/src/game/pickups.rs::position gap: minor: returns the flight positions only; each kind is drawn by dropped_item_geometry (item), entity_geometry (orb) and mob_geometry (arrow)
ItemPickupParticleGroup.State.submit port crates/horizon-client/src/game/item_draw.rs::Game::dropped_item_geometry gap: minor: draws the item kind only; orb and arrow pickups are drawn in entity_geometry and mob_geometry
LargeSmokeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Smoke arm, LargeSmoke branch (scale 2.5)
LavaParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Size::Lava: size * (1 - t^2)
LavaParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Lava: smoke puffs while the random draw beats age/lifetime
LavaParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Lava arm: gravity 0.75, friction 0.999, lifetime 16 / (rand*0.8+0.2)
NoteParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make Note arm: colour from the pitch, friction 0.66, lifetime 6, size x1.5
NoteParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Size::GrowIn over 32 ticks
NoteParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Note arm
LargeSmokeParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke arm, LargeSmoke branch (scale 2.5)
LavaParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::Lava: size * (1 - t^2)
LavaParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Lava: smoke puffs while the random draw beats age/lifetime
LavaParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Lava arm: gravity 0.75, friction 0.999, lifetime 16 / (rand*0.8+0.2)
NoteParticle.<init> inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Note arm: colour from the pitch, friction 0.66, lifetime 6, size x1.5
NoteParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::GrowIn over 32 ticks
NoteParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Note arm
NoxiousGasCloudParticle.tick missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
NoxiousGasCloudParticle.pickRandomParticleSpawnPoint missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
NoxiousGasCloudParticle.spawnNoxiousGasParticle missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
NoxiousGasParticle.tick missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears; the fade-out is missing with it
NoxiousGasParticle.Provider.createParticle missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
Particle.<init> port crates/horizon-client/src/particles.rs::Particle::base_at 4-arg constructor (box and lifetime draw); the 7-arg one is Particle::base_moving
Particle.<init> port crates/horizon-client-render/src/particles.rs::Particle::base_at 4-arg constructor (box and lifetime draw); the 7-arg one is Particle::base_moving
Particle.toString skip:debug
Particle.setLocationFromBoundingbox port crates/horizon-client/src/particles.rs::Particle::set_location_from_bb
Particle.setLocationFromBoundingbox port crates/horizon-client-render/src/particles.rs::Particle::set_location_from_bb
Particle.LifetimeAlpha.isOpaque inline crates/horizon-client-core/src/particle_type.rs::ParticleType::translucent_layer the layer is a fixed per-type table; VaultConnection is the non-opaque case
ParticleDescription.fromJson port crates/horizon-client/src/particles.rs::ParticleEngine::load_sprites reads the textures list from particles/*.json
ParticleEngine.makeParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make gap: minor: VibrationSignal options return None here; ParticleEngine::vibration creates them
ParticleDescription.fromJson port crates/horizon-client-render/src/particles.rs::ParticleEngine::load_sprites reads the textures list from particles/*.json
ParticleEngine.makeParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: VibrationSignal options return None here; ParticleEngine::vibration creates them
ParticleEngine.createParticleGroup skip:other no render-type groups: ParticleEngine::render draws every particle in one pass, and the ITEM_PICKUP group is tick_pickups
ParticleEngine.countParticles skip:debug
ParticleEngine.hasSpaceInParticleLimit missing minor: no per-type particle cap; vanilla limits live SPORE_BLOSSOM air particles to 1000
ParticleEngine.clearParticles port crates/horizon-client/src/particles.rs::ParticleEngine::clear clears emitters, live and pending particles; no limit counts to clear
ParticleGroup.tickParticles port crates/horizon-client/src/particles.rs::ParticleEngine::tick ticks live particles and drops the removed ones
ParticleEngine.clearParticles port crates/horizon-client-render/src/particles.rs::ParticleEngine::clear clears emitters, live and pending particles; no limit counts to clear
ParticleGroup.tickParticles port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick ticks live particles and drops the removed ones
ParticleGroup.tickParticle skip:debug crash-report wrapper around particle.tick
ParticleResources.register skip:data provider table; Horizon matches particle types inside ParticleEngine::make
ParticleResources.reload port crates/horizon-client/src/particles.rs::ParticleEngine::reload gap: minor: vanilla clears live particles on a resource reload; this keeps them
ParticleResources.loadParticleDescription port crates/horizon-client/src/particles.rs::ParticleEngine::load_sprites
ParticleResources.reload port crates/horizon-client-render/src/particles.rs::ParticleEngine::reload gap: minor: vanilla clears live particles on a resource reload; this keeps them
ParticleResources.loadParticleDescription port crates/horizon-client-render/src/particles.rs::ParticleEngine::load_sprites
ParticleResources.MutableSpriteSet.get skip:other index form of SpriteSet.get: no vanilla caller; Horizon picks a random set sprite (sprite_from_set)
PlayerCloudParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make Cloud arm: friction 0.96, lifetime from the random draw x2.5, GrowIn
PlayerCloudParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Size::GrowIn
PlayerCloudParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Cloud: sinks to the local player's feet within 2 blocks
PlayerCloudParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Cloud arm
PlayerCloudParticle.SneezeProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Sneeze arm: tint 0.22/1.0/0.53, alpha 0.4
PortalParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by free_move path: moves the box without block collision
PortalParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Size::Portal
PortalParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords Light::AgeEmission4: block light plus age^4 emission
PortalParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Portal: eases from the start point along the velocity
PortalParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Portal arm
QuadParticleGroup.extractRenderState port crates/horizon-client/src/particles.rs::ParticleEngine::render gap: minor: no frustum point test; every live particle is drawn
ReversePortalParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Size::ReversePortal
ReversePortalParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::ReversePortal
ReversePortalParticle.ReversePortalProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make ReversePortal branch of the Portal arm
RisingParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make rising arm (Soul, SculkSoul, flames): velocity scaled by 0.01, position jitter 0.05
SculkChargeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make SculkCharge arm: roll from the option, lifetime nextInt(12)+8
SculkChargePopParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make SculkChargePop arm: lifetime nextInt(4)+6
ShriekParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Shriek: waits delay ticks, then base tick
ShriekParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Shriek arm: size 0.85, lifetime 30, delay from the option
SimpleAnimatedParticle.setFadeColor inline crates/horizon-client/src/particles.rs::ParticleEngine::make EndRod arm: fade colour 0xF2DEC9; applied by Behaviour::SimpleAnimated
SimpleVerticalParticle.PauseMobGrowthProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make PauseMobGrowth arm
SimpleVerticalParticle.ResetMobGrowthProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make ResetMobGrowth arm
SingleQuadParticle.extract port crates/horizon-client/src/particles.rs::ParticleEngine::render roll lerp and camera-facing rotation per particle
SingleQuadParticle.extractRotatedQuad port crates/horizon-client/src/particles.rs::ParticleEngine::render quad centre from the lerped position minus the camera
PlayerCloudParticle.<init> inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Cloud arm: friction 0.96, lifetime from the random draw x2.5, GrowIn
PlayerCloudParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::GrowIn
PlayerCloudParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Cloud: sinks to the local player's feet within 2 blocks
PlayerCloudParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Cloud arm
PlayerCloudParticle.SneezeProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Sneeze arm: tint 0.22/1.0/0.53, alpha 0.4
PortalParticle.move port crates/horizon-client-render/src/particles.rs::Particle::move_by free_move path: moves the box without block collision
PortalParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::Portal
PortalParticle.getLightCoords port crates/horizon-client-render/src/particles.rs::Particle::light_coords Light::AgeEmission4: block light plus age^4 emission
PortalParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Portal: eases from the start point along the velocity
PortalParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Portal arm
QuadParticleGroup.extractRenderState port crates/horizon-client-render/src/particles.rs::ParticleEngine::render gap: minor: no frustum point test; every live particle is drawn
ReversePortalParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::ReversePortal
ReversePortalParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::ReversePortal
ReversePortalParticle.ReversePortalProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make ReversePortal branch of the Portal arm
RisingParticle.<init> inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make rising arm (Soul, SculkSoul, flames): velocity scaled by 0.01, position jitter 0.05
SculkChargeParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make SculkCharge arm: roll from the option, lifetime nextInt(12)+8
SculkChargePopParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make SculkChargePop arm: lifetime nextInt(4)+6
ShriekParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Shriek: waits delay ticks, then base tick
ShriekParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Shriek arm: size 0.85, lifetime 30, delay from the option
SimpleAnimatedParticle.setFadeColor inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make EndRod arm: fade colour 0xF2DEC9; applied by Behaviour::SimpleAnimated
SimpleVerticalParticle.PauseMobGrowthProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make PauseMobGrowth arm
SimpleVerticalParticle.ResetMobGrowthProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make ResetMobGrowth arm
SingleQuadParticle.extract port crates/horizon-client-render/src/particles.rs::ParticleEngine::render roll lerp and camera-facing rotation per particle
SingleQuadParticle.extractRotatedQuad port crates/horizon-client-render/src/particles.rs::ParticleEngine::render quad centre from the lerped position minus the camera
SingleQuadParticle.toString skip:debug
SingleQuadParticle.Layer.bySprite port crates/horizon-client/src/particles.rs::ParticleEngine::reload gap: minor: one translucent flag per sprite from the atlas; vanilla also splits block and item atlases (TRANSLUCENT_TERRAIN, TRANSLUCENT_ITEMS)
SmokeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Smoke arm, Smoke branch (scale 1.0)
SnowflakeParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make Poof/Snowflake/Spit arm, Snowflake branch: gravity 0.225, friction 1.0
SnowflakeParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Snowflake: base tick, sprite from age, drag 0.95/0.9/0.95
SnowflakeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Snowflake branch: colour 0.923/0.964/0.999
SonicBoomParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Explosion|SonicBoom arm, SonicBoom branch: lifetime 16, size 1.5
SpellParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle gap: player: the spyglass check is missing: while scoping in first person, vanilla makes spell particles within 3 blocks of the eye fully transparent; Horizon only lerps alpha
SingleQuadParticle.Layer.bySprite port crates/horizon-client-render/src/particles.rs::ParticleEngine::reload gap: minor: one translucent flag per sprite from the atlas; vanilla also splits block and item atlases (TRANSLUCENT_TERRAIN, TRANSLUCENT_ITEMS)
SmokeParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke arm, Smoke branch (scale 1.0)
SnowflakeParticle.<init> inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof/Snowflake/Spit arm, Snowflake branch: gravity 0.225, friction 1.0
SnowflakeParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Snowflake: base tick, sprite from age, drag 0.95/0.9/0.95
SnowflakeParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Snowflake branch: colour 0.923/0.964/0.999
SonicBoomParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Explosion|SonicBoom arm, SonicBoom branch: lifetime 16, size 1.5
SpellParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle gap: player: the spyglass check is missing: while scoping in first person, vanilla makes spell particles within 3 blocks of the eye fully transparent; Horizon only lerps alpha
SpellParticle.isCloseToScopingPlayer missing player: spell particles near the eye stay visible while the player looks through a spyglass in first person; vanilla hides them
SpellParticle.InstantProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Effect|InstantEffect arm: colour and power from the option
SpellParticle.MobEffectProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make EntityEffect arm: colour and alpha from the option
SpellParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make uncoloured spell arm (Infested, TrialOmen, RaidOmen)
SpellParticle.WitchProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Witch arm: purple brightness from the engine random
SpitParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Poof/Snowflake/Spit arm, Spit branch: gravity 0.5, Animated
SplashParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Rain|Splash arm, Splash branch: gravity 0.04
SquidInkParticle.GlowInkProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make GlowSquidInk arm: colour (0.2, 0.8, 0.6)
SquidInkParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make SquidInk arm: black
SulfurBubbleParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::SulfurBubble: still-water check, bounds, growth
SulfurBubbleParticle.randomHorizontalWiggling inline crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle SulfurBubble arm, the wiggle closure applied to x and z
SulfurBubbleParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make SulfurBubbles arm
SuspendedParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make Underwater/CrimsonSpore/WarpedSpore/SporeBlossomAir arm: spawned 0.125 below the point
SuspendedParticle.CrimsonSporeProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make CrimsonSpore arm: gaussian drift, colour 0.9/0.4/0.5
SuspendedParticle.SporeBlossomAirProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make gap: minor: SporeBlossomAir arm; the SPORE_BLOSSOM particle limit (1000) is not applied
SuspendedParticle.UnderwaterProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Underwater arm: colour 0.4/0.4/0.7
SuspendedParticle.WarpedSporeProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make WarpedSpore arm: colour 0.1/0.1/0.3, size 0.001
SuspendedTownParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by free_move path: moves the box without block collision
SuspendedTownParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::SuspendedTown: lifetime countdown, drift, 0.99 damping
SuspendedTownParticle.ComposterFillProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Composter arm: white, lifetime 3 + nextInt(5)
SuspendedTownParticle.DolphinSpeedProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Dolphin arm: blue, alpha from the engine random, half lifetime
SuspendedTownParticle.EggCrackProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make EggCrack arm: white
SuspendedTownParticle.HappyVillagerProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make HappyVillager arm: white
SuspendedTownParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make plain arm (Mycelium): no colour change
TerrainParticle.<init> port crates/horizon-client/src/particles.rs::Particle::terrain crumb from a quarter of the block sprite, tinted, half size, mirrored UV
TerrainParticle.createTerrainParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make gap: minor: the air, moving-piston and noTerrainParticles checks are not in this arm; the callers' gating was not checked
TerrainParticle.CrumblingProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make BlockCrumble arm: zero speed, lifetime nextInt(10)+1
TerrainParticle.DustPillarProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make DustPillar arm: gaussian speed, lifetime nextInt(20)+20
TotemParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make TotemOfUndying arm
TrackingEmitter.tick port crates/horizon-client/src/particles.rs::ParticleEngine::emit 16 tries per tick; the countdown and removal are in ParticleEngine::tick
TrailParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::Trail: eases towards the target over its lifetime
TrailParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Trail arm: target, colour jitter, duration
TrialSpawnerDetectionParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make TrialSpawnerDetection arm: gravity -0.1, Block15 light, GrowIn
TrialSpawnerDetectionParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size Size::GrowIn
TrialSpawnerDetectionParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make TrialSpawnerDetection arm with scale 1.5
VibrationSignalParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::vibration flies to the listener in the arrival ticks
WakeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Fishing arm (WakeParticle)
WaterCurrentDownParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::CurrentDown: steers by angle, ends off water or on ground
WaterCurrentDownParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make CurrentDown arm
WaterDropParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle Behaviour::WaterDrop: gravity, drag, ends on ground or in fluid
WaterDropParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Rain arm
WhiteAshParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make WhiteAsh branch of the Smoke arm; the provider's motion is drawn from the engine random
WhiteSmokeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make Smoke arm, WhiteSmoke branch (scale 1.0)
SpellParticle.InstantProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Effect|InstantEffect arm: colour and power from the option
SpellParticle.MobEffectProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make EntityEffect arm: colour and alpha from the option
SpellParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make uncoloured spell arm (Infested, TrialOmen, RaidOmen)
SpellParticle.WitchProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Witch arm: purple brightness from the engine random
SpitParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof/Snowflake/Spit arm, Spit branch: gravity 0.5, Animated
SplashParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Rain|Splash arm, Splash branch: gravity 0.04
SquidInkParticle.GlowInkProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make GlowSquidInk arm: colour (0.2, 0.8, 0.6)
SquidInkParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make SquidInk arm: black
SulfurBubbleParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::SulfurBubble: still-water check, bounds, growth
SulfurBubbleParticle.randomHorizontalWiggling inline crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle SulfurBubble arm, the wiggle closure applied to x and z
SulfurBubbleParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make SulfurBubbles arm
SuspendedParticle.<init> inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Underwater/CrimsonSpore/WarpedSpore/SporeBlossomAir arm: spawned 0.125 below the point
SuspendedParticle.CrimsonSporeProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make CrimsonSpore arm: gaussian drift, colour 0.9/0.4/0.5
SuspendedParticle.SporeBlossomAirProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: SporeBlossomAir arm; the SPORE_BLOSSOM particle limit (1000) is not applied
SuspendedParticle.UnderwaterProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Underwater arm: colour 0.4/0.4/0.7
SuspendedParticle.WarpedSporeProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make WarpedSpore arm: colour 0.1/0.1/0.3, size 0.001
SuspendedTownParticle.move port crates/horizon-client-render/src/particles.rs::Particle::move_by free_move path: moves the box without block collision
SuspendedTownParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::SuspendedTown: lifetime countdown, drift, 0.99 damping
SuspendedTownParticle.ComposterFillProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Composter arm: white, lifetime 3 + nextInt(5)
SuspendedTownParticle.DolphinSpeedProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Dolphin arm: blue, alpha from the engine random, half lifetime
SuspendedTownParticle.EggCrackProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make EggCrack arm: white
SuspendedTownParticle.HappyVillagerProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make HappyVillager arm: white
SuspendedTownParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make plain arm (Mycelium): no colour change
TerrainParticle.<init> port crates/horizon-client-render/src/particles.rs::Particle::terrain crumb from a quarter of the block sprite, tinted, half size, mirrored UV
TerrainParticle.createTerrainParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: the air, moving-piston and noTerrainParticles checks are not in this arm; the callers' gating was not checked
TerrainParticle.CrumblingProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make BlockCrumble arm: zero speed, lifetime nextInt(10)+1
TerrainParticle.DustPillarProvider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustPillar arm: gaussian speed, lifetime nextInt(20)+20
TotemParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make TotemOfUndying arm
TrackingEmitter.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::emit 16 tries per tick; the countdown and removal are in ParticleEngine::tick
TrailParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Trail: eases towards the target over its lifetime
TrailParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Trail arm: target, colour jitter, duration
TrialSpawnerDetectionParticle.<init> inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make TrialSpawnerDetection arm: gravity -0.1, Block15 light, GrowIn
TrialSpawnerDetectionParticle.getQuadSize port crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::GrowIn
TrialSpawnerDetectionParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make TrialSpawnerDetection arm with scale 1.5
VibrationSignalParticle.Provider.createParticle port crates/horizon-client-render/src/particles.rs::ParticleEngine::vibration flies to the listener in the arrival ticks
WakeParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Fishing arm (WakeParticle)
WaterCurrentDownParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::CurrentDown: steers by angle, ends off water or on ground
WaterCurrentDownParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make CurrentDown arm
WaterDropParticle.tick port crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::WaterDrop: gravity, drag, ends on ground or in fluid
WaterDropParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Rain arm
WhiteAshParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make WhiteAsh branch of the Smoke arm; the provider's motion is drawn from the engine random
WhiteSmokeParticle.Provider.createParticle inline crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke arm, WhiteSmoke branch (scale 1.0)
ClientPackSource.findExplodedAssetPacks skip:other IDE-only: looks for a resourcepacks folder next to the asset dir in development runs
ClientPackSource.createVanillaPackSource skip:data pack source assembly; Horizon reads its assets from folders directly
ClientPackSource.getPackTitle skip:data pack display names
ClientPackSource.populatePackList skip:data pack discovery
DefaultPlayerSkin.create port crates/horizon-client/src/tab_list.rs::default_skin gap: minor: returns the texture path (the model is in the path); no PlayerSkin record
DryFoliageColorReloadListener.prepare port crates/horizon-client/src/biome.rs::colormap PNG decode of colormap/dry_foliage; the caller loads the three colormaps
FoliageColorReloadListener.prepare port crates/horizon-client/src/biome.rs::colormap PNG decode of colormap/foliage
GrassColorReloadListener.prepare port crates/horizon-client/src/biome.rs::colormap PNG decode of colormap/grass
DefaultPlayerSkin.create port crates/horizon-client-render/src/tab_list.rs::default_skin gap: minor: returns the texture path (the model is in the path); no PlayerSkin record
DryFoliageColorReloadListener.prepare port crates/horizon-client-render/src/biome.rs::colormap PNG decode of colormap/dry_foliage; the caller loads the three colormaps
FoliageColorReloadListener.prepare port crates/horizon-client-render/src/biome.rs::colormap PNG decode of colormap/foliage
GrassColorReloadListener.prepare port crates/horizon-client-render/src/biome.rs::colormap PNG decode of colormap/grass
IndexedAssetSource.createIndexFs skip:data legacy objects/ asset index; Horizon reads assets/ folders directly
LegacyStuffWrapper.getPixels port crates/horizon-client/src/hud.rs::decode gap: minor: PNG decode to bytes; vanilla returns ARGB ints
LegacyStuffWrapper.getPixels port crates/horizon-client-render/src/hud.rs::decode gap: minor: PNG decode to bytes; vanilla returns ARGB ints
MapTextureManager.resetData skip:other frees GPU map textures on close; Horizon keeps its map atlas slots in Game::maps, no gameplay effect
MapTextureManager.getOrCreateMapInstance port crates/horizon-client/src/game/maps.rs::Game::map_texture gives the map its atlas slot, allocated on first use
MapTextureManager.MapInstance.replaceMapData port crates/horizon-client/src/game/maps.rs::MapData::update_color gap: minor: vanilla also flags an upload when the saved-data object is swapped; Horizon flags per changed colour
MapTextureManager.MapInstance.updateTextureIfNeeded port crates/horizon-client/src/game/maps.rs::Game::map_texture uploads the 128x128 colours when dirty
SkinManager.get port crates/horizon-client/src/skins.rs::lookup gap: minor: the packed textures come from ResolvedProfile::textures; the debug default-skin override is not ported
SkinManager.registerTextures port crates/horizon-client/src/skins.rs::lookup gap: minor: returns the skin location only; cape and elytra are downloaded here but not returned
SkinManager.TextureCache.getOrLoad port crates/horizon-client/src/skins.rs::Downloader::state one download per URL, then its state
SkinManager.TextureCache.getTextureLocation port crates/horizon-client/src/skins.rs::skin_location gap: minor: only the skins/ location; capes and elytra have no location fn
SkinManager.get port crates/horizon-client-render/src/skins.rs::lookup gap: minor: the packed textures come from ResolvedProfile::textures; the debug default-skin override is not ported
SkinManager.registerTextures port crates/horizon-client-render/src/skins.rs::lookup gap: minor: returns the skin location only; cape and elytra are downloaded here but not returned
SkinManager.TextureCache.getOrLoad port crates/horizon-client-render/src/skins.rs::Downloader::state one download per URL, then its state
SkinManager.TextureCache.getTextureLocation port crates/horizon-client-render/src/skins.rs::skin_location gap: minor: only the skins/ location; capes and elytra have no location fn
SplashManager.getSplash port crates/horizon-client/src/title.rs::choose_splash gap: player: no '<NAME> IS YOU' splash; vanilla sometimes shows the logged-in player's name instead of a splash on the title screen
WaypointStyle.validate port crates/horizon-client/src/locator_bar.rs::WaypointStyle::parse validation is folded into the parse
WaypointStyleManager.apply port crates/horizon-client/src/locator_bar.rs::WaypointStyles::load gap: minor: loads the arrow and dot sprites from the assets folder into one map
1 HugeExplosionParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::HugeExplosion: age, sprite from age, removed at lifetime
2 HugeExplosionParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Explosion arm (SonicBoom shares it): quad size from xAux, full bright
3 HugeExplosionSeedParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::ExplosionSeed: six EXPLOSION particles per tick, removed at lifetime
4 ItemPickupParticle.tick port crates/horizon-client/src/game/pickups.rs::Game::tick_pickups crates/horizon-client/src/game/pickups.rs::Game::tick_pickups life to LIFE_TIME (3) then removed; follows the collector
5 ItemPickupParticle.saveOldPosition inline crates/horizon-client/src/game/pickups.rs::Game::tick_pickups crates/horizon-client/src/game/pickups.rs::Game::tick_pickups target_old = target, done inside tick_pickups
6 ItemPickupParticleGroup.extractRenderState port crates/horizon-client/src/game/pickups.rs::position crates/horizon-client/src/game/pickups.rs::position gap: minor: returns the flight positions only; each kind is drawn by dropped_item_geometry (item), entity_geometry (orb) and mob_geometry (arrow)
7 ItemPickupParticleGroup.State.submit port crates/horizon-client/src/game/item_draw.rs::Game::dropped_item_geometry crates/horizon-client/src/game/item_draw.rs::Game::dropped_item_geometry gap: minor: draws the item kind only; orb and arrow pickups are drawn in entity_geometry and mob_geometry
8 LargeSmokeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke arm, LargeSmoke branch (scale 2.5)
9 LavaParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::Lava: size * (1 - t^2)
10 LavaParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Lava: smoke puffs while the random draw beats age/lifetime
11 LavaParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Lava arm: gravity 0.75, friction 0.999, lifetime 16 / (rand*0.8+0.2)
12 NoteParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Note arm: colour from the pitch, friction 0.66, lifetime 6, size x1.5
13 NoteParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::GrowIn over 32 ticks
14 NoteParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Note arm
15 NoxiousGasCloudParticle.tick missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
16 NoxiousGasCloudParticle.pickRandomParticleSpawnPoint missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
17 NoxiousGasCloudParticle.spawnNoxiousGasParticle missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
18 NoxiousGasParticle.tick missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears; the fade-out is missing with it
19 NoxiousGasParticle.Provider.createParticle missing player: potent sulfur in vanilla 26.3 gives off drifting noxious gas clouds; Horizon has no noxious_gas particle type and no PotentSulfurBlockEntity client code, so no cloud appears
20 Particle.<init> port crates/horizon-client/src/particles.rs::Particle::base_at crates/horizon-client-render/src/particles.rs::Particle::base_at 4-arg constructor (box and lifetime draw); the 7-arg one is Particle::base_moving
21 Particle.toString skip:debug
22 Particle.setLocationFromBoundingbox port crates/horizon-client/src/particles.rs::Particle::set_location_from_bb crates/horizon-client-render/src/particles.rs::Particle::set_location_from_bb
23 Particle.LifetimeAlpha.isOpaque inline crates/horizon-client-core/src/particle_type.rs::ParticleType::translucent_layer crates/horizon-client-core/src/particle_type.rs::ParticleType::translucent_layer the layer is a fixed per-type table; VaultConnection is the non-opaque case
24 ParticleDescription.fromJson port crates/horizon-client/src/particles.rs::ParticleEngine::load_sprites crates/horizon-client-render/src/particles.rs::ParticleEngine::load_sprites reads the textures list from particles/*.json
25 ParticleEngine.makeParticle port crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: VibrationSignal options return None here; ParticleEngine::vibration creates them
26 ParticleEngine.createParticleGroup skip:other no render-type groups: ParticleEngine::render draws every particle in one pass, and the ITEM_PICKUP group is tick_pickups
27 ParticleEngine.countParticles skip:debug
28 ParticleEngine.hasSpaceInParticleLimit missing minor: no per-type particle cap; vanilla limits live SPORE_BLOSSOM air particles to 1000
29 ParticleEngine.clearParticles port crates/horizon-client/src/particles.rs::ParticleEngine::clear crates/horizon-client-render/src/particles.rs::ParticleEngine::clear clears emitters, live and pending particles; no limit counts to clear
30 ParticleGroup.tickParticles port crates/horizon-client/src/particles.rs::ParticleEngine::tick crates/horizon-client-render/src/particles.rs::ParticleEngine::tick ticks live particles and drops the removed ones
31 ParticleGroup.tickParticle skip:debug crash-report wrapper around particle.tick
32 ParticleResources.register skip:data provider table; Horizon matches particle types inside ParticleEngine::make
33 ParticleResources.reload port crates/horizon-client/src/particles.rs::ParticleEngine::reload crates/horizon-client-render/src/particles.rs::ParticleEngine::reload gap: minor: vanilla clears live particles on a resource reload; this keeps them
34 ParticleResources.loadParticleDescription port crates/horizon-client/src/particles.rs::ParticleEngine::load_sprites crates/horizon-client-render/src/particles.rs::ParticleEngine::load_sprites
35 ParticleResources.MutableSpriteSet.get skip:other index form of SpriteSet.get: no vanilla caller; Horizon picks a random set sprite (sprite_from_set)
36 PlayerCloudParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Cloud arm: friction 0.96, lifetime from the random draw x2.5, GrowIn
37 PlayerCloudParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::GrowIn
38 PlayerCloudParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Cloud: sinks to the local player's feet within 2 blocks
39 PlayerCloudParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Cloud arm
40 PlayerCloudParticle.SneezeProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Sneeze arm: tint 0.22/1.0/0.53, alpha 0.4
41 PortalParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by crates/horizon-client-render/src/particles.rs::Particle::move_by free_move path: moves the box without block collision
42 PortalParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::Portal
43 PortalParticle.getLightCoords port crates/horizon-client/src/particles.rs::Particle::light_coords crates/horizon-client-render/src/particles.rs::Particle::light_coords Light::AgeEmission4: block light plus age^4 emission
44 PortalParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Portal: eases from the start point along the velocity
45 PortalParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Portal arm
46 QuadParticleGroup.extractRenderState port crates/horizon-client/src/particles.rs::ParticleEngine::render crates/horizon-client-render/src/particles.rs::ParticleEngine::render gap: minor: no frustum point test; every live particle is drawn
47 ReversePortalParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::ReversePortal
48 ReversePortalParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::ReversePortal
49 ReversePortalParticle.ReversePortalProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make ReversePortal branch of the Portal arm
50 RisingParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make rising arm (Soul, SculkSoul, flames): velocity scaled by 0.01, position jitter 0.05
51 SculkChargeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SculkCharge arm: roll from the option, lifetime nextInt(12)+8
52 SculkChargePopParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SculkChargePop arm: lifetime nextInt(4)+6
53 ShriekParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Shriek: waits delay ticks, then base tick
54 ShriekParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Shriek arm: size 0.85, lifetime 30, delay from the option
55 SimpleAnimatedParticle.setFadeColor inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make EndRod arm: fade colour 0xF2DEC9; applied by Behaviour::SimpleAnimated
56 SimpleVerticalParticle.PauseMobGrowthProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make PauseMobGrowth arm
57 SimpleVerticalParticle.ResetMobGrowthProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make ResetMobGrowth arm
58 SingleQuadParticle.extract port crates/horizon-client/src/particles.rs::ParticleEngine::render crates/horizon-client-render/src/particles.rs::ParticleEngine::render roll lerp and camera-facing rotation per particle
59 SingleQuadParticle.extractRotatedQuad port crates/horizon-client/src/particles.rs::ParticleEngine::render crates/horizon-client-render/src/particles.rs::ParticleEngine::render quad centre from the lerped position minus the camera
60 SingleQuadParticle.toString skip:debug
61 SingleQuadParticle.Layer.bySprite port crates/horizon-client/src/particles.rs::ParticleEngine::reload crates/horizon-client-render/src/particles.rs::ParticleEngine::reload gap: minor: one translucent flag per sprite from the atlas; vanilla also splits block and item atlases (TRANSLUCENT_TERRAIN, TRANSLUCENT_ITEMS)
62 SmokeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke arm, Smoke branch (scale 1.0)
63 SnowflakeParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof/Snowflake/Spit arm, Snowflake branch: gravity 0.225, friction 1.0
64 SnowflakeParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Snowflake: base tick, sprite from age, drag 0.95/0.9/0.95
65 SnowflakeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Snowflake branch: colour 0.923/0.964/0.999
66 SonicBoomParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Explosion|SonicBoom arm, SonicBoom branch: lifetime 16, size 1.5
67 SpellParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle gap: player: the spyglass check is missing: while scoping in first person, vanilla makes spell particles within 3 blocks of the eye fully transparent; Horizon only lerps alpha
68 SpellParticle.isCloseToScopingPlayer missing player: spell particles near the eye stay visible while the player looks through a spyglass in first person; vanilla hides them
69 SpellParticle.InstantProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Effect|InstantEffect arm: colour and power from the option
70 SpellParticle.MobEffectProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make EntityEffect arm: colour and alpha from the option
71 SpellParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make uncoloured spell arm (Infested, TrialOmen, RaidOmen)
72 SpellParticle.WitchProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Witch arm: purple brightness from the engine random
73 SpitParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Poof/Snowflake/Spit arm, Spit branch: gravity 0.5, Animated
74 SplashParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Rain|Splash arm, Splash branch: gravity 0.04
75 SquidInkParticle.GlowInkProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make GlowSquidInk arm: colour (0.2, 0.8, 0.6)
76 SquidInkParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SquidInk arm: black
77 SulfurBubbleParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::SulfurBubble: still-water check, bounds, growth
78 SulfurBubbleParticle.randomHorizontalWiggling inline crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle SulfurBubble arm, the wiggle closure applied to x and z
79 SulfurBubbleParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make SulfurBubbles arm
80 SuspendedParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Underwater/CrimsonSpore/WarpedSpore/SporeBlossomAir arm: spawned 0.125 below the point
81 SuspendedParticle.CrimsonSporeProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make CrimsonSpore arm: gaussian drift, colour 0.9/0.4/0.5
82 SuspendedParticle.SporeBlossomAirProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: SporeBlossomAir arm; the SPORE_BLOSSOM particle limit (1000) is not applied
83 SuspendedParticle.UnderwaterProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Underwater arm: colour 0.4/0.4/0.7
84 SuspendedParticle.WarpedSporeProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make WarpedSpore arm: colour 0.1/0.1/0.3, size 0.001
85 SuspendedTownParticle.move port crates/horizon-client/src/particles.rs::Particle::move_by crates/horizon-client-render/src/particles.rs::Particle::move_by free_move path: moves the box without block collision
86 SuspendedTownParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::SuspendedTown: lifetime countdown, drift, 0.99 damping
87 SuspendedTownParticle.ComposterFillProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Composter arm: white, lifetime 3 + nextInt(5)
88 SuspendedTownParticle.DolphinSpeedProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Dolphin arm: blue, alpha from the engine random, half lifetime
89 SuspendedTownParticle.EggCrackProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make EggCrack arm: white
90 SuspendedTownParticle.HappyVillagerProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make HappyVillager arm: white
91 SuspendedTownParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make plain arm (Mycelium): no colour change
92 TerrainParticle.<init> port crates/horizon-client/src/particles.rs::Particle::terrain crates/horizon-client-render/src/particles.rs::Particle::terrain crumb from a quarter of the block sprite, tinted, half size, mirrored UV
93 TerrainParticle.createTerrainParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make gap: minor: the air, moving-piston and noTerrainParticles checks are not in this arm; the callers' gating was not checked
94 TerrainParticle.CrumblingProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make BlockCrumble arm: zero speed, lifetime nextInt(10)+1
95 TerrainParticle.DustPillarProvider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make DustPillar arm: gaussian speed, lifetime nextInt(20)+20
96 TotemParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make TotemOfUndying arm
97 TrackingEmitter.tick port crates/horizon-client/src/particles.rs::ParticleEngine::emit crates/horizon-client-render/src/particles.rs::ParticleEngine::emit 16 tries per tick; the countdown and removal are in ParticleEngine::tick
98 TrailParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::Trail: eases towards the target over its lifetime
99 TrailParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Trail arm: target, colour jitter, duration
100 TrialSpawnerDetectionParticle.<init> inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make TrialSpawnerDetection arm: gravity -0.1, Block15 light, GrowIn
101 TrialSpawnerDetectionParticle.getQuadSize port crates/horizon-client/src/particles.rs::Particle::quad_size crates/horizon-client-render/src/particles.rs::Particle::quad_size Size::GrowIn
102 TrialSpawnerDetectionParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make TrialSpawnerDetection arm with scale 1.5
103 VibrationSignalParticle.Provider.createParticle port crates/horizon-client/src/particles.rs::ParticleEngine::vibration crates/horizon-client-render/src/particles.rs::ParticleEngine::vibration flies to the listener in the arrival ticks
104 WakeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Fishing arm (WakeParticle)
105 WaterCurrentDownParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::CurrentDown: steers by angle, ends off water or on ground
106 WaterCurrentDownParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make CurrentDown arm
107 WaterDropParticle.tick port crates/horizon-client/src/particles.rs::ParticleEngine::tick_particle crates/horizon-client-render/src/particles.rs::ParticleEngine::tick_particle Behaviour::WaterDrop: gravity, drag, ends on ground or in fluid
108 WaterDropParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Rain arm
109 WhiteAshParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make WhiteAsh branch of the Smoke arm; the provider's motion is drawn from the engine random
110 WhiteSmokeParticle.Provider.createParticle inline crates/horizon-client/src/particles.rs::ParticleEngine::make crates/horizon-client-render/src/particles.rs::ParticleEngine::make Smoke arm, WhiteSmoke branch (scale 1.0)
111 ClientPackSource.findExplodedAssetPacks skip:other IDE-only: looks for a resourcepacks folder next to the asset dir in development runs
112 ClientPackSource.createVanillaPackSource skip:data pack source assembly; Horizon reads its assets from folders directly
113 ClientPackSource.getPackTitle skip:data pack display names
114 ClientPackSource.populatePackList skip:data pack discovery
115 DefaultPlayerSkin.create port crates/horizon-client/src/tab_list.rs::default_skin crates/horizon-client-render/src/tab_list.rs::default_skin gap: minor: returns the texture path (the model is in the path); no PlayerSkin record
116 DryFoliageColorReloadListener.prepare port crates/horizon-client/src/biome.rs::colormap crates/horizon-client-render/src/biome.rs::colormap PNG decode of colormap/dry_foliage; the caller loads the three colormaps
117 FoliageColorReloadListener.prepare port crates/horizon-client/src/biome.rs::colormap crates/horizon-client-render/src/biome.rs::colormap PNG decode of colormap/foliage
118 GrassColorReloadListener.prepare port crates/horizon-client/src/biome.rs::colormap crates/horizon-client-render/src/biome.rs::colormap PNG decode of colormap/grass
119 IndexedAssetSource.createIndexFs skip:data legacy objects/ asset index; Horizon reads assets/ folders directly
120 LegacyStuffWrapper.getPixels port crates/horizon-client/src/hud.rs::decode crates/horizon-client-render/src/hud.rs::decode gap: minor: PNG decode to bytes; vanilla returns ARGB ints
121 MapTextureManager.resetData skip:other frees GPU map textures on close; Horizon keeps its map atlas slots in Game::maps, no gameplay effect
122 MapTextureManager.getOrCreateMapInstance port crates/horizon-client/src/game/maps.rs::Game::map_texture crates/horizon-client/src/game/maps.rs::Game::map_texture gives the map its atlas slot, allocated on first use
123 MapTextureManager.MapInstance.replaceMapData port crates/horizon-client/src/game/maps.rs::MapData::update_color crates/horizon-client/src/game/maps.rs::MapData::update_color gap: minor: vanilla also flags an upload when the saved-data object is swapped; Horizon flags per changed colour
124 MapTextureManager.MapInstance.updateTextureIfNeeded port crates/horizon-client/src/game/maps.rs::Game::map_texture crates/horizon-client/src/game/maps.rs::Game::map_texture uploads the 128x128 colours when dirty
125 SkinManager.get port crates/horizon-client/src/skins.rs::lookup crates/horizon-client-render/src/skins.rs::lookup gap: minor: the packed textures come from ResolvedProfile::textures; the debug default-skin override is not ported
126 SkinManager.registerTextures port crates/horizon-client/src/skins.rs::lookup crates/horizon-client-render/src/skins.rs::lookup gap: minor: returns the skin location only; cape and elytra are downloaded here but not returned
127 SkinManager.TextureCache.getOrLoad port crates/horizon-client/src/skins.rs::Downloader::state crates/horizon-client-render/src/skins.rs::Downloader::state one download per URL, then its state
128 SkinManager.TextureCache.getTextureLocation port crates/horizon-client/src/skins.rs::skin_location crates/horizon-client-render/src/skins.rs::skin_location gap: minor: only the skins/ location; capes and elytra have no location fn
129 SplashManager.getSplash port crates/horizon-client/src/title.rs::choose_splash crates/horizon-client/src/title.rs::choose_splash gap: player: no '<NAME> IS YOU' splash; vanilla sometimes shows the logged-in player's name instead of a splash on the title screen
130 WaypointStyle.validate port crates/horizon-client/src/locator_bar.rs::WaypointStyle::parse crates/horizon-client/src/locator_bar.rs::WaypointStyle::parse validation is folded into the parse
131 WaypointStyleManager.apply port crates/horizon-client/src/locator_bar.rs::WaypointStyles::load crates/horizon-client/src/locator_bar.rs::WaypointStyles::load gap: minor: loads the arrow and dot sprites from the assets folder into one map
+29 -29
View File
@@ -3,35 +3,35 @@ EquipmentClientInfo.Layer.onlyIfDyed skip:data equipment asset factory; Horizon
EquipmentClientInfo.Layer.getTextureLocation port crates/horizon-client/src/game/armor_stands.rs::ArmorStandAssets::load builds entity/equipment/<kind>/<texture>; gap: minor: only humanoid, humanoid_leggings and wings are read here
EquipmentClientInfo.TrimOverride.validate skip:java codec validator; TrimOverride::list keeps an override with neither texture nor palette (minor)
EquipmentClientInfo.TrimPredicate.validate skip:java codec validator; TrimOverride::list keeps a predicate with neither material nor pattern (minor)
EquipmentClientInfo.TrimPredicate.matches port crates/horizon-client/src/trims.rs::TrimOverride::matches material and pattern id comparison
ModelBakery.bakeModels port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models bakes block states; gap: minor: items and standalone models bake in separate fns (item_bake.rs::bake_item_model)
EquipmentClientInfo.TrimPredicate.matches port crates/horizon-client-render/src/trims.rs::TrimOverride::matches material and pattern id comparison
ModelBakery.bakeModels port crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models bakes block states; gap: minor: items and standalone models bake in separate fns (item_bake.rs::bake_item_model)
ModelBakery.ModelBakerImpl.getModel port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve an unknown id falls back to the missing model
ModelDiscovery.createAndQueueWrapper inline crates/horizon-client/src/model_library.rs::ParsedModels::block_models parent queue; no wrapper object is kept
ModelDiscovery.createAndQueueWrapper inline crates/horizon-client-render/src/model_library.rs::ParsedModels::block_models parent queue; no wrapper object is kept
ModelDiscovery.addSpecialModel inline crates/horizon-assets/src/resolve.rs::ModelLibrary::with_shared_item_generator gap: minor: only builtin/generated is registered; a non-root special model is not rejected
ModelDiscovery.resolve port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve resolved per model id, not as a batch map
ModelDiscovery.discoverDependencies inline crates/horizon-client/src/model_library.rs::ParsedModels::block_models pushes each model's parent until the set is complete
ModelDiscovery.discoverDependencies inline crates/horizon-client-render/src/model_library.rs::ParsedModels::block_models pushes each model's parent until the set is complete
ModelDiscovery.propagateValidity port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve a chain that reaches a cycle is an error when resolved
ModelDiscovery.ModelWrapper.updateSlot skip:java per-model result cache
ModelDiscovery.ModelWrapper.getSimpleProperty skip:java per-model result cache
ModelDiscovery.ModelWrapper.resolveParticleMaterial port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models block particle sprite; the item side is item_bake.rs::bake_item_model
ModelDiscovery.ModelWrapper.resolveParticleMaterial port crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models block particle sprite; the item side is item_bake.rs::bake_item_model
ModelDiscovery.ModelWrapper.bakeDefaultState skip:java cache of the identity-rotation geometry
ModelDiscovery.ModelWrapper.bakeTopGeometry port crates/horizon-assets/src/bake.rs::bake_block_model bakes with the blockstate rotation; per-state cache skipped
ModelGroupCollector.build skip:java groups states for shared baked geometry; Horizon has no model-group ids
ModelGroupCollector.GroupKey.create skip:java group key of build
ModelGroupCollector.GroupKey.getColoringValues skip:java group key of build
ModelManager.reload port crates/horizon-client/src/assets.rs::RenderAssets::load one synchronous load: models, block states, item infos, then bake and store
ModelManager.loadBlockModels port crates/horizon-client/src/model_library.rs::ParsedModels::load every models/**.json by id, parsed in parallel
ModelManager.discoverModelDependencies port crates/horizon-client/src/model_library.rs::ParsedModels::block_models referenced models and their parents
ModelManager.loadModels port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models bakes block states and their models
ModelManager.createBlockStateToModelDispatch inline crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models missing model for a state without a baked model
ModelManager.reload port crates/horizon-client-render/src/assets.rs::RenderAssets::load one synchronous load: models, block states, item infos, then bake and store
ModelManager.loadBlockModels port crates/horizon-client-render/src/model_library.rs::ParsedModels::load every models/**.json by id, parsed in parallel
ModelManager.discoverModelDependencies port crates/horizon-client-render/src/model_library.rs::ParsedModels::block_models referenced models and their parents
ModelManager.loadModels port crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models bakes block states and their models
ModelManager.createBlockStateToModelDispatch inline crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models missing model for a state without a baked model
ModelManager.buildModelGroups skip:java wrapper of ModelGroupCollector.build; render sharing only
ModelManager.apply inline crates/horizon-client/src/assets.rs::RenderAssets::load the baked result is stored in the returned struct
ModelManager.apply inline crates/horizon-client-render/src/assets.rs::RenderAssets::load the baked result is stored in the returned struct
ModelManager.requiresRender skip:java render-skip optimisation for equal model groups; no visible effect
ResolvedModel.findTopTextureSlots port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve texture slots merged along the parent chain
ResolvedModel.findTopAmbientOcclusion port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve ambient occlusion from the first model that sets it, default true
ResolvedModel.findTopGuiLight port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve gui_light from the first model that sets it, default side
ResolvedModel.findTopGeometry port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve first element list up the parent chain
ResolvedModel.resolveParticleMaterial port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models block particle slot; the item side is item_bake.rs::bake_item_model
ResolvedModel.resolveParticleMaterial port crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models block particle slot; the item side is item_bake.rs::bake_item_model
ResolvedModel.findTopTransform port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve display transform per context, inherited up the chain
ResolvedModel.findTopTransforms port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve display transforms for every context
SimpleModelWrapper.bake port crates/horizon-assets/src/bake.rs::bake_block_model gap: minor: no rejection of block models that use non-block sprites
@@ -60,7 +60,7 @@ CuboidRotation.scaleFactorForAxis inline crates/horizon-assets/src/bake.rs::Elem
CuboidRotation.EulerXYZRotation.transformation port crates/horizon-assets/src/bake.rs::ElementMatrix::from_rotation Euler XYZ branch
CuboidRotation.SingleAxisRotation.transformation port crates/horizon-assets/src/bake.rs::ElementMatrix::from_rotation single-axis branch
FaceBakery.defaultFaceUV port crates/horizon-assets/src/bake.rs::default_uv default face UVs by direction
FaceBakery.computeMaterialTransparency port crates/horizon-client/src/sprites.rs::Sprites::region_opaque gap: minor: only the opaque-region check; force_translucent is not applied here
FaceBakery.computeMaterialTransparency port crates/horizon-client-render/src/sprites.rs::Sprites::region_opaque gap: minor: only the opaque-region check; force_translucent is not applied here
FaceBakery.bakeVertex inline crates/horizon-assets/src/bake.rs::bake_face vertex position and UV inside bake_face
FaceBakery.rotateVertexBy inline crates/horizon-assets/src/bake.rs::bake_face element rotation about its origin
FaceBakery.calculateFacing port crates/horizon-assets/src/bake.rs::facing quad normal, then closest direction
@@ -84,18 +84,18 @@ BakedQuad.MaterialInfo.of port crates/horizon-client/src/item_render.rs::FileSpr
BakedQuad.MaterialInfo.flags skip:java translucent and animated bit flags used to skip work; Horizon ticks animated textures by its setting
ItemQuads.split port crates/horizon-client/src/item_render.rs::submit_quads quads with translucent sprites go to the translucent pass
QuadCollection.computeMaterialFlags skip:java flag bits of the quad list; see BakedQuad.MaterialInfo.flags
QuadCollection.getQuads port crates/horizon-client/src/mesher.rs::Mesher::mesh quads filtered by cull direction
QuadCollection.getQuads port crates/horizon-client-render/src/mesher.rs::Mesher::mesh quads filtered by cull direction
QuadCollection.materialFlags skip:java cached flag bits
QuadCollection.Builder.addAll skip:java collection builder
QuadCollection.Builder.createFromSublists skip:java sublist layout of a quad collection
AtlasManager.getAtlasOrThrow skip:java atlas map lookup; Horizon keeps one sprite table
AtlasManager.forEach skip:java map iteration
AtlasManager.close skip:java GPU release; freed with its owner
AtlasManager.get port crates/horizon-client/src/sprites.rs::Sprites::insert sprite layer added on first use; missing texture when it fails to load
AtlasManager.get port crates/horizon-client-render/src/sprites.rs::Sprites::insert sprite layer added on first use; missing texture when it fails to load
AtlasManager.prepareSharedState skip:java future-based stitch plumbing
AtlasManager.reload skip:java async reload; sprites load synchronously in RenderAssets::load
AtlasManager.updateSpriteMaps port crates/horizon-client/src/sprites.rs::Sprites::finish lays out every layer at one size; gap: minor: no duplicate-sprite warning
AtlasManager.AtlasEntry.scheduleLoad port crates/horizon-client/src/sprites.rs::Sprites::insert gap: minor: sprites load on demand, not per atlas source
AtlasManager.updateSpriteMaps port crates/horizon-client-render/src/sprites.rs::Sprites::finish lays out every layer at one size; gap: minor: no duplicate-sprite warning
AtlasManager.AtlasEntry.scheduleLoad port crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: sprites load on demand, not per atlas source
AtlasManager.PendingStitch.joinAndUpload skip:java future join
AtlasManager.PendingStitchResults.joinAndUpload skip:java future join
MaterialBaker.get port crates/horizon-assets/src/item_bake.rs::bake_item_model sprite that is not known falls back to missingno
@@ -110,12 +110,12 @@ TextureSlots.Data.Builder.addReference skip:java builder
TextureSlots.Data.Builder.addTexture skip:java builder
TextureSlots.Data.Builder.build skip:java builder
TextureSlots.Resolver.resolve port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve alias chain resolution; the batch hint (horizon-protocol resolver.rs) is a DNS resolver and is not this
resources/palette/Palette.listAndLoad port crates/horizon-client/src/trims.rs::TrimTexture::generate gap: minor: palettes load on demand, none listed up front
resources/palette/Palette.tryLoad port crates/horizon-client/src/trims.rs::TrimTexture::generate gap: minor: a broken palette skips the recolour instead of an empty palette
resources/palette/Palette.load port crates/horizon-client/src/trims.rs::TrimTexture::generate palette PNG read as ARGB
resources/palette/Palette.listAndLoad port crates/horizon-client-render/src/trims.rs::TrimTexture::generate gap: minor: palettes load on demand, none listed up front
resources/palette/Palette.tryLoad port crates/horizon-client-render/src/trims.rs::TrimTexture::generate gap: minor: a broken palette skips the recolour instead of an empty palette
resources/palette/Palette.load port crates/horizon-client-render/src/trims.rs::TrimTexture::generate palette PNG read as ARGB
PaletteMapping.apply port crates/horizon-assets/src/palette.rs::apply_palette colour swap; alpha scaled by the target's alpha
PalettedTextureManager.loadBaseTexture port crates/horizon-client/src/trims.rs::TrimTexture::generate base texture and its base_palette from the mcmeta
PalettedTextureManager.allocateSlot port crates/horizon-client/src/sprites.rs::Sprites::insert gap: minor: one array layer per texture, no dynamic atlas tree
PalettedTextureManager.loadBaseTexture port crates/horizon-client-render/src/trims.rs::TrimTexture::generate base texture and its base_palette from the mcmeta
PalettedTextureManager.allocateSlot port crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: one array layer per texture, no dynamic atlas tree
PalettedTextureManager.close skip:java GPU release
PalettedTextureManager.reload port crates/horizon-client/src/game/armor_stands.rs::ArmorStandAssets::reload_trims trim data reloaded; models kept
PalettedTextureManager.AtlasTexture.dumpContents skip:debug debug dump
@@ -135,15 +135,15 @@ ServerPackManager.allowServerPacks port crates/horizon-client/src/server_packs.r
ServerPackManager.rejectServerPacks port crates/horizon-client/src/server_packs.rs::ServerPacks::reject prompt declined; removes the unaccepted packs
ServerPackManager.cleanupRemovedPacks inline crates/horizon-client/src/server_packs.rs::ServerPacks::tick forgets removed packs and reports why
ServerPackManager.updateDownloads port crates/horizon-client/src/server_packs.rs::ServerPacks::tick gap: minor: returns the download requests; the download itself starts in game/server_packs.rs::Game::start_pack_downloads
AbstractSoundInstance.getOrResolve port crates/horizon-client/src/sound_engine.rs::SoundEngine::resolve event lookup, then a random sound from it
BeeSoundInstance.tick port crates/horizon-client/src/sound_engine.rs::SoundInstance::tick Ticking::Bee follows the bee; pitch and volume from speed
AbstractSoundInstance.getOrResolve port crates/horizon-client-render/src/sound_engine.rs::SoundEngine::resolve event lookup, then a random sound from it
BeeSoundInstance.tick port crates/horizon-client-render/src/sound_engine.rs::SoundInstance::tick Ticking::Bee follows the bee; pitch and volume from speed
DirectionalSoundInstance.setPosition port crates/horizon-client/src/game/end.rs::Game::tick_end gap: minor: the end flash plays without a position, so the 10-block offset toward the view is not kept
ElytraOnPlayerSoundInstance.tick missing player: no elytra wind loop (entity.elytra.flying) while gliding; gliding is silent
EntityBoundSoundInstance.tick missing minor: a sound tied to an entity does not follow it; it stays at its start point
RidingEntitySoundInstance.tick missing player: no riding loop for a happy ghast or nautilus (HAPPY_GHAST_RIDING, NAUTILUS_RIDING)
RidingMinecartSoundInstance.shoudlPlaySound port crates/horizon-client/src/sound_engine.rs::SoundInstance::tick RidingMinecart arm; the predicate is always true for OldMinecartBehavior, Horizon's only minecart
RidingMinecartSoundInstance.shoudlPlaySound port crates/horizon-client-render/src/sound_engine.rs::SoundInstance::tick RidingMinecart arm; the predicate is always true for OldMinecartBehavior, Horizon's only minecart
SnifferSoundInstance.tick port crates/horizon-client/src/game/sniffers.rs::Game::tick_sniffer_effects gap: player: the digging sound plays once when digging starts; vanilla loops it while digging
Sound.Type.getByName port crates/horizon-client/src/sound_events.rs::parse_sound type file or event; other values reject the sound
SoundEventRegistrationSerializer.deserialize port crates/horizon-client/src/sound_events.rs::parse_file replace and subtitle per event
SoundEventRegistrationSerializer.getSounds inline crates/horizon-client/src/sound_events.rs::parse_file sounds array inside parse_file
SoundEventRegistrationSerializer.getType inline crates/horizon-client/src/sound_events.rs::parse_sound type field inside parse_sound
Sound.Type.getByName port crates/horizon-client-render/src/sound_events.rs::parse_sound type file or event; other values reject the sound
SoundEventRegistrationSerializer.deserialize port crates/horizon-client-render/src/sound_events.rs::parse_file replace and subtitle per event
SoundEventRegistrationSerializer.getSounds inline crates/horizon-client-render/src/sound_events.rs::parse_file sounds array inside parse_file
SoundEventRegistrationSerializer.getType inline crates/horizon-client-render/src/sound_events.rs::parse_sound type field inside parse_sound
1 EquipmentClientInfo.Layer.leatherDyeable skip:data equipment asset factory; Horizon reads the equipment JSON in armor_stands.rs
3 EquipmentClientInfo.Layer.getTextureLocation port crates/horizon-client/src/game/armor_stands.rs::ArmorStandAssets::load builds entity/equipment/<kind>/<texture>; gap: minor: only humanoid, humanoid_leggings and wings are read here
4 EquipmentClientInfo.TrimOverride.validate skip:java codec validator; TrimOverride::list keeps an override with neither texture nor palette (minor)
5 EquipmentClientInfo.TrimPredicate.validate skip:java codec validator; TrimOverride::list keeps a predicate with neither material nor pattern (minor)
6 EquipmentClientInfo.TrimPredicate.matches port crates/horizon-client/src/trims.rs::TrimOverride::matches crates/horizon-client-render/src/trims.rs::TrimOverride::matches material and pattern id comparison
7 ModelBakery.bakeModels port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models bakes block states; gap: minor: items and standalone models bake in separate fns (item_bake.rs::bake_item_model)
8 ModelBakery.ModelBakerImpl.getModel port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve an unknown id falls back to the missing model
9 ModelDiscovery.createAndQueueWrapper inline crates/horizon-client/src/model_library.rs::ParsedModels::block_models crates/horizon-client-render/src/model_library.rs::ParsedModels::block_models parent queue; no wrapper object is kept
10 ModelDiscovery.addSpecialModel inline crates/horizon-assets/src/resolve.rs::ModelLibrary::with_shared_item_generator gap: minor: only builtin/generated is registered; a non-root special model is not rejected
11 ModelDiscovery.resolve port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve resolved per model id, not as a batch map
12 ModelDiscovery.discoverDependencies inline crates/horizon-client/src/model_library.rs::ParsedModels::block_models crates/horizon-client-render/src/model_library.rs::ParsedModels::block_models pushes each model's parent until the set is complete
13 ModelDiscovery.propagateValidity port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve a chain that reaches a cycle is an error when resolved
14 ModelDiscovery.ModelWrapper.updateSlot skip:java per-model result cache
15 ModelDiscovery.ModelWrapper.getSimpleProperty skip:java per-model result cache
16 ModelDiscovery.ModelWrapper.resolveParticleMaterial port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models block particle sprite; the item side is item_bake.rs::bake_item_model
17 ModelDiscovery.ModelWrapper.bakeDefaultState skip:java cache of the identity-rotation geometry
18 ModelDiscovery.ModelWrapper.bakeTopGeometry port crates/horizon-assets/src/bake.rs::bake_block_model bakes with the blockstate rotation; per-state cache skipped
19 ModelGroupCollector.build skip:java groups states for shared baked geometry; Horizon has no model-group ids
20 ModelGroupCollector.GroupKey.create skip:java group key of build
21 ModelGroupCollector.GroupKey.getColoringValues skip:java group key of build
22 ModelManager.reload port crates/horizon-client/src/assets.rs::RenderAssets::load crates/horizon-client-render/src/assets.rs::RenderAssets::load one synchronous load: models, block states, item infos, then bake and store
23 ModelManager.loadBlockModels port crates/horizon-client/src/model_library.rs::ParsedModels::load crates/horizon-client-render/src/model_library.rs::ParsedModels::load every models/**.json by id, parsed in parallel
24 ModelManager.discoverModelDependencies port crates/horizon-client/src/model_library.rs::ParsedModels::block_models crates/horizon-client-render/src/model_library.rs::ParsedModels::block_models referenced models and their parents
25 ModelManager.loadModels port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models bakes block states and their models
26 ModelManager.createBlockStateToModelDispatch inline crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models missing model for a state without a baked model
27 ModelManager.buildModelGroups skip:java wrapper of ModelGroupCollector.build; render sharing only
28 ModelManager.apply inline crates/horizon-client/src/assets.rs::RenderAssets::load crates/horizon-client-render/src/assets.rs::RenderAssets::load the baked result is stored in the returned struct
29 ModelManager.requiresRender skip:java render-skip optimisation for equal model groups; no visible effect
30 ResolvedModel.findTopTextureSlots port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve texture slots merged along the parent chain
31 ResolvedModel.findTopAmbientOcclusion port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve ambient occlusion from the first model that sets it, default true
32 ResolvedModel.findTopGuiLight port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve gui_light from the first model that sets it, default side
33 ResolvedModel.findTopGeometry port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve first element list up the parent chain
34 ResolvedModel.resolveParticleMaterial port crates/horizon-client/src/models/catalog.rs::StateModels::from_facts_with_models crates/horizon-client-render/src/models/catalog.rs::StateModels::from_facts_with_models block particle slot; the item side is item_bake.rs::bake_item_model
35 ResolvedModel.findTopTransform port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve display transform per context, inherited up the chain
36 ResolvedModel.findTopTransforms port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve display transforms for every context
37 SimpleModelWrapper.bake port crates/horizon-assets/src/bake.rs::bake_block_model gap: minor: no rejection of block models that use non-block sprites
60 CuboidRotation.EulerXYZRotation.transformation port crates/horizon-assets/src/bake.rs::ElementMatrix::from_rotation Euler XYZ branch
61 CuboidRotation.SingleAxisRotation.transformation port crates/horizon-assets/src/bake.rs::ElementMatrix::from_rotation single-axis branch
62 FaceBakery.defaultFaceUV port crates/horizon-assets/src/bake.rs::default_uv default face UVs by direction
63 FaceBakery.computeMaterialTransparency port crates/horizon-client/src/sprites.rs::Sprites::region_opaque crates/horizon-client-render/src/sprites.rs::Sprites::region_opaque gap: minor: only the opaque-region check; force_translucent is not applied here
64 FaceBakery.bakeVertex inline crates/horizon-assets/src/bake.rs::bake_face vertex position and UV inside bake_face
65 FaceBakery.rotateVertexBy inline crates/horizon-assets/src/bake.rs::bake_face element rotation about its origin
66 FaceBakery.calculateFacing port crates/horizon-assets/src/bake.rs::facing quad normal, then closest direction
84 BakedQuad.MaterialInfo.flags skip:java translucent and animated bit flags used to skip work; Horizon ticks animated textures by its setting
85 ItemQuads.split port crates/horizon-client/src/item_render.rs::submit_quads quads with translucent sprites go to the translucent pass
86 QuadCollection.computeMaterialFlags skip:java flag bits of the quad list; see BakedQuad.MaterialInfo.flags
87 QuadCollection.getQuads port crates/horizon-client/src/mesher.rs::Mesher::mesh crates/horizon-client-render/src/mesher.rs::Mesher::mesh quads filtered by cull direction
88 QuadCollection.materialFlags skip:java cached flag bits
89 QuadCollection.Builder.addAll skip:java collection builder
90 QuadCollection.Builder.createFromSublists skip:java sublist layout of a quad collection
91 AtlasManager.getAtlasOrThrow skip:java atlas map lookup; Horizon keeps one sprite table
92 AtlasManager.forEach skip:java map iteration
93 AtlasManager.close skip:java GPU release; freed with its owner
94 AtlasManager.get port crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert sprite layer added on first use; missing texture when it fails to load
95 AtlasManager.prepareSharedState skip:java future-based stitch plumbing
96 AtlasManager.reload skip:java async reload; sprites load synchronously in RenderAssets::load
97 AtlasManager.updateSpriteMaps port crates/horizon-client/src/sprites.rs::Sprites::finish crates/horizon-client-render/src/sprites.rs::Sprites::finish lays out every layer at one size; gap: minor: no duplicate-sprite warning
98 AtlasManager.AtlasEntry.scheduleLoad port crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: sprites load on demand, not per atlas source
99 AtlasManager.PendingStitch.joinAndUpload skip:java future join
100 AtlasManager.PendingStitchResults.joinAndUpload skip:java future join
101 MaterialBaker.get port crates/horizon-assets/src/item_bake.rs::bake_item_model sprite that is not known falls back to missingno
110 TextureSlots.Data.Builder.addTexture skip:java builder
111 TextureSlots.Data.Builder.build skip:java builder
112 TextureSlots.Resolver.resolve port crates/horizon-assets/src/resolve.rs::ModelLibrary::resolve alias chain resolution; the batch hint (horizon-protocol resolver.rs) is a DNS resolver and is not this
113 resources/palette/Palette.listAndLoad port crates/horizon-client/src/trims.rs::TrimTexture::generate crates/horizon-client-render/src/trims.rs::TrimTexture::generate gap: minor: palettes load on demand, none listed up front
114 resources/palette/Palette.tryLoad port crates/horizon-client/src/trims.rs::TrimTexture::generate crates/horizon-client-render/src/trims.rs::TrimTexture::generate gap: minor: a broken palette skips the recolour instead of an empty palette
115 resources/palette/Palette.load port crates/horizon-client/src/trims.rs::TrimTexture::generate crates/horizon-client-render/src/trims.rs::TrimTexture::generate palette PNG read as ARGB
116 PaletteMapping.apply port crates/horizon-assets/src/palette.rs::apply_palette colour swap; alpha scaled by the target's alpha
117 PalettedTextureManager.loadBaseTexture port crates/horizon-client/src/trims.rs::TrimTexture::generate crates/horizon-client-render/src/trims.rs::TrimTexture::generate base texture and its base_palette from the mcmeta
118 PalettedTextureManager.allocateSlot port crates/horizon-client/src/sprites.rs::Sprites::insert crates/horizon-client-render/src/sprites.rs::Sprites::insert gap: minor: one array layer per texture, no dynamic atlas tree
119 PalettedTextureManager.close skip:java GPU release
120 PalettedTextureManager.reload port crates/horizon-client/src/game/armor_stands.rs::ArmorStandAssets::reload_trims trim data reloaded; models kept
121 PalettedTextureManager.AtlasTexture.dumpContents skip:debug debug dump
135 ServerPackManager.rejectServerPacks port crates/horizon-client/src/server_packs.rs::ServerPacks::reject prompt declined; removes the unaccepted packs
136 ServerPackManager.cleanupRemovedPacks inline crates/horizon-client/src/server_packs.rs::ServerPacks::tick forgets removed packs and reports why
137 ServerPackManager.updateDownloads port crates/horizon-client/src/server_packs.rs::ServerPacks::tick gap: minor: returns the download requests; the download itself starts in game/server_packs.rs::Game::start_pack_downloads
138 AbstractSoundInstance.getOrResolve port crates/horizon-client/src/sound_engine.rs::SoundEngine::resolve crates/horizon-client-render/src/sound_engine.rs::SoundEngine::resolve event lookup, then a random sound from it
139 BeeSoundInstance.tick port crates/horizon-client/src/sound_engine.rs::SoundInstance::tick crates/horizon-client-render/src/sound_engine.rs::SoundInstance::tick Ticking::Bee follows the bee; pitch and volume from speed
140 DirectionalSoundInstance.setPosition port crates/horizon-client/src/game/end.rs::Game::tick_end gap: minor: the end flash plays without a position, so the 10-block offset toward the view is not kept
141 ElytraOnPlayerSoundInstance.tick missing player: no elytra wind loop (entity.elytra.flying) while gliding; gliding is silent
142 EntityBoundSoundInstance.tick missing minor: a sound tied to an entity does not follow it; it stays at its start point
143 RidingEntitySoundInstance.tick missing player: no riding loop for a happy ghast or nautilus (HAPPY_GHAST_RIDING, NAUTILUS_RIDING)
144 RidingMinecartSoundInstance.shoudlPlaySound port crates/horizon-client/src/sound_engine.rs::SoundInstance::tick crates/horizon-client-render/src/sound_engine.rs::SoundInstance::tick RidingMinecart arm; the predicate is always true for OldMinecartBehavior, Horizon's only minecart
145 SnifferSoundInstance.tick port crates/horizon-client/src/game/sniffers.rs::Game::tick_sniffer_effects gap: player: the digging sound plays once when digging starts; vanilla loops it while digging
146 Sound.Type.getByName port crates/horizon-client/src/sound_events.rs::parse_sound crates/horizon-client-render/src/sound_events.rs::parse_sound type file or event; other values reject the sound
147 SoundEventRegistrationSerializer.deserialize port crates/horizon-client/src/sound_events.rs::parse_file crates/horizon-client-render/src/sound_events.rs::parse_file replace and subtitle per event
148 SoundEventRegistrationSerializer.getSounds inline crates/horizon-client/src/sound_events.rs::parse_file crates/horizon-client-render/src/sound_events.rs::parse_file sounds array inside parse_file
149 SoundEventRegistrationSerializer.getType inline crates/horizon-client/src/sound_events.rs::parse_sound crates/horizon-client-render/src/sound_events.rs::parse_sound type field inside parse_sound
+77 -77
View File
@@ -1,29 +1,29 @@
ActiveTextCollector.accept inline crates/horizon-client/src/screen_draw.rs::text default overload: left-aligned text at x,y with default parameters
ActiveTextCollector.accept inline crates/horizon-client-render/src/screen_draw.rs::text default overload: left-aligned text at x,y with default parameters
ActiveTextCollector.acceptScrolling missing minor: forwards to the scrolling helper, which Horizon lacks; long text is clipped
ActiveTextCollector.acceptScrollingWithDefaultCenter port crates/horizon-client/src/ui.rs::centered_text gap: minor: centres the message; wider text is clipped instead of scrolled
ActiveTextCollector.acceptScrollingWithDefaultCenter port crates/horizon-client-render/src/ui.rs::centered_text gap: minor: centres the message; wider text is clipped instead of scrolled
ActiveTextCollector.defaultScrollingHelper missing minor: wider text does not slide back and forth; ui.rs centered_text clips it
ActiveTextCollector.findElementUnderCursor port crates/horizon-client/src/chat.rs::Chat::style_at gap: minor: hit test covers chat lines only; book links use game/books.rs book_link_at
ActiveTextCollector.isPointInRectangle port crates/horizon-client/src/ui.rs::hovered half-open rectangle test with the same bounds
ActiveTextCollector.ClickableStyleFinder.accept port crates/horizon-client/src/chat.rs::Chat::style_at gap: minor: only chat lines are searched for click and hover styles
ActiveTextCollector.findElementUnderCursor port crates/horizon-client-render/src/chat.rs::Chat::style_at gap: minor: hit test covers chat lines only; book links use game/books.rs book_link_at
ActiveTextCollector.isPointInRectangle port crates/horizon-client-render/src/ui.rs::hovered half-open rectangle test with the same bounds
ActiveTextCollector.ClickableStyleFinder.accept port crates/horizon-client-render/src/chat.rs::Chat::style_at gap: minor: only chat lines are searched for click and hover styles
ActiveTextCollector.ClickableStyleFinder.acceptScrolling missing minor: no scrolling text (see defaultScrollingHelper)
ActiveTextCollector.Parameters.withScale skip:java record copy-with helper; Horizon has no pose matrix per text
ActiveTextCollector.Parameters.withOpacity skip:java record copy-with helper; opacity is the colour's alpha byte in Horizon
ActiveTextCollector.Parameters.withScissor missing minor: a nested scissor is not intersected with the enclosing rectangle; Draw::Scissor replaces it
ComponentPath.path skip:other focus path builder for nested containers; Horizon focus is a flat per-screen state
ComponentPath.Path.applyFocus skip:other focus path propagation; Horizon focus is a flat per-screen state
Font.bidirectionalShaping port crates/horizon-client/src/bidi.rs::visual_str Arabic shaping and bidi reorder
Font.bidirectionalShaping port crates/horizon-client-render/src/bidi.rs::visual_str Arabic shaping and bidi reorder
Font.prepare8xTextOutline skip:other no vanilla 26.3 caller passes a non-zero outline colour; text displays, name tags and map labels pass 0 or a background
Font.prepareBackground port crates/horizon-client/src/hud_overlays.rs::text_with_backdrop background box behind text; callers pass their own bounds
Font.getGlyph port crates/horizon-client/src/font.rs::Font::glyph_styled obfuscated glyph is picked in HudBatch::text_styled via random_glyph
Font.prepareBackground port crates/horizon-client-render/src/hud_overlays.rs::text_with_backdrop background box behind text; callers pass their own bounds
Font.getGlyph port crates/horizon-client-render/src/font.rs::Font::glyph_styled obfuscated glyph is picked in HudBatch::text_styled via random_glyph
Font.PreparedTextBuilder.markSize skip:other bounds bookkeeping of prepared text; Horizon has no prepared-text object and hit-tests by advance
Font.PreparedTextBuilder.markBackground inline crates/horizon-client/src/hud_overlays.rs::text_with_backdrop gap: minor: the background box is 2 px around the text; vanilla grows it by 1 px around each glyph
Font.PreparedTextBuilder.addGlyph inline crates/horizon-client/src/hud.rs::HudBatch::text_styled glyph quad pushed directly into the batch
Font.PreparedTextBuilder.addEffect inline crates/horizon-client/src/hud.rs::HudBatch::text_styled underline and strikethrough rectangles drawn inline
Font.PreparedTextBuilder.markBackground inline crates/horizon-client-render/src/hud_overlays.rs::text_with_backdrop gap: minor: the background box is 2 px around the text; vanilla grows it by 1 px around each glyph
Font.PreparedTextBuilder.addGlyph inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph quad pushed directly into the batch
Font.PreparedTextBuilder.addEffect inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline and strikethrough rectangles drawn inline
Font.PreparedTextBuilder.addEmptyGlyph skip:other hit areas for glyphs with no image; Chat::style_at hit-tests by advance width instead
Font.PreparedTextBuilder.accept port crates/horizon-client/src/hud.rs::HudBatch::text_styled per-character draw with bold, italic, shadow, underline and strikethrough
Font.PreparedTextBuilder.accept port crates/horizon-client-render/src/hud.rs::HudBatch::text_styled per-character draw with bold, italic, shadow, underline and strikethrough
Font.PreparedTextBuilder.visit skip:other visitor over prepared glyphs for draw order and hit tests; Horizon draws straight into the batch
Font.PreparedTextBuilder.getTextColor inline crates/horizon-client/src/hud.rs::HudBatch::text_styled style colour with the base colour's alpha
Font.PreparedTextBuilder.getShadowColor inline crates/horizon-client/src/hud.rs::HudBatch::text_styled gap: minor: style shadow colour is ignored; shadow is always 0.25 of the text colour
Font.PreparedTextBuilder.getTextColor inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled style colour with the base colour's alpha
Font.PreparedTextBuilder.getShadowColor inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled gap: minor: style shadow colour is ignored; shadow is always 0.25 of the text colour
Font.PreparedTextBuilder.bounds skip:other bounds of prepared text for vanilla hit tests; Horizon hit-tests by advance
Gui.update skip:other narrator-only update (handleDelayedNarration); Horizon has no narrator
Gui.isPausing port crates/horizon-client/src/game.rs::Game::pauses_game gap: minor: checks the open screen only, not the overlay part
@@ -35,115 +35,115 @@ Gui.buildInitialScreens missing player: first launch skips vanilla's accessibil
Gui.addInitialScreens missing player: same as buildInitialScreens: no onboarding screen or ban notice is queued
Gui.canInterruptScreen missing minor: unsure: no check that stops a server-opened screen from replacing an open one was found
Gui.renderActiveTextDebug skip:debug debug overlay of text bounds
GuiGraphicsExtractor.enableScissor port crates/horizon-client/src/screen_draw.rs::paint gap: minor: callers push a rectangle; there is no stack, so enclosing rectangles are not intersected
GuiGraphicsExtractor.enableScissor port crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: callers push a rectangle; there is no stack, so enclosing rectangles are not intersected
GuiGraphicsExtractor.outline missing minor: unsure: no one-pixel outline draw was found in Horizon's UI
GuiGraphicsExtractor.innerFill port crates/horizon-client/src/hud.rs::HudBatch::fill gap: minor: one colour only; a second gradient colour (color2) is not drawn
GuiGraphicsExtractor.textWithWordWrap port crates/horizon-client/src/screen_draw.rs::Measure::split gap: minor: only the wrap; the caller draws each line at y+9
GuiGraphicsExtractor.blitSprite port crates/horizon-client/src/hud.rs::HudBatch::sprite_scaled gap: minor: tile and nine-slice scaling is in ui.rs (tiled, draw_nine_slice)
GuiGraphicsExtractor.blitNineSliceInnerSegment port crates/horizon-client/src/ui.rs::draw_nine_slice inner segments of a nine-slice sprite
GuiGraphicsExtractor.blitTiledSprite port crates/horizon-client/src/ui.rs::tiled
GuiGraphicsExtractor.innerBlit port crates/horizon-client/src/screen_draw.rs::blit texture rectangle by UV; the atlas lookup is in HudBatch::rect_uv
GuiGraphicsExtractor.innerTiledBlit port crates/horizon-client/src/ui.rs::tile one tiled quad
GuiGraphicsExtractor.innerFill port crates/horizon-client-render/src/hud.rs::HudBatch::fill gap: minor: one colour only; a second gradient colour (color2) is not drawn
GuiGraphicsExtractor.textWithWordWrap port crates/horizon-client-render/src/screen_draw.rs::Measure::split gap: minor: only the wrap; the caller draws each line at y+9
GuiGraphicsExtractor.blitSprite port crates/horizon-client-render/src/hud.rs::HudBatch::sprite_scaled gap: minor: tile and nine-slice scaling is in ui.rs (tiled, draw_nine_slice)
GuiGraphicsExtractor.blitNineSliceInnerSegment port crates/horizon-client-render/src/ui.rs::draw_nine_slice inner segments of a nine-slice sprite
GuiGraphicsExtractor.blitTiledSprite port crates/horizon-client-render/src/ui.rs::tiled
GuiGraphicsExtractor.innerBlit port crates/horizon-client-render/src/screen_draw.rs::blit texture rectangle by UV; the atlas lookup is in HudBatch::rect_uv
GuiGraphicsExtractor.innerTiledBlit port crates/horizon-client-render/src/ui.rs::tile one tiled quad
GuiGraphicsExtractor.item port crates/horizon-client/src/game.rs::Game::draw_item gap: minor: no seed or owner is passed to the item model
GuiGraphicsExtractor.fakeItem inline crates/horizon-client/src/game.rs::Game::draw_item same as item with no owner
GuiGraphicsExtractor.itemBar inline crates/horizon-client/src/hud_overlays.rs::item_decorations damage bar drawn in item_decorations
GuiGraphicsExtractor.itemCount inline crates/horizon-client/src/hud_overlays.rs::item_decorations stack count drawn in item_decorations
GuiGraphicsExtractor.itemBar inline crates/horizon-client-render/src/hud_overlays.rs::item_decorations damage bar drawn in item_decorations
GuiGraphicsExtractor.itemCount inline crates/horizon-client-render/src/hud_overlays.rs::item_decorations stack count drawn in item_decorations
GuiGraphicsExtractor.map port crates/horizon-client/src/game/cartography.rs::Game::draw_cartography gap: player: the map image is drawn only in the cartography preview; map markers (decorations) are not drawn there
GuiGraphicsExtractor.entity port crates/horizon-client/src/game/perspective.rs::Game::draw_player_preview gap: player: only the local player is previewed; the smithing armour-stand preview has no port
GuiGraphicsExtractor.skin missing minor: no skin customisation preview was found; the inventory preview is draw_player_preview
GuiGraphicsExtractor.book missing player: the enchanting table screen does not draw its open book; Horizon's book drawing is for written books only
GuiGraphicsExtractor.profilerChart skip:debug F3 profiler pie chart; Horizon's debug_chart.rs covers its own charts
GuiGraphicsExtractor.setTooltipForNextFrame inline crates/horizon-client/src/screen_draw.rs::tooltip the overloads route to the tooltip draw
GuiGraphicsExtractor.setComponentTooltipForNextFrame port crates/horizon-client/src/screen_draw.rs::tooltip gap: minor: tooltip images (TooltipComponent) are not drawn
GuiGraphicsExtractor.setTooltipForNextFrameInternal port crates/horizon-client/src/ui.rs::tooltip frame and background sprites beside the cursor
GuiGraphicsExtractor.extractDeferredElements port crates/horizon-client/src/screen_draw.rs::paint gap: minor: deferred hover effects come from chat only (see componentHoverEffect)
GuiGraphicsExtractor.setTooltipForNextFrame inline crates/horizon-client-render/src/screen_draw.rs::tooltip the overloads route to the tooltip draw
GuiGraphicsExtractor.setComponentTooltipForNextFrame port crates/horizon-client-render/src/screen_draw.rs::tooltip gap: minor: tooltip images (TooltipComponent) are not drawn
GuiGraphicsExtractor.setTooltipForNextFrameInternal port crates/horizon-client-render/src/ui.rs::tooltip frame and background sprites beside the cursor
GuiGraphicsExtractor.extractDeferredElements port crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: deferred hover effects come from chat only (see componentHoverEffect)
GuiGraphicsExtractor.componentHoverEffect port crates/horizon-client/src/game/chat.rs::Game::draw_chat_screen gap: player: hover tooltips exist only for text in chat; item and entity hover events show nothing
GuiGraphicsExtractor.textRendererForWidget skip:ui builds a text collector for a widget; Horizon draws widget text directly
GuiGraphicsExtractor.textRenderer skip:ui builds a text collector; Horizon draws text directly
GuiGraphicsExtractor.createDefaultTextParameters skip:ui default pose, opacity and scissor for text; Horizon passes colour and rectangle directly
GuiGraphicsExtractor.RenderingTextCollector.accept port crates/horizon-client/src/screen_draw.rs::text gap: minor: no hover or click registration here (see Chat::style_at)
GuiGraphicsExtractor.RenderingTextCollector.accept port crates/horizon-client-render/src/screen_draw.rs::text gap: minor: no hover or click registration here (see Chat::style_at)
GuiGraphicsExtractor.RenderingTextCollector.acceptScrolling missing minor: no scrolling text (see defaultScrollingHelper)
GuiGraphicsExtractor.ScissorStack.push inline crates/horizon-client/src/screen_draw.rs::paint gap: minor: the pushed rectangle replaces the current one; it is not intersected
GuiGraphicsExtractor.ScissorStack.pop inline crates/horizon-client/src/screen_draw.rs::paint gap: minor: Draw::NoScissor clears the scissor instead of restoring the enclosing one
GuiGraphicsExtractor.ScissorStack.push inline crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: the pushed rectangle replaces the current one; it is not intersected
GuiGraphicsExtractor.ScissorStack.pop inline crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: Draw::NoScissor clears the scissor instead of restoring the enclosing one
GuiGraphicsExtractor.ScissorStack.containsPoint missing minor: hover ignores the scissor, so a widget clipped out of view can still highlight
Hud.extractHotbarAndDecorations port crates/horizon-client/src/hud_layout.rs::hotbar items and decorations are drawn by Game::draw_item
Hud.extractHotbarAndDecorations port crates/horizon-client-render/src/hud_layout.rs::hotbar items and decorations are drawn by Game::draw_item
Hud.<init> skip:java constructor state setup
Hud.extractSubtitleOverlay port crates/horizon-client/src/hud_overlays.rs::SubtitleOverlay::extract
Hud.extractChat port crates/horizon-client/src/chat.rs::Chat::layout
Hud.extractSubtitleOverlay port crates/horizon-client-render/src/hud_overlays.rs::SubtitleOverlay::extract
Hud.extractChat port crates/horizon-client-render/src/chat.rs::Chat::layout
Hud.getMobEffectSprite port crates/horizon-client/src/game/potions.rs::Game::draw_effect_icons sprite lookup is inside the effect icon draw
Hud.extractDemoOverlay skip:other Horizon has no demo mode, so there is no demo timer overlay
Hud.getCameraPlayer missing minor: unsure: no camera-entity lookup found; the HUD always uses the local player
Hud.getPlayerVehicleWithHealth port crates/horizon-client/src/hud_layout.rs::vehicle_health gap: minor: the vehicle is chosen by the caller
Hud.extractArmor inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout armour row inside the health layout
Hud.extractHearts inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout heart row inside the health layout
Hud.extractHeart port crates/horizon-client/src/hud_layout.rs::heart heart sprite choice for one heart
Hud.getAirBubbleYLine inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout air bubble row position
Hud.getCurrentAirSupplyBubble inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout air bubble count
Hud.extractFood inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout food row inside the health layout
Hud.extractTextureOverlay port crates/horizon-client/src/hud_overlays.rs::camera_overlays gap: player: the powder-snow freeze outline is not drawn; only the equippable camera overlay (pumpkin) is
Hud.getPlayerVehicleWithHealth port crates/horizon-client-render/src/hud_layout.rs::vehicle_health gap: minor: the vehicle is chosen by the caller
Hud.extractArmor inline crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout armour row inside the health layout
Hud.extractHearts inline crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout heart row inside the health layout
Hud.extractHeart port crates/horizon-client-render/src/hud_layout.rs::heart heart sprite choice for one heart
Hud.getAirBubbleYLine inline crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout air bubble row position
Hud.getCurrentAirSupplyBubble inline crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout air bubble count
Hud.extractFood inline crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout food row inside the health layout
Hud.extractTextureOverlay port crates/horizon-client-render/src/hud_overlays.rs::camera_overlays gap: player: the powder-snow freeze outline is not drawn; only the equippable camera overlay (pumpkin) is
Hud.extractSlot port crates/horizon-client/src/game.rs::Game::draw_slot_item
Hud.setNowPlaying port crates/horizon-client/src/hud_overlays.rs::Titles::set_overlay the animate flag gives the rainbow colour
Hud.setNowPlaying port crates/horizon-client-render/src/hud_overlays.rs::Titles::set_overlay the animate flag gives the rainbow colour
Hud.onDisconnected missing minor: unsure: no HUD reset on disconnect found; titles clear only on the ClearTitles packet
Hud.willPrioritizeJumpInfo port crates/horizon-client/src/locator_bar.rs::ContextualBar::next the jumping input comes from Game::mount_jumping
Hud.HeartType.getSprite port crates/horizon-client/src/hud_layout.rs::heart
Hud.HeartType.forPlayer inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout heart kind comes from the health inputs
AbstractButton.extractDefaultSprite port crates/horizon-client/src/screen_draw.rs::button disabled, highlighted and normal sprites
Hud.HeartType.getSprite port crates/horizon-client-render/src/hud_layout.rs::heart
Hud.HeartType.forPlayer inline crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout heart kind comes from the health inputs
AbstractButton.extractDefaultSprite port crates/horizon-client-render/src/screen_draw.rs::button disabled, highlighted and normal sprites
AbstractButton.keyPressed missing minor: Enter or Space does not press a focused button; Enter only confirms a title text edit
AbstractContainerWidget.setFocused port crates/horizon-client/src/pack_screen.rs::PackScreen::set_focus gap: minor: screen-level focus only; no child-container focus
AbstractContainerWidget.mouseClicked port crates/horizon-client/src/ui.rs::Scroll::press gap: minor: child click dispatch is per screen; only the scrollbar press is here
AbstractScrollArea.isOverScrollbar inline crates/horizon-client/src/ui.rs::Scroll::press scrollbar column test folded into the press
AbstractScrollArea.scrollBarY port crates/horizon-client/src/ui.rs::scrollbar_thumb thumb top
AbstractScrollArea.extractScrollbar port crates/horizon-client/src/ui.rs::scrollbar gap: minor: no disabled-scroller sprite and no cursor request
AbstractContainerWidget.setFocused port crates/horizon-client-render/src/pack_screen.rs::PackScreen::set_focus gap: minor: screen-level focus only; no child-container focus
AbstractContainerWidget.mouseClicked port crates/horizon-client-render/src/ui.rs::Scroll::press gap: minor: child click dispatch is per screen; only the scrollbar press is here
AbstractScrollArea.isOverScrollbar inline crates/horizon-client-render/src/ui.rs::Scroll::press scrollbar column test folded into the press
AbstractScrollArea.scrollBarY port crates/horizon-client-render/src/ui.rs::scrollbar_thumb thumb top
AbstractScrollArea.extractScrollbar port crates/horizon-client-render/src/ui.rs::scrollbar gap: minor: no disabled-scroller sprite and no cursor request
AbstractScrollArea.defaultSettings skip:java settings record builder; the sizes are constants in ui.rs
AbstractSelectionList.swap port crates/horizon-client/src/multiplayer.rs::Screen::click gap: minor: mouse move up or down works; keyboard Shift+arrow reorder is not ported
AbstractSelectionList.clearEntriesExcept skip:other only the stats screen calls it; Horizon's stats screen draws its rows directly
AbstractSelectionList.replaceEntries port crates/horizon-client/src/pack_screen.rs::PackScreen::update_list
AbstractSelectionList.getNextY port crates/horizon-client/src/pack_screen.rs::List::next_y
AbstractSelectionList.addEntry port crates/horizon-client/src/pack_screen.rs::List::add
AbstractSelectionList.replaceEntries port crates/horizon-client-render/src/pack_screen.rs::PackScreen::update_list
AbstractSelectionList.getNextY port crates/horizon-client-render/src/pack_screen.rs::List::next_y
AbstractSelectionList.addEntry port crates/horizon-client-render/src/pack_screen.rs::List::add
AbstractSelectionList.addEntryToTop skip:service only the chat report selection screen calls it; Horizon has no chat reporting
AbstractSelectionList.repositionEntries port crates/horizon-client/src/pack_screen.rs::List::reposition
AbstractSelectionList.repositionEntries port crates/horizon-client-render/src/pack_screen.rs::List::reposition
AbstractSelectionList.removeEntryFromTop skip:service only the chat report selection screen calls it; Horizon has no chat reporting
AbstractSelectionList.updateSizeAndPosition port crates/horizon-client/src/pack_screen.rs::List::update_size
AbstractSelectionList.extractListSeparators port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list header and footer separators, with the in-world variant
AbstractSelectionList.extractListBackground port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list menu list background sprite
AbstractSelectionList.enableScissor port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list scissor clamped to the screen
AbstractSelectionList.scrollToEntry port crates/horizon-client/src/pack_screen.rs::List::scroll_to
AbstractSelectionList.setFocused port crates/horizon-client/src/pack_screen.rs::PackScreen::set_focus gap: minor: focusing a row does not select it; vanilla selects the focused entry
AbstractSelectionList.updateSizeAndPosition port crates/horizon-client-render/src/pack_screen.rs::List::update_size
AbstractSelectionList.extractListSeparators port crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list header and footer separators, with the in-world variant
AbstractSelectionList.extractListBackground port crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list menu list background sprite
AbstractSelectionList.enableScissor port crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list scissor clamped to the screen
AbstractSelectionList.scrollToEntry port crates/horizon-client-render/src/pack_screen.rs::List::scroll_to
AbstractSelectionList.setFocused port crates/horizon-client-render/src/pack_screen.rs::PackScreen::set_focus gap: minor: focusing a row does not select it; vanilla selects the focused entry
AbstractSelectionList.nextEntry missing minor: arrow keys do not move the selection between rows in the pack or server lists
AbstractSelectionList.extractListItems port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list rows culled to the visible band
AbstractSelectionList.extractItem port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list selection outline and row content
AbstractSelectionList.extractSelection port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list two fills: outline colour and black inner
AbstractSelectionList.extractListItems port crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list rows culled to the visible band
AbstractSelectionList.extractItem port crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list selection outline and row content
AbstractSelectionList.extractSelection port crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list two fills: outline colour and black inner
AbstractSelectionList.getRowBottom skip:other only the LAN-found narration uses it; Horizon has no narrator
AbstractSelectionList.narrationPriority skip:other screen-reader priority; Horizon has no narrator
AbstractSelectionList.removeEntry skip:other rows are rebuilt from the model when they change (update_list, server list), so there is no single-row removal
AbstractSelectionList.narrateListElementPosition skip:other narration only
AbstractSelectionList.TrackedList.set skip:java delegate list wrapper
AbstractSliderButton.getSprite inline crates/horizon-client/src/ui.rs::slider gap: minor: track highlight follows hover only; keyboard focus does not highlight
AbstractSliderButton.getHandleSprite inline crates/horizon-client/src/ui.rs::slider gap: minor: handle highlight follows hover only
AbstractSliderButton.getSprite inline crates/horizon-client-render/src/ui.rs::slider gap: minor: track highlight follows hover only; keyboard focus does not highlight
AbstractSliderButton.getHandleSprite inline crates/horizon-client-render/src/ui.rs::slider gap: minor: handle highlight follows hover only
AbstractSliderButton.updateWidgetNarration skip:other narration only
AbstractSliderButton.extractWidgetRenderState port crates/horizon-client/src/ui.rs::slider gap: minor: the label is clipped rather than scrolled
AbstractSliderButton.handleCursor port crates/horizon-client/src/widgets.rs::widget_cursor gap: minor: no resize cursor while dragging
AbstractSliderButton.extractWidgetRenderState port crates/horizon-client-render/src/ui.rs::slider gap: minor: the label is clipped rather than scrolled
AbstractSliderButton.handleCursor port crates/horizon-client-render/src/widgets.rs::widget_cursor gap: minor: no resize cursor while dragging
AbstractSliderButton.setFocused missing minor: keyboard focus does not enable value changes; there is no change-value state
AbstractSliderButton.keyPressed missing minor: Left and Right do not move a focused slider; Enter does not toggle it
AbstractSliderButton.setValue port crates/horizon-client/src/options_ui.rs::set_slider gap: minor: the 0..1 clamp is done by the caller (ui.rs slider_value)
AbstractStringWidget.extractWidgetRenderState port crates/horizon-client/src/screen_draw.rs::string_widget gap: minor: hover tooltip and click cursor for styled text are not drawn
AbstractSliderButton.setValue port crates/horizon-client-render/src/options_ui.rs::set_slider gap: minor: the 0..1 clamp is done by the caller (ui.rs slider_value)
AbstractStringWidget.extractWidgetRenderState port crates/horizon-client-render/src/screen_draw.rs::string_widget gap: minor: hover tooltip and click cursor for styled text are not drawn
AbstractStringWidget.onClick missing minor: clicking a styled label with a click event does nothing here; book links and chat links do work
AbstractStringWidget.setMessage skip:ui width is measured at draw time
AbstractStringWidget.handleStyleClick missing minor: same as onClick: no click handling for labels
AbstractTextAreaWidget.mouseClicked port crates/horizon-client/src/game/books.rs::Game::book_page_click gap: minor: a scrollbar press inside the area is not checked
AbstractTextAreaWidget.keyPressed port crates/horizon-client/src/game/books.rs::Game::book_page_key gap: minor: up and down scroll the area in vanilla; not checked here
AbstractTextAreaWidget.extractWidgetRenderState port crates/horizon-client/src/game/books.rs::Game::draw_book gap: minor: scroll offset inside the page not verified
AbstractTextAreaWidget.isMouseOver port crates/horizon-client/src/screen_draw.rs::inside gap: minor: the scrollbar width is not added to the hit area
AbstractTextAreaWidget.isMouseOver port crates/horizon-client-render/src/screen_draw.rs::inside gap: minor: the scrollbar width is not added to the hit area
AbstractTextAreaWidget.extractBackground skip:ui frame drawn by the book screen; no behaviour
AbstractTextAreaWidget.extractBorder skip:ui frame sprite; no behaviour
AbstractTextAreaWidget.withinContentAreaTopBottom skip:ui visibility cull while drawing lines
AbstractWidget.extractRenderState port crates/horizon-client/src/ui.rs::hovered gap: minor: the scissor test is not part of the hover check
AbstractWidget.extractTooltipForNextRenderPass port crates/horizon-client/src/ui.rs::tooltip gap: minor: unsure: widget hover delay not checked
AbstractWidget.extractScrollingStringOverContents port crates/horizon-client/src/ui.rs::centered_text gap: minor: text is clipped, not scrolled
AbstractWidget.extractRenderState port crates/horizon-client-render/src/ui.rs::hovered gap: minor: the scissor test is not part of the hover check
AbstractWidget.extractTooltipForNextRenderPass port crates/horizon-client-render/src/ui.rs::tooltip gap: minor: unsure: widget hover delay not checked
AbstractWidget.extractScrollingStringOverContents port crates/horizon-client-render/src/ui.rs::centered_text gap: minor: text is clipped, not scrolled
AbstractWidget.mouseClicked port crates/horizon-client/src/title.rs::Title::click gap: minor: click dispatch is per screen; the press sound is audio.rs Audio::play_button_click
AbstractWidget.mouseReleased port crates/horizon-client/src/ui.rs::Scroll::release gap: minor: only the scroll release; widget onRelease is per screen
AbstractWidget.mouseDragged port crates/horizon-client/src/ui.rs::Scroll::drag gap: minor: only scroll drag; widget onDrag is per screen
AbstractWidget.mouseReleased port crates/horizon-client-render/src/ui.rs::Scroll::release gap: minor: only the scroll release; widget onRelease is per screen
AbstractWidget.mouseDragged port crates/horizon-client-render/src/ui.rs::Scroll::drag gap: minor: only scroll drag; widget onDrag is per screen
AbstractWidget.nextFocusPath missing minor: unsure: no per-widget focus path; Horizon focus is per screen
AbstractWidget.isMouseOver port crates/horizon-client/src/screen_draw.rs::inside gap: minor: isActive is checked by the caller
AbstractWidget.isMouseOver port crates/horizon-client-render/src/screen_draw.rs::inside gap: minor: isActive is checked by the caller
AbstractWidget.narrationPriority skip:other narration only
AbstractWidget.defaultButtonNarrationText skip:other narration only
1 ActiveTextCollector.accept inline crates/horizon-client/src/screen_draw.rs::text crates/horizon-client-render/src/screen_draw.rs::text default overload: left-aligned text at x,y with default parameters
2 ActiveTextCollector.acceptScrolling missing minor: forwards to the scrolling helper, which Horizon lacks; long text is clipped
3 ActiveTextCollector.acceptScrollingWithDefaultCenter port crates/horizon-client/src/ui.rs::centered_text crates/horizon-client-render/src/ui.rs::centered_text gap: minor: centres the message; wider text is clipped instead of scrolled
4 ActiveTextCollector.defaultScrollingHelper missing minor: wider text does not slide back and forth; ui.rs centered_text clips it
5 ActiveTextCollector.findElementUnderCursor port crates/horizon-client/src/chat.rs::Chat::style_at crates/horizon-client-render/src/chat.rs::Chat::style_at gap: minor: hit test covers chat lines only; book links use game/books.rs book_link_at
6 ActiveTextCollector.isPointInRectangle port crates/horizon-client/src/ui.rs::hovered crates/horizon-client-render/src/ui.rs::hovered half-open rectangle test with the same bounds
7 ActiveTextCollector.ClickableStyleFinder.accept port crates/horizon-client/src/chat.rs::Chat::style_at crates/horizon-client-render/src/chat.rs::Chat::style_at gap: minor: only chat lines are searched for click and hover styles
8 ActiveTextCollector.ClickableStyleFinder.acceptScrolling missing minor: no scrolling text (see defaultScrollingHelper)
9 ActiveTextCollector.Parameters.withScale skip:java record copy-with helper; Horizon has no pose matrix per text
10 ActiveTextCollector.Parameters.withOpacity skip:java record copy-with helper; opacity is the colour's alpha byte in Horizon
11 ActiveTextCollector.Parameters.withScissor missing minor: a nested scissor is not intersected with the enclosing rectangle; Draw::Scissor replaces it
12 ComponentPath.path skip:other focus path builder for nested containers; Horizon focus is a flat per-screen state
13 ComponentPath.Path.applyFocus skip:other focus path propagation; Horizon focus is a flat per-screen state
14 Font.bidirectionalShaping port crates/horizon-client/src/bidi.rs::visual_str crates/horizon-client-render/src/bidi.rs::visual_str Arabic shaping and bidi reorder
15 Font.prepare8xTextOutline skip:other no vanilla 26.3 caller passes a non-zero outline colour; text displays, name tags and map labels pass 0 or a background
16 Font.prepareBackground port crates/horizon-client/src/hud_overlays.rs::text_with_backdrop crates/horizon-client-render/src/hud_overlays.rs::text_with_backdrop background box behind text; callers pass their own bounds
17 Font.getGlyph port crates/horizon-client/src/font.rs::Font::glyph_styled crates/horizon-client-render/src/font.rs::Font::glyph_styled obfuscated glyph is picked in HudBatch::text_styled via random_glyph
18 Font.PreparedTextBuilder.markSize skip:other bounds bookkeeping of prepared text; Horizon has no prepared-text object and hit-tests by advance
19 Font.PreparedTextBuilder.markBackground inline crates/horizon-client/src/hud_overlays.rs::text_with_backdrop crates/horizon-client-render/src/hud_overlays.rs::text_with_backdrop gap: minor: the background box is 2 px around the text; vanilla grows it by 1 px around each glyph
20 Font.PreparedTextBuilder.addGlyph inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph quad pushed directly into the batch
21 Font.PreparedTextBuilder.addEffect inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline and strikethrough rectangles drawn inline
22 Font.PreparedTextBuilder.addEmptyGlyph skip:other hit areas for glyphs with no image; Chat::style_at hit-tests by advance width instead
23 Font.PreparedTextBuilder.accept port crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled per-character draw with bold, italic, shadow, underline and strikethrough
24 Font.PreparedTextBuilder.visit skip:other visitor over prepared glyphs for draw order and hit tests; Horizon draws straight into the batch
25 Font.PreparedTextBuilder.getTextColor inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled style colour with the base colour's alpha
26 Font.PreparedTextBuilder.getShadowColor inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled gap: minor: style shadow colour is ignored; shadow is always 0.25 of the text colour
27 Font.PreparedTextBuilder.bounds skip:other bounds of prepared text for vanilla hit tests; Horizon hit-tests by advance
28 Gui.update skip:other narrator-only update (handleDelayedNarration); Horizon has no narrator
29 Gui.isPausing port crates/horizon-client/src/game.rs::Game::pauses_game crates/horizon-client/src/game.rs::Game::pauses_game gap: minor: checks the open screen only, not the overlay part
35 Gui.addInitialScreens missing player: same as buildInitialScreens: no onboarding screen or ban notice is queued
36 Gui.canInterruptScreen missing minor: unsure: no check that stops a server-opened screen from replacing an open one was found
37 Gui.renderActiveTextDebug skip:debug debug overlay of text bounds
38 GuiGraphicsExtractor.enableScissor port crates/horizon-client/src/screen_draw.rs::paint crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: callers push a rectangle; there is no stack, so enclosing rectangles are not intersected
39 GuiGraphicsExtractor.outline missing minor: unsure: no one-pixel outline draw was found in Horizon's UI
40 GuiGraphicsExtractor.innerFill port crates/horizon-client/src/hud.rs::HudBatch::fill crates/horizon-client-render/src/hud.rs::HudBatch::fill gap: minor: one colour only; a second gradient colour (color2) is not drawn
41 GuiGraphicsExtractor.textWithWordWrap port crates/horizon-client/src/screen_draw.rs::Measure::split crates/horizon-client-render/src/screen_draw.rs::Measure::split gap: minor: only the wrap; the caller draws each line at y+9
42 GuiGraphicsExtractor.blitSprite port crates/horizon-client/src/hud.rs::HudBatch::sprite_scaled crates/horizon-client-render/src/hud.rs::HudBatch::sprite_scaled gap: minor: tile and nine-slice scaling is in ui.rs (tiled, draw_nine_slice)
43 GuiGraphicsExtractor.blitNineSliceInnerSegment port crates/horizon-client/src/ui.rs::draw_nine_slice crates/horizon-client-render/src/ui.rs::draw_nine_slice inner segments of a nine-slice sprite
44 GuiGraphicsExtractor.blitTiledSprite port crates/horizon-client/src/ui.rs::tiled crates/horizon-client-render/src/ui.rs::tiled
45 GuiGraphicsExtractor.innerBlit port crates/horizon-client/src/screen_draw.rs::blit crates/horizon-client-render/src/screen_draw.rs::blit texture rectangle by UV; the atlas lookup is in HudBatch::rect_uv
46 GuiGraphicsExtractor.innerTiledBlit port crates/horizon-client/src/ui.rs::tile crates/horizon-client-render/src/ui.rs::tile one tiled quad
47 GuiGraphicsExtractor.item port crates/horizon-client/src/game.rs::Game::draw_item crates/horizon-client/src/game.rs::Game::draw_item gap: minor: no seed or owner is passed to the item model
48 GuiGraphicsExtractor.fakeItem inline crates/horizon-client/src/game.rs::Game::draw_item crates/horizon-client/src/game.rs::Game::draw_item same as item with no owner
49 GuiGraphicsExtractor.itemBar inline crates/horizon-client/src/hud_overlays.rs::item_decorations crates/horizon-client-render/src/hud_overlays.rs::item_decorations damage bar drawn in item_decorations
50 GuiGraphicsExtractor.itemCount inline crates/horizon-client/src/hud_overlays.rs::item_decorations crates/horizon-client-render/src/hud_overlays.rs::item_decorations stack count drawn in item_decorations
51 GuiGraphicsExtractor.map port crates/horizon-client/src/game/cartography.rs::Game::draw_cartography crates/horizon-client/src/game/cartography.rs::Game::draw_cartography gap: player: the map image is drawn only in the cartography preview; map markers (decorations) are not drawn there
52 GuiGraphicsExtractor.entity port crates/horizon-client/src/game/perspective.rs::Game::draw_player_preview crates/horizon-client/src/game/perspective.rs::Game::draw_player_preview gap: player: only the local player is previewed; the smithing armour-stand preview has no port
53 GuiGraphicsExtractor.skin missing minor: no skin customisation preview was found; the inventory preview is draw_player_preview
54 GuiGraphicsExtractor.book missing player: the enchanting table screen does not draw its open book; Horizon's book drawing is for written books only
55 GuiGraphicsExtractor.profilerChart skip:debug F3 profiler pie chart; Horizon's debug_chart.rs covers its own charts
56 GuiGraphicsExtractor.setTooltipForNextFrame inline crates/horizon-client/src/screen_draw.rs::tooltip crates/horizon-client-render/src/screen_draw.rs::tooltip the overloads route to the tooltip draw
57 GuiGraphicsExtractor.setComponentTooltipForNextFrame port crates/horizon-client/src/screen_draw.rs::tooltip crates/horizon-client-render/src/screen_draw.rs::tooltip gap: minor: tooltip images (TooltipComponent) are not drawn
58 GuiGraphicsExtractor.setTooltipForNextFrameInternal port crates/horizon-client/src/ui.rs::tooltip crates/horizon-client-render/src/ui.rs::tooltip frame and background sprites beside the cursor
59 GuiGraphicsExtractor.extractDeferredElements port crates/horizon-client/src/screen_draw.rs::paint crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: deferred hover effects come from chat only (see componentHoverEffect)
60 GuiGraphicsExtractor.componentHoverEffect port crates/horizon-client/src/game/chat.rs::Game::draw_chat_screen crates/horizon-client/src/game/chat.rs::Game::draw_chat_screen gap: player: hover tooltips exist only for text in chat; item and entity hover events show nothing
61 GuiGraphicsExtractor.textRendererForWidget skip:ui builds a text collector for a widget; Horizon draws widget text directly
62 GuiGraphicsExtractor.textRenderer skip:ui builds a text collector; Horizon draws text directly
63 GuiGraphicsExtractor.createDefaultTextParameters skip:ui default pose, opacity and scissor for text; Horizon passes colour and rectangle directly
64 GuiGraphicsExtractor.RenderingTextCollector.accept port crates/horizon-client/src/screen_draw.rs::text crates/horizon-client-render/src/screen_draw.rs::text gap: minor: no hover or click registration here (see Chat::style_at)
65 GuiGraphicsExtractor.RenderingTextCollector.acceptScrolling missing minor: no scrolling text (see defaultScrollingHelper)
66 GuiGraphicsExtractor.ScissorStack.push inline crates/horizon-client/src/screen_draw.rs::paint crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: the pushed rectangle replaces the current one; it is not intersected
67 GuiGraphicsExtractor.ScissorStack.pop inline crates/horizon-client/src/screen_draw.rs::paint crates/horizon-client-render/src/screen_draw.rs::paint gap: minor: Draw::NoScissor clears the scissor instead of restoring the enclosing one
68 GuiGraphicsExtractor.ScissorStack.containsPoint missing minor: hover ignores the scissor, so a widget clipped out of view can still highlight
69 Hud.extractHotbarAndDecorations port crates/horizon-client/src/hud_layout.rs::hotbar crates/horizon-client-render/src/hud_layout.rs::hotbar items and decorations are drawn by Game::draw_item
70 Hud.<init> skip:java constructor state setup
71 Hud.extractSubtitleOverlay port crates/horizon-client/src/hud_overlays.rs::SubtitleOverlay::extract crates/horizon-client-render/src/hud_overlays.rs::SubtitleOverlay::extract
72 Hud.extractChat port crates/horizon-client/src/chat.rs::Chat::layout crates/horizon-client-render/src/chat.rs::Chat::layout
73 Hud.getMobEffectSprite port crates/horizon-client/src/game/potions.rs::Game::draw_effect_icons crates/horizon-client/src/game/potions.rs::Game::draw_effect_icons sprite lookup is inside the effect icon draw
74 Hud.extractDemoOverlay skip:other Horizon has no demo mode, so there is no demo timer overlay
75 Hud.getCameraPlayer missing minor: unsure: no camera-entity lookup found; the HUD always uses the local player
76 Hud.getPlayerVehicleWithHealth port crates/horizon-client/src/hud_layout.rs::vehicle_health crates/horizon-client-render/src/hud_layout.rs::vehicle_health gap: minor: the vehicle is chosen by the caller
77 Hud.extractArmor inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout armour row inside the health layout
78 Hud.extractHearts inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout heart row inside the health layout
79 Hud.extractHeart port crates/horizon-client/src/hud_layout.rs::heart crates/horizon-client-render/src/hud_layout.rs::heart heart sprite choice for one heart
80 Hud.getAirBubbleYLine inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout air bubble row position
81 Hud.getCurrentAirSupplyBubble inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout air bubble count
82 Hud.extractFood inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout food row inside the health layout
83 Hud.extractTextureOverlay port crates/horizon-client/src/hud_overlays.rs::camera_overlays crates/horizon-client-render/src/hud_overlays.rs::camera_overlays gap: player: the powder-snow freeze outline is not drawn; only the equippable camera overlay (pumpkin) is
84 Hud.extractSlot port crates/horizon-client/src/game.rs::Game::draw_slot_item crates/horizon-client/src/game.rs::Game::draw_slot_item
85 Hud.setNowPlaying port crates/horizon-client/src/hud_overlays.rs::Titles::set_overlay crates/horizon-client-render/src/hud_overlays.rs::Titles::set_overlay the animate flag gives the rainbow colour
86 Hud.onDisconnected missing minor: unsure: no HUD reset on disconnect found; titles clear only on the ClearTitles packet
87 Hud.willPrioritizeJumpInfo port crates/horizon-client/src/locator_bar.rs::ContextualBar::next crates/horizon-client/src/locator_bar.rs::ContextualBar::next the jumping input comes from Game::mount_jumping
88 Hud.HeartType.getSprite port crates/horizon-client/src/hud_layout.rs::heart crates/horizon-client-render/src/hud_layout.rs::heart
89 Hud.HeartType.forPlayer inline crates/horizon-client/src/hud_layout.rs::HealthHud::layout crates/horizon-client-render/src/hud_layout.rs::HealthHud::layout heart kind comes from the health inputs
90 AbstractButton.extractDefaultSprite port crates/horizon-client/src/screen_draw.rs::button crates/horizon-client-render/src/screen_draw.rs::button disabled, highlighted and normal sprites
91 AbstractButton.keyPressed missing minor: Enter or Space does not press a focused button; Enter only confirms a title text edit
92 AbstractContainerWidget.setFocused port crates/horizon-client/src/pack_screen.rs::PackScreen::set_focus crates/horizon-client-render/src/pack_screen.rs::PackScreen::set_focus gap: minor: screen-level focus only; no child-container focus
93 AbstractContainerWidget.mouseClicked port crates/horizon-client/src/ui.rs::Scroll::press crates/horizon-client-render/src/ui.rs::Scroll::press gap: minor: child click dispatch is per screen; only the scrollbar press is here
94 AbstractScrollArea.isOverScrollbar inline crates/horizon-client/src/ui.rs::Scroll::press crates/horizon-client-render/src/ui.rs::Scroll::press scrollbar column test folded into the press
95 AbstractScrollArea.scrollBarY port crates/horizon-client/src/ui.rs::scrollbar_thumb crates/horizon-client-render/src/ui.rs::scrollbar_thumb thumb top
96 AbstractScrollArea.extractScrollbar port crates/horizon-client/src/ui.rs::scrollbar crates/horizon-client-render/src/ui.rs::scrollbar gap: minor: no disabled-scroller sprite and no cursor request
97 AbstractScrollArea.defaultSettings skip:java settings record builder; the sizes are constants in ui.rs
98 AbstractSelectionList.swap port crates/horizon-client/src/multiplayer.rs::Screen::click crates/horizon-client/src/multiplayer.rs::Screen::click gap: minor: mouse move up or down works; keyboard Shift+arrow reorder is not ported
99 AbstractSelectionList.clearEntriesExcept skip:other only the stats screen calls it; Horizon's stats screen draws its rows directly
100 AbstractSelectionList.replaceEntries port crates/horizon-client/src/pack_screen.rs::PackScreen::update_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::update_list
101 AbstractSelectionList.getNextY port crates/horizon-client/src/pack_screen.rs::List::next_y crates/horizon-client-render/src/pack_screen.rs::List::next_y
102 AbstractSelectionList.addEntry port crates/horizon-client/src/pack_screen.rs::List::add crates/horizon-client-render/src/pack_screen.rs::List::add
103 AbstractSelectionList.addEntryToTop skip:service only the chat report selection screen calls it; Horizon has no chat reporting
104 AbstractSelectionList.repositionEntries port crates/horizon-client/src/pack_screen.rs::List::reposition crates/horizon-client-render/src/pack_screen.rs::List::reposition
105 AbstractSelectionList.removeEntryFromTop skip:service only the chat report selection screen calls it; Horizon has no chat reporting
106 AbstractSelectionList.updateSizeAndPosition port crates/horizon-client/src/pack_screen.rs::List::update_size crates/horizon-client-render/src/pack_screen.rs::List::update_size
107 AbstractSelectionList.extractListSeparators port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list header and footer separators, with the in-world variant
108 AbstractSelectionList.extractListBackground port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list menu list background sprite
109 AbstractSelectionList.enableScissor port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list scissor clamped to the screen
110 AbstractSelectionList.scrollToEntry port crates/horizon-client/src/pack_screen.rs::List::scroll_to crates/horizon-client-render/src/pack_screen.rs::List::scroll_to
111 AbstractSelectionList.setFocused port crates/horizon-client/src/pack_screen.rs::PackScreen::set_focus crates/horizon-client-render/src/pack_screen.rs::PackScreen::set_focus gap: minor: focusing a row does not select it; vanilla selects the focused entry
112 AbstractSelectionList.nextEntry missing minor: arrow keys do not move the selection between rows in the pack or server lists
113 AbstractSelectionList.extractListItems port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list rows culled to the visible band
114 AbstractSelectionList.extractItem port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list selection outline and row content
115 AbstractSelectionList.extractSelection port crates/horizon-client/src/pack_screen.rs::PackScreen::draw_list crates/horizon-client-render/src/pack_screen.rs::PackScreen::draw_list two fills: outline colour and black inner
116 AbstractSelectionList.getRowBottom skip:other only the LAN-found narration uses it; Horizon has no narrator
117 AbstractSelectionList.narrationPriority skip:other screen-reader priority; Horizon has no narrator
118 AbstractSelectionList.removeEntry skip:other rows are rebuilt from the model when they change (update_list, server list), so there is no single-row removal
119 AbstractSelectionList.narrateListElementPosition skip:other narration only
120 AbstractSelectionList.TrackedList.set skip:java delegate list wrapper
121 AbstractSliderButton.getSprite inline crates/horizon-client/src/ui.rs::slider crates/horizon-client-render/src/ui.rs::slider gap: minor: track highlight follows hover only; keyboard focus does not highlight
122 AbstractSliderButton.getHandleSprite inline crates/horizon-client/src/ui.rs::slider crates/horizon-client-render/src/ui.rs::slider gap: minor: handle highlight follows hover only
123 AbstractSliderButton.updateWidgetNarration skip:other narration only
124 AbstractSliderButton.extractWidgetRenderState port crates/horizon-client/src/ui.rs::slider crates/horizon-client-render/src/ui.rs::slider gap: minor: the label is clipped rather than scrolled
125 AbstractSliderButton.handleCursor port crates/horizon-client/src/widgets.rs::widget_cursor crates/horizon-client-render/src/widgets.rs::widget_cursor gap: minor: no resize cursor while dragging
126 AbstractSliderButton.setFocused missing minor: keyboard focus does not enable value changes; there is no change-value state
127 AbstractSliderButton.keyPressed missing minor: Left and Right do not move a focused slider; Enter does not toggle it
128 AbstractSliderButton.setValue port crates/horizon-client/src/options_ui.rs::set_slider crates/horizon-client-render/src/options_ui.rs::set_slider gap: minor: the 0..1 clamp is done by the caller (ui.rs slider_value)
129 AbstractStringWidget.extractWidgetRenderState port crates/horizon-client/src/screen_draw.rs::string_widget crates/horizon-client-render/src/screen_draw.rs::string_widget gap: minor: hover tooltip and click cursor for styled text are not drawn
130 AbstractStringWidget.onClick missing minor: clicking a styled label with a click event does nothing here; book links and chat links do work
131 AbstractStringWidget.setMessage skip:ui width is measured at draw time
132 AbstractStringWidget.handleStyleClick missing minor: same as onClick: no click handling for labels
133 AbstractTextAreaWidget.mouseClicked port crates/horizon-client/src/game/books.rs::Game::book_page_click crates/horizon-client/src/game/books.rs::Game::book_page_click gap: minor: a scrollbar press inside the area is not checked
134 AbstractTextAreaWidget.keyPressed port crates/horizon-client/src/game/books.rs::Game::book_page_key crates/horizon-client/src/game/books.rs::Game::book_page_key gap: minor: up and down scroll the area in vanilla; not checked here
135 AbstractTextAreaWidget.extractWidgetRenderState port crates/horizon-client/src/game/books.rs::Game::draw_book crates/horizon-client/src/game/books.rs::Game::draw_book gap: minor: scroll offset inside the page not verified
136 AbstractTextAreaWidget.isMouseOver port crates/horizon-client/src/screen_draw.rs::inside crates/horizon-client-render/src/screen_draw.rs::inside gap: minor: the scrollbar width is not added to the hit area
137 AbstractTextAreaWidget.extractBackground skip:ui frame drawn by the book screen; no behaviour
138 AbstractTextAreaWidget.extractBorder skip:ui frame sprite; no behaviour
139 AbstractTextAreaWidget.withinContentAreaTopBottom skip:ui visibility cull while drawing lines
140 AbstractWidget.extractRenderState port crates/horizon-client/src/ui.rs::hovered crates/horizon-client-render/src/ui.rs::hovered gap: minor: the scissor test is not part of the hover check
141 AbstractWidget.extractTooltipForNextRenderPass port crates/horizon-client/src/ui.rs::tooltip crates/horizon-client-render/src/ui.rs::tooltip gap: minor: unsure: widget hover delay not checked
142 AbstractWidget.extractScrollingStringOverContents port crates/horizon-client/src/ui.rs::centered_text crates/horizon-client-render/src/ui.rs::centered_text gap: minor: text is clipped, not scrolled
143 AbstractWidget.mouseClicked port crates/horizon-client/src/title.rs::Title::click crates/horizon-client/src/title.rs::Title::click gap: minor: click dispatch is per screen; the press sound is audio.rs Audio::play_button_click
144 AbstractWidget.mouseReleased port crates/horizon-client/src/ui.rs::Scroll::release crates/horizon-client-render/src/ui.rs::Scroll::release gap: minor: only the scroll release; widget onRelease is per screen
145 AbstractWidget.mouseDragged port crates/horizon-client/src/ui.rs::Scroll::drag crates/horizon-client-render/src/ui.rs::Scroll::drag gap: minor: only scroll drag; widget onDrag is per screen
146 AbstractWidget.nextFocusPath missing minor: unsure: no per-widget focus path; Horizon focus is per screen
147 AbstractWidget.isMouseOver port crates/horizon-client/src/screen_draw.rs::inside crates/horizon-client-render/src/screen_draw.rs::inside gap: minor: isActive is checked by the caller
148 AbstractWidget.narrationPriority skip:other narration only
149 AbstractWidget.defaultButtonNarrationText skip:other narration only
+49 -49
View File
@@ -1,17 +1,17 @@
BossHealthOverlay.extractBar port crates/horizon-client/src/hud_overlays.rs::boss_overlay background bar, then progress at the lerped width; the notch overlay only when not PROGRESS
BossHealthOverlay.extractBar port crates/horizon-client-render/src/hud_overlays.rs::boss_overlay background bar, then progress at the lerped width; the notch overlay only when not PROGRESS
BossHealthOverlay.shouldDarkenScreen port crates/horizon-client/src/boss_overlay.rs::BossOverlay::should_darken any bar asks to darken
Button.Builder.build skip:java builder: makes a Plain button and sets its tooltip
ChatComponent.forEachLine port crates/horizon-client/src/chat.rs::Chat::layout visible lines bottom-up with the alpha filter, inlined in layout
ChatComponent.addMessageToDisplayQueue port crates/horizon-client/src/chat.rs::Chat::add_lines wrap at width/scale, keep the scroll when chatting, trim to 100 lines
ChatComponent.addMessageToQueue port crates/horizon-client/src/chat.rs::Chat::add_message newest first, trimmed to 100 messages
ChatComponent.forEachLine port crates/horizon-client-render/src/chat.rs::Chat::layout visible lines bottom-up with the alpha filter, inlined in layout
ChatComponent.addMessageToDisplayQueue port crates/horizon-client-render/src/chat.rs::Chat::add_lines wrap at width/scale, keep the scroll when chatting, trim to 100 lines
ChatComponent.addMessageToQueue port crates/horizon-client-render/src/chat.rs::Chat::add_message newest first, trimmed to 100 messages
ChatComponent.processMessageDeletionQueue missing player: a message the server deletes stays in chat; the delete-chat packet is only named in horizon-protocol/src/ids.rs and never decoded
ChatComponent.deleteMessage missing player: a server message delete does nothing in Horizon; the removed line stays visible
ChatComponent.deleteMessageOrDelay missing player: no 60-tick delayed removal and no deleted marker; see deleteMessage
ChatComponent.refreshTrimmedMessages port crates/horizon-client/src/chat.rs::Chat::rewrap gap: minor: rewrap also resets the scroll to 0; vanilla keeps the position
ChatComponent.scrollChat port crates/horizon-client/src/chat.rs::Chat::scroll_by clamp to the page and clear new-message marker at the bottom
ChatComponent.getHeight port crates/horizon-client/src/chat.rs::ChatOptions::height_px focused or unfocused chat height in px
ChatComponent.defaultUnfocusedPct inline crates/horizon-client/src/chat.rs::ChatOptions::default the default 70/160 is stored as a constant, not computed from the height formula
ChatComponent.getLineHeight port crates/horizon-client/src/chat.rs::ChatOptions::line_height 9 * (line spacing + 1)
ChatComponent.refreshTrimmedMessages port crates/horizon-client-render/src/chat.rs::Chat::rewrap gap: minor: rewrap also resets the scroll to 0; vanilla keeps the position
ChatComponent.scrollChat port crates/horizon-client-render/src/chat.rs::Chat::scroll_by clamp to the page and clear new-message marker at the bottom
ChatComponent.getHeight port crates/horizon-client-render/src/chat.rs::ChatOptions::height_px focused or unfocused chat height in px
ChatComponent.defaultUnfocusedPct inline crates/horizon-client-render/src/chat.rs::ChatOptions::default the default 70/160 is stored as a constant, not computed from the height formula
ChatComponent.getLineHeight port crates/horizon-client-render/src/chat.rs::ChatOptions::line_height 9 * (line spacing + 1)
ChatComponent.saveAsDraft missing player: Save Chat Drafts does nothing (options_ui.rs notes no drafts yet); text left in the box is not kept for the next open
ChatComponent.createScreen port crates/horizon-client/src/game/chat.rs::Game::open_chat gap: player: no draft is restored; the chat opens with the initial text its caller passes
ChatComponent.preserveCurrentChatScreen missing minor: unsure: Horizon keeps no chat screen across a dimension change; game/nether_portal.rs:577 only leaves Chat alone during a portal effect, the change path was not checked
@@ -19,12 +19,12 @@ ChatComponent.storeState inline crates/horizon-client/src/game/remote.rs::Game::
ChatComponent.restoreState inline crates/horizon-client/src/game/remote.rs::Game::poll_remote no restore: the chat is never cleared on Reconfigured, so there is nothing to put back
ChatComponent.ClickableTextOnlyGraphicsAccess.updatePose skip:ui pose bookkeeping of the text collector; chat draws with its own scale and translate
ChatComponent.DrawingBackgroundGraphicsAccess.updatePose skip:ui pose bookkeeping of the text collector; chat draws with its own scale and translate
ChatComponent.DrawingBackgroundGraphicsAccess.handleMessage port crates/horizon-client/src/chat.rs::Chat::layout line text drawn at its bottom with the text opacity
ChatComponent.DrawingBackgroundGraphicsAccess.handleTag port crates/horizon-client/src/chat.rs::Chat::layout indicator bar filled from x -4 to -2 with the line alpha
ChatComponent.DrawingFocusedGraphicsAccess.updateLocalMousePos inline crates/horizon-client/src/chat.rs::Chat::line_at the mouse mapped into line space inside line_at
ChatComponent.DrawingBackgroundGraphicsAccess.handleMessage port crates/horizon-client-render/src/chat.rs::Chat::layout line text drawn at its bottom with the text opacity
ChatComponent.DrawingBackgroundGraphicsAccess.handleTag port crates/horizon-client-render/src/chat.rs::Chat::layout indicator bar filled from x -4 to -2 with the line alpha
ChatComponent.DrawingFocusedGraphicsAccess.updateLocalMousePos inline crates/horizon-client-render/src/chat.rs::Chat::line_at the mouse mapped into line space inside line_at
ChatComponent.DrawingFocusedGraphicsAccess.updatePose skip:ui pose bookkeeping; the mouse mapping is done in Chat::line_at
ChatComponent.DrawingFocusedGraphicsAccess.handleMessage port crates/horizon-client/src/chat.rs::Chat::style_at gap: player: no pointing-hand cursor over clickable chat text; only widgets set the cursor (widgets.rs:28)
ChatComponent.DrawingFocusedGraphicsAccess.isMouseOver inline crates/horizon-client/src/chat.rs::Chat::indicator_at the rectangle test of the indicator bar; tag icons are not drawn
ChatComponent.DrawingFocusedGraphicsAccess.handleMessage port crates/horizon-client-render/src/chat.rs::Chat::style_at gap: player: no pointing-hand cursor over clickable chat text; only widgets set the cursor (widgets.rs:28)
ChatComponent.DrawingFocusedGraphicsAccess.isMouseOver inline crates/horizon-client-render/src/chat.rs::Chat::indicator_at the rectangle test of the indicator bar; tag icons are not drawn
ChatComponent.DrawingFocusedGraphicsAccess.handleTagIcon missing minor: no tag icons; Horizon never tags a message as modified, so the Modified icon never shows
ChatComponent.DrawingFocusedGraphicsAccess.showTooltip port crates/horizon-client/src/game/chat.rs::Game::draw_chat_screen gap: minor: every indicator shows the systemSinglePlayer text as its tooltip
Checkbox.adjustWidth missing minor: the checkbox width is never capped or its label wrapped; dialog_screen.rs:137 sets the width to the full label
@@ -34,26 +34,26 @@ Checkbox.updateWidgetNarration skip:other narration text; Horizon has no narrat
Checkbox.extractContents port crates/horizon-client/src/game/dialogs.rs::Game::draw_dialog box sprite for checked and focused states, then the label (Part::Check)
Checkbox.Builder.selected skip:java builder setter
Checkbox.Builder.build skip:java builder: makes the checkbox and its tooltip
CommandSuggestions.mouseScrolled port crates/horizon-client/src/chat.rs::ChatScreen::scroll wheel over the suggestion list, clamped to the list
CommandSuggestions.mouseClicked port crates/horizon-client/src/chat.rs::ChatScreen::click click on a suggestion row uses it, else the input box
CommandSuggestions.mouseScrolled port crates/horizon-client-render/src/chat.rs::ChatScreen::scroll wheel over the suggestion list, clamped to the list
CommandSuggestions.mouseClicked port crates/horizon-client-render/src/chat.rs::ChatScreen::click click on a suggestion row uses it, else the input box
CommandSuggestions.getUsageNarration skip:other narration text; no narrator in Horizon
CommandSuggestions.sortSuggestions port crates/horizon-client/src/chat.rs::ChatScreen::show_suggestions suggestions starting with the typed word first, including the minecraft: prefix
CommandSuggestions.sortSuggestions port crates/horizon-client-render/src/chat.rs::ChatScreen::show_suggestions suggestions starting with the typed word first, including the minecraft: prefix
CommandSuggestions.hasMessageArguments missing minor: a /say or /msg style command with a message argument counts as a command here; Horizon's parse keeps no argument kinds (see update_usage_info comment)
CommandSuggestions.getExceptionMessage port crates/horizon-client/src/chat.rs::ChatScreen::update_usage_info parse errors shown with their context (e.with_context)
CommandSuggestions.fillNodeUsage port crates/horizon-client/src/chat.rs::ChatScreen::update_usage_info smart usage lines, without the literal nodes
CommandSuggestions.recomputeUsageBoxWidth port crates/horizon-client/src/chat.rs::ChatScreen::update_usage_info usage width is the widest line
CommandSuggestions.formatChat port crates/horizon-client/src/chat.rs::ChatScreen::format argument colours over the input
CommandSuggestions.calculateSuggestionSuffix port crates/horizon-client/src/chat.rs::ChatScreen::select the grey suffix for the highlighted suggestion (strip the typed prefix)
CommandSuggestions.extractSuggestions port crates/horizon-client/src/chat.rs::ChatScreen::draw the suggestion list drawn when it is open
CommandSuggestions.extractUsage port crates/horizon-client/src/chat.rs::ChatScreen::draw usage lines drawn upward from the bottom, as vanilla's bottom anchor
CommandSuggestions.getExceptionMessage port crates/horizon-client-render/src/chat.rs::ChatScreen::update_usage_info parse errors shown with their context (e.with_context)
CommandSuggestions.fillNodeUsage port crates/horizon-client-render/src/chat.rs::ChatScreen::update_usage_info smart usage lines, without the literal nodes
CommandSuggestions.recomputeUsageBoxWidth port crates/horizon-client-render/src/chat.rs::ChatScreen::update_usage_info usage width is the widest line
CommandSuggestions.formatChat port crates/horizon-client-render/src/chat.rs::ChatScreen::format argument colours over the input
CommandSuggestions.calculateSuggestionSuffix port crates/horizon-client-render/src/chat.rs::ChatScreen::select the grey suffix for the highlighted suggestion (strip the typed prefix)
CommandSuggestions.extractSuggestions port crates/horizon-client-render/src/chat.rs::ChatScreen::draw the suggestion list drawn when it is open
CommandSuggestions.extractUsage port crates/horizon-client-render/src/chat.rs::ChatScreen::draw usage lines drawn upward from the bottom, as vanilla's bottom anchor
CommandSuggestions.getNarrationMessage skip:other narration text; no narrator in Horizon
CommandSuggestions.hasAllowedInput port crates/horizon-client/src/chat.rs::ChatAbilities::allows gap: minor: a /say style command is judged as a command, not a message (see hasMessageArguments)
CommandSuggestions.SuggestionsList.extractRenderState port crates/horizon-client/src/chat.rs::ChatScreen::draw_list rows, scroll marks, highlight and tooltip; gap: minor: no pointing-hand cursor over the rows
CommandSuggestions.SuggestionsList.mouseClicked port crates/horizon-client/src/chat.rs::ChatScreen::click row click selects and uses the suggestion
CommandSuggestions.SuggestionsList.keyPressed port crates/horizon-client/src/chat.rs::ChatScreen::key up, down and tab cycle and use the suggestion
CommandSuggestions.SuggestionsList.cycle port crates/horizon-client/src/chat.rs::ChatScreen::cycle moves the selection and the scroll offset
CommandSuggestions.hasAllowedInput port crates/horizon-client-render/src/chat.rs::ChatAbilities::allows gap: minor: a /say style command is judged as a command, not a message (see hasMessageArguments)
CommandSuggestions.SuggestionsList.extractRenderState port crates/horizon-client-render/src/chat.rs::ChatScreen::draw_list rows, scroll marks, highlight and tooltip; gap: minor: no pointing-hand cursor over the rows
CommandSuggestions.SuggestionsList.mouseClicked port crates/horizon-client-render/src/chat.rs::ChatScreen::click row click selects and uses the suggestion
CommandSuggestions.SuggestionsList.keyPressed port crates/horizon-client-render/src/chat.rs::ChatScreen::key up, down and tab cycle and use the suggestion
CommandSuggestions.SuggestionsList.cycle port crates/horizon-client-render/src/chat.rs::ChatScreen::cycle moves the selection and the scroll offset
CommandSuggestions.SuggestionsList.getNarrationMessage skip:other narration text; no narrator in Horizon
ComponentRenderUtils.stripColor port crates/horizon-client/src/chat.rs::Chat::displayed with Chat Colors off the section codes are stripped before wrapping
ComponentRenderUtils.stripColor port crates/horizon-client-render/src/chat.rs::Chat::displayed with Chat Colors off the section codes are stripped before wrapping
ContainerObjectSelectionList.nextFocusPath port crates/horizon-client-input/src/gamepad.rs::focus_step gap: minor: picks the nearest target by geometry, not row by row with a wrap to the next entry
ContainerObjectSelectionList.setFocused missing minor: unsure: no list focus model beyond gamepad focus_step; losing focus does not clear a selection here
ContainerObjectSelectionList.updateWidgetNarration skip:other narration text; no narrator in Horizon
@@ -61,12 +61,12 @@ ContainerObjectSelectionList.Entry.setFocused missing minor: unsure: focus insi
ContainerObjectSelectionList.Entry.focusPathAtIndex missing minor: unsure: no per-row focus path; see focus_step
ContainerObjectSelectionList.Entry.nextFocusPath port crates/horizon-client-input/src/gamepad.rs::focus_step gap: minor: moves by nearest target rectangle, not by child index within the row
ContainerObjectSelectionList.Entry.updateNarration skip:other narration text; no narrator in Horizon
CycleButton.extractContents port crates/horizon-client/src/options_ui.rs::OptionsUi::draw option button sprite and its label
CycleButton.onPress port crates/horizon-client/src/options_ui.rs::Opt::cycle click cycles forward; the back flag comes from the caller
CycleButton.extractContents port crates/horizon-client-render/src/options_ui.rs::OptionsUi::draw option button sprite and its label
CycleButton.onPress port crates/horizon-client-render/src/options_ui.rs::Opt::cycle click cycles forward; the back flag comes from the caller
CycleButton.getCycledValue skip:other only feeds the narration of the next value
CycleButton.mouseScrolled missing player: the mouse wheel over an option button does not change its value; OptionsUi::scroll_at only scrolls the list
CycleButton.updateValue inline crates/horizon-client/src/options_ui.rs::Opt::cycle labels are read live from Settings (Opt::label), so no cached message needs updating
CycleButton.createLabelForValue port crates/horizon-client/src/options_ui.rs::Opt::label value label or full name, from the setting
CycleButton.updateValue inline crates/horizon-client-render/src/options_ui.rs::Opt::cycle labels are read live from Settings (Opt::label), so no cached message needs updating
CycleButton.createLabelForValue port crates/horizon-client-render/src/options_ui.rs::Opt::label value label or full name, from the setting
CycleButton.updateWidgetNarration skip:other narration text; no narrator in Horizon
CycleButton.createDefaultNarrationMessage skip:other narration text; no narrator in Horizon
CycleButton.builder skip:java builder
@@ -93,18 +93,18 @@ DebugScreenOverlay.toggleLightmapTexture port crates/horizon-client/src/debug_ch
DebugScreenOverlay.toggleProfilerChart missing minor: no profiler chart (see showProfilerChart)
DebugScreenOverlay.logRemoteSample missing minor: unsure: the debug_sample packet is only named in horizon-protocol/src/ids.rs, so a server's samples are not logged
EditBox.createNarrationMessage skip:other narration text; no narrator in Horizon
EditBox.getHighlighted port crates/horizon-client/src/ui.rs::EditBox::selected_text the text between cursor and highlight
EditBox.moveCursorTo port crates/horizon-client/src/ui.rs::EditBox::set_cursor sets the cursor and keeps the highlight unless extending
EditBox.setCursorPosition port crates/horizon-client/src/ui.rs::EditBox::set_cursor clamps and scrolls to the cursor
EditBox.getHighlighted port crates/horizon-client-render/src/ui.rs::EditBox::selected_text the text between cursor and highlight
EditBox.moveCursorTo port crates/horizon-client-render/src/ui.rs::EditBox::set_cursor sets the cursor and keeps the highlight unless extending
EditBox.setCursorPosition port crates/horizon-client-render/src/ui.rs::EditBox::set_cursor clamps and scrolls to the cursor
EditBox.canConsumeInput missing minor: unsure: no editable flag on the box; whether a box takes typed input is the caller's focus routing
EditBox.preeditUpdated missing minor: no IME composition; Horizon has no preedit input
EditBox.selectWord port crates/horizon-client/src/ui.rs::EditBox::click a double click selects the word (the double flag)
EditBox.applyFormat port crates/horizon-client/src/ui.rs::EditBox::draw the format text passed to draw
EditBox.updateTextPosition port crates/horizon-client/src/ui.rs::EditBox::text_x text_x of the shown part; text_y is its sibling
EditBox.setMaxLength port crates/horizon-client/src/ui.rs::Caret::sync gap: minor: sets the limit only; a longer value is not cut to it
EditBox.setFocused port crates/horizon-client/src/ui.rs::Caret::draw focus restarts the blink clock here; gap: minor: no IME or narration side effects
EditBox.selectWord port crates/horizon-client-render/src/ui.rs::EditBox::click a double click selects the word (the double flag)
EditBox.applyFormat port crates/horizon-client-render/src/ui.rs::EditBox::draw the format text passed to draw
EditBox.updateTextPosition port crates/horizon-client-render/src/ui.rs::EditBox::text_x text_x of the shown part; text_y is its sibling
EditBox.setMaxLength port crates/horizon-client-render/src/ui.rs::Caret::sync gap: minor: sets the limit only; a longer value is not cut to it
EditBox.setFocused port crates/horizon-client-render/src/ui.rs::Caret::draw focus restarts the blink clock here; gap: minor: no IME or narration side effects
EditBox.setEditable missing minor: unsure: no read-only flag on the box in ui.rs; a box vanilla locks would accept typing
EditBox.setHighlightPos port crates/horizon-client/src/ui.rs::EditBox::set_cursor sets the highlight and scrolls
EditBox.setHighlightPos port crates/horizon-client-render/src/ui.rs::EditBox::set_cursor sets the highlight and scrolls
EditBox.setHint inline crates/horizon-client/src/title/create_world.rs::Title::create_field the hint is passed when the box is made and drawn while it is empty and unfocused
FittingMultiLineTextWidget.setWidth skip:ui layout: wrap width
FittingMultiLineTextWidget.minimizeHeight skip:ui layout: height to content
@@ -130,15 +130,15 @@ LockIconButton.createNarrationMessage skip:other narration text; no narrator in
LockIconButton.extractContents port crates/horizon-client/src/game/lan_screen.rs::Game::draw_options_view lock or unlock sprite by state
LogoRenderer.extractRenderState port crates/horizon-client/src/title.rs::Title::draw logo top 44 rows and edition banner; gap: minor: no easter-egg logo variant
MultiLineEditBox.updateWidgetNarration skip:other narration text; no narrator in Horizon
MultiLineEditBox.onClick port crates/horizon-client/src/screen_draw.rs::TextField::click click places the cursor; gap: minor: no double-click word select
MultiLineEditBox.onClick port crates/horizon-client-render/src/screen_draw.rs::TextField::click click places the cursor; gap: minor: no double-click word select
MultiLineEditBox.onDrag missing minor: unsure: TextField has no drag selection in screen_draw.rs
MultiLineEditBox.charTyped port crates/horizon-client/src/screen_draw.rs::TextField::insert_text typed text replaces the selection or goes at the cursor
MultiLineEditBox.charTyped port crates/horizon-client-render/src/screen_draw.rs::TextField::insert_text typed text replaces the selection or goes at the cursor
MultiLineEditBox.preeditUpdated missing minor: no IME composition; Horizon has no preedit input
MultiLineEditBox.extractContents port crates/horizon-client/src/screen_draw.rs::TextField::draw placeholder, lines, caret and selection highlight
MultiLineEditBox.extractContents port crates/horizon-client-render/src/screen_draw.rs::TextField::draw placeholder, lines, caret and selection highlight
MultiLineEditBox.extractDecorations missing minor: no character count under a limited box; TextField has no limit
MultiLineEditBox.scrollToCursor port crates/horizon-client/src/screen_draw.rs::TextField::scroll_to keeps the cursor line in view
MultiLineEditBox.seekCursorScreen port crates/horizon-client/src/screen_draw.rs::TextField::click maps the pointer to a cursor position
MultiLineEditBox.setFocused inline crates/horizon-client/src/screen_draw.rs::TextField::draw gap: minor: focus does not restart the caret blink here; the caller passes the blink clock
MultiLineEditBox.scrollToCursor port crates/horizon-client-render/src/screen_draw.rs::TextField::scroll_to keeps the cursor line in view
MultiLineEditBox.seekCursorScreen port crates/horizon-client-render/src/screen_draw.rs::TextField::click maps the pointer to a cursor position
MultiLineEditBox.setFocused inline crates/horizon-client-render/src/screen_draw.rs::TextField::draw gap: minor: focus does not restart the caret blink here; the caller passes the blink clock
MultiLineEditBox.Builder.build skip:java builder
MultiLineTextWidget.getHeight skip:ui layout: wrapped line count times 9; Measure::split does the wrap when drawing
MultiLineTextWidget.getFreshCacheKey skip:java cache key for the wrapped lines
1 BossHealthOverlay.extractBar port crates/horizon-client/src/hud_overlays.rs::boss_overlay crates/horizon-client-render/src/hud_overlays.rs::boss_overlay background bar, then progress at the lerped width; the notch overlay only when not PROGRESS
2 BossHealthOverlay.shouldDarkenScreen port crates/horizon-client/src/boss_overlay.rs::BossOverlay::should_darken crates/horizon-client/src/boss_overlay.rs::BossOverlay::should_darken any bar asks to darken
3 Button.Builder.build skip:java builder: makes a Plain button and sets its tooltip
4 ChatComponent.forEachLine port crates/horizon-client/src/chat.rs::Chat::layout crates/horizon-client-render/src/chat.rs::Chat::layout visible lines bottom-up with the alpha filter, inlined in layout
5 ChatComponent.addMessageToDisplayQueue port crates/horizon-client/src/chat.rs::Chat::add_lines crates/horizon-client-render/src/chat.rs::Chat::add_lines wrap at width/scale, keep the scroll when chatting, trim to 100 lines
6 ChatComponent.addMessageToQueue port crates/horizon-client/src/chat.rs::Chat::add_message crates/horizon-client-render/src/chat.rs::Chat::add_message newest first, trimmed to 100 messages
7 ChatComponent.processMessageDeletionQueue missing player: a message the server deletes stays in chat; the delete-chat packet is only named in horizon-protocol/src/ids.rs and never decoded
8 ChatComponent.deleteMessage missing player: a server message delete does nothing in Horizon; the removed line stays visible
9 ChatComponent.deleteMessageOrDelay missing player: no 60-tick delayed removal and no deleted marker; see deleteMessage
10 ChatComponent.refreshTrimmedMessages port crates/horizon-client/src/chat.rs::Chat::rewrap crates/horizon-client-render/src/chat.rs::Chat::rewrap gap: minor: rewrap also resets the scroll to 0; vanilla keeps the position
11 ChatComponent.scrollChat port crates/horizon-client/src/chat.rs::Chat::scroll_by crates/horizon-client-render/src/chat.rs::Chat::scroll_by clamp to the page and clear new-message marker at the bottom
12 ChatComponent.getHeight port crates/horizon-client/src/chat.rs::ChatOptions::height_px crates/horizon-client-render/src/chat.rs::ChatOptions::height_px focused or unfocused chat height in px
13 ChatComponent.defaultUnfocusedPct inline crates/horizon-client/src/chat.rs::ChatOptions::default crates/horizon-client-render/src/chat.rs::ChatOptions::default the default 70/160 is stored as a constant, not computed from the height formula
14 ChatComponent.getLineHeight port crates/horizon-client/src/chat.rs::ChatOptions::line_height crates/horizon-client-render/src/chat.rs::ChatOptions::line_height 9 * (line spacing + 1)
15 ChatComponent.saveAsDraft missing player: Save Chat Drafts does nothing (options_ui.rs notes no drafts yet); text left in the box is not kept for the next open
16 ChatComponent.createScreen port crates/horizon-client/src/game/chat.rs::Game::open_chat crates/horizon-client/src/game/chat.rs::Game::open_chat gap: player: no draft is restored; the chat opens with the initial text its caller passes
17 ChatComponent.preserveCurrentChatScreen missing minor: unsure: Horizon keeps no chat screen across a dimension change; game/nether_portal.rs:577 only leaves Chat alone during a portal effect, the change path was not checked
19 ChatComponent.restoreState inline crates/horizon-client/src/game/remote.rs::Game::poll_remote crates/horizon-client/src/game/remote.rs::Game::poll_remote no restore: the chat is never cleared on Reconfigured, so there is nothing to put back
20 ChatComponent.ClickableTextOnlyGraphicsAccess.updatePose skip:ui pose bookkeeping of the text collector; chat draws with its own scale and translate
21 ChatComponent.DrawingBackgroundGraphicsAccess.updatePose skip:ui pose bookkeeping of the text collector; chat draws with its own scale and translate
22 ChatComponent.DrawingBackgroundGraphicsAccess.handleMessage port crates/horizon-client/src/chat.rs::Chat::layout crates/horizon-client-render/src/chat.rs::Chat::layout line text drawn at its bottom with the text opacity
23 ChatComponent.DrawingBackgroundGraphicsAccess.handleTag port crates/horizon-client/src/chat.rs::Chat::layout crates/horizon-client-render/src/chat.rs::Chat::layout indicator bar filled from x -4 to -2 with the line alpha
24 ChatComponent.DrawingFocusedGraphicsAccess.updateLocalMousePos inline crates/horizon-client/src/chat.rs::Chat::line_at crates/horizon-client-render/src/chat.rs::Chat::line_at the mouse mapped into line space inside line_at
25 ChatComponent.DrawingFocusedGraphicsAccess.updatePose skip:ui pose bookkeeping; the mouse mapping is done in Chat::line_at
26 ChatComponent.DrawingFocusedGraphicsAccess.handleMessage port crates/horizon-client/src/chat.rs::Chat::style_at crates/horizon-client-render/src/chat.rs::Chat::style_at gap: player: no pointing-hand cursor over clickable chat text; only widgets set the cursor (widgets.rs:28)
27 ChatComponent.DrawingFocusedGraphicsAccess.isMouseOver inline crates/horizon-client/src/chat.rs::Chat::indicator_at crates/horizon-client-render/src/chat.rs::Chat::indicator_at the rectangle test of the indicator bar; tag icons are not drawn
28 ChatComponent.DrawingFocusedGraphicsAccess.handleTagIcon missing minor: no tag icons; Horizon never tags a message as modified, so the Modified icon never shows
29 ChatComponent.DrawingFocusedGraphicsAccess.showTooltip port crates/horizon-client/src/game/chat.rs::Game::draw_chat_screen crates/horizon-client/src/game/chat.rs::Game::draw_chat_screen gap: minor: every indicator shows the systemSinglePlayer text as its tooltip
30 Checkbox.adjustWidth missing minor: the checkbox width is never capped or its label wrapped; dialog_screen.rs:137 sets the width to the full label
34 Checkbox.extractContents port crates/horizon-client/src/game/dialogs.rs::Game::draw_dialog crates/horizon-client/src/game/dialogs.rs::Game::draw_dialog box sprite for checked and focused states, then the label (Part::Check)
35 Checkbox.Builder.selected skip:java builder setter
36 Checkbox.Builder.build skip:java builder: makes the checkbox and its tooltip
37 CommandSuggestions.mouseScrolled port crates/horizon-client/src/chat.rs::ChatScreen::scroll crates/horizon-client-render/src/chat.rs::ChatScreen::scroll wheel over the suggestion list, clamped to the list
38 CommandSuggestions.mouseClicked port crates/horizon-client/src/chat.rs::ChatScreen::click crates/horizon-client-render/src/chat.rs::ChatScreen::click click on a suggestion row uses it, else the input box
39 CommandSuggestions.getUsageNarration skip:other narration text; no narrator in Horizon
40 CommandSuggestions.sortSuggestions port crates/horizon-client/src/chat.rs::ChatScreen::show_suggestions crates/horizon-client-render/src/chat.rs::ChatScreen::show_suggestions suggestions starting with the typed word first, including the minecraft: prefix
41 CommandSuggestions.hasMessageArguments missing minor: a /say or /msg style command with a message argument counts as a command here; Horizon's parse keeps no argument kinds (see update_usage_info comment)
42 CommandSuggestions.getExceptionMessage port crates/horizon-client/src/chat.rs::ChatScreen::update_usage_info crates/horizon-client-render/src/chat.rs::ChatScreen::update_usage_info parse errors shown with their context (e.with_context)
43 CommandSuggestions.fillNodeUsage port crates/horizon-client/src/chat.rs::ChatScreen::update_usage_info crates/horizon-client-render/src/chat.rs::ChatScreen::update_usage_info smart usage lines, without the literal nodes
44 CommandSuggestions.recomputeUsageBoxWidth port crates/horizon-client/src/chat.rs::ChatScreen::update_usage_info crates/horizon-client-render/src/chat.rs::ChatScreen::update_usage_info usage width is the widest line
45 CommandSuggestions.formatChat port crates/horizon-client/src/chat.rs::ChatScreen::format crates/horizon-client-render/src/chat.rs::ChatScreen::format argument colours over the input
46 CommandSuggestions.calculateSuggestionSuffix port crates/horizon-client/src/chat.rs::ChatScreen::select crates/horizon-client-render/src/chat.rs::ChatScreen::select the grey suffix for the highlighted suggestion (strip the typed prefix)
47 CommandSuggestions.extractSuggestions port crates/horizon-client/src/chat.rs::ChatScreen::draw crates/horizon-client-render/src/chat.rs::ChatScreen::draw the suggestion list drawn when it is open
48 CommandSuggestions.extractUsage port crates/horizon-client/src/chat.rs::ChatScreen::draw crates/horizon-client-render/src/chat.rs::ChatScreen::draw usage lines drawn upward from the bottom, as vanilla's bottom anchor
49 CommandSuggestions.getNarrationMessage skip:other narration text; no narrator in Horizon
50 CommandSuggestions.hasAllowedInput port crates/horizon-client/src/chat.rs::ChatAbilities::allows crates/horizon-client-render/src/chat.rs::ChatAbilities::allows gap: minor: a /say style command is judged as a command, not a message (see hasMessageArguments)
51 CommandSuggestions.SuggestionsList.extractRenderState port crates/horizon-client/src/chat.rs::ChatScreen::draw_list crates/horizon-client-render/src/chat.rs::ChatScreen::draw_list rows, scroll marks, highlight and tooltip; gap: minor: no pointing-hand cursor over the rows
52 CommandSuggestions.SuggestionsList.mouseClicked port crates/horizon-client/src/chat.rs::ChatScreen::click crates/horizon-client-render/src/chat.rs::ChatScreen::click row click selects and uses the suggestion
53 CommandSuggestions.SuggestionsList.keyPressed port crates/horizon-client/src/chat.rs::ChatScreen::key crates/horizon-client-render/src/chat.rs::ChatScreen::key up, down and tab cycle and use the suggestion
54 CommandSuggestions.SuggestionsList.cycle port crates/horizon-client/src/chat.rs::ChatScreen::cycle crates/horizon-client-render/src/chat.rs::ChatScreen::cycle moves the selection and the scroll offset
55 CommandSuggestions.SuggestionsList.getNarrationMessage skip:other narration text; no narrator in Horizon
56 ComponentRenderUtils.stripColor port crates/horizon-client/src/chat.rs::Chat::displayed crates/horizon-client-render/src/chat.rs::Chat::displayed with Chat Colors off the section codes are stripped before wrapping
57 ContainerObjectSelectionList.nextFocusPath port crates/horizon-client-input/src/gamepad.rs::focus_step crates/horizon-client-input/src/gamepad.rs::focus_step gap: minor: picks the nearest target by geometry, not row by row with a wrap to the next entry
58 ContainerObjectSelectionList.setFocused missing minor: unsure: no list focus model beyond gamepad focus_step; losing focus does not clear a selection here
59 ContainerObjectSelectionList.updateWidgetNarration skip:other narration text; no narrator in Horizon
61 ContainerObjectSelectionList.Entry.focusPathAtIndex missing minor: unsure: no per-row focus path; see focus_step
62 ContainerObjectSelectionList.Entry.nextFocusPath port crates/horizon-client-input/src/gamepad.rs::focus_step crates/horizon-client-input/src/gamepad.rs::focus_step gap: minor: moves by nearest target rectangle, not by child index within the row
63 ContainerObjectSelectionList.Entry.updateNarration skip:other narration text; no narrator in Horizon
64 CycleButton.extractContents port crates/horizon-client/src/options_ui.rs::OptionsUi::draw crates/horizon-client-render/src/options_ui.rs::OptionsUi::draw option button sprite and its label
65 CycleButton.onPress port crates/horizon-client/src/options_ui.rs::Opt::cycle crates/horizon-client-render/src/options_ui.rs::Opt::cycle click cycles forward; the back flag comes from the caller
66 CycleButton.getCycledValue skip:other only feeds the narration of the next value
67 CycleButton.mouseScrolled missing player: the mouse wheel over an option button does not change its value; OptionsUi::scroll_at only scrolls the list
68 CycleButton.updateValue inline crates/horizon-client/src/options_ui.rs::Opt::cycle crates/horizon-client-render/src/options_ui.rs::Opt::cycle labels are read live from Settings (Opt::label), so no cached message needs updating
69 CycleButton.createLabelForValue port crates/horizon-client/src/options_ui.rs::Opt::label crates/horizon-client-render/src/options_ui.rs::Opt::label value label or full name, from the setting
70 CycleButton.updateWidgetNarration skip:other narration text; no narrator in Horizon
71 CycleButton.createDefaultNarrationMessage skip:other narration text; no narrator in Horizon
72 CycleButton.builder skip:java builder
93 DebugScreenOverlay.toggleProfilerChart missing minor: no profiler chart (see showProfilerChart)
94 DebugScreenOverlay.logRemoteSample missing minor: unsure: the debug_sample packet is only named in horizon-protocol/src/ids.rs, so a server's samples are not logged
95 EditBox.createNarrationMessage skip:other narration text; no narrator in Horizon
96 EditBox.getHighlighted port crates/horizon-client/src/ui.rs::EditBox::selected_text crates/horizon-client-render/src/ui.rs::EditBox::selected_text the text between cursor and highlight
97 EditBox.moveCursorTo port crates/horizon-client/src/ui.rs::EditBox::set_cursor crates/horizon-client-render/src/ui.rs::EditBox::set_cursor sets the cursor and keeps the highlight unless extending
98 EditBox.setCursorPosition port crates/horizon-client/src/ui.rs::EditBox::set_cursor crates/horizon-client-render/src/ui.rs::EditBox::set_cursor clamps and scrolls to the cursor
99 EditBox.canConsumeInput missing minor: unsure: no editable flag on the box; whether a box takes typed input is the caller's focus routing
100 EditBox.preeditUpdated missing minor: no IME composition; Horizon has no preedit input
101 EditBox.selectWord port crates/horizon-client/src/ui.rs::EditBox::click crates/horizon-client-render/src/ui.rs::EditBox::click a double click selects the word (the double flag)
102 EditBox.applyFormat port crates/horizon-client/src/ui.rs::EditBox::draw crates/horizon-client-render/src/ui.rs::EditBox::draw the format text passed to draw
103 EditBox.updateTextPosition port crates/horizon-client/src/ui.rs::EditBox::text_x crates/horizon-client-render/src/ui.rs::EditBox::text_x text_x of the shown part; text_y is its sibling
104 EditBox.setMaxLength port crates/horizon-client/src/ui.rs::Caret::sync crates/horizon-client-render/src/ui.rs::Caret::sync gap: minor: sets the limit only; a longer value is not cut to it
105 EditBox.setFocused port crates/horizon-client/src/ui.rs::Caret::draw crates/horizon-client-render/src/ui.rs::Caret::draw focus restarts the blink clock here; gap: minor: no IME or narration side effects
106 EditBox.setEditable missing minor: unsure: no read-only flag on the box in ui.rs; a box vanilla locks would accept typing
107 EditBox.setHighlightPos port crates/horizon-client/src/ui.rs::EditBox::set_cursor crates/horizon-client-render/src/ui.rs::EditBox::set_cursor sets the highlight and scrolls
108 EditBox.setHint inline crates/horizon-client/src/title/create_world.rs::Title::create_field crates/horizon-client/src/title/create_world.rs::Title::create_field the hint is passed when the box is made and drawn while it is empty and unfocused
109 FittingMultiLineTextWidget.setWidth skip:ui layout: wrap width
110 FittingMultiLineTextWidget.minimizeHeight skip:ui layout: height to content
130 LockIconButton.extractContents port crates/horizon-client/src/game/lan_screen.rs::Game::draw_options_view crates/horizon-client/src/game/lan_screen.rs::Game::draw_options_view lock or unlock sprite by state
131 LogoRenderer.extractRenderState port crates/horizon-client/src/title.rs::Title::draw crates/horizon-client/src/title.rs::Title::draw logo top 44 rows and edition banner; gap: minor: no easter-egg logo variant
132 MultiLineEditBox.updateWidgetNarration skip:other narration text; no narrator in Horizon
133 MultiLineEditBox.onClick port crates/horizon-client/src/screen_draw.rs::TextField::click crates/horizon-client-render/src/screen_draw.rs::TextField::click click places the cursor; gap: minor: no double-click word select
134 MultiLineEditBox.onDrag missing minor: unsure: TextField has no drag selection in screen_draw.rs
135 MultiLineEditBox.charTyped port crates/horizon-client/src/screen_draw.rs::TextField::insert_text crates/horizon-client-render/src/screen_draw.rs::TextField::insert_text typed text replaces the selection or goes at the cursor
136 MultiLineEditBox.preeditUpdated missing minor: no IME composition; Horizon has no preedit input
137 MultiLineEditBox.extractContents port crates/horizon-client/src/screen_draw.rs::TextField::draw crates/horizon-client-render/src/screen_draw.rs::TextField::draw placeholder, lines, caret and selection highlight
138 MultiLineEditBox.extractDecorations missing minor: no character count under a limited box; TextField has no limit
139 MultiLineEditBox.scrollToCursor port crates/horizon-client/src/screen_draw.rs::TextField::scroll_to crates/horizon-client-render/src/screen_draw.rs::TextField::scroll_to keeps the cursor line in view
140 MultiLineEditBox.seekCursorScreen port crates/horizon-client/src/screen_draw.rs::TextField::click crates/horizon-client-render/src/screen_draw.rs::TextField::click maps the pointer to a cursor position
141 MultiLineEditBox.setFocused inline crates/horizon-client/src/screen_draw.rs::TextField::draw crates/horizon-client-render/src/screen_draw.rs::TextField::draw gap: minor: focus does not restart the caret blink here; the caller passes the blink clock
142 MultiLineEditBox.Builder.build skip:java builder
143 MultiLineTextWidget.getHeight skip:ui layout: wrapped line count times 9; Measure::split does the wrap when drawing
144 MultiLineTextWidget.getFreshCacheKey skip:java cache key for the wrapped lines
+30 -30
View File
@@ -1,43 +1,43 @@
MultilineTextField.setCharacterLimit port crates/horizon-client/src/game/books.rs::book_page_box gap: minor: only the book page sets a character limit (PAGE_CHARS); other MultiLineEditBox users are not ported
MultilineTextField.setLineLimit inline crates/horizon-client/src/game/books.rs::Game::page_keep the 14-line limit (LINES) is checked in page_keep; there is no limit field
MultilineTextField.setValue port crates/horizon-client/src/ui.rs::EditBox::set_value gap: minor: no line-limit check when the text is set (allowOverflowLineLimit path)
MultilineTextField.insertText port crates/horizon-client/src/ui.rs::EditBox::insert_text the line limit is checked by Game::page_keep, not here
MultilineTextField.deleteText port crates/horizon-client/src/ui.rs::EditBox::delete_chars
MultilineTextField.getSelected port crates/horizon-client/src/ui.rs::EditBox::selected
MultilineTextField.setValue port crates/horizon-client-render/src/ui.rs::EditBox::set_value gap: minor: no line-limit check when the text is set (allowOverflowLineLimit path)
MultilineTextField.insertText port crates/horizon-client-render/src/ui.rs::EditBox::insert_text the line limit is checked by Game::page_keep, not here
MultilineTextField.deleteText port crates/horizon-client-render/src/ui.rs::EditBox::delete_chars
MultilineTextField.getSelected port crates/horizon-client-render/src/ui.rs::EditBox::selected
MultilineTextField.getLineAtCursor port crates/horizon-client/src/game/books.rs::Game::caret_on the visual row holding the caret, with its x
MultilineTextField.getLineView port crates/horizon-client/src/game/books.rs::Game::page_rows visual rows as character ranges
MultilineTextField.seekCursor port crates/horizon-client/src/ui.rs::EditBox::set_cursor
MultilineTextField.seekCursor port crates/horizon-client-render/src/ui.rs::EditBox::set_cursor
MultilineTextField.seekCursorLine port crates/horizon-client/src/game/books.rs::Game::book_move_line gap: minor: column kept without vanilla's 2 px bias (LINE_SEEK_PIXEL_BIAS)
MultilineTextField.seekCursorToPoint port crates/horizon-client/src/game/books.rs::Game::page_index_at
MultilineTextField.selectWordAtCursor missing player: double-clicking a word on a book page does not select it; Game::book_page_click only sets the caret
MultilineTextField.keyPressed port crates/horizon-client/src/game/books.rs::Game::book_input gap: player: Home and End go to the start and end of the whole page, not of the visual line (EditBox::key); Enter, arrows and Ctrl keys are handled
MultilineTextField.getSelectedText port crates/horizon-client/src/ui.rs::EditBox::selected_text
MultilineTextField.getSelectedText port crates/horizon-client-render/src/ui.rs::EditBox::selected_text
MultilineTextField.getCursorLineView inline crates/horizon-client/src/game/books.rs::Game::book_move_line gap: player: Home and End do not use the caret's line range (see keyPressed)
MultilineTextField.getNextWord port crates/horizon-client/src/ui.rs::multiline_word_position start of the next word; Ctrl+Right and Ctrl+Delete reach it through EditBox::word_position
MultilineTextField.getNextWord port crates/horizon-client-render/src/ui.rs::multiline_word_position start of the next word; Ctrl+Right and Ctrl+Delete reach it through EditBox::word_position
MultilineTextField.getWordEndPosition missing minor: the word end only feeds selectWordAtCursor, which is missing for book pages
MultilineTextField.onValueChange inline crates/horizon-client/src/game/books.rs::Game::page_keep the page text is stored there after the limit check; visual rows are computed on demand by page_rows
MultilineTextField.reflowDisplayLines port crates/horizon-client/src/game/books.rs::Game::page_rows same wrap breaks as font.split
MultilineTextField.truncateFullText port crates/horizon-client/src/ui.rs::EditBox::set_value truncates to max_length characters
MultilineTextField.truncateInsertionText inline crates/horizon-client/src/ui.rs::EditBox::insert_text room left under max_length
MultilineTextField.truncateFullText port crates/horizon-client-render/src/ui.rs::EditBox::set_value truncates to max_length characters
MultilineTextField.truncateInsertionText inline crates/horizon-client-render/src/ui.rs::EditBox::insert_text room left under max_length
MultilineTextField.overflowsLineLimit port crates/horizon-client/src/game/books.rs::Game::page_keep counts page_rows, which adds the row after a trailing newline as vanilla does
ObjectSelectionList.nextFocusPath missing minor: no arrow-key focus or selection in the title, server or pack lists
ObjectSelectionList.updateWidgetNarration skip:other screen-reader narration; Horizon has no narration output
OptionsList.addBig port crates/horizon-client/src/options_ui.rs::OptionsUi::layout Row::Big: 310 wide at width/2 - 155
OptionsList.addHeader port crates/horizon-client/src/options_ui.rs::OptionsUi::layout gap: minor: the header is centred text, not a focusable widget
OptionsList.addBig port crates/horizon-client-render/src/options_ui.rs::OptionsUi::layout Row::Big: 310 wide at width/2 - 155
OptionsList.addHeader port crates/horizon-client-render/src/options_ui.rs::OptionsUi::layout gap: minor: the header is centred text, not a focusable widget
OptionsList.findOption skip:ui widget lookup only; rows are rebuilt from Settings in OptionsUi::layout each frame
OptionsList.applyUnsavedChanges inline crates/horizon-client/src/options_ui.rs::set_slider gap: minor: delayed sliders (render, simulation, biome blend distance, wheel sensitivity) apply on every step, not 600 ms after the last move or on close
OptionsList.resetOption inline crates/horizon-client/src/options_ui.rs::OptionsUi::slider_shown gap: minor: only sliders show the stored value at once; other options redraw from Settings each frame
OptionsList.Entry.big port crates/horizon-client/src/options_ui.rs::option_widget 310 wide; the row's place is OptionsUi::layout (Row::Big)
OptionsList.Entry.small port crates/horizon-client/src/options_ui.rs::option_widget pair placement at width/2 - 155 and + 5 in OptionsUi::layout (Row::Pair)
OptionsList.Entry.extractContent inline crates/horizon-client/src/options_ui.rs::OptionsUi::layout positions the row's widgets; OptionsUi::draw paints them
OptionsList.applyUnsavedChanges inline crates/horizon-client-render/src/options_ui.rs::set_slider gap: minor: delayed sliders (render, simulation, biome blend distance, wheel sensitivity) apply on every step, not 600 ms after the last move or on close
OptionsList.resetOption inline crates/horizon-client-render/src/options_ui.rs::OptionsUi::slider_shown gap: minor: only sliders show the stored value at once; other options redraw from Settings each frame
OptionsList.Entry.big port crates/horizon-client-render/src/options_ui.rs::option_widget 310 wide; the row's place is OptionsUi::layout (Row::Big)
OptionsList.Entry.small port crates/horizon-client-render/src/options_ui.rs::option_widget pair placement at width/2 - 155 and + 5 in OptionsUi::layout (Row::Pair)
OptionsList.Entry.extractContent inline crates/horizon-client-render/src/options_ui.rs::OptionsUi::layout positions the row's widgets; OptionsUi::draw paints them
OptionsList.Entry.findOption skip:ui widget lookup only; rows are rebuilt from Settings each frame
OptionsList.HeaderEntry.extractContent inline crates/horizon-client/src/options_ui.rs::OptionsUi::layout header centred on the row (Row::Header)
OptionsList.HeaderEntry.extractContent inline crates/horizon-client-render/src/options_ui.rs::OptionsUi::layout header centred on the row (Row::Header)
PlainTextButton.extractContents missing player: the title's bottom copyright text that opens Credits is not a button; Horizon draws "Not affiliated with Mojang or Microsoft" there instead
PlayerFaceExtractor.extractHat port crates/horizon-client/src/tab_list.rs::face hat layer: UV 40, flipped for Dinnerbone and Grumm
PlayerFaceExtractor.extractHat port crates/horizon-client-render/src/tab_list.rs::face hat layer: UV 40, flipped for Dinnerbone and Grumm
PlayerFaceWidget.extractWidgetRenderState skip:service head in the friends list (AbstractFriendsEntryContainerWidget)
PlayerSkinWidget.extractWidgetRenderState skip:service skin preview on the chat report screen (SkinReportScreen)
PlayerSkinWidget.onDrag skip:service drag-to-rotate of the chat report skin preview
PlayerTabOverlay.extractTablistScore inline crates/horizon-client/src/tab_list.rs::TabList::layout the score column is drawn in layout; hearts go through TabList::hearts
PlayerTabOverlay.extractTablistScore inline crates/horizon-client-render/src/tab_list.rs::TabList::layout the score column is drawn in layout; hearts go through TabList::hearts
PopupScreen.init port crates/horizon-client/src/game/lan_screen.rs::Popup::new gap: minor: only the lock question (title, message, Yes and No); images and extra buttons are not ported
PopupScreen.buildButtonRow inline crates/horizon-client/src/game/lan_screen.rs::Popup::new two buttons min((214 - 6) / 2, 150) wide, 6 apart
PopupScreen.repositionElements inline crates/horizon-client/src/game/lan_screen.rs::Popup::new centres the popup on the screen
@@ -58,11 +58,11 @@ ScrollableLayout.Container.setFocused missing minor: focusing a row does not sc
ScrollableLayout.Container.setX skip:ui positions set by each screen's layout
ScrollableLayout.Container.setY skip:ui positions set by each screen's layout
ScrollableLayout.Container.setScrollAmount inline crates/horizon-client/src/game/server_links.rs::Game::server_links_scroll gap: minor: clamps the server links list only; other scroll areas clamp in their own code
SelectableEntry.mouseOverIcon port crates/horizon-client/src/pack_screen.rs::PackScreen::entry_click 32 px icon of a pack row; the world row's icon uses the same test in Title::click_action
SelectableEntry.mouseOverLeftHalf port crates/horizon-client/src/pack_screen.rs::PackScreen::entry_click left 16 px of the pack icon (unselect)
SelectableEntry.mouseOverIcon port crates/horizon-client-render/src/pack_screen.rs::PackScreen::entry_click 32 px icon of a pack row; the world row's icon uses the same test in Title::click_action
SelectableEntry.mouseOverLeftHalf port crates/horizon-client-render/src/pack_screen.rs::PackScreen::entry_click left 16 px of the pack icon (unselect)
SelectableEntry.mouseOverRightHalf port crates/horizon-client/src/multiplayer.rs::over_right_half join half of a server row
SelectableEntry.mouseOverTopRightQuarter port crates/horizon-client/src/pack_screen.rs::PackScreen::entry_click move-up arrow of a pack row
SelectableEntry.mouseOverBottomRightQuarter port crates/horizon-client/src/pack_screen.rs::PackScreen::entry_click move-down arrow of a pack row
SelectableEntry.mouseOverTopRightQuarter port crates/horizon-client-render/src/pack_screen.rs::PackScreen::entry_click move-up arrow of a pack row
SelectableEntry.mouseOverBottomRightQuarter port crates/horizon-client-render/src/pack_screen.rs::PackScreen::entry_click move-down arrow of a pack row
SelectableEntry.mouseOverTopLeftQuarter port crates/horizon-client/src/multiplayer.rs::over_top_left move-up arrow of a server row
SelectableEntry.mouseOverBottomLeftQuarter port crates/horizon-client/src/multiplayer.rs::over_bottom_left move-down arrow of a server row
SplashRenderer.extractRenderState missing player: the random splash line on the title screen is not drawn; Title::draw has no splash
@@ -73,15 +73,15 @@ SpriteIconButton.Builder.sprite skip:java builder setter; Horizon draws its ico
SpriteIconButton.Builder.build skip:java builder; no object is needed
SpriteIconButton.CenteredIcon.extractContents skip:service FriendsButton (social)
SpriteIconButton.TextAndIcon.extractContents skip:other no caller in 26.3
StringWidget.setMaxWidth port crates/horizon-client/src/screen_draw.rs::string_widget clips at max_width (CLAMPED)
StringWidget.getWidth port crates/horizon-client/src/screen_draw.rs::label_width the smaller of max width and text width
StringWidget.visitLines port crates/horizon-client/src/screen_draw.rs::string_widget gap: minor: SCROLLING overflow (scrolling text) is not ported; CLAMPED draws "..."
StringWidget.setMaxWidth port crates/horizon-client-render/src/screen_draw.rs::string_widget clips at max_width (CLAMPED)
StringWidget.getWidth port crates/horizon-client-render/src/screen_draw.rs::label_width the smaller of max width and text width
StringWidget.visitLines port crates/horizon-client-render/src/screen_draw.rs::string_widget gap: minor: SCROLLING overflow (scrolling text) is not ported; CLAMPED draws "..."
TabButton.updateWidgetNarration skip:other screen-reader text; Horizon has no narration output
TextCursorUtils.extractInsertCursor port crates/horizon-client/src/ui.rs::EditBox::draw insert caret is a 1 px bar; blinks every 300 ms
TextCursorUtils.extractInsertCursor port crates/horizon-client-render/src/ui.rs::EditBox::draw insert caret is a 1 px bar; blinks every 300 ms
Tooltip.create skip:java factory; Horizon passes the lines to ui::tooltip
Tooltip.toCharSequence port crates/horizon-client/src/screen_draw.rs::tooltip wraps at 170 px as splitTooltip does; no per-language cache
WidgetSprites.get port crates/horizon-client/src/ui.rs::button disabled and hovered pick the sprite; gap: minor: keyboard focus does not pick the highlighted sprite
WidgetTooltipHolder.refreshTooltipForNextRenderPass port crates/horizon-client/src/ui.rs::tooltip gap: minor: tooltips show only under the pointer, not for keyboard focus
Tooltip.toCharSequence port crates/horizon-client-render/src/screen_draw.rs::tooltip wraps at 170 px as splitTooltip does; no per-language cache
WidgetSprites.get port crates/horizon-client-render/src/ui.rs::button disabled and hovered pick the sprite; gap: minor: keyboard focus does not pick the highlighted sprite
WidgetTooltipHolder.refreshTooltipForNextRenderPass port crates/horizon-client-render/src/ui.rs::tooltip gap: minor: tooltips show only under the pointer, not for keyboard focus
WidgetTooltipHolder.createTooltipPositioner missing minor: a keyboard-focused widget gets no tooltip placed below or above it
DebugEntryBiome.display missing minor: F3 biome line not drawn
DebugEntryBiome.printBiome missing minor: biome id text for the F3 biome line
Can't render this file because it contains an unexpected character in line 35 and column 134.
+49 -49
View File
@@ -1,10 +1,10 @@
ContainerEventHandler.getChildAt port crates/horizon-client/src/pack_screen.rs::PackScreen::button_at gap: minor: says whether a button is under the pointer; list rows are hit-tested in PackScreen::click
ContainerEventHandler.mouseReleased port crates/horizon-client/src/pack_screen.rs::PackScreen::release gap: minor: only clears list scrollbar holds; no focused child gets the release
ContainerEventHandler.mouseDragged port crates/horizon-client/src/pack_screen.rs::PackScreen::drag drags a held list scrollbar
ContainerEventHandler.mouseScrolled port crates/horizon-client/src/pack_screen.rs::PackScreen::scroll list under the pointer scrolls 18 px per notch
ContainerEventHandler.keyPressed port crates/horizon-client/src/pack_screen.rs::PackScreen::shortcut gap: minor: only Ctrl+A/C/V/X here; Backspace is PackScreen::erase
ContainerEventHandler.getChildAt port crates/horizon-client-render/src/pack_screen.rs::PackScreen::button_at gap: minor: says whether a button is under the pointer; list rows are hit-tested in PackScreen::click
ContainerEventHandler.mouseReleased port crates/horizon-client-render/src/pack_screen.rs::PackScreen::release gap: minor: only clears list scrollbar holds; no focused child gets the release
ContainerEventHandler.mouseDragged port crates/horizon-client-render/src/pack_screen.rs::PackScreen::drag drags a held list scrollbar
ContainerEventHandler.mouseScrolled port crates/horizon-client-render/src/pack_screen.rs::PackScreen::scroll list under the pointer scrolls 18 px per notch
ContainerEventHandler.keyPressed port crates/horizon-client-render/src/pack_screen.rs::PackScreen::shortcut gap: minor: only Ctrl+A/C/V/X here; Backspace is PackScreen::erase
ContainerEventHandler.keyReleased skip:other no widget in the pack screen acts on key release
ContainerEventHandler.charTyped port crates/horizon-client/src/pack_screen.rs::PackScreen::type_text typed text goes to the search box when it has focus
ContainerEventHandler.charTyped port crates/horizon-client-render/src/pack_screen.rs::PackScreen::type_text typed text goes to the search box when it has focus
ContainerEventHandler.preeditUpdated missing minor: no IME composition (preedit) anywhere in Horizon
ContainerEventHandler.getBorderForArrowNavigation missing minor: arrow keys do not move focus; pack screen focus is set by clicks (PackScreen::set_focus)
ContainerEventHandler.getCurrentFocusPath missing minor: no focus path; PackScreen::focus is read only inside the screen
@@ -81,70 +81,70 @@ CodepointMap.computeIfAbsent skip:java codepoint lookup table; Horizon uses Has
CodepointMap.remove skip:java codepoint lookup table; Horizon uses HashMap and BTreeSet
CodepointMap.forEach skip:java codepoint lookup table; Horizon uses HashMap and BTreeSet
CodepointMap.keySet skip:java codepoint lookup table; Horizon uses HashMap and BTreeSet
FontManager.createFontSet port crates/horizon-client/src/font.rs::Font::load_set a font's providers into a set
FontManager.reload port crates/horizon-client/src/hud.rs::HudAtlas::pack fonts are rebuilt with the atlas (Font::load at hud.rs:582); no async reload
FontManager.safeLoad inline crates/horizon-client/src/font.rs::Font::load_set a TrueType provider that fails to load is dropped; a bitmap sheet that fails warns
FontManager.resolveProviders port crates/horizon-client/src/font.rs::providers reference expansion in order, depth 8; no dependency sort
FontManager.createFontSet port crates/horizon-client-render/src/font.rs::Font::load_set a font's providers into a set
FontManager.reload port crates/horizon-client-render/src/hud.rs::HudAtlas::pack fonts are rebuilt with the atlas (Font::load at hud.rs:582); no async reload
FontManager.safeLoad inline crates/horizon-client-render/src/font.rs::Font::load_set a TrueType provider that fails to load is dropped; a bitmap sheet that fails warns
FontManager.resolveProviders port crates/horizon-client-render/src/font.rs::providers reference expansion in order, depth 8; no dependency sort
FontManager.finalizeProviderLoading skip:java prewarm of glyph lookups; the fallback is the missing box that Font::resolve gives
FontManager.getFontOptions port crates/horizon-client/src/game/options.rs::Game::apply_ui_settings force unicode and japanese flags read from settings
FontManager.apply port crates/horizon-client/src/hud.rs::HudAtlas::pack new font sets replace the old ones with the atlas
FontManager.apply port crates/horizon-client-render/src/hud.rs::HudAtlas::pack new font sets replace the old ones with the atlas
FontManager.updateOptions port crates/horizon-client/src/game/options.rs::Game::apply_ui_settings sets the Font uniform and japanese flags when they change (options.rs:299-301)
FontManager.loadResourceStack inline crates/horizon-client/src/font.rs::providers gap: minor: one fonts.json per font id from the resource root, not a stack of packs
FontManager.loadResourceStack inline crates/horizon-client-render/src/font.rs::providers gap: minor: one fonts.json per font id from the resource root, not a stack of packs
FontManager.getSpriteFont missing minor: atlas sprite fonts (sprite objects in text) are not parsed; they draw the missing box
FontManager.close skip:java Rust drop frees the atlas, font sets and providers
FontManager.BuilderResult.resolve port crates/horizon-client/src/font.rs::providers reference builders expanded in place
FontManager.BuilderResult.mergeFilters inline crates/horizon-client/src/font.rs::providers the reference's filter merged onto each expanded provider
FontManager.CachedFontProvider.getGlyphSource port crates/horizon-client/src/font.rs::Font::glyph_in gap: minor: atlas sprite and player descriptions fall back to the missing glyph
FontManager.BuilderResult.resolve port crates/horizon-client-render/src/font.rs::providers reference builders expanded in place
FontManager.BuilderResult.mergeFilters inline crates/horizon-client-render/src/font.rs::providers the reference's filter merged onto each expanded provider
FontManager.CachedFontProvider.getGlyphSource port crates/horizon-client-render/src/font.rs::Font::glyph_in gap: minor: atlas sprite and player descriptions fall back to the missing glyph
FontManager.CachedFontProvider.glyphs skip:java one-entry lookup cache
FontManager.CachedFontProvider.effect port crates/horizon-client/src/font.rs::Font::white the white glyph under underline and strikethrough
FontManager.CachedFontProvider.effect port crates/horizon-client-render/src/font.rs::Font::white the white glyph under underline and strikethrough
FontManager.UnresolvedBuilderBundle.add skip:java collects builders; providers() reads them directly
FontManager.UnresolvedBuilderBundle.listBuilders skip:java collects builders
FontManager.UnresolvedBuilderBundle.resolve port crates/horizon-client/src/font.rs::providers reference expansion for the bundle
FontOption.Filter.apply port crates/horizon-client/src/font.rs::Filter::passes option match per provider
FontOption.Filter.merge inline crates/horizon-client/src/font.rs::providers filter merge while expanding references
FontSet.reload port crates/horizon-client/src/font.rs::Font::load_set providers into the font set
FontSet.resetTextures port crates/horizon-client/src/font.rs::Font::reset_cache glyph cache and atlas cursor cleared
FontSet.selectProviders port crates/horizon-client/src/font.rs::Font::glyphs_by_width gap: minor: width buckets hold only Space and atlas bitmap glyphs, so TrueType and unihex never appear as obfuscated characters
FontManager.UnresolvedBuilderBundle.resolve port crates/horizon-client-render/src/font.rs::providers reference expansion for the bundle
FontOption.Filter.apply port crates/horizon-client-render/src/font.rs::Filter::passes option match per provider
FontOption.Filter.merge inline crates/horizon-client-render/src/font.rs::providers filter merge while expanding references
FontSet.reload port crates/horizon-client-render/src/font.rs::Font::load_set providers into the font set
FontSet.resetTextures port crates/horizon-client-render/src/font.rs::Font::reset_cache glyph cache and atlas cursor cleared
FontSet.selectProviders port crates/horizon-client-render/src/font.rs::Font::glyphs_by_width gap: minor: width buckets hold only Space and atlas bitmap glyphs, so TrueType and unihex never appear as obfuscated characters
FontSet.hasFishyAdvance missing minor: no check for advances under 0 or over 32
FontSet.computeGlyphInfo port crates/horizon-client/src/font.rs::Font::resolve gap: minor: no skip of a glyph with a fishy advance in favour of a later provider
FontSet.computeGlyphInfo port crates/horizon-client-render/src/font.rs::Font::resolve gap: minor: no skip of a glyph with a fishy advance in favour of a later provider
FontSet.DelayedBake.get skip:java lazy bake into the atlas; Font::resolve bakes at once
FontTexture.dumpContents skip:debug writes the atlas to a PNG for debugging
GlyphRenderTypes.createForGrayscaleTexture skip:ui one textured quad path for all glyphs (hud.rs text_styled)
GlyphRenderTypes.createForColorTexture skip:ui one textured quad path for all glyphs (hud.rs text_styled)
GlyphRenderTypes.select port crates/horizon-client/src/game/names.rs::Game::name_tag_geometry gap: minor: normal and see-through only; polygon-offset text has no draw path
GlyphStitcher.reset port crates/horizon-client/src/font.rs::Font::reset_cache atlas cursor rewound
GlyphStitcher.stitch port crates/horizon-client/src/font.rs::Region::place rectangle placed in the atlas region
PlainTextRenderable.render port crates/horizon-client/src/hud.rs::HudBatch::text_styled shadow pass first, then the front text
GlyphStitcher.reset port crates/horizon-client-render/src/font.rs::Font::reset_cache atlas cursor rewound
GlyphStitcher.stitch port crates/horizon-client-render/src/font.rs::Region::place rectangle placed in the atlas region
PlainTextRenderable.render port crates/horizon-client-render/src/hud.rs::HudBatch::text_styled shadow pass first, then the front text
PlayerGlyphProvider.Instance.renderSprite missing minor: player-head text objects are not parsed
PlayerGlyphProvider.Instance.renderQuad missing minor: no player-head glyphs (same gap)
TextFieldHelper.charTyped inline crates/horizon-client/src/game/sign_edit.rs::Game::sign_input typed-text branch; EditBox::insert_text filters the text
TextFieldHelper.moveBy inline crates/horizon-client/src/ui.rs::EditBox::key arrow keys; Ctrl moves by word
TextFieldHelper.moveByChars inline crates/horizon-client/src/ui.rs::EditBox::key arrow keys, Home and End
TextFieldHelper.moveByWords inline crates/horizon-client/src/ui.rs::EditBox::key Ctrl+arrow word moves
TextFieldHelper.removeFromCursor inline crates/horizon-client/src/ui.rs::EditBox::key Backspace and Delete
TextFieldHelper.removeWordsFromCursor inline crates/horizon-client/src/ui.rs::EditBox::key Ctrl+Backspace and Ctrl+Delete
TextFieldHelper.removeCharsFromCursor port crates/horizon-client/src/ui.rs::EditBox::delete_chars deletes the selection or n characters
TextFieldHelper.moveBy inline crates/horizon-client-render/src/ui.rs::EditBox::key arrow keys; Ctrl moves by word
TextFieldHelper.moveByChars inline crates/horizon-client-render/src/ui.rs::EditBox::key arrow keys, Home and End
TextFieldHelper.moveByWords inline crates/horizon-client-render/src/ui.rs::EditBox::key Ctrl+arrow word moves
TextFieldHelper.removeFromCursor inline crates/horizon-client-render/src/ui.rs::EditBox::key Backspace and Delete
TextFieldHelper.removeWordsFromCursor inline crates/horizon-client-render/src/ui.rs::EditBox::key Ctrl+Backspace and Ctrl+Delete
TextFieldHelper.removeCharsFromCursor port crates/horizon-client-render/src/ui.rs::EditBox::delete_chars deletes the selection or n characters
TextFieldHelper.cut port crates/horizon-client-input/src/clipboard.rs::apply Cut arm: copy the selection, then clear it
TextFieldHelper.paste port crates/horizon-client-input/src/clipboard.rs::apply Paste arm: insert the clipboard text
TextFieldHelper.getSelected port crates/horizon-client/src/ui.rs::EditBox::selected_text
TextFieldHelper.deleteSelection inline crates/horizon-client/src/ui.rs::EditBox::delete_chars selection branch
TextFieldHelper.setCursorToEnd port crates/horizon-client/src/ui.rs::EditBox::move_cursor_to_end
TextFieldHelper.setCursorPos port crates/horizon-client/src/ui.rs::EditBox::set_cursor no vanilla caller (callers 0)
TextFieldHelper.getSelected port crates/horizon-client-render/src/ui.rs::EditBox::selected_text
TextFieldHelper.deleteSelection inline crates/horizon-client-render/src/ui.rs::EditBox::delete_chars selection branch
TextFieldHelper.setCursorToEnd port crates/horizon-client-render/src/ui.rs::EditBox::move_cursor_to_end
TextFieldHelper.setCursorPos port crates/horizon-client-render/src/ui.rs::EditBox::set_cursor no vanilla caller (callers 0)
TextFieldHelper.setSelectionRange skip:other no vanilla caller; Horizon sets cursor and highlight separately (EditBox::set_cursor)
BakedSheetGlyph.left inline crates/horizon-client/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.top inline crates/horizon-client/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.right inline crates/horizon-client/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.bottom inline crates/horizon-client/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.renderChar inline crates/horizon-client/src/hud.rs::HudBatch::text_styled shadow pass, bold double draw, italic shear
BakedSheetGlyph.render inline crates/horizon-client/src/hud.rs::HudBatch::text_styled glyph quad with shear and bold
BakedSheetGlyph.renderEffect inline crates/horizon-client/src/hud.rs::HudBatch::text_styled underline and strikethrough rectangles
BakedSheetGlyph.buildEffect inline crates/horizon-client/src/hud.rs::HudBatch::text_styled rectangle quad of an effect
BakedSheetGlyph.left inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.top inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.right inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.bottom inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
BakedSheetGlyph.renderChar inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled shadow pass, bold double draw, italic shear
BakedSheetGlyph.render inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph quad with shear and bold
BakedSheetGlyph.renderEffect inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline and strikethrough rectangles
BakedSheetGlyph.buildEffect inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled rectangle quad of an effect
BakedSheetGlyph.createGlyph skip:java factory for a glyph instance
BakedSheetGlyph.createEffect skip:java factory for an effect instance
BakedSheetGlyph.EffectInstance.right inline crates/horizon-client/src/hud.rs::HudBatch::text_styled underline end: pen x plus advance
BakedSheetGlyph.EffectInstance.bottom inline crates/horizon-client/src/hud.rs::HudBatch::text_styled underline row, 1 px at pen y plus 8
BakedSheetGlyph.GlyphInstance.activeRight inline crates/horizon-client/src/hud.rs::HudBatch::text_styled advance including the bold offset
SpecialGlyphs.generate port crates/horizon-client/src/font.rs::Font::white gap: minor: white texel only; the missing-box outline is drawn in HudBatch::text_styled, not generated
BakedSheetGlyph.EffectInstance.right inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline end: pen x plus advance
BakedSheetGlyph.EffectInstance.bottom inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline row, 1 px at pen y plus 8
BakedSheetGlyph.GlyphInstance.activeRight inline crates/horizon-client-render/src/hud.rs::HudBatch::text_styled advance including the bold offset
SpecialGlyphs.generate port crates/horizon-client-render/src/font.rs::Font::white gap: minor: white texel only; the missing-box outline is drawn in HudBatch::text_styled, not generated
BitmapProvider.Definition.validateDimensions missing minor: no check of the bitmap grid; a ragged grid loads
BitmapProvider.Definition.validate missing minor: no check that ascent is at most height
BitmapProvider.Definition.getActualGlyphWidth port crates/horizon-client/src/font.rs::used_width rightmost column with any visible pixel
BitmapProvider.Definition.getActualGlyphWidth port crates/horizon-client-render/src/font.rs::used_width rightmost column with any visible pixel
1 ContainerEventHandler.getChildAt port crates/horizon-client/src/pack_screen.rs::PackScreen::button_at crates/horizon-client-render/src/pack_screen.rs::PackScreen::button_at gap: minor: says whether a button is under the pointer; list rows are hit-tested in PackScreen::click
2 ContainerEventHandler.mouseReleased port crates/horizon-client/src/pack_screen.rs::PackScreen::release crates/horizon-client-render/src/pack_screen.rs::PackScreen::release gap: minor: only clears list scrollbar holds; no focused child gets the release
3 ContainerEventHandler.mouseDragged port crates/horizon-client/src/pack_screen.rs::PackScreen::drag crates/horizon-client-render/src/pack_screen.rs::PackScreen::drag drags a held list scrollbar
4 ContainerEventHandler.mouseScrolled port crates/horizon-client/src/pack_screen.rs::PackScreen::scroll crates/horizon-client-render/src/pack_screen.rs::PackScreen::scroll list under the pointer scrolls 18 px per notch
5 ContainerEventHandler.keyPressed port crates/horizon-client/src/pack_screen.rs::PackScreen::shortcut crates/horizon-client-render/src/pack_screen.rs::PackScreen::shortcut gap: minor: only Ctrl+A/C/V/X here; Backspace is PackScreen::erase
6 ContainerEventHandler.keyReleased skip:other no widget in the pack screen acts on key release
7 ContainerEventHandler.charTyped port crates/horizon-client/src/pack_screen.rs::PackScreen::type_text crates/horizon-client-render/src/pack_screen.rs::PackScreen::type_text typed text goes to the search box when it has focus
8 ContainerEventHandler.preeditUpdated missing minor: no IME composition (preedit) anywhere in Horizon
9 ContainerEventHandler.getBorderForArrowNavigation missing minor: arrow keys do not move focus; pack screen focus is set by clicks (PackScreen::set_focus)
10 ContainerEventHandler.getCurrentFocusPath missing minor: no focus path; PackScreen::focus is read only inside the screen
81 CodepointMap.remove skip:java codepoint lookup table; Horizon uses HashMap and BTreeSet
82 CodepointMap.forEach skip:java codepoint lookup table; Horizon uses HashMap and BTreeSet
83 CodepointMap.keySet skip:java codepoint lookup table; Horizon uses HashMap and BTreeSet
84 FontManager.createFontSet port crates/horizon-client/src/font.rs::Font::load_set crates/horizon-client-render/src/font.rs::Font::load_set a font's providers into a set
85 FontManager.reload port crates/horizon-client/src/hud.rs::HudAtlas::pack crates/horizon-client-render/src/hud.rs::HudAtlas::pack fonts are rebuilt with the atlas (Font::load at hud.rs:582); no async reload
86 FontManager.safeLoad inline crates/horizon-client/src/font.rs::Font::load_set crates/horizon-client-render/src/font.rs::Font::load_set a TrueType provider that fails to load is dropped; a bitmap sheet that fails warns
87 FontManager.resolveProviders port crates/horizon-client/src/font.rs::providers crates/horizon-client-render/src/font.rs::providers reference expansion in order, depth 8; no dependency sort
88 FontManager.finalizeProviderLoading skip:java prewarm of glyph lookups; the fallback is the missing box that Font::resolve gives
89 FontManager.getFontOptions port crates/horizon-client/src/game/options.rs::Game::apply_ui_settings crates/horizon-client/src/game/options.rs::Game::apply_ui_settings force unicode and japanese flags read from settings
90 FontManager.apply port crates/horizon-client/src/hud.rs::HudAtlas::pack crates/horizon-client-render/src/hud.rs::HudAtlas::pack new font sets replace the old ones with the atlas
91 FontManager.updateOptions port crates/horizon-client/src/game/options.rs::Game::apply_ui_settings crates/horizon-client/src/game/options.rs::Game::apply_ui_settings sets the Font uniform and japanese flags when they change (options.rs:299-301)
92 FontManager.loadResourceStack inline crates/horizon-client/src/font.rs::providers crates/horizon-client-render/src/font.rs::providers gap: minor: one fonts.json per font id from the resource root, not a stack of packs
93 FontManager.getSpriteFont missing minor: atlas sprite fonts (sprite objects in text) are not parsed; they draw the missing box
94 FontManager.close skip:java Rust drop frees the atlas, font sets and providers
95 FontManager.BuilderResult.resolve port crates/horizon-client/src/font.rs::providers crates/horizon-client-render/src/font.rs::providers reference builders expanded in place
96 FontManager.BuilderResult.mergeFilters inline crates/horizon-client/src/font.rs::providers crates/horizon-client-render/src/font.rs::providers the reference's filter merged onto each expanded provider
97 FontManager.CachedFontProvider.getGlyphSource port crates/horizon-client/src/font.rs::Font::glyph_in crates/horizon-client-render/src/font.rs::Font::glyph_in gap: minor: atlas sprite and player descriptions fall back to the missing glyph
98 FontManager.CachedFontProvider.glyphs skip:java one-entry lookup cache
99 FontManager.CachedFontProvider.effect port crates/horizon-client/src/font.rs::Font::white crates/horizon-client-render/src/font.rs::Font::white the white glyph under underline and strikethrough
100 FontManager.UnresolvedBuilderBundle.add skip:java collects builders; providers() reads them directly
101 FontManager.UnresolvedBuilderBundle.listBuilders skip:java collects builders
102 FontManager.UnresolvedBuilderBundle.resolve port crates/horizon-client/src/font.rs::providers crates/horizon-client-render/src/font.rs::providers reference expansion for the bundle
103 FontOption.Filter.apply port crates/horizon-client/src/font.rs::Filter::passes crates/horizon-client-render/src/font.rs::Filter::passes option match per provider
104 FontOption.Filter.merge inline crates/horizon-client/src/font.rs::providers crates/horizon-client-render/src/font.rs::providers filter merge while expanding references
105 FontSet.reload port crates/horizon-client/src/font.rs::Font::load_set crates/horizon-client-render/src/font.rs::Font::load_set providers into the font set
106 FontSet.resetTextures port crates/horizon-client/src/font.rs::Font::reset_cache crates/horizon-client-render/src/font.rs::Font::reset_cache glyph cache and atlas cursor cleared
107 FontSet.selectProviders port crates/horizon-client/src/font.rs::Font::glyphs_by_width crates/horizon-client-render/src/font.rs::Font::glyphs_by_width gap: minor: width buckets hold only Space and atlas bitmap glyphs, so TrueType and unihex never appear as obfuscated characters
108 FontSet.hasFishyAdvance missing minor: no check for advances under 0 or over 32
109 FontSet.computeGlyphInfo port crates/horizon-client/src/font.rs::Font::resolve crates/horizon-client-render/src/font.rs::Font::resolve gap: minor: no skip of a glyph with a fishy advance in favour of a later provider
110 FontSet.DelayedBake.get skip:java lazy bake into the atlas; Font::resolve bakes at once
111 FontTexture.dumpContents skip:debug writes the atlas to a PNG for debugging
112 GlyphRenderTypes.createForGrayscaleTexture skip:ui one textured quad path for all glyphs (hud.rs text_styled)
113 GlyphRenderTypes.createForColorTexture skip:ui one textured quad path for all glyphs (hud.rs text_styled)
114 GlyphRenderTypes.select port crates/horizon-client/src/game/names.rs::Game::name_tag_geometry crates/horizon-client/src/game/names.rs::Game::name_tag_geometry gap: minor: normal and see-through only; polygon-offset text has no draw path
115 GlyphStitcher.reset port crates/horizon-client/src/font.rs::Font::reset_cache crates/horizon-client-render/src/font.rs::Font::reset_cache atlas cursor rewound
116 GlyphStitcher.stitch port crates/horizon-client/src/font.rs::Region::place crates/horizon-client-render/src/font.rs::Region::place rectangle placed in the atlas region
117 PlainTextRenderable.render port crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled shadow pass first, then the front text
118 PlayerGlyphProvider.Instance.renderSprite missing minor: player-head text objects are not parsed
119 PlayerGlyphProvider.Instance.renderQuad missing minor: no player-head glyphs (same gap)
120 TextFieldHelper.charTyped inline crates/horizon-client/src/game/sign_edit.rs::Game::sign_input crates/horizon-client/src/game/sign_edit.rs::Game::sign_input typed-text branch; EditBox::insert_text filters the text
121 TextFieldHelper.moveBy inline crates/horizon-client/src/ui.rs::EditBox::key crates/horizon-client-render/src/ui.rs::EditBox::key arrow keys; Ctrl moves by word
122 TextFieldHelper.moveByChars inline crates/horizon-client/src/ui.rs::EditBox::key crates/horizon-client-render/src/ui.rs::EditBox::key arrow keys, Home and End
123 TextFieldHelper.moveByWords inline crates/horizon-client/src/ui.rs::EditBox::key crates/horizon-client-render/src/ui.rs::EditBox::key Ctrl+arrow word moves
124 TextFieldHelper.removeFromCursor inline crates/horizon-client/src/ui.rs::EditBox::key crates/horizon-client-render/src/ui.rs::EditBox::key Backspace and Delete
125 TextFieldHelper.removeWordsFromCursor inline crates/horizon-client/src/ui.rs::EditBox::key crates/horizon-client-render/src/ui.rs::EditBox::key Ctrl+Backspace and Ctrl+Delete
126 TextFieldHelper.removeCharsFromCursor port crates/horizon-client/src/ui.rs::EditBox::delete_chars crates/horizon-client-render/src/ui.rs::EditBox::delete_chars deletes the selection or n characters
127 TextFieldHelper.cut port crates/horizon-client-input/src/clipboard.rs::apply crates/horizon-client-input/src/clipboard.rs::apply Cut arm: copy the selection, then clear it
128 TextFieldHelper.paste port crates/horizon-client-input/src/clipboard.rs::apply crates/horizon-client-input/src/clipboard.rs::apply Paste arm: insert the clipboard text
129 TextFieldHelper.getSelected port crates/horizon-client/src/ui.rs::EditBox::selected_text crates/horizon-client-render/src/ui.rs::EditBox::selected_text
130 TextFieldHelper.deleteSelection inline crates/horizon-client/src/ui.rs::EditBox::delete_chars crates/horizon-client-render/src/ui.rs::EditBox::delete_chars selection branch
131 TextFieldHelper.setCursorToEnd port crates/horizon-client/src/ui.rs::EditBox::move_cursor_to_end crates/horizon-client-render/src/ui.rs::EditBox::move_cursor_to_end
132 TextFieldHelper.setCursorPos port crates/horizon-client/src/ui.rs::EditBox::set_cursor crates/horizon-client-render/src/ui.rs::EditBox::set_cursor no vanilla caller (callers 0)
133 TextFieldHelper.setSelectionRange skip:other no vanilla caller; Horizon sets cursor and highlight separately (EditBox::set_cursor)
134 BakedSheetGlyph.left inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
135 BakedSheetGlyph.top inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
136 BakedSheetGlyph.right inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
137 BakedSheetGlyph.bottom inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph edge with bold thickness and italic shear
138 BakedSheetGlyph.renderChar inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled shadow pass, bold double draw, italic shear
139 BakedSheetGlyph.render inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled glyph quad with shear and bold
140 BakedSheetGlyph.renderEffect inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline and strikethrough rectangles
141 BakedSheetGlyph.buildEffect inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled rectangle quad of an effect
142 BakedSheetGlyph.createGlyph skip:java factory for a glyph instance
143 BakedSheetGlyph.createEffect skip:java factory for an effect instance
144 BakedSheetGlyph.EffectInstance.right inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline end: pen x plus advance
145 BakedSheetGlyph.EffectInstance.bottom inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled underline row, 1 px at pen y plus 8
146 BakedSheetGlyph.GlyphInstance.activeRight inline crates/horizon-client/src/hud.rs::HudBatch::text_styled crates/horizon-client-render/src/hud.rs::HudBatch::text_styled advance including the bold offset
147 SpecialGlyphs.generate port crates/horizon-client/src/font.rs::Font::white crates/horizon-client-render/src/font.rs::Font::white gap: minor: white texel only; the missing-box outline is drawn in HudBatch::text_styled, not generated
148 BitmapProvider.Definition.validateDimensions missing minor: no check of the bitmap grid; a ragged grid loads
149 BitmapProvider.Definition.validate missing minor: no check that ascent is at most height
150 BitmapProvider.Definition.getActualGlyphWidth port crates/horizon-client/src/font.rs::used_width crates/horizon-client-render/src/font.rs::used_width rightmost column with any visible pixel
Loaded 100 of 145 files, more files were not shown because too many files have changed in this diff. Show more