## [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.
Developer information
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle.
maven { name = "Modrinth"; url = "https://api.modrinth.com/maven" }