Fly with the Java port of nether-pathfinder - #19
Merged
Merged
Conversation
The whole of babbaj's nether-pathfinder in plain Java, under cheesecake.process.elytra.pathfinder, as it stands on the java-port branch of 0Mattias/nether-pathfinder at 6d807d0, written for babbaj/nether-pathfinder#31. Each class is the C++ file of the same name: the chunk octree, the raytracer, the A* search over octree cubes, the Nether terrain generator and the region-file reader. The page allocator, the thread pool, the JNI layer and the Unsafe accessors have no counterpart: a chunk is an object that lives as long as it is referenced, the table is a ConcurrentHashMap, and lookups, inserts, the search and rays can run at once from any thread. The tests hold the port to the native library's answers. An FNV-1a hash of each of 625 generated chunks and the hit and hit position of 4000 rays over generated terrain, recorded by the oracle in that repository, are reproduced to the bit. The search, the table, region files, cancel, the segment time-out and the rays the native library could not take -- a point, a coordinate that is not finite, an end on a voxel corner -- have tests of their own. Nothing uses the package yet; the next commit does. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
NetherPathfinderContext asks cheesecake.process.elytra.pathfinder for paths and lines of sight, with a Chunk object where the native library handed out a pointer: the chunk packer fills a Chunk, a block update sets a bit on one, the solver's block lookups cache one, and there is nothing to free. The Unsafe fill of an all-solid section is Chunk.fillSection. The dev.babbaj:nether-pathfinder dependency, its maven repository, the nested jar and the natives it carried for each platform go, and with them the system check: every system is supported, so NullElytraProcess goes too, and elytraCustomAllocator is kept only so that a settings file naming it still loads. What the native library made necessary is reconsidered, as #18 asked: - The read-write lock stays, on the same sides as before, so that the threads run in the order the flights were tested in. The port needs none of it, and dropping it is a follow-up. - destroy() no longer takes the write lock to free the context. Closing the table under a running ray or search only changes what it answers. - A path calculation that has not answered in thirty seconds rebuilds its context instead of leaking one, since there is no hung thread to join. - UnusableRays stays, for the answers the flight wants: a point is visible from itself, a ray that is not finite is not, and an end on a voxel corner is decided by the voxel the ray crosses last. CI checks the jar for the pathfinder's classes instead of the nested jar, the headless client's proof that the mod ran is a line the provider now logs, and the detection of the native library's exit(696969) goes. The README's status bullets say what is left of the three upstream issues. Closes #18. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The headless client's proof that the mod ran is the "Cheesecake loaded" line the provider logs, and the first run of it never matched: the client colours its log lines, and the escape codes sit between the logger's name in parentheses and the message, so a fixed string with a space between the two finds nothing. A pattern that allows anything between them matches the line as a local client wrote it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Baritone's CachedRegion writes a chunk's two bits per block with BitSet.toByteArray(): bit n sits in byte n / 8 at position n % 8, the lowest bit first. The native reader took a byte's bits from the top down (baritone.cpp, get2Bits: `>> (6 - (i % 8))`) and the port copied it, so block x of every aligned run of four along x came back as block x ^ 3: each such run mirrored, in every chunk a search took from the region cache rather than from the game. Hard to see in flight, since the cache only fills in what the game has not loaded and terrain in runs of four is close to its own mirror image, but wrong. The test packed its file the same wrong way and passed; it now builds the chunk with a BitSet as CachedChunk does, sets one block solid and one water, and checks that the mirror positions are air. The region directory is Baritone's `cache`, not `regions`, in the docs and the test, and the oracle's doc names its real path. The same fix, on the port's own branch, is 0Mattias/nether-pathfinder 4784d69. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Sep 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Nether pathfinder is now the Java port of babbaj's nether-pathfinder, under
cheesecake.process.elytra.pathfinder, in place of the native library and its nested jar. The port was written for babbaj/nether-pathfinder#31 and goes to Baritone next.Four commits: the package with its tests and oracle files; the seam; a grep in the smoke test that tolerates the log's colour codes; and a fix to the region reader, which took each byte's two-bit block types from the top down while Baritone writes them lowest bit first, so every aligned run of four blocks along x came back mirrored in any chunk a search took from the region cache (the native library has the same bug).
NetherPathfinderContextgets aChunkwhere it had a pointer; the dependency, the maven repository, theUnsafefill, the system check andNullElytraProcessgo;elytraCustomAllocatorstays as a deprecated no-op so that settings files naming it still load.What the native library made necessary, reconsidered as #18 asked: the read-write lock stays on the same sides as before;
destroy()no longer takes the write lock; the thirty-second watchdog rebuilds the context instead of leaking one;UnusableRaysstays, for the answers the flight wants. The README's status bullets say what is left of the three upstream issues. CI checks the jar for the classes rather than the nested jar, takes aCheesecake loadedline the provider now logs as proof the mod ran, and drops the detection of the native exit code.Verified locally:
./gradlew buildgreen with 100 tests, 34 of them the port's; the four in-world elytra flights passed (above the build limit, auto-jump, Nether below and above the roof).From the port's branch: rays 0.56 to 0.67 µs against the native 0.75, searches and terrain generation level with native, generated chunks and ray hits bit-identical to the native oracle.
Closes #18.
🤖 Generated with Claude Code