From 1e9786d5b923bffd8f02ef1964a6672540183aed Mon Sep 17 00:00:00 2001 From: Leijurv Date: Thu, 22 Nov 2018 09:39:54 -0800 Subject: [PATCH] add a secondary failure cutoff --- src/api/java/baritone/api/Settings.java | 18 ++++++++++++---- .../api/pathing/calc/IPathFinder.java | 2 +- .../baritone/behavior/PathingBehavior.java | 16 +++++++++----- .../pathing/calc/AStarPathFinder.java | 21 ++++++++++++++----- .../pathing/calc/AbstractNodeCostSearch.java | 16 ++++++-------- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 7fce0254..f4fd7db1 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -247,14 +247,24 @@ public class Settings { public Setting movementTimeoutTicks = new Setting<>(100); /** - * Pathing can never take longer than this + * Pathing ends after this amount of time, if a path has been found */ - public Setting pathTimeoutMS = new Setting<>(2000L); + public Setting primaryTimeoutMS = new Setting<>(500L); /** - * Planning ahead while executing a segment can never take longer than this + * Pathing can never take longer than this, even if that means failing to find any path at all */ - public Setting planAheadTimeoutMS = new Setting<>(4000L); + public Setting failureTimeoutMS = new Setting<>(2000L); + + /** + * Planning ahead while executing a segment ends after this amount of time, if a path has been found + */ + public Setting planAheadPrimaryTimeoutMS = new Setting<>(4000L); + + /** + * Planning ahead while executing a segment can never take longer than this, even if that means failing to find any path at all + */ + public Setting planAheadFailureTimeoutMS = new Setting<>(5000L); /** * For debugging, consider nodes much much slower diff --git a/src/api/java/baritone/api/pathing/calc/IPathFinder.java b/src/api/java/baritone/api/pathing/calc/IPathFinder.java index f70196a6..fa83295f 100644 --- a/src/api/java/baritone/api/pathing/calc/IPathFinder.java +++ b/src/api/java/baritone/api/pathing/calc/IPathFinder.java @@ -36,7 +36,7 @@ public interface IPathFinder { * * @return The final path */ - PathCalculationResult calculate(long timeout); + PathCalculationResult calculate(long primaryTimeout, long failureTimeout); /** * Intended to be called concurrently with calculatePath from a different thread to tell if it's finished yet diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 1943b215..f2017eef 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -40,7 +40,10 @@ import baritone.utils.PathRenderer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.EmptyChunk; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Optional; import java.util.concurrent.LinkedBlockingQueue; import java.util.stream.Collectors; @@ -396,11 +399,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, logDebug("no goal"); // TODO should this be an exception too? definitely should be checked by caller return; } - long timeout; + long primaryTimeout; + long failureTimeout; if (current == null) { - timeout = Baritone.settings().pathTimeoutMS.get(); + primaryTimeout = Baritone.settings().primaryTimeoutMS.get(); + failureTimeout = Baritone.settings().failureTimeoutMS.get(); } else { - timeout = Baritone.settings().planAheadTimeoutMS.get(); + primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.get(); + failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.get(); } CalculationContext context = new CalculationContext(baritone); // not safe to create on the other thread, it looks up a lot of stuff in minecraft AbstractNodeCostSearch pathfinder = createPathfinder(start, goal, current == null ? null : current.getPath(), context); @@ -410,7 +416,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, logDebug("Starting to search for path from " + start + " to " + goal); } - PathCalculationResult calcResult = pathfinder.calculate(timeout); + PathCalculationResult calcResult = pathfinder.calculate(primaryTimeout, failureTimeout); Optional path = calcResult.getPath(); if (Baritone.settings().cutoffAtLoadBoundary.get()) { path = path.map(p -> { diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java index f6592094..aa83bc44 100644 --- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java @@ -49,7 +49,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel } @Override - protected Optional calculate0(long timeout) { + protected Optional calculate0(long primaryTimeout, long failureTimeout) { startNode = getNodeAtPosition(startX, startY, startZ, BetterBlockPos.longHash(startX, startY, startZ)); startNode.cost = 0; startNode.combinedCost = startNode.estimatedCostToGoal; @@ -68,10 +68,11 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel long startTime = System.nanoTime() / 1000000L; boolean slowPath = Baritone.settings().slowPath.get(); if (slowPath) { - logDebug("slowPath is on, path timeout will be " + Baritone.settings().slowPathTimeoutMS.get() + "ms instead of " + timeout + "ms"); + logDebug("slowPath is on, path timeout will be " + Baritone.settings().slowPathTimeoutMS.get() + "ms instead of " + primaryTimeout + "ms"); } - long timeoutTime = startTime + (slowPath ? Baritone.settings().slowPathTimeoutMS.get() : timeout); - //long lastPrintout = 0; + long primaryTimeoutTime = startTime + (slowPath ? Baritone.settings().slowPathTimeoutMS.get() : primaryTimeout); + long failureTimeoutTime = startTime + (slowPath ? Baritone.settings().slowPathTimeoutMS.get() : failureTimeout); + boolean failing = true; int numNodes = 0; int numMovementsConsidered = 0; int numEmptyChunk = 0; @@ -79,7 +80,14 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get(); boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get(); - while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.nanoTime() / 1000000L - timeoutTime < 0 && !cancelRequested) { + while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && !cancelRequested) { + long now = System.nanoTime() / 1000000L; + if (now - failureTimeoutTime >= 0 || (!failing && now - primaryTimeoutTime >= 0)) { + break; + } + if (failing == bestPathSoFar().isPresent()) { + throw new IllegalStateException(); + } if (slowPath) { try { Thread.sleep(Baritone.settings().slowPathTimeDelayMS.get()); @@ -166,6 +174,9 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel } bestHeuristicSoFar[i] = heuristic; bestSoFar[i] = neighbor; + if (getDistFromStartSq(neighbor) > MIN_DIST_PATH * MIN_DIST_PATH) { + failing = false; + } } } } diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index ac4efa4d..6d9ad67e 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -83,13 +83,14 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { cancelRequested = true; } - public synchronized PathCalculationResult calculate(long timeout) { + @Override + public synchronized PathCalculationResult calculate(long primaryTimeout, long failureTimeout) { if (isFinished) { throw new IllegalStateException("Path Finder is currently in use, and cannot be reused!"); } this.cancelRequested = false; try { - IPath path = calculate0(timeout).map(IPath::postProcess).orElse(null); + IPath path = calculate0(primaryTimeout, failureTimeout).map(IPath::postProcess).orElse(null); isFinished = true; if (cancelRequested) { return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION, path); @@ -112,7 +113,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { } } - protected abstract Optional calculate0(long timeout); + protected abstract Optional calculate0(long primaryTimeout, long failureTimeout); /** * Determines the distance squared from the specified node to the start @@ -157,7 +158,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { @Override public Optional bestPathSoFar() { - if (startNode == null || bestSoFar == null || bestSoFar[0] == null) { + if (startNode == null || bestSoFar == null) { return Optional.empty(); } for (int i = 0; i < bestSoFar.length; i++) { @@ -165,12 +166,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { continue; } if (getDistFromStartSq(bestSoFar[i]) > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared - try { - return Optional.of(new Path(startNode, bestSoFar[i], 0, goal, context)); - } catch (IllegalStateException ex) { - System.out.println("Unable to construct path to render"); - return Optional.empty(); - } + return Optional.of(new Path(startNode, bestSoFar[i], 0, goal, context)); } } // instead of returning bestSoFar[0], be less misleading