splice next into current if no backtrack, fixes #122, fixes #249

This commit is contained in:
Leijurv 2018-11-06 11:18:13 -08:00
parent cbc8a6d45b
commit 9c93d3a474
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
7 changed files with 180 additions and 31 deletions

View File

@ -377,6 +377,16 @@ public class Settings {
*/
public Setting<Boolean> walkWhileBreaking = new Setting<>(true);
/**
* If we are more than 500 movements into the current path, discard the oldest segments, as they are no longer useful
*/
public Setting<Integer> maxPathHistoryLength = new Setting<>(500);
/**
* If the current path is too long, cut off this many movements from the beginning.
*/
public Setting<Integer> pathHistoryCutoffAmount = new Setting<>(100);
/**
* Rescan for the goal once every 5 ticks.
* Set to 0 to disable.

View File

@ -21,6 +21,7 @@ import baritone.api.Settings;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.IMovement;
import baritone.api.utils.BetterBlockPos;
import net.minecraft.util.math.BlockPos;
import java.util.List;
@ -132,4 +133,33 @@ public interface IPath {
default IPath staticCutoff(Goal destination) {
return this;
}
/**
* Performs a series of checks to ensure that the assembly of the path went as expected.
*/
default void sanityCheck() {
List<BetterBlockPos> path = positions();
List<IMovement> movements = movements();
if (!getSrc().equals(path.get(0))) {
throw new IllegalStateException("Start node does not equal first path element");
}
if (!getDest().equals(path.get(path.size() - 1))) {
throw new IllegalStateException("End node does not equal last path element");
}
if (path.size() != movements.size() + 1) {
throw new IllegalStateException("Size of path array is unexpected");
}
for (int i = 0; i < path.size() - 1; i++) {
BlockPos src = path.get(i);
BlockPos dest = path.get(i + 1);
IMovement movement = movements.get(i);
if (!src.equals(movement.getSrc())) {
throw new IllegalStateException("Path source is not equal to the movement source");
}
if (!dest.equals(movement.getDest())) {
throw new IllegalStateException("Path destination is not equal to the movement destination");
}
}
}
}

View File

@ -31,9 +31,9 @@ import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.interfaces.IGoalRenderPos;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.calc.CutoffPath;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.CutoffPath;
import baritone.pathing.path.PathExecutor;
import baritone.utils.BlockBreakHelper;
import baritone.utils.Helper;
@ -156,6 +156,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
current.onTick();
return;
}
current = current.trySplice(next);
if (next != null && current.getPath().getDest().equals(next.getPath().getDest())) {
next = null;
}
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
// if we aren't calculating right now

View File

@ -24,6 +24,7 @@ import baritone.api.pathing.movement.IMovement;
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;
@ -104,32 +105,6 @@ class Path implements IPath {
path.addAll(tempPath);
}
/**
* Performs a series of checks to ensure that the assembly of the path went as expected.
*/
private void sanityCheck() {
if (!start.equals(path.get(0))) {
throw new IllegalStateException("Start node does not equal first path element");
}
if (!end.equals(path.get(path.size() - 1))) {
throw new IllegalStateException("End node does not equal last path element");
}
if (path.size() != movements.size() + 1) {
throw new IllegalStateException("Size of path array is unexpected");
}
for (int i = 0; i < path.size() - 1; i++) {
BlockPos src = path.get(i);
BlockPos dest = path.get(i + 1);
Movement movement = movements.get(i);
if (!src.equals(movement.getSrc())) {
throw new IllegalStateException("Path source is not equal to the movement source");
}
if (!dest.equals(movement.getDest())) {
throw new IllegalStateException("Path destination is not equal to the movement destination");
}
}
}
private void assembleMovements() {
if (path.isEmpty() || !movements.isEmpty()) {
throw new IllegalStateException();

View File

@ -15,7 +15,7 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.calc;
package baritone.pathing.path;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
@ -35,11 +35,16 @@ public class CutoffPath implements IPath {
private final Goal goal;
CutoffPath(IPath prev, int lastPositionToInclude) {
path = prev.positions().subList(0, lastPositionToInclude + 1);
movements = prev.movements().subList(0, lastPositionToInclude + 1);
public CutoffPath(IPath prev, int firstPositionToInclude, int lastPositionToInclude) {
path = prev.positions().subList(firstPositionToInclude, lastPositionToInclude + 1);
movements = prev.movements().subList(firstPositionToInclude, lastPositionToInclude);
numNodes = prev.getNumNodesConsidered();
goal = prev.getGoal();
sanityCheck();
}
public CutoffPath(IPath prev, int lastPositionToInclude) {
this(prev, 0, lastPositionToInclude);
}
@Override

View File

@ -454,6 +454,43 @@ public class PathExecutor implements IPathExecutor, Helper {
return pathPosition;
}
public PathExecutor trySplice(PathExecutor next) {
if (next == null) {
return cutIfTooLong();
}
return SplicedPath.trySplice(path, next.path).map(path -> {
if (!path.getDest().equals(next.getPath().getDest())) {
throw new IllegalStateException();
}
PathExecutor ret = new PathExecutor(path);
ret.pathPosition = pathPosition;
ret.currentMovementOriginalCostEstimate = currentMovementOriginalCostEstimate;
ret.costEstimateIndex = costEstimateIndex;
ret.ticksOnCurrent = ticksOnCurrent;
return ret;
}).orElse(cutIfTooLong());
}
private PathExecutor cutIfTooLong() {
if (pathPosition > Baritone.settings().maxPathHistoryLength.get()) {
int cutoffAmt = Baritone.settings().pathHistoryCutoffAmount.get();
CutoffPath newPath = new CutoffPath(path, cutoffAmt, path.length() - 1);
if (!newPath.getDest().equals(path.getDest())) {
throw new IllegalStateException();
}
logDebug("Discarding earliest segment movements, length cut from " + path.length() + " to " + newPath.length());
PathExecutor ret = new PathExecutor(newPath);
ret.pathPosition = pathPosition - cutoffAmt;
ret.currentMovementOriginalCostEstimate = currentMovementOriginalCostEstimate;
if (costEstimateIndex != null) {
ret.costEstimateIndex = costEstimateIndex - cutoffAmt;
}
ret.ticksOnCurrent = ticksOnCurrent;
return ret;
}
return this;
}
@Override
public IPath getPath() {
return path;

View File

@ -0,0 +1,88 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.path;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.IMovement;
import baritone.api.utils.BetterBlockPos;
import java.util.*;
public class SplicedPath implements IPath {
private final List<BetterBlockPos> path;
private final List<IMovement> movements;
private final int numNodes;
private final Goal goal;
private SplicedPath(List<BetterBlockPos> path, List<IMovement> movements, int numNodesConsidered, Goal goal) {
this.path = path;
this.movements = movements;
this.numNodes = numNodesConsidered;
this.goal = goal;
sanityCheck();
}
@Override
public Goal getGoal() {
return goal;
}
@Override
public List<IMovement> movements() {
return Collections.unmodifiableList(movements);
}
@Override
public List<BetterBlockPos> positions() {
return Collections.unmodifiableList(path);
}
@Override
public int getNumNodesConsidered() {
return numNodes;
}
public static Optional<SplicedPath> trySplice(IPath first, IPath second) {
if (second == null || first == null) {
return Optional.empty();
}
if (!Objects.equals(first.getGoal(), second.getGoal())) {
return Optional.empty();
}
if (!first.getDest().equals(second.getSrc())) {
return Optional.empty();
}
HashSet<BetterBlockPos> a = new HashSet<>(first.positions());
for (int i = 1; i < second.length(); i++) {
if (a.contains(second.positions().get(i))) {
return Optional.empty();
}
}
List<BetterBlockPos> positions = new ArrayList<>();
List<IMovement> movements = new ArrayList<>();
positions.addAll(first.positions());
positions.addAll(second.positions().subList(1, second.length()));
movements.addAll(first.movements());
movements.addAll(second.movements());
return Optional.of(new SplicedPath(positions, movements, first.getNumNodesConsidered() + second.getNumNodesConsidered(), first.getGoal()));
}
}