better path splicing

This commit is contained in:
Leijurv 2018-08-16 15:10:15 -07:00
parent 399fa003dd
commit e0f2159276
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
4 changed files with 53 additions and 28 deletions

View File

@ -35,17 +35,22 @@ public class Settings {
public Setting<Boolean> chuckCaching = new Setting<>(false);
public Setting<Boolean> allowWaterBucketFall = new Setting<>(true);
public Setting<Integer> planningTickLookAhead = new Setting<>(150);
public Setting<Boolean> renderPath = new Setting<>(true);
public Setting<Boolean> chatDebug = new Setting<>(true);
public Setting<Boolean> chatControl = new Setting<>(true); // probably false in impact
public Setting<Boolean> renderPath = new Setting<>(true);
public Setting<Boolean> fadePath = new Setting<>(false); // give this a better name in the UI, like "better path fps" idk
public Setting<Number> pathTimeoutMS = new Setting<>(4000L);
public Setting<Boolean> slowPath = new Setting<>(false);
public Setting<Number> slowPathTimeDelayMS = new Setting<>(100L);
public Setting<Number> slowPathTimeoutMS = new Setting<>(40000L);
public Setting<List<Item>> acceptableThrowAwayItems = new Setting<>(Arrays.asList(
Item.getItemFromBlock(Blocks.DIRT),
Item.getItemFromBlock(Blocks.COBBLESTONE),
Item.getItemFromBlock(Blocks.NETHERRACK)
));
public Setting<Boolean> renderGoal = new Setting<>(true);
public Setting<Integer> pathingMaxChunkBorderFetch = new Setting<>(50);
public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.9);
public final Map<String, Setting<?>> byName;
public final List<Setting<?>> allSettings;
@ -63,8 +68,8 @@ public class Settings {
this.klass = (Class<T>) value.getClass();
}
public final T get() {
return value;
public final <K extends T> K get() {
return (K) value;
}
public final String getName() {

View File

@ -93,7 +93,7 @@ public class PathingBehavior extends Behavior {
// if we aren't calculating right now
return;
}
findPathInNewThread(playerFeet(), true);
findPathInNewThread(playerFeet(), true, Optional.empty());
}
return;
}
@ -126,7 +126,7 @@ public class PathingBehavior extends Behavior {
if (ticksRemainingInSegment().get() < Baritone.settings().planningTickLookAhead.get()) {
// and this path has 5 seconds or less left
displayChatMessageRaw("Path almost over. Planning ahead...");
findPathInNewThread(current.getPath().getDest(), false);
findPathInNewThread(current.getPath().getDest(), false, Optional.of(current.getPath()));
}
}
}
@ -160,11 +160,17 @@ public class PathingBehavior extends Behavior {
}
public void path() {
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
synchronized (pathPlanLock) {
if (current != null) {
displayChatMessageRaw("Currently executing a path. Please cancel it first.");
return;
}
findPathInNewThread(playerFeet(), true);
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
return;
}
findPathInNewThread(playerFeet(), true, Optional.empty());
}
}
}
@ -174,7 +180,7 @@ public class PathingBehavior extends Behavior {
* @param start
* @param talkAboutIt
*/
private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt) {
private void findPathInNewThread(final BlockPos start, final boolean talkAboutIt, final Optional<IPath> previous) {
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
throw new IllegalStateException("Already doing it");
@ -186,7 +192,7 @@ public class PathingBehavior extends Behavior {
displayChatMessageRaw("Starting to search for path from " + start + " to " + goal);
}
findPath(start).map(IPath::cutoffAtLoadedChunks).map(PathExecutor::new).ifPresent(path -> {
findPath(start, previous).map(IPath::cutoffAtLoadedChunks).map(PathExecutor::new).ifPresent(path -> {
synchronized (pathPlanLock) {
if (current == null) {
current = path;
@ -219,13 +225,13 @@ public class PathingBehavior extends Behavior {
* @param start
* @return
*/
private Optional<IPath> findPath(BlockPos start) {
private Optional<IPath> findPath(BlockPos start, Optional<IPath> previous) {
if (goal == null) {
displayChatMessageRaw("no goal");
return Optional.empty();
}
try {
IPathFinder pf = new AStarPathFinder(start, goal);
IPathFinder pf = new AStarPathFinder(start, goal, previous.map(IPath::positions));
return pf.calculate();
} catch (Exception e) {
e.printStackTrace();
@ -251,6 +257,7 @@ public class PathingBehavior extends Behavior {
PathExecutor current = this.current; // this should prevent most race conditions?
PathExecutor next = this.next; // like, now it's not possible for current!=null to be true, then suddenly false because of another thread
// TODO is this enough, or do we need to acquire a lock here?
// TODO benchmark synchronized in render loop
// Render the current path, if there is one
if (current != null && current.getPath() != null) {

View File

@ -52,6 +52,8 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.Random;
@ -62,8 +64,11 @@ import java.util.Random;
*/
public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
public AStarPathFinder(BlockPos start, Goal goal) {
private final Optional<HashSet<BetterBlockPos>> favoredPositions;
public AStarPathFinder(BlockPos start, Goal goal, Optional<Collection<BetterBlockPos>> favoredPositions) {
super(start, goal);
this.favoredPositions = favoredPositions.map(HashSet::new); // <-- okay this is epic
}
@Override
@ -72,26 +77,30 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
startNode.cost = 0;
startNode.combinedCost = startNode.estimatedCostToGoal;
IOpenSet openSet = new BinaryHeapOpenSet();
startNode.isOpen = true;
openSet.insert(startNode);
startNode.isOpen = true;
bestSoFar = new PathNode[COEFFICIENTS.length];//keep track of the best node by the metric of (estimatedCostToGoal + cost / COEFFICIENTS[i])
double[] bestHeuristicSoFar = new double[COEFFICIENTS.length];
for (int i = 0; i < bestHeuristicSoFar.length; i++) {
bestHeuristicSoFar[i] = Double.MAX_VALUE;
}
CalculationContext calcContext = new CalculationContext();
HashSet<BetterBlockPos> favored = favoredPositions.orElse(null);
currentlyRunning = this;
long startTime = System.currentTimeMillis();
boolean slowPath = Baritone.settings().slowPath.get();
long timeoutTime = startTime + (slowPath ? 40000 : 4000);
long timeoutTime = startTime + (slowPath ? Baritone.settings().slowPathTimeoutMS : Baritone.settings().pathTimeoutMS).<Long>get();
long lastPrintout = 0;
int numNodes = 0;
CalculationContext calcContext = new CalculationContext();
int numEmptyChunk = 0;
boolean favoring = favoredPositions.isPresent(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior
boolean cache = Baritone.settings().chuckCaching.get();
while (!openSet.isEmpty() && numEmptyChunk < 50 && System.currentTimeMillis() < timeoutTime) {
int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get();
double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.currentTimeMillis() < timeoutTime) {
if (slowPath) {
try {
Thread.sleep(100);
Thread.sleep(Baritone.settings().slowPathTimeDelayMS.<Long>get());
} catch (InterruptedException ex) {
}
}
@ -109,7 +118,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
return Optional.of(new Path(startNode, currentNode, numNodes));
}
//long constructStart = System.nanoTime();
Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at myPos, in random order
Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at currentNodePos, in random order
shuffle(possibleMovements);
//long constructEnd = System.nanoTime();
//System.out.println(constructEnd - constructStart);
@ -117,16 +126,16 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
if (movementToGetToNeighbor == null) {
continue;
}
BetterBlockPos dest = (BetterBlockPos) movementToGetToNeighbor.getDest();
boolean isPositionCached = false;
if (cache) {
if (CachedWorldProvider.INSTANCE.getCurrentWorld() != null) {
if (CachedWorldProvider.INSTANCE.getCurrentWorld().getBlockType(movementToGetToNeighbor.getDest()) != null) {
if (CachedWorldProvider.INSTANCE.getCurrentWorld().getBlockType(dest) != null) {
isPositionCached = true;
}
}
}
if (!isPositionCached && Minecraft.getMinecraft().world.getChunk(movementToGetToNeighbor.getDest()) instanceof EmptyChunk) {
if (!isPositionCached && Minecraft.getMinecraft().world.getChunk(dest) instanceof EmptyChunk) {
numEmptyChunk++;
continue;
}
@ -141,7 +150,10 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
if (actionCost <= 0) {
throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " calculated implausible cost " + actionCost);
}
PathNode neighbor = getNodeAtPosition((BetterBlockPos) movementToGetToNeighbor.getDest());
if (favoring && favored.contains(dest)) {
actionCost *= favorCoeff;
}
PathNode neighbor = getNodeAtPosition(dest);
double tentativeCost = currentNode.cost + actionCost;
if (tentativeCost < neighbor.cost) {
if (tentativeCost < 0) {

View File

@ -20,6 +20,7 @@ package baritone.bot.pathing.path;
import baritone.bot.pathing.movement.Movement;
import baritone.bot.utils.Helper;
import baritone.bot.utils.Utils;
import baritone.bot.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
@ -44,7 +45,7 @@ public interface IPath extends Helper {
* All positions along the way.
* Should begin with the same as getSrc and end with the same as getDest
*/
List<BlockPos> positions();
List<BetterBlockPos> positions();
/**
* Number of positions in this path
@ -62,7 +63,7 @@ public interface IPath extends Helper {
* @return
*/
default Movement subsequentMovement(BlockPos currentPosition) {
List<BlockPos> pos = positions();
List<BetterBlockPos> pos = positions();
List<Movement> movements = movements();
for (int i = 0; i < pos.size(); i++) {
if (currentPosition.equals(pos.get(i))) {
@ -98,15 +99,15 @@ public interface IPath extends Helper {
/**
* Where does this path start
*/
default BlockPos getSrc() {
default BetterBlockPos getSrc() {
return positions().get(0);
}
/**
* Where does this path end
*/
default BlockPos getDest() {
List<BlockPos> pos = positions();
default BetterBlockPos getDest() {
List<BetterBlockPos> pos = positions();
return pos.get(pos.size() - 1);
}