diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java index 911c0dc7..f1a31553 100644 --- a/src/main/java/baritone/pathing/calc/Path.java +++ b/src/main/java/baritone/pathing/calc/Path.java @@ -139,11 +139,12 @@ class Path implements IPath { for (Moves moves : Moves.values()) { Movement move = moves.apply0(src); if (move.getDest().equals(dest)) { + // TODO instead of recalculating here, could we take pathNode.cost - pathNode.prevNode.cost to get the cost as-calculated? move.recalculateCost(); // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution return move; } } - // leave this as IllegalStateException; it's caught in AbstractNodeCostSearch + // this is no longer called from bestPathSoFar, now it's in postprocessing throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src)); } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementFall.java b/src/main/java/baritone/pathing/movement/movements/MovementFall.java index 818ae124..f901c61f 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementFall.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementFall.java @@ -114,7 +114,9 @@ public class MovementFall extends Movement { @Override public boolean safeToCancel(MovementState state) { - return state.getStatus() != MovementStatus.RUNNING; + // if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall + // then it's safe to cancel this + return playerFeet().equals(src) || state.getStatus() != MovementStatus.RUNNING; } private static BetterBlockPos[] buildPositionsToBreak(BetterBlockPos src, BetterBlockPos dest) { diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 22fc5909..2310f773 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -163,6 +163,14 @@ public class MovementParkour extends Movement { return res.cost; } + @Override + public boolean safeToCancel(MovementState state) { + // once this movement is instantiated, the state is default to PREPPING + // but once it's ticked for the first time it changes to RUNNING + // since we don't really know anything about momentum, it suffices to say Parkour can only be canceled on the 0th tick + return state.getStatus() != MovementState.MovementStatus.RUNNING; + } + @Override public MovementState updateState(MovementState state) { super.updateState(state); diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java index abd870e7..7c4ba237 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java @@ -319,6 +319,14 @@ public class MovementTraverse extends Movement { } } + @Override + public boolean safeToCancel(MovementState state) { + // if we're in the process of breaking blocks before walking forwards + // or if this isn't a sneak place (the block is already there) + // then it's safe to cancel this + return state.getStatus() != MovementState.MovementStatus.RUNNING || MovementHelper.canWalkOn(dest.down()); + } + @Override protected boolean prepared(MovementState state) { if (playerFeet().equals(src) || playerFeet().equals(src.down())) { diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java index 117e8008..9aeeac69 100644 --- a/src/main/java/baritone/pathing/path/PathExecutor.java +++ b/src/main/java/baritone/pathing/path/PathExecutor.java @@ -20,6 +20,7 @@ package baritone.pathing.path; import baritone.Baritone; import baritone.api.event.events.TickEvent; import baritone.api.pathing.movement.ActionCosts; +import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.Movement; import baritone.pathing.movement.MovementHelper; @@ -33,6 +34,7 @@ import net.minecraft.util.math.BlockPos; import java.util.Collections; import java.util.HashSet; +import java.util.Optional; import java.util.Set; import static baritone.pathing.movement.MovementState.MovementStatus.*; @@ -242,6 +244,10 @@ public class PathExecutor implements Helper { cancel(); return true; } + if (shouldPause()) { + logDebug("Pausing since current best path is a backtrack"); + return true; + } MovementState.MovementStatus movementStatus = movement.update(); if (movementStatus == UNREACHABLE || movementStatus == FAILED) { logDebug("Movement returns status " + movementStatus); @@ -270,6 +276,32 @@ public class PathExecutor implements Helper { return false; // movement is in progress } + private boolean shouldPause() { + Optional current = AbstractNodeCostSearch.getCurrentlyRunning(); + if (!current.isPresent()) { + return false; + } + if (!player().onGround) { + return false; + } + if (!MovementHelper.canWalkOn(playerFeet().down())) { + // we're in some kind of sketchy situation, maybe parkouring + return false; + } + if (!MovementHelper.canWalkThrough(playerFeet()) || !MovementHelper.canWalkThrough(playerFeet().up())) { + // suffocating? + return false; + } + if (!path.movements().get(pathPosition).safeToCancel()) { + return false; + } + Optional currentBest = current.get().bestPathSoFar(); + if (!currentBest.isPresent()) { + return false; + } + return currentBest.get().positions().contains(playerFeet()); + } + private boolean possiblyOffPath(Tuple status, double leniency) { double distanceFromPath = status.getFirst(); if (distanceFromPath > leniency) {