From 15178932ea06f8b41b661fb7fe18d57907152296 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Mon, 16 Feb 2026 00:22:43 -0800 Subject: [PATCH 1/2] elytra jump takeoff --- src/api/java/baritone/api/Settings.java | 5 +- .../java/baritone/process/ElytraProcess.java | 114 +++++------------- .../process/elytra/ElytraBehavior.java | 8 +- 3 files changed, 36 insertions(+), 91 deletions(-) diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index dc7669e75..799e4dd63 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -31,7 +31,6 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,8 +42,8 @@ import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.List; import java.util.*; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -1489,7 +1488,7 @@ public final class Settings { public final Setting elytraRenderSimulation = new Setting<>(true); /** - * Automatically path to and jump off of ledges to initiate elytra flight when grounded. + * Automatically jump to initiate elytra flight when grounded. */ public final Setting elytraAutoJump = new Setting<>(false); diff --git a/src/main/java/baritone/process/ElytraProcess.java b/src/main/java/baritone/process/ElytraProcess.java index 276ab431b..8453fd8cb 100644 --- a/src/main/java/baritone/process/ElytraProcess.java +++ b/src/main/java/baritone/process/ElytraProcess.java @@ -18,16 +18,12 @@ package baritone.process; import baritone.Baritone; -import baritone.api.IBaritone; import baritone.api.event.events.*; import baritone.api.event.events.type.EventState; import baritone.api.event.listener.AbstractGameEventListener; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalBlock; import baritone.api.pathing.goals.GoalXZ; -import baritone.api.pathing.goals.GoalYLevel; -import baritone.api.pathing.movement.IMovement; -import baritone.api.pathing.path.IPathExecutor; import baritone.api.process.IBaritoneProcess; import baritone.api.process.IElytraProcess; import baritone.api.process.PathingCommand; @@ -36,13 +32,10 @@ import baritone.api.utils.Rotation; import baritone.api.utils.RotationUtils; import baritone.api.utils.input.Input; -import baritone.pathing.movement.CalculationContext; -import baritone.pathing.movement.movements.MovementFall; import baritone.process.elytra.ElytraBehavior; import baritone.process.elytra.NetherPathfinderContext; import baritone.process.elytra.NullElytraProcess; import baritone.utils.BaritoneProcessHelper; -import baritone.utils.PathingCommandContext; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; @@ -53,21 +46,18 @@ import net.minecraft.world.level.block.AirBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import java.util.*; -import static baritone.api.pathing.movement.ActionCosts.COST_INF; - public class ElytraProcess extends BaritoneProcessHelper implements IBaritoneProcess, IElytraProcess, AbstractGameEventListener { public State state; private boolean goingToLandingSpot; private BetterBlockPos landingSpot; private boolean reachedGoal; // this basically just prevents potential notification spam - private Goal goal; private ElytraBehavior behavior; private boolean predictingTerrain; + private long startedJumpStateTime = 0L; @Override public void onLostControl() { @@ -75,7 +65,7 @@ public void onLostControl() { this.goingToLandingSpot = false; this.landingSpot = null; this.reachedGoal = false; - this.goal = null; + startedJumpStateTime = 0L; destroyBehaviorAsync(); } @@ -105,8 +95,6 @@ public void resetState() { } } - private static final String AUTO_JUMP_FAILURE_MSG = "Failed to compute a walking path to a spot to jump off from. Consider starting from a higher location, near an overhang. Or, you can disable elytraAutoJump and just manually begin gliding."; - @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { final long seedSetting = Baritone.settings().elytraNetherSeed.value; @@ -124,7 +112,6 @@ public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (calcFailed) { onLostControl(); - logDirect(AUTO_JUMP_FAILURE_MSG); return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } @@ -187,7 +174,6 @@ public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (ctx.player().isFallFlying()) { behavior.landingMode = this.state == State.LANDING; - this.goal = null; baritone.getInputOverrideHandler().clearAllKeys(); behavior.tick(); return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); @@ -205,46 +191,51 @@ public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (this.state == State.FLYING || this.state == State.START_FLYING) { this.state = ctx.player().isOnGround() && Baritone.settings().elytraAutoJump.value - ? State.LOCATE_JUMP + ? State.JUMP : State.START_FLYING; } - if (this.state == State.LOCATE_JUMP) { + if (this.state == State.JUMP) { + if (startedJumpStateTime == 0L) { + startedJumpStateTime = System.currentTimeMillis(); + } if (shouldLandForSafety()) { logDirect("Not taking off, because elytra durability or fireworks are so low that I would immediately emergency land anyway."); onLostControl(); return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } - if (this.goal == null) { - this.goal = new GoalYLevel(31); + final boolean isJumpBlocked = !ctx.world().getBlockCollisions(ctx.player(), ctx.player().getBoundingBox().move(0, 0.5, 0)).iterator().hasNext(); + if (ctx.player().isOnGround() && isJumpBlocked) { + ctx.player().jumpFromGround(); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } - final IPathExecutor executor = baritone.getPathingBehavior().getCurrent(); - if (executor != null && executor.getPath().getGoal() == this.goal) { - final IMovement fall = executor.getPath().movements().stream() - .filter(movement -> movement instanceof MovementFall) - .findFirst().orElse(null); - - if (fall != null) { - final BetterBlockPos from = new BetterBlockPos( - (fall.getSrc().x + fall.getDest().x) / 2, - (fall.getSrc().y + fall.getDest().y) / 2, - (fall.getSrc().z + fall.getDest().z) / 2 + final boolean canStartFlying = !ctx.player().isOnGround() && !ctx.player().isFallFlying(); + + if (canStartFlying) { + this.state = State.START_FLYING; + } else { + // todo: not sure if this is the best way to handle this. maybe just let the player decide when/where to walk to + if (System.currentTimeMillis() - startedJumpStateTime > 2500) { + logDirect("Unable to perform autoJump takeoff, pathing forward"); + final GoalXZ goal = GoalXZ.fromDirection( + ctx.playerFeetAsVec(), + ctx.player().getYHeadRot(), + 5 ); - behavior.pathManager.pathToDestination(from).whenComplete((result, ex) -> { + final BetterBlockPos forwardBlockPos = new BetterBlockPos(goal.getX(), ctx.player().position().y(), goal.getZ()); + behavior.pathManager.pathToDestination(forwardBlockPos).whenComplete((result, ex) -> { if (ex == null) { - this.state = State.GET_TO_JUMP; + startedJumpStateTime = 0L; + this.state = State.JUMP; return; } onLostControl(); }); this.state = State.PAUSE; - } else { - onLostControl(); - logDirect(AUTO_JUMP_FAILURE_MSG); - return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); + return new PathingCommand(goal, PathingCommandType.SET_GOAL_AND_PAUSE); } + return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH); } - return new PathingCommandContext(this.goal, PathingCommandType.SET_GOAL_AND_PAUSE, new WalkOffCalculationContext(baritone)); } // yucky @@ -252,27 +243,13 @@ public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); } - if (this.state == State.GET_TO_JUMP) { - final IPathExecutor executor = baritone.getPathingBehavior().getCurrent(); - final boolean canStartFlying = ctx.player().fallDistance > 1.0f - && !isSafeToCancel - && executor != null - && executor.getPath().movements().get(executor.getPosition()) instanceof MovementFall; - - if (canStartFlying) { - this.state = State.START_FLYING; - } else { - return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH); - } - } - if (this.state == State.START_FLYING) { if (!isSafeToCancel) { // owned baritone.getPathingBehavior().secretInternalSegmentCancel(); } baritone.getInputOverrideHandler().clearAllKeys(); - if (ctx.player().fallDistance > 1.0f) { + if (!ctx.player().isOnGround() && !ctx.player().input.jumping) { baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, true); } } @@ -394,9 +371,8 @@ public boolean isSafeToCancel() { } public enum State { - LOCATE_JUMP("Finding spot to jump off"), + JUMP("Takeoff"), PAUSE("Waiting for elytra path"), - GET_TO_JUMP("Walking to takeoff"), START_FLYING("Begin flying"), FLYING("Flying"), LANDING("Landing"); @@ -442,34 +418,6 @@ public void onPostTick(TickEvent event) { if (this.behavior != null && procThisTick == this) this.behavior.onPostTick(event); } - /** - * Custom calculation context which makes the player fall into lava - */ - public static final class WalkOffCalculationContext extends CalculationContext { - - public WalkOffCalculationContext(IBaritone baritone) { - super(baritone, true); - this.allowFallIntoLava = true; - this.minFallHeight = 8; - this.maxFallHeightNoWater = 10000; - } - - @Override - public double costOfPlacingAt(int x, int y, int z, BlockState current) { - return COST_INF; - } - - @Override - public double breakCostMultiplierAt(int x, int y, int z, BlockState current) { - return COST_INF; - } - - @Override - public double placeBucketCost() { - return COST_INF; - } - } - private static boolean isInBounds(BlockPos pos) { return pos.getY() >= 0 && pos.getY() < 128; } diff --git a/src/main/java/baritone/process/elytra/ElytraBehavior.java b/src/main/java/baritone/process/elytra/ElytraBehavior.java index d4913f466..7a382d08a 100644 --- a/src/main/java/baritone/process/elytra/ElytraBehavior.java +++ b/src/main/java/baritone/process/elytra/ElytraBehavior.java @@ -53,9 +53,9 @@ import net.minecraft.world.phys.Vec3; import java.awt.*; +import java.util.*; import java.util.List; import java.util.Queue; -import java.util.*; import java.util.concurrent.*; import java.util.function.UnaryOperator; @@ -359,7 +359,7 @@ private void pathfindAroundObstacles() { return; } } - if (!canSeeAny && rangeStartIncl < rangeEndExcl - 2 && process.state != ElytraProcess.State.GET_TO_JUMP) { + if (!canSeeAny && rangeStartIncl < rangeEndExcl - 2) { this.pathRecalcSegment(OptionalInt.of(rangeEndExcl - 1)).thenRun(() -> logVerbose("Recalculated segment since no path points were visible")); } } @@ -465,9 +465,7 @@ public void onReceivePacket(PacketEvent event) { } public void pathTo() { - if (!Baritone.settings().elytraAutoJump.value || ctx.player().isFallFlying()) { - this.pathManager.pathToDestination(); - } + this.pathManager.pathToDestination(); } public void destroy() { From 2c6bb868b4455662e0aec7908537e31445f96427 Mon Sep 17 00:00:00 2001 From: rfresh2 <89827146+rfresh2@users.noreply.github.com> Date: Mon, 16 Feb 2026 00:22:43 -0800 Subject: [PATCH 2/2] set goal in pathingcommand --- src/main/java/baritone/process/ElytraProcess.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/baritone/process/ElytraProcess.java b/src/main/java/baritone/process/ElytraProcess.java index 8453fd8cb..09a0b10fd 100644 --- a/src/main/java/baritone/process/ElytraProcess.java +++ b/src/main/java/baritone/process/ElytraProcess.java @@ -214,7 +214,7 @@ public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (canStartFlying) { this.state = State.START_FLYING; } else { - // todo: not sure if this is the best way to handle this. maybe just let the player decide when/where to walk to + // todo: would be better if we searched for a safe pos to takeoff from, and then pathed directly there if (System.currentTimeMillis() - startedJumpStateTime > 2500) { logDirect("Unable to perform autoJump takeoff, pathing forward"); final GoalXZ goal = GoalXZ.fromDirection( @@ -222,17 +222,7 @@ public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { ctx.player().getYHeadRot(), 5 ); - final BetterBlockPos forwardBlockPos = new BetterBlockPos(goal.getX(), ctx.player().position().y(), goal.getZ()); - behavior.pathManager.pathToDestination(forwardBlockPos).whenComplete((result, ex) -> { - if (ex == null) { - startedJumpStateTime = 0L; - this.state = State.JUMP; - return; - } - onLostControl(); - }); - this.state = State.PAUSE; - return new PathingCommand(goal, PathingCommandType.SET_GOAL_AND_PAUSE); + return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH); } return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH); }