Перейти к содержимому
Mineforgian

Ferrite

Ferrite — A Rust-powered Minecraft mod improving chunk generation performance, with 7× faster terrain compute proven on equivalent workloads. Low-end hardware testing needed to ship the full optimization.

Загрузки
6K
Подписчики
34
Обновлён
13 августа 2026 г.
Лицензия
MIT

Опубликован 19 апреля 2026 г.

Ferrite

A performance mod for Minecraft 26.2 (Fabric, JDK 25). Java handles integration and mixins; native Rust does the heavy per-tick math where crossing the JNI boundary actually pays. Server-side compatible: install on a server, players don't need it.

Headline numbers, all measured on real worlds:

  • Cramming (default on): ~65% entity-tick reduction at 1000+ packed mobs. Bit-for-bit vanilla push math.
  • Redstone (/ferrite redstone ac on): Alternate Current algorithm plus a Rust BFS kernel. A lag machine that held vanilla at 1.4-1.8 TPS recovered to a flat 20.00 TPS. Zero mismatches across 150,000+ oracle checks. Off by default so contraptions tuned to vanilla update order keep working.
  • Hoppers (default on): extract loops skip drained slots, up to ~85% cheaper on partially-emptied chests. Opt-in hopper highway multiplies chain throughput ~3x for storage systems.
  • Idle sign and furnace tickers suppressed (default on): ~70% block-entity tick reduction at scale, self-healing, mod-subclass safe.
  • Pre-gen and predictive chunk forcing (opt-in): 90-118 chunks/s spawn pre-generation with resume, and a generation ring that leads your flight path so you never see terrain loading.

Worldgen math (noise, biomes, density functions) is ported bit-exact and validated every release; parity checks run 63/63 noise and 50/50 density on 26.2.

Every 5 seconds the mod logs where your tick time goes, so optimization targets real bottlenecks. Runtime toggle: /ferrite log monitors off.

Requirements

  • Minecraft 26.2 (26.1.2 and 1.21.11 builds available as older releases)
  • Java 25, Fabric Loader 0.19.3+, Fabric API 0.154.2+26.2
  • Singleplayer and multiplayer

Platforms

Natives bundled for Windows x86_64, Linux x86_64, Linux aarch64 (Not fully tested on a Raspberry Pi 4B), and macOS (universal). If the native fails to load, Ferrite falls back to vanilla behavior automatically: no crashes, no broken worlds.

How to help

Play 10+ minutes with mob farms or crowded worlds, search latest.log for [ferrite], and share the [cramming-dispatch] and [entity-tick] lines in a GitHub issue. Low-end hardware reports are especially useful.

Full measurement tables, methodology, and source: github.com/VoiceLessQ/Ferrite

Credits

MIT licensed.

Ченджлог

0.7.2-alpha+26.2Альфа26.2 · 13 августа 2026 г.

[0.7.2-alpha] - 2026-08-13

Fixed

  • Moonrise compatibility crash at boot (#12). Moonrise replaces the vanilla light engine internals, which removed the injection targets of the two ThreadedLevelLightEngine diagnostic mixins and hard-crashed the game at init. A mixin config plugin now detects Moonrise and skips those two mixins; for now the [light] monitor reports no data when Moonrise is installed, since Moonrise owns lighting at that point. A Moonrise-aware light probe may come later. Verified against Moonrise 1.1.0: boot, existing-world play, and fresh world creation all clean.

Changed

  • Monitor logging defaults off on small heaps. Max heap of 3 GB or less (Pi-class servers, often on slow SD-card I/O) now boots with the periodic monitor reports silenced instead of paying ~5 log lines/sec. Counters still run; /ferrite log monitors on or -Dferrite.log.monitors.on=true re-enables at any time. Normal heaps keep the old default.
  • Dispatch and oracle telemetry respects the small-heap monitor default (PR #10, contributed by cwright814). The [cramming-dispatch], [physics-dispatch], [redstone-oracle], and [chunkgen-features] periodic lines predate MonitorLog and bypassed it; on a Pi-class server they were most of the log file. Now routed through MonitorLog, so heaps of 3 GB or less boot with them silenced and /ferrite log monitors on re-enables them.

Added

  • Per-category log muting (#14). /ferrite log <category> off silences one monitor tag (physics-dispatch, cramming-dispatch, redstone-oracle, and every other bracket tag) without touching the rest; on resumes it on the next report window and /ferrite log status lists what is muted. Counters keep running while muted. The global /ferrite log monitors switch is unchanged.

  • Module toggles persist across restarts (#13). Cramming, the hopper layer, AC redstone, monitor logging, and muted log categories now save to config/ferrite.properties on every toggle and reload at boot. The file stores only deviations from defaults, so it stays empty (absent, in fact) until something is changed, and reverting a toggle removes its line. Diagnostic and experiment flags stay session-only on purpose, as does prewarm, since enabling it during boot breaks spawn loading.

  • Entity spatial query index (opt-in, -Dferrite.entityquery.cache=true). Sections holding 32+ entities get a per-section bitset grid (4-block cells); box queries visit only candidate entities in vanilla iteration order, so consumer order, abort semantics, and mid-tick liveness are preserved exactly. At a 1022-zombie farm: query cost 14.4-16.8 down to 10.3 ms/tick (34% cut), whole-server mspt 36-40 down to ~32.7, zero oracle mismatches across 83,000+ sampled queries. Default off pending broader soak; -Dferrite.entityquery.oracle=<1-in-N> enables field validation.

  • -Dferrite.pregen.inflight=<n> sets the pre-gen inflight cap at boot (dedicated servers and headless benches; the runtime command still overrides). While adding it, the 200 default was re-validated on a constrained 4-core / 2 GB profile: 42.8 chunks/s vs 34.8 at cap 50, the same relationship as on desktop hardware, so the default stands on weak CPUs too.

  • One-line hardware stamp at boot: [hw] arch cores maxHeap jvm native monitors, so shared log excerpts self-describe the host they came from. Field reports from low-end hardware no longer need follow-up questions about specs.

  • [entity-tick] misc-top breakdown. When the misc entity bucket has a tick over 5 ms in a window, a second line names the top three entity types by time (total, worst single entity, count). Prompted by a Raspberry Pi field report (PR #8) where misc spiked to 47.8 ms with no way to tell which entity type was responsible.

0.7.1-alpha+26.2Альфа26.2 · 27 июля 2026 г.

[0.7.1-alpha] - 2026-07-27

Fixed

  • /ferrite biome validate compared against the wrong dimension. The validator used whichever biome source was constructed last, which is the nether's, so the in-game command reported a screaming 0/2000 with all-nether answers while the boot-time validator was fine. It now picks the captured source whose biome set contains plains. The long-standing 1999/2000 was also diagnosed and closed: an exact fitness tie between lush_caves and dripstone_caves at a climate point real terrain never produces; vanilla and Ferrite break the tie in different but equally valid orders. No in-game effect.

Changed

  • Fat LTO release profile for the native library. The workspace had no release profile at all; lto = "fat" plus codegen-units = 1 cuts the Windows dll from 2.1 MB to 794 KB (cross-crate dead code eliminated), with debuginfo stripped but the symbol table kept so native crash reports stay readable. Parity re-verified on the LTO build: noise 63/63, density 50/50 bit-exact, biome 1999/2000 (the documented tie). No panic = "abort": unwinding is what lets a native panic fall back to vanilla instead of killing the server. In-game A/B at a 1022-zombie cramming farm: 38-41 ms/tick LTO vs 37-40 ms/tick old profile, within noise; perf-neutral, kept for the size win.
  • Removed the aarch64 to x86_64 native fallback in the loader: a wrong-arch library can never load, so the fallback only replaced an honest "not bundled for this platform" log with a misleading "failed to load" one.

[0.7.0-alpha] - 2026-07-27

Known issues

  • Biome parity reads 1999/2000 in the validator: the one miss is an exact fitness tie between lush_caves and dripstone_caves at a climate point outside the range real terrain produces (validator samples wider than the game's climate space). Vanilla and Ferrite break the tie in different but equally valid orders. No in-game effect; real climate points match 100%.
  • The deep-marker diagnostic walk registers no interior cache routes on 26.2. Affects default-off diagnostics only; no live path reads those fingerprints.

Added

  • Linux aarch64 native support (PR #8, contributed by cwright814, tested on a Raspberry Pi 4B). The jar now bundles a fourth native built by a new CI cross-compile job; RustBridge picks it by os.arch at load time, and local Gradle builds on ARM hosts target it automatically. Verified in the field: a full server on a 2GB Pi 4B under OpenJ9 with memory to spare.
  • Building-from-source section in the README: toolchain prerequisites per platform, the one-command Gradle build, and what a locally built jar bundles versus the CI release jars.
  • Pre-gen now skips chunks that are already generated. Before paying a ticket and a FULL-status promotion, the driver checks the live chunk holder, then stream-scans the region file for just the chunk's Status field (no full deserialize). Re-running pre-gen over existing terrain completes at thousands of chunks per second instead of re-loading every chunk from disk; measured 289/289 skipped sub-second on a fully generated area, with virgin-generation throughput unchanged. Skip counts show in /ferrite pregen status.

Fixed

  • An unreadable region file no longer makes pre-gen skip chunks. If the Status scan failed (locked file, IO worker shutting down, a region the reader cannot open), the chunk was treated as already generated and silently left ungenerated. The scan now fails open: it names the chunk in the log and generates it. Verified by holding an exclusive lock on a region file during a 121-chunk run, which produced 121 warnings and 121 generated chunks instead of 121 silent skips. Chunks whose generation itself fails are logged too, rather than counted as done.
  • Malformed IntervalSelect nodes now stop the walker instead of encoding wrong caves. A density function node whose threshold and child counts disagree used to encode as a degenerate node, which reads as valid bytecode and produces wrong cave terrain with no error anywhere. The walker now rejects it and says what it saw. Every IntervalSelect in the live 26.2 registry passes; density parity stays 50/50 bit-exact at 2000 samples.
0.6.6-alpha+26.1.2Альфа26.1.1, 26.1.2 · 13 июля 2026 г.

[0.6.6-alpha] - 2026-07-13

Fixed

  • Five latent redstone defects found in a full review of the AC port. An exception mid-cascade left stale graph state that poisoned every later cascade in that world; removed wires reached the Rust BFS kernel as phantom power-15 sources through a sign-truncation bug (this path is default-on); an out-of-range power value could abort the whole JVM via a release-mode panic across the JNI boundary (now hard-clamped on both sides); the parity oracle produced guaranteed false positives on experimental-redstone worlds (now skipped); and a single exception permanently disabled the oracle and phase counters through stuck thread-locals (they self-heal every tick now). None of these changed measured performance; all validators stay bit-exact.

Changed

  • AC redstone lag machine restesting The vanilla path held 1.4-1.8 TPS (up to 716 ms per tick); enabling /ferrite redstone ac on mid-choke recovered to a flat 20.00 TPS in about 40 seconds, ~13x fewer cascades and ~6x cheaper gate updates on the same build. README benchmark section carries the numbers.
  • Chunkforce predicts flight direction. With /ferrite chunkforce on, the force-gen ring center now leads a moving player by up to 12 chunks along their velocity instead of spending half the budget on terrain behind them. Flight test on 26.1.2 (view distance 16, simulation distance 12): 24,581 chunks forced in ~2.5 minutes at ~160 chunks/s with TPS 20.00 held; the generation front stays out of sight at top creative-fly speed. Stationary players keep the old radial behavior.
  • Pregen inflight cap raised 50 to 200 (+25% throughput). Four 3721-chunk virgin-terrain runs measured cap 50 at 90-96 chunks/s and cap 200 at 114-118 chunks/s; 400 added nothing. Tunable at runtime with /ferrite pregen inflight <n>.
  • Walkability cache: fill strategy fixed, then shelved after A/B. Session 5's pre-fill box thrashed the 512-slot cache (hit rate 1-17%, ~4400 snapshots per 5 s). Session 6 replaced it with a lazy snapshot on first miss, restricted to sections the PathNavigationRegion actually backs, and grew the kind cache to 2-way set-associative (2048 sets x 2 ways, LRU). That fixed the cache itself: hit rate 71-94%, snapshots 24-57 per 5 s. An A/B with 294 chasing zombies then hit 84-87% and still moved nav tick cost at most ~5%, inside noise, because vanilla already fronts getPathTypeFromState with a per-position PathTypeCache and our intercept only ever serves vanilla's misses. Shelved: code stays in tree, default off, post-mortem in JOURNEY. Opt in with -Dferrite.nav.cache=true, or -Pferrite.navCache=true / -Pferrite.navParity=true on runClient.

Added

  • [chunk-save] monitor. Times SerializableChunkData.copyOf (server thread) and write (background encode) separately, one line per 5 s window when saves happened. First measurements settled the chunk-save port candidate: the palette bit-pack already runs on the background executor in 26.1.x, and the tick thread pays only 0.3-0.5 ms/tick of copyOf under sustained flight. Candidate closed; monitor stays.

Fixed

  • Workspace is clippy-clean. All ~120 warnings cleared across the four crates: bind! codegen now emits From impls without the Copy .clone(), the api layer's Into impls flipped to From, slice params replace &Vec, and dead verbatim-port items carry explicit allows. Style lints that fight the vanilla ports (index loops, negated float comparisons that keep vanilla NaN semantics, JNI argument counts) are allowed at crate level in rust-mod with a justification comment. Workspace resolver pinned to 2; the macros crate declares proc-macro = true instead of crate-type.
  • Unsafe JNI buffer helpers hardened. get_i32_slice_mut (surface_jni.rs) and get_byte_slice_mut (redstone_queues_jni.rs) returned &mut [_] from a shared &JByteBuffer, so nothing stopped a caller from holding two aliased mutable slices over one direct buffer. Never a live bug (each is called once per JNI call), but the invariant was unwritten. Both are now unsafe fn with a # Safety contract (no-alias, capacity, alignment) and SAFETY notes at each call site. The two clippy::mut_from_ref errors are gone, and build.yml now runs clippy on the linux job so deny-level lints fail CI.
0.6.5-alpha+26.1.2Альфа26.1.1, 26.1.2 · 26 июня 2026 г.

[0.6.5-alpha] - 2026-06-26

Changed

  • Walkability cache default off. -Dferrite.nav.cache now defaults to false. Session 5's first live counters showed the pre-fill box thrashing the 512-slot direct-mapped cache (hit rate 1-17%, ~4400 snapshots per 5 s, net regression in casual play). The default path stays vanilla until the session 6 fill-strategy fix lands; set -Dferrite.nav.cache=true to opt in for measurement.

Added

  • Walkability cache session 4. WalkNodeEvaluatorMixin intercepts WalkNodeEvaluator.getPathTypeFromState(BlockGetter, BlockPos) at HEAD. For sections already snapshotted, returns PathType directly from a Java-side direct-mapped section cache (512 slots, ~5-10 ns per lookup) instead of calling level.getBlockState followed by the 50-line classification chain. The Java-side cache is filled in snapshotSection alongside the Rust store and evicted on block-kind changes.

    kindToPathType maps the unambiguous kinds: AIR/LADDER/SCAFFOLDING/CARPET to OPEN; OPAQUE_FULL/SLAB/STAIRS to BLOCKED; FENCE/WALL to FENCE; TRAPDOOR to TRAPDOOR; WATER to WATER; LAVA to LAVA; LEAVES to LEAVES. DOOR, FENCE_GATE, and OTHER fall through to vanilla (state-dependent).

    encodeBlockKind now redirects MAGMA_BLOCK, HONEY_BLOCK, POWDER_SNOW, lit campfires, and LAVA_CAULDRON to KIND_OTHER to prevent false BLOCKED returns for those blocks.

    Parity correction: LiquidBlock.isPathfindable(LAND) is true in 26.1.x (water blocks return PathType.WATER, not BLOCKED). Updated kindToPathType and predictCategory accordingly.

  • Walkability cache session 5: A/B flags and hit-rate counters. -Dferrite.nav.cache (default true) gates the whole cache for clean vanilla-baseline measurement runs; -Dferrite.nav.parity (default false) gates the parity validator, which had been running per-node JNI and string work on every ground-mob findPath after validation was already complete. Hit/ambiguous/miss/snapshot counters in NavigationCacheBridge feed a [nav-cache] line in the 5 s monitor report, so measurement runs report hit rate alongside timing deltas.

Fixed

  • Nav-cache snapshot gate desync. The section-snapshot gate in PathFinderMixin checked the Rust store while the hot path reads the Java 512-slot kind cache. A slot collision or door eviction emptied the Java slot while Rust still reported cached, so the section never refilled and went permanently cold. The gate now checks the Java cache (hasJavaSection), which also drops the per-section JNI call from the pre-fill loop.
  • Asymmetric door eviction. Placing or removing a door evicted the Java cache slot but not the Rust section store (empty match arms in nav_cache.rs). Eviction is now symmetric: any kind-crossing change evicts both stores; door open/close (DOOR to DOOR) is still filtered.
  • Snapshot box could cache wrong-AIR sections. The pre-fill bounding box extended past the chunks PathNavigationRegion actually backs, where the region serves EmptyLevelChunk (all AIR). Those sections were cached as permanently wrong AIR data invisible to the parity gate, which only checks in-region path nodes. The box is now clamped to region-backed chunks (new PathNavigationRegionAccessor) and world build height, and null getChunkNow entries are skipped.
0.6.4-alpha+26.1.2Альфа26.1.1, 26.1.2 · 20 мая 2026 г.

Direction

Next: session 4 of the walkability cache — replace vanilla's per-node getBlockState calls inside PathFinder with reads from the Rust section store. The parity gate from 0.6.4-alpha gates that swap.

[0.6.4-alpha] — 2026-05-17

Added

  • Dispatcher latency probe (/ferrite probe dispatcher on, default off). Captures queue-wait per priority lane and per-task wall time on the worldgen and light executors. Measurement on fast-flight load: task body is 4-10x the dispatcher's worst tail, so the dispatcher is not the bottleneck. Probe stays in tree for re-measurement under other workloads.

  • Walkability cache infrastructure (sessions 1-3). Block-kind cache for the pathfinding subsystem: Rust section store (4096-cell flat arrays, evict on block change), JNI surface, Java bridge with 18-category block classifier, lazy section fill on path requests, and a parity gate that validates cache predictions against vanilla's node evaluator. Parity result: 6 critical mismatches out of hundreds of nodes checked per session (all structural 2-block-model limits). The performance swap (session 4) is the follow-on.

Removed

  • Dead SurfaceValidator.onServerTick method and its fields (zero callers).

Internal

  • Threading audit (docs/COMPATIBILITY.md): three-tier safety classification of every non-final static field on worldgen and entity-tick paths, plus Rust-side concurrency posture (zero unsafe statics, zero plain cells).
  • Doc index (docs/DOC_MAP.md) and various doc updates across JOURNEY, FUTURE_PLANS, and per-subsystem writeups.
0.6.3-alphaАльфа26.1.2 · 6 мая 2026 г.

[0.6.3-alpha] — 2026-05-03

Added

  • AC offer-based Rust kernel (/ferrite redstone ac-rust on). Mirrors AC's powerNetwork() loop in Rust: offer-based propagation with flow-direction tracking, priority-queue ordered output. Parity-clean (0 oracle mismatches sustained across Phase 3 validation). ~16% aggregate wire-cost reduction vs the existing relaxation kernel on heavy workloads.

Notes

  • Existing relaxation kernel (RUST_BFS) stays in tree as fallback. Both kernels coexist; AC-Rust activates first when enabled, BFS takes over if the AC path bails (overflow / native unavailable).
  • Phase 3 depower fix: runRustAcBatch() now calls findPower(wire, true) after findExternalPower() to pull outside-cascade wire contributions before serializing. Fixes boundary wire power=0 mismatches the oracle surfaced during initial validation (~5% mismatch rate before fix, 0 after).

Комментарии

Загружаем…