diff --git a/README.md b/README.md index ef568f0cd..d88647f3c 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/cabaletta/baritone/issues) [![Minecraft](https://img.shields.io/badge/MC-1.12.2-green.svg)](https://minecraft.gamepedia.com/1.12.2) -A Minecraft pathfinder bot. This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/), -the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone focuses on reliability and particularly performance (it's over [29x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths). +A Minecraft pathfinder bot. Baritone is the pathfinding system used in [Impact](https://impactdevelopment.github.io/) since 4.4. There's a [showcase video](https://www.youtube.com/watch?v=yI8hgW_m6dQ) made by @Adovin#3153 on Baritone's integration into Impact. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a video I made showing off what it can do. +This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/), +the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone focuses on reliability and particularly performance (it's over [29x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths). + Here are some links to help to get started: - [Features](FEATURES.md) diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 419e8e712..e2e4604d2 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -411,7 +411,7 @@ public class Settings { *

* Also on cosmic prisons this should be set to true since you don't actually mine the ore it just gets replaced with stone. */ - public Setting cancelOnGoalInvalidation = new Setting<>(false); + public Setting cancelOnGoalInvalidation = new Setting<>(true); /** * The "axis" command (aka GoalAxis) will go to a axis, or diagonal axis, at this Y level. diff --git a/src/api/java/baritone/api/pathing/calc/IPath.java b/src/api/java/baritone/api/pathing/calc/IPath.java index f2309e0e6..ad25911a8 100644 --- a/src/api/java/baritone/api/pathing/calc/IPath.java +++ b/src/api/java/baritone/api/pathing/calc/IPath.java @@ -52,7 +52,9 @@ public interface IPath { * This path is actually going to be executed in the world. Do whatever additional processing is required. * (as opposed to Path objects that are just constructed every frame for rendering) */ - default void postProcess() {} + default IPath postProcess() { + throw new UnsupportedOperationException(); + } /** * Returns the number of positions in this path. Equivalent to {@code positions().size()}. @@ -119,7 +121,7 @@ public interface IPath { * @return The result of this cut-off operation */ default IPath cutoffAtLoadedChunks() { - return this; + throw new UnsupportedOperationException(); } /** @@ -131,7 +133,7 @@ public interface IPath { * @see Settings#pathCutoffFactor */ default IPath staticCutoff(Goal destination) { - return this; + throw new UnsupportedOperationException(); } diff --git a/src/api/java/baritone/api/pathing/calc/IPathFinder.java b/src/api/java/baritone/api/pathing/calc/IPathFinder.java index 446f7e051..f70196a69 100644 --- a/src/api/java/baritone/api/pathing/calc/IPathFinder.java +++ b/src/api/java/baritone/api/pathing/calc/IPathFinder.java @@ -18,6 +18,7 @@ package baritone.api.pathing.calc; import baritone.api.pathing.goals.Goal; +import baritone.api.utils.PathCalculationResult; import java.util.Optional; @@ -35,7 +36,7 @@ public interface IPathFinder { * * @return The final path */ - Optional calculate(long timeout); + PathCalculationResult calculate(long timeout); /** * Intended to be called concurrently with calculatePath from a different thread to tell if it's finished yet diff --git a/src/api/java/baritone/api/process/PathingCommandType.java b/src/api/java/baritone/api/process/PathingCommandType.java index f2336d261..da64748aa 100644 --- a/src/api/java/baritone/api/process/PathingCommandType.java +++ b/src/api/java/baritone/api/process/PathingCommandType.java @@ -49,7 +49,7 @@ public enum PathingCommandType { /** * Set the goal and path. *

- * Revalidate the current goal, and cancel if it's no longer valid, or if the new goal is {@code null}. + * Cancel the current path if the goals are not equal */ FORCE_REVALIDATE_GOAL_AND_PATH } diff --git a/src/api/java/baritone/api/utils/PathCalculationResult.java b/src/api/java/baritone/api/utils/PathCalculationResult.java new file mode 100644 index 000000000..69d2a9b3e --- /dev/null +++ b/src/api/java/baritone/api/utils/PathCalculationResult.java @@ -0,0 +1,41 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.api.utils; + +import baritone.api.pathing.calc.IPath; + +import java.util.Optional; + +public class PathCalculationResult { + + public final Optional path; + public final Type type; + + public PathCalculationResult(Type type, Optional path) { + this.path = path; + this.type = type; + } + + public enum Type { + SUCCESS_TO_GOAL, + SUCCESS_SEGMENT, + FAILURE, + CANCELLATION, + EXCEPTION, + } +} diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java index 53b771da9..515509954 100644 --- a/src/main/java/baritone/behavior/PathingBehavior.java +++ b/src/main/java/baritone/behavior/PathingBehavior.java @@ -28,6 +28,7 @@ import baritone.api.pathing.calc.IPathFinder; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.goals.GoalXZ; import baritone.api.utils.BetterBlockPos; +import baritone.api.utils.PathCalculationResult; import baritone.api.utils.interfaces.IGoalRenderPos; import baritone.pathing.calc.AStarPathFinder; import baritone.pathing.calc.AbstractNodeCostSearch; @@ -379,7 +380,8 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, logDebug("Starting to search for path from " + start + " to " + goal); } - Optional path = findPath(start, previous, context); + PathCalculationResult calcResult = findPath(start, previous, context); + Optional path = calcResult.path; if (Baritone.settings().cutoffAtLoadBoundary.get()) { path = path.map(p -> { IPath result = p.cutoffAtLoadedChunks(); @@ -411,7 +413,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING); current = executor.get(); } else { - queuePathEvent(PathEvent.CALC_FAILED); + if (calcResult.type != PathCalculationResult.Type.CANCELLATION && calcResult.type != PathCalculationResult.Type.EXCEPTION) { + // don't dispatch CALC_FAILED on cancellation + queuePathEvent(PathEvent.CALC_FAILED); + } } } else { if (next == null) { @@ -425,18 +430,16 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, throw new IllegalStateException("I have no idea what to do with this path"); } } - } - - if (talkAboutIt && current != null && current.getPath() != null) { - if (goal == null || goal.isInGoal(current.getPath().getDest())) { - logDebug("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); - } else { - logDebug("Found path segment from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); - + if (talkAboutIt && current != null && current.getPath() != null) { + if (goal == null || goal.isInGoal(current.getPath().getDest())) { + logDebug("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); + } else { + logDebug("Found path segment from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); + } + } + synchronized (pathCalcLock) { + isPathCalcInProgress = false; } - } - synchronized (pathCalcLock) { - isPathCalcInProgress = false; } }); } @@ -447,11 +450,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, * @param start * @return */ - private Optional findPath(BlockPos start, Optional previous, CalculationContext context) { + private PathCalculationResult findPath(BlockPos start, Optional previous, CalculationContext context) { Goal goal = this.goal; if (goal == null) { logDebug("no goal"); - return Optional.empty(); + return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION, Optional.empty()); } if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof IGoalRenderPos) { BlockPos pos = ((IGoalRenderPos) goal).getGoalPos(); @@ -478,7 +481,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior, } catch (Exception e) { logDebug("Pathing exception: " + e); e.printStackTrace(); - return Optional.empty(); + return new PathCalculationResult(PathCalculationResult.Type.EXCEPTION, Optional.empty()); } } diff --git a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java index bbbe32add..708b5ab05 100644 --- a/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java +++ b/src/main/java/baritone/pathing/calc/AbstractNodeCostSearch.java @@ -21,6 +21,7 @@ import baritone.Baritone; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.calc.IPathFinder; import baritone.api.pathing.goals.Goal; +import baritone.api.utils.PathCalculationResult; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import java.util.Optional; @@ -82,16 +83,26 @@ public abstract class AbstractNodeCostSearch implements IPathFinder { cancelRequested = true; } - public synchronized Optional calculate(long timeout) { + public synchronized PathCalculationResult calculate(long timeout) { if (isFinished) { throw new IllegalStateException("Path Finder is currently in use, and cannot be reused!"); } this.cancelRequested = false; try { Optional path = calculate0(timeout); - path.ifPresent(IPath::postProcess); + path = path.map(IPath::postProcess); isFinished = true; - return path; + if (cancelRequested) { + return new PathCalculationResult(PathCalculationResult.Type.CANCELLATION, path); + } + if (!path.isPresent()) { + return new PathCalculationResult(PathCalculationResult.Type.FAILURE, path); + } + if (goal.isInGoal(path.get().getDest())) { + return new PathCalculationResult(PathCalculationResult.Type.SUCCESS_TO_GOAL, path); + } else { + return new PathCalculationResult(PathCalculationResult.Type.SUCCESS_SEGMENT, path); + } } finally { // this is run regardless of what exception may or may not be raised by calculate0 currentlyRunning = null; diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java index 93f021c6a..873fef641 100644 --- a/src/main/java/baritone/pathing/calc/Path.java +++ b/src/main/java/baritone/pathing/calc/Path.java @@ -17,7 +17,6 @@ package baritone.pathing.calc; -import baritone.api.BaritoneAPI; import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; @@ -25,9 +24,8 @@ import baritone.api.utils.BetterBlockPos; import baritone.pathing.movement.Movement; import baritone.pathing.movement.Moves; import baritone.pathing.path.CutoffPath; -import net.minecraft.client.Minecraft; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.chunk.EmptyChunk; +import baritone.utils.Helper; +import baritone.utils.pathing.PathBase; import java.util.ArrayList; import java.util.Collections; @@ -39,7 +37,7 @@ import java.util.List; * * @author leijurv */ -class Path implements IPath { +class Path extends PathBase { /** * The start position of this path @@ -59,6 +57,8 @@ class Path implements IPath { private final List movements; + private final List nodes; + private final Goal goal; private final int numNodes; @@ -71,8 +71,9 @@ class Path implements IPath { this.numNodes = numNodes; this.path = new ArrayList<>(); this.movements = new ArrayList<>(); + this.nodes = new ArrayList<>(); this.goal = goal; - assemblePath(start, end); + assemblePath(end); } @Override @@ -81,62 +82,80 @@ class Path implements IPath { } /** - * Assembles this path given the start and end nodes. + * Assembles this path given the end node. * - * @param start The start node - * @param end The end node + * @param end The end node */ - private void assemblePath(PathNode start, PathNode end) { + private void assemblePath(PathNode end) { if (!path.isEmpty() || !movements.isEmpty()) { throw new IllegalStateException(); } PathNode current = end; LinkedList tempPath = new LinkedList<>(); + LinkedList tempNodes = new LinkedList(); // Repeatedly inserting to the beginning of an arraylist is O(n^2) // Instead, do it into a linked list, then convert at the end - while (!current.equals(start)) { + while (current != null) { + tempNodes.addFirst(current); tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z)); current = current.previous; } - tempPath.addFirst(this.start); // Can't directly convert from the PathNode pseudo linked list to an array because we don't know how long it is // inserting into a LinkedList keeps track of length, then when we addall (which calls .toArray) it's able // to performantly do that conversion since it knows the length. path.addAll(tempPath); + nodes.addAll(tempNodes); } - private void assembleMovements() { + private boolean assembleMovements() { if (path.isEmpty() || !movements.isEmpty()) { throw new IllegalStateException(); } for (int i = 0; i < path.size() - 1; i++) { - movements.add(runBackwards(path.get(i), path.get(i + 1))); + double cost = nodes.get(i + 1).cost - nodes.get(i).cost; + Movement move = runBackwards(path.get(i), path.get(i + 1), cost); + if (move == null) { + return true; + } else { + movements.add(move); + } } + return false; } - private static Movement runBackwards(BetterBlockPos src, BetterBlockPos dest) { // TODO this is horrifying + private static Movement runBackwards(BetterBlockPos src, BetterBlockPos dest, double cost) { 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 + // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution + move.override(cost); return move; } } // 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)); + Helper.HELPER.logDebug("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src)); + return null; } @Override - public void postProcess() { + public IPath postProcess() { if (verified) { throw new IllegalStateException(); } verified = true; - assembleMovements(); - // more post processing here + boolean failed = assembleMovements(); movements.forEach(Movement::checkLoadedChunk); + + if (failed) { // at least one movement became impossible during calculation + CutoffPath res = new CutoffPath(this, movements().size()); + if (res.movements().size() != movements.size()) { + throw new IllegalStateException(); + } + return res; + } + // more post processing here sanityCheck(); + return this; } @Override @@ -166,28 +185,4 @@ class Path implements IPath { public BetterBlockPos getDest() { return end; } - - @Override - public IPath cutoffAtLoadedChunks() { - for (int i = 0; i < positions().size(); i++) { - BlockPos pos = positions().get(i); - if (Minecraft.getMinecraft().world.getChunk(pos) instanceof EmptyChunk) { - return new CutoffPath(this, i); - } - } - return this; - } - - @Override - public IPath staticCutoff(Goal destination) { - if (length() < BaritoneAPI.getSettings().pathCutoffMinimumLength.get()) { - return this; - } - if (destination == null || destination.isInGoal(getDest())) { - return this; - } - double factor = BaritoneAPI.getSettings().pathCutoffFactor.get(); - int newLength = (int) (length() * factor); - return new CutoffPath(this, newLength); - } } diff --git a/src/main/java/baritone/pathing/movement/Movement.java b/src/main/java/baritone/pathing/movement/Movement.java index fb316ed36..31dd952bf 100644 --- a/src/main/java/baritone/pathing/movement/Movement.java +++ b/src/main/java/baritone/pathing/movement/Movement.java @@ -95,7 +95,7 @@ public abstract class Movement implements IMovement, Helper, MovementHelper { return getCost(); } - protected void override(double cost) { + public void override(double cost) { this.cost = cost; } diff --git a/src/main/java/baritone/pathing/path/CutoffPath.java b/src/main/java/baritone/pathing/path/CutoffPath.java index 9714d8ce7..30b2d4e93 100644 --- a/src/main/java/baritone/pathing/path/CutoffPath.java +++ b/src/main/java/baritone/pathing/path/CutoffPath.java @@ -21,11 +21,12 @@ import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; import baritone.api.utils.BetterBlockPos; +import baritone.utils.pathing.PathBase; import java.util.Collections; import java.util.List; -public class CutoffPath implements IPath { +public class CutoffPath extends PathBase { private final List path; diff --git a/src/main/java/baritone/pathing/path/SplicedPath.java b/src/main/java/baritone/pathing/path/SplicedPath.java index 33b0b97f5..5048a84a0 100644 --- a/src/main/java/baritone/pathing/path/SplicedPath.java +++ b/src/main/java/baritone/pathing/path/SplicedPath.java @@ -21,10 +21,11 @@ import baritone.api.pathing.calc.IPath; import baritone.api.pathing.goals.Goal; import baritone.api.pathing.movement.IMovement; import baritone.api.utils.BetterBlockPos; +import baritone.utils.pathing.PathBase; import java.util.*; -public class SplicedPath implements IPath { +public class SplicedPath extends PathBase { private final List path; private final List movements; diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java index 94e02e03a..241fafa18 100644 --- a/src/main/java/baritone/process/GetToBlockProcess.java +++ b/src/main/java/baritone/process/GetToBlockProcess.java @@ -28,6 +28,7 @@ import baritone.utils.BaritoneProcessHelper; import net.minecraft.block.Block; import net.minecraft.util.math.BlockPos; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -44,7 +45,8 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl @Override public void getToBlock(Block block) { gettingTo = block; - rescan(); + knownLocations = null; + rescan(new ArrayList<>()); } @Override @@ -55,7 +57,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl @Override public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { if (knownLocations == null) { - rescan(); + rescan(new ArrayList<>()); } if (knownLocations.isEmpty()) { logDirect("No known locations of " + gettingTo + ", canceling GetToBlock"); @@ -73,7 +75,8 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl } int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain - Baritone.getExecutor().execute(this::rescan); + List current = new ArrayList<>(knownLocations); + Baritone.getExecutor().execute(() -> rescan(current)); } Goal goal = new GoalComposite(knownLocations.stream().map(GoalGetToBlock::new).toArray(Goal[]::new)); if (goal.isInGoal(playerFeet())) { @@ -93,7 +96,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl return "Get To Block " + gettingTo; } - private void rescan() { - knownLocations = MineProcess.searchWorld(Collections.singletonList(gettingTo), 64, world()); + private void rescan(List known) { + knownLocations = MineProcess.searchWorld(Collections.singletonList(gettingTo), 64, world(), known); } } \ No newline at end of file diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java index bfceac75d..1db47fc88 100644 --- a/src/main/java/baritone/process/MineProcess.java +++ b/src/main/java/baritone/process/MineProcess.java @@ -56,6 +56,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro private List mining; private List knownOreLocations; private BlockPos branchPoint; + private GoalRunAway branchPointRunaway; private int desiredQuantity; private int tickCount; @@ -87,7 +88,8 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro } int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get(); if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain - baritone.getExecutor().execute(this::rescan); + List curr = new ArrayList<>(knownOreLocations); + baritone.getExecutor().execute(() -> rescan(curr)); } if (Baritone.settings().legitMine.get()) { addNearby(); @@ -99,7 +101,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro cancel(); return null; } - return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH); + return new PathingCommand(goal, PathingCommandType.FORCE_REVALIDATE_GOAL_AND_PATH); } @Override @@ -126,31 +128,37 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return null; } // only in non-Xray mode (aka legit mode) do we do this + int y = Baritone.settings().legitMineYLevel.get(); if (branchPoint == null) { - int y = Baritone.settings().legitMineYLevel.get(); if (!baritone.getPathingBehavior().isPathing() && playerFeet().y == y) { // cool, path is over and we are at desired y branchPoint = playerFeet(); + branchPointRunaway = null; } else { return new GoalYLevel(y); } } - - if (playerFeet().equals(branchPoint)) { - // TODO mine 1x1 shafts to either side - branchPoint = branchPoint.north(10); + // TODO shaft mode, mine 1x1 shafts to either side + // TODO also, see if the GoalRunAway with maintain Y at 11 works even from the surface + if (branchPointRunaway == null) { + branchPointRunaway = new GoalRunAway(1, Optional.of(y), branchPoint) { + @Override + public boolean isInGoal(int x, int y, int z) { + return false; + } + }; } - return new GoalBlock(branchPoint); + return branchPointRunaway; } - private void rescan() { + private void rescan(List already) { if (mining == null) { return; } if (Baritone.settings().legitMine.get()) { return; } - List locs = searchWorld(mining, ORE_LOCATIONS_COUNT, world()); + List locs = searchWorld(mining, ORE_LOCATIONS_COUNT, world(), already); locs.addAll(droppedItemsScan(mining, world())); if (locs.isEmpty()) { logDebug("No locations for " + mining + " known, cancelling"); @@ -205,7 +213,10 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro return ret; } - public static List searchWorld(List mining, int max, World world) { + /*public static List searchWorld(List mining, int max, World world) { + + }*/ + public static List searchWorld(List mining, int max, World world, List alreadyKnown) { List locs = new ArrayList<>(); List uninteresting = new ArrayList<>(); //long b = System.currentTimeMillis(); @@ -225,6 +236,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(uninteresting, max, 10, 26)); //System.out.println("Scan of loaded chunks took " + (System.currentTimeMillis() - before) + "ms"); } + locs.addAll(alreadyKnown); return prune(locs, mining, max, world); } @@ -283,6 +295,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro this.desiredQuantity = quantity; this.knownOreLocations = new ArrayList<>(); this.branchPoint = null; - rescan(); + this.branchPointRunaway = null; + rescan(new ArrayList<>()); } } diff --git a/src/main/java/baritone/utils/PathingControlManager.java b/src/main/java/baritone/utils/PathingControlManager.java index e75f7796f..5d1b03038 100644 --- a/src/main/java/baritone/utils/PathingControlManager.java +++ b/src/main/java/baritone/utils/PathingControlManager.java @@ -78,7 +78,7 @@ public class PathingControlManager { break; case FORCE_REVALIDATE_GOAL_AND_PATH: p.secretInternalSetGoalAndPath(cmd.goal); - if (cmd.goal == null || revalidateGoal(cmd.goal)) { + if (cmd.goal == null || forceRevalidate(cmd.goal) || revalidateGoal(cmd.goal)) { // pwnage p.cancelSegmentIfSafe(); } @@ -100,6 +100,17 @@ public class PathingControlManager { } } + public boolean forceRevalidate(Goal newGoal) { + PathExecutor current = baritone.getPathingBehavior().getCurrent(); + if (current != null) { + if (newGoal.isInGoal(current.getPath().getDest())) { + return false; + } + return !newGoal.toString().equals(current.getPath().getGoal().toString()); + } + return false; + } + public boolean revalidateGoal(Goal newGoal) { PathExecutor current = baritone.getPathingBehavior().getCurrent(); if (current != null) { diff --git a/src/main/java/baritone/utils/pathing/PathBase.java b/src/main/java/baritone/utils/pathing/PathBase.java new file mode 100644 index 000000000..57ee941d4 --- /dev/null +++ b/src/main/java/baritone/utils/pathing/PathBase.java @@ -0,0 +1,52 @@ +/* + * This file is part of Baritone. + * + * Baritone is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Baritone is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Baritone. If not, see . + */ + +package baritone.utils.pathing; + +import baritone.api.BaritoneAPI; +import baritone.api.pathing.calc.IPath; +import baritone.api.pathing.goals.Goal; +import baritone.pathing.path.CutoffPath; +import net.minecraft.client.Minecraft; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.EmptyChunk; + +public abstract class PathBase implements IPath { + @Override + public IPath cutoffAtLoadedChunks() { + for (int i = 0; i < positions().size(); i++) { + BlockPos pos = positions().get(i); + if (Minecraft.getMinecraft().world.getChunk(pos) instanceof EmptyChunk) { + return new CutoffPath(this, i); + } + } + return this; + } + + @Override + public IPath staticCutoff(Goal destination) { + if (length() < BaritoneAPI.getSettings().pathCutoffMinimumLength.get()) { + return this; + } + if (destination == null || destination.isInGoal(getDest())) { + return this; + } + double factor = BaritoneAPI.getSettings().pathCutoffFactor.get(); + int newLength = (int) ((length() - 1) * factor); + return new CutoffPath(this, newLength); + } +}