Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/api/java/baritone/api/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,21 @@ public final class Settings {
*/
public final Setting<Boolean> sprintInWater = new Setting<>(true);

/**
* Jump while sprinting on flat traverses for extra speed
*/
public final Setting<Boolean> allowJumpSprint = new Setting<>(false);

/**
* Allow jump-sprinting on long flat diagonals
*/
public final Setting<Boolean> allowJumpSprintDiagonal = new Setting<>(true);

/**
* Allow head-hit jump pulses under low ceilings to maintain speed
*/
public final Setting<Boolean> allowHeadHits = new Setting<>(true);

/**
* When GetToBlockProcess or MineProcess fails to calculate a path, instead of just giving up, mark the closest instance
* of that block as "unreachable" and go towards the next closest. GetToBlock expands this search to the whole "vein"; MineProcess does not.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
public class MovementAscend extends Movement {

private int ticksWithoutPlacement = 0;
// Latch to guarantee a jump within a short window once we commit to takeoff
private int takeoffLatchTicks = 0;

public MovementAscend(IBaritone baritone, BetterBlockPos src, BetterBlockPos dest) {
super(baritone, src, dest, new BetterBlockPos[]{dest, src.above(2), dest.above()}, dest.below());
Expand All @@ -46,6 +48,7 @@ public MovementAscend(IBaritone baritone, BetterBlockPos src, BetterBlockPos des
public void reset() {
super.reset();
ticksWithoutPlacement = 0;
takeoffLatchTicks = 0;
}

@Override
Expand Down Expand Up @@ -161,11 +164,8 @@ public MovementState updateState(MovementState state) {
return state.setStatus(MovementStatus.UNREACHABLE);
}
super.updateState(state);
// TODO incorporate some behavior from ActionClimb (specifically how it waited until it was at most 1.2 blocks away before starting to jump
// for efficiency in ascending minimal height staircases, which is just repeated MovementAscend, so that it doesn't bonk its head on the ceiling repeatedly)
if (state.getStatus() != MovementStatus.RUNNING) {
return state;
}
// Allow approach timing even if state isn't yet RUNNING, as long as the landing block is walkable.
boolean isRunning = state.getStatus() == MovementStatus.RUNNING;

if (ctx.playerFeet().equals(dest) || ctx.playerFeet().equals(dest.offset(getDirection().below()))) {
return state.setStatus(MovementStatus.SUCCESS);
Expand All @@ -188,6 +188,69 @@ public MovementState updateState(MovementState state) {
return state;
}
MovementHelper.moveTowards(ctx, state, dest);
// Maintain forward; adjust sprint and jump timing based on edge distance for clean cadence
state.setInput(Input.MOVE_FORWARD, true);
if (Baritone.settings().sprintAscends.value) {
int dx = Integer.signum(dest.x - src.x);
int dz = Integer.signum(dest.z - src.z);
boolean alongX = Math.abs(dx) == 1;

double px = ctx.player().position().x;
double pz = ctx.player().position().z;
double vx = ctx.player().getDeltaMovement().x;
double vz = ctx.player().getDeltaMovement().z;
double speedXZ = Math.hypot(vx, vz);
// Speed factor in [0,1]: 0 near slow walk, 1 at fast sprint/boosts
double speedFactor = Math.max(0.0, Math.min(1.0, (speedXZ - 0.19D) / 0.08D));
// Distance to the leading edge of the current block in the direction of travel
double edgeDist;
if (alongX) {
double edgeX = dx > 0 ? (src.x + 1.0D) : (double) src.x;
edgeDist = Math.max(0.0, dx > 0 ? (edgeX - px) : (px - edgeX));
} else {
double edgeZ = dz > 0 ? (src.z + 1.0D) : (double) src.z;
edgeDist = Math.max(0.0, dz > 0 ? (edgeZ - pz) : (pz - edgeZ));
}

// Small lateral tolerance: avoid jumping if we're too far off the center line
double lateralOffset = alongX ? Math.abs((src.z + 0.5D) - pz) : Math.abs((src.x + 0.5D) - px);
boolean centered = lateralOffset <= 0.28D;

boolean onGround = ctx.player().onGround();
// Secondary proximity using dest center to avoid missing the window if edge calc drifts
double flatDistToDestCenter = Math.max(Math.abs((dest.x + 0.5D) - px), Math.abs((dest.z + 0.5D) - pz));
// Dynamic thresholds based on approach speed: earlier taper / earlier jump when too fast
double taperStart = 0.60D + 0.25D * speedFactor; // up to 0.85 at high speed
double jumpDist = 0.32D + 0.10D * speedFactor; // up to 0.42 at high speed
boolean withinTaper = onGround && centered && edgeDist < taperStart && edgeDist > jumpDist;
boolean shouldJump = onGround && (
(centered && edgeDist <= jumpDist) ||
flatDistToDestCenter <= 0.85D ||
ctx.player().horizontalCollision
);

// Takeoff latch: once we enter taper or are very close, guarantee jump in the next 2 ticks
if (withinTaper || (onGround && edgeDist <= (jumpDist + 0.08D))) {
takeoffLatchTicks = Math.max(takeoffLatchTicks, 2 + (int) Math.round(2 * speedFactor));
}
if (takeoffLatchTicks > 0) {
takeoffLatchTicks--;
// While latched, bias toward jumping sooner rather than later
if (onGround) {
shouldJump = true;
}
}

// Apply inputs without early returns to avoid missing the jump window due to ordering elsewhere
state.setInput(Input.SPRINT, !withinTaper);
if (shouldJump) {
state.setInput(Input.SPRINT, true);
state.setInput(Input.JUMP, true);
}
if (!onGround) {
state.setInput(Input.SPRINT, true);
}
}
if (MovementHelper.isBottomSlab(jumpingOnto) && !MovementHelper.isBottomSlab(BlockStateInterface.get(ctx, src.below()))) {
return state; // don't jump while walking from a non double slab into a bottom slab
}
Expand All @@ -197,10 +260,10 @@ public MovementState updateState(MovementState state) {
return state;
}

int xAxis = Math.abs(src.getX() - dest.getX()); // either 0 or 1
int zAxis = Math.abs(src.getZ() - dest.getZ()); // either 0 or 1
double flatDistToNext = xAxis * Math.abs((dest.getX() + 0.5D) - ctx.player().position().x) + zAxis * Math.abs((dest.getZ() + 0.5D) - ctx.player().position().z);
double sideDist = zAxis * Math.abs((dest.getX() + 0.5D) - ctx.player().position().x) + xAxis * Math.abs((dest.getZ() + 0.5D) - ctx.player().position().z);
int xAxis = Math.abs(dest.x - src.x); // either 0 or 1
int zAxis = Math.abs(dest.z - src.z); // either 0 or 1
double flatDistToNext = xAxis * Math.abs((dest.x + 0.5D) - ctx.player().position().x) + zAxis * Math.abs((dest.z + 0.5D) - ctx.player().position().z);
double sideDist = zAxis * Math.abs((dest.x + 0.5D) - ctx.player().position().x) + xAxis * Math.abs((dest.z + 0.5D) - ctx.player().position().z);

double lateralMotion = xAxis * ctx.player().getDeltaMovement().z + zAxis * ctx.player().getDeltaMovement().x;
if (Math.abs(lateralMotion) > 0.1) {
Expand All @@ -218,7 +281,8 @@ public MovementState updateState(MovementState state) {
// Once we are pointing the right way and moving, start jumping
// This is slightly more efficient because otherwise we might start jumping before moving, and fall down without moving onto the block we want to jump onto
// Also wait until we are close enough, because we might jump and hit our head on an adjacent block
return state.setInput(Input.JUMP, true);
// Re-engage sprint at jump to preserve momentum up the block
return state.setInput(Input.SPRINT, true).setInput(Input.JUMP, true);
}

public boolean headBonkClear() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,10 @@ public MovementState updateState(MovementState state) {
if (state.getStatus() != MovementStatus.RUNNING) {
return state;
}
// Keep sprint through descends when not in liquid; prevents de-sprinting during downhill chains
if (!MovementHelper.isLiquid(ctx, ctx.playerFeet())) {
state.setInput(Input.SPRINT, true);
}

BlockPos playerFeet = ctx.playerFeet();
BlockPos fakeDest = new BlockPos(dest.getX() * 2 - src.getX(), dest.getY(), dest.getZ() * 2 - src.getZ());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ public MovementState updateState(MovementState state) {
}
if (sprint()) {
state.setInput(Input.SPRINT, true);
// keep sprint while airborne to avoid unintended de-sprint on diagonal hops
if (!ctx.player().onGround()) {
state.setInput(Input.SPRINT, true);
}
}
MovementHelper.moveTowards(ctx, state, dest);
return state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,11 +244,9 @@ public MovementState updateState(MovementState state) {
boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(ctx, positionToPlace) || ladder || MovementHelper.canUseFrostWalker(ctx, positionToPlace);
BlockPos feet = ctx.playerFeet();
if (feet.getY() != dest.getY() && !ladder) {
logDebug("Wrong Y coordinate");
if (feet.getY() < dest.getY()) {
System.out.println("In movement traverse");
return state.setInput(Input.JUMP, true);
}
// When jump-sprinting across flat traverses, being airborne is expected; do not warn.
// Keep sprint held while airborne to maintain cadence; PathExecutor manages jump timing.
state.setInput(Input.SPRINT, true);
return state;
}

Expand All @@ -271,6 +269,7 @@ public MovementState updateState(MovementState state) {
BlockState intoAbove = BlockStateInterface.get(ctx, into.above());
if (wasTheBridgeBlockAlwaysThere && (!MovementHelper.isLiquid(ctx, feet) || Baritone.settings().sprintInWater.value) && (!MovementHelper.avoidWalkingInto(intoBelow) || MovementHelper.isWater(intoBelow)) && !MovementHelper.avoidWalkingInto(intoAbove)) {
state.setInput(Input.SPRINT, true);
// Let PathExecutor decide final jump timing; we only hint here to avoid conflicting inputs near edges
}

BlockState destDown = BlockStateInterface.get(ctx, dest.below());
Expand Down
Loading