Skip to content

Conversation

babbaj
Copy link
Collaborator

@babbaj babbaj commented Apr 4, 2025

Started by @underscore-zi
nether-pathfinder changes have been merged in babbaj/nether-pathfinder#20
Closes #4187

@babbaj babbaj changed the title Nether elytra update Elytra in overworld Apr 4, 2025
@babbaj babbaj marked this pull request as ready for review April 4, 2025 07:29
Copy link

@thelampgod thelampgod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow!

@underscore-zi
Copy link

underscore-zi commented Apr 5, 2025

I do have a couple minor commits over on https://github.com/underscore-zi/baritone

First is respecting the allowRoof setting when searching for a landing spot. I had left a TODO in for this but hadn't done so yet.

Second is adding Cobblestone and Obsidian to allowed landing blocks. In vanilla the current list is fine but I was using this around 2b's spawn and it had some issues finding landing spots.

@ZacSharp
Copy link
Collaborator

ZacSharp commented Apr 6, 2025

Can you please wait three days with merging? I'd like to properly read through and test this, but won't be able to do so before April 8.

@babbaj
Copy link
Collaborator Author

babbaj commented Apr 6, 2025

leijurv never merges my PRs anyways

@leijurv
Copy link
Member

leijurv commented Apr 6, 2025

Can you please wait three days with merging?

say no more, i'll check back next month

Copy link
Collaborator

@ZacSharp ZacSharp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, didn't expect quite as much breakage, but this adds at least two ways to crash the game.

  • Disabling elytraUseBaritoneCache unconditionally causes an NPE, crashing the game unless this happens inside a command
  • Disabling elytraAllowAboveRoof while flying above the nether roof and then causing recalculation crashes the game. I didn't even get a crash report, but no segfault either?
  • Enabling elytraPredictTerrain in the overworld leads to endless recalculation and chat spam. Actually not a crash though.

Some less severe points

  • The wall of text printed by #elytra unless elytraTermsAccepted is now outdated. It mentions elytra flight only being for the nether (now wrong) and also recommends elytraAutoJump, which has hardly any chance of working in the overworld, and should also mention that terrain prediction is nether-only.
  • The path is automatically recalculated when elytraNetherSeed changes, elytraAllowThighsSpaces does not have this effect. Not sure whether automatically recalculating is better.

I also really do not like how we are offsetting positions back and forth all across the code. Just look at how many times this went wrong with the existing chunk cache.
Can't we just use exactly one coordinate type (absolute world coordinates) in Baritone and shift to 0 based at the API boundary?
You didn't want to do this in nether-pathfinder itself, but maybe we can wrap the java side of the API to do the shifting?

Comment on lines 85 to 89
if (this.dimension == Level.NETHER) dim = NetherPathfinder.DIMENSION_NETHER;
else if (this.dimension == Level.END) dim = NetherPathfinder.DIMENSION_END;
else dim = NetherPathfinder.DIMENSION_END;
int height = Math.min(world.dimensionType().height(), 384);
if (!Baritone.settings().elytraAllowAboveRoof.value && dim == NetherPathfinder.DIMENSION_NETHER) height = Math.min(height, 128);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch. Can you please autoformat your code with whatever formatting the rest of Baritone uses?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using properly formatted braces would make it take up more lines for no benefit

boolean isSolid = pair.second() != AIR_BLOCK_STATE;
Octree.setBlock(ptr, pos.getX() & 15, pos.getY(), pos.getZ() & 15, isSolid);
});
// not inserting or deleting from the cache hashmap so we should be fine not being exclusive
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except iirc C++ considers any data race undefined behavior and doing this across an ffi boundary won't make things better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's undefined behavior if another thread is writing to the data at the same time we are reading it but that is not the case here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are the writing thread here, but since we only have the read lock another thread may do the reading required to trigger undefined behavior.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case you forgot / didn't see it, there's an Octree.setBlock call in this block. The hashmap reading is hopefully fine, as the comment says.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pathfinder racing with this would be inconsequential however multiple calls to this to nearby blocks could cause bad data to be written so i will change it to use a write lock. The read executor is still single threaded so there currently isn't a difference anyways.

@babbaj
Copy link
Collaborator Author

babbaj commented Apr 10, 2025

Disabling elytraUseBaritoneCache unconditionally causes an NPE, crashing the game unless this happens inside a command

fixed

  • Disabling elytraAllowAboveRoof while flying above the nether roof and then causing recalculation crashes the game. I didn't even get a crash report, but no segfault either?

I don't think this description is accurate. If elytraAllowAboveRoof is off and we put ourself above the roof then there is a crash (nether-pathfinder printing "retard" to stderr and calling std::terminate) but changing that setting while flying has no effect except possibly when it finds a landing spot.

I have not yet fixed this but I will probably fix it by pausing pathfinding until the player goes back below the roof.

Enabling elytraPredictTerrain in the overworld leads to endless recalculation and chat spam. Actually not a crash though.

fixed

The path is automatically recalculated when elytraNetherSeed changes, elytraAllowThighsSpaces does not have this effect. Not sure whether automatically recalculating is better.

fixed to behave the same

@underscore-zi
Copy link

Have nether-pathfinder generate a path to y=320, then on the java side, add a path point after that that's at like same x,z but y=350 or something. Then the next path point is the goal x,z at y=350.

I don't have much time to work on this at the moment, but I originally used an implementation kinda like that and was working on a less hacked together implementation more recently but haven't finished. So I'm just kinda dumping what I had for my future-self or if someone else gives it a stab:

To allow it to follow a path that goes outside of the pathfinders limits ElytraBehavior:clearView has to be patched to use ctx.world().clip(...) instead of the native pathfinder when above the y-limit. And ElytraBehavior:passable to use this.bsi like the ignoreLava path instead of this.boi.

Then for actually generating the path without pathfinder support for GoalY, I took advantage of the fact that it would attempt to pathFind again when near the end of an incomplete(finished=false) path.

When pathFinding it would check the source. If its above or near 320 and above the height map of the area it would just generate point path. If going far enough it would attempt to pathfind to 75%[0] the minimum distance with y=320, or it would just pathfind to the destination.

This allowed it to fly under a roof by just repeatedly creating incomplete paths going 75% the minimum distance and eventually switch to the point path whenever the route became clear.

Also its worth noting that the point path did need to be more detailed than just the destination point as it didn't like to fly if the next point wasn't loaded in. Though that might be fixable by patching clearView to be true when at elevation instead of using clip(...).

[0] 75% wasn't chosen for any particular reason, just giving some breathing room

@Murat65536 Murat65536 mentioned this pull request Aug 4, 2025
@lawnguy1201
Copy link

What has happened with this?

@kittenvr
Copy link

What has happened with this?

A random guy has commented on this 3 months later

@lawnguy1201
Copy link

What has happened with this?

A random guy has commented on this 3 months later

no shit

@kittenvr
Copy link

What has happened with this?

A random guy has commented on this 3 months later

no shit

So why are you asking if you already know

@underscore-zi
Copy link

underscore-zi commented Aug 12, 2025

Still actively working on it.

I have something that generally works and goes above the build limit. Though I've been working out some bugs where it seems to get stuck momentarily as if it can't see the next node (despite clear raytraces to it).

Also some issues with generated the transitions between the different path generators since it usually tries to transition right at the edge of loaded chunks when it tries to pathfind right when a new chunk gets loaded.

@lawnguy1201
Copy link

Still actively working on it.

I have something that generally works and goes above the build limit. Though I've been working out some bugs where it seems to get stuck momentarily as if it can't see the next node (despite clear raytraces to it).

Also some issues with generated the transitions between the different path generators since it usually tries to transition right at the edge of loaded chunks when it tries to pathfind right when a new chunk gets loaded.

Nice, would there be anyway I could get the .jar. working on a project and it need B to fly in the OW.

@underscore-zi
Copy link

underscore-zi commented Aug 22, 2025

I'm trying to troubleshoot some behavior and wondering if any of you all might be able to point me to where in code this behavior might be coming from.

2025-08-22-113218482-2c80a.webm

Basically, as the Elytra crosses the build limit it starts to have trouble following the path. It'll follow the path, then seem to get stuck and start spinning. This is similar to the behavior that happens when about to enter an unloaded chunk though it is loaded in this case.

I suspect something sees it as unloaded (ctx.world().isLoaded returns false for y > build limit, but I've patched that already in ElytraBehavior). Though I'm not sure where this spin behavior comes from exactly. And if I reduce the flight level to be under the build limit, it works without issue. So I'm thinking there is some check buried away I've missed besides the one in attemptNextSegment

Edit: and for what its worth raytraces all come up green.

@kittenvr
Copy link

I'm trying to troubleshoot some behavior and wondering if any of you all might be able to point me to where in code this behavior might be coming from.
2025-08-22-113218482-2c80a.webm

Basically, as the Elytra crosses the build limit it starts to have trouble following the path. It'll follow the path, then seem to get stuck and start spinning. This is similar to the behavior that happens when about to enter an unloaded chunk though it is loaded in this case.

I suspect something sees it as unloaded (ctx.world().isLoaded returns false for y > build limit, but I've patched that already in ElytraBehavior). Though I'm not sure where this spin behavior comes from exactly. And if I reduce the flight level to be under the build limit, it works without issue. So I'm thinking there is some check buried away I've missed besides the one in attemptNextSegment

Edit: and for what its worth raytraces all come up green.

are you sure the chunks arent actually unloaded

@underscore-zi
Copy link

are you sure the chunks arent actually unloaded

Yes

@ZacSharp
Copy link
Collaborator

Having a short look at the solver it looks like isHitboxClear might also need patching to not use context.raytrace. Not sure why passable needs to use bsi instead of boi since boi.get returns false/air for out of bounds positions, which is what we need here.

@leijurv
Copy link
Member

leijurv commented Aug 23, 2025

yeah looks like something messed up with the raytracer. out of bounds (above the ceiling) should return air

@underscore-zi
Copy link

Thanks! Fixed it. Was able to trace the bug down from isHitBoxClear.

It was indeed a raytracing bug, miscalculated when a target was in/out of bounds resulting in misusing the NetherPathfinder for OOB raytraces.

@nonokirby
Copy link

Is this pull stable enough to fork and run currently, or does it have major issues still? specifically looking to elytrafly in/around 2b's spawn if knowing terrain helps.

@ZacSharp
Copy link
Collaborator

As far as I know there are no known (new) bugs, so should definitely be usable.

(The reason this isn't merged is a pending functional change)

@underscore-zi
Copy link

I have some commits implementing flight above the build limit over on: https://github.com/underscore-zi/baritone

I do make one major structural change which might raise some eyebrows. I've extended the API with IElytraPathfinderContext and IElytraPathfinderContextFactory

So now, the NetherPathfinderContext basically already implemented the interface, and I've added a new SkyPathfinderContext which also implements the interface and wraps the NetherPathfinder to extend it adding support for flight above the build limit. ElytraBehavior uses the appropriate context for the dimension/settings, keeping the original performance if users want that.

In defense of having this in the API is does serve to implement a feature I've wanted, the ability to navigate between waypoints without doing the whole takeoff/fly/land process for every point or changing the destination when the flight gets close to each point. I made a nice like flight replayer for myself with this.

@ZacSharp
Copy link
Collaborator

ZacSharp commented Sep 4, 2025

Tried to come up with a funky way to review this. Wouldn't have expected that two people working on one pr is such a big problem on a "collaboration platform".

SkyPathfinderContext uses the wrong naming convention for it's private helpers.

underscore-zi/baritone@20c1631...94a466b#diff-aa0f9f28257c586978349ec09d0ec52c19858ebfc79ff63b56b498a69ca16d14R28
I don't like exposing nether-pathfinder API directly in our API. And UnpackedSegmend is imho a prime example of what's considered an implementation detail.

underscore-zi/baritone@20c1631...94a466b#diff-f881174eae586d93b19f8eb3f9c26af571c0ca278f7d9a108cba4d66a71f519fR397-R398
Aren't there fields caching these two values?

underscore-zi/baritone@20c1631...94a466b#diff-f881174eae586d93b19f8eb3f9c26af571c0ca278f7d9a108cba4d66a71f519fR443-R458
It looks weird to have both a special case when the field is null in the getter and a null-replacement in the setter.

underscore-zi/baritone@20c1631...94a466b#diff-eebf5e50d8fe55d39379412b51279851bba3a6f3019584be8ea2bfd36ce71fe1R85
I like how this is no longer being passed around. It uses the exact same internal storage and is fundamentally tied to the context, so might as well be part of it.


Honestly I'm not happy with the two new interfaces. IElytraPathfinderContextFactory feels like it's mostly boilerplate and IElytraPathfinderContext is just bad API. It is what netherpathfinder expects and using it internally makes sense, but it's a messy implementation detail.
There's also a concern about deadlocks here, because giving API users control of the context lock means the thing can lock and unlock in ways we do not expect. The thread "safety" in this part of Baritone is a mess already.

Flying around without landing sounds very reasonable though, so maybe there's a way to implement that feature without putting implementation details into the API package?


A somewhat unrelated idea I had is that iirc the pathfinder uses a symmetric movement set so there is no difference between going forwards or backwards. That means if the goal is already in render distance and we are still above the world we could run the pathfinder from the goal towards the build limit / our current position to determine where to transition down. Not sure whether that helps with anything.

# Conflicts:
#	src/main/java/baritone/process/ElytraProcess.java
#	src/main/java/baritone/process/elytra/ElytraBehavior.java
#	src/main/java/baritone/process/elytra/NetherPathfinderContext.java
@babbaj
Copy link
Collaborator Author

babbaj commented Sep 4, 2025

just merged his branch into mine. he was also a few commits behind so I had to merge and fix some conflicts.

@underscore-zi
Copy link

And UnpackedSegmend is imho a prime example of what's considered an implementation detail.

I feel like the Stream<BetterBLockPos> and boolean wrapper are what would be necessary to expose to allow someone else to provide a path. The name is a bit off though since the public side would have no knowledge of the "packed" segments.

Perhaps a simpler option would be to only allow the API user to provide waypoints and leave the path to Baritone. That perhaps fits better with Baritone more generally and would probably be the main usecase. One use-case I had for full pathing was flying down 2b diagonal highways where there was some active wither griefing so I couldn't bounce.

I don't like exposing nether-pathfinder API directly in our API.

Yeah, I wasn't the biggest fan of my own approach there though I mostly was just trying not to break anything outside of my own code. So isolated it via the abstraction. But yeah, I think I can clean that up quite a bit.

Raytracing stuff can be pulled back internal, no reason to have that overloadable if the base implementation supports OOB traces it handles all cases. Though it adds a bit of overhead as it needs to check which tracer to use. Chunk/block information can be obtained by any mod already so no point in providing that either; that also removes the locks.

Which would leave pathFindAsync, cancel and maybe destroy which feels much more sane. And I think that might remove the Factory too as there wouldn't be a need to provide the Baritone cache path into it.

@underscore-zi
Copy link

Committed to my fork again: https://github.com/underscore-zi/baritone

I pulled everything new out of the API, though I still use a simpler interface internally so the original Nether code can be swapped in depending on settings.

@Murat65536
Copy link
Contributor

Fixing a few of the things Codacy is mad about might also be a good idea. Mostly naming things. I wouldn't worry about the NPath complexity.

@underscore-zi
Copy link

I believe I've addressed all of the issues from Codacy that were still relevant. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for auto-flight with Elytras in the overworld and the End.
9 participants