planning ahead

This commit is contained in:
Leijurv 2018-08-13 12:35:44 -07:00
parent 88c81a9635
commit 85fdc2df34
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
3 changed files with 114 additions and 23 deletions

View File

@ -49,17 +49,80 @@ public class PathingBehavior extends Behavior {
private Goal goal; private Goal goal;
private volatile boolean isPathCalcInProgress;
private final Object pathCalcLock = new Object();
private final Object pathPlanLock = new Object();
@Override @Override
public void onTick(TickEvent event) { public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT || current == null) { if (event.getType() == TickEvent.Type.OUT || current == null) {
return; return;
} }
current.onTick(event); boolean safe = current.onTick(event);
synchronized (pathPlanLock) {
if (current.failed() || current.finished()) { if (current.failed() || current.finished()) {
current = null; current = null;
if (!goal.isInGoal(playerFeet())) if (next != null && !next.getPath().positions().contains(playerFeet())) {
// if the current path failed, we may not actually be on the next one, so make sure
displayChatMessageRaw("Discarding next path as it does not contain current position");
// for example if we had a nicely planned ahead path that starts where current ends
// that's all fine and good
// but if we fail in the middle of current
// we're nowhere close to our planned ahead path
// so need to discard it sadly.
next = null;
}
if (next != null) {
current = next;
next = null;
return;
}
if (goal.isInGoal(playerFeet())) {
return;
}
// at this point, current just ended, but we aren't in the goal and have no plan for the future
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
// if we aren't calculating right now
return;
}
findPathInNewThread(playerFeet(), true); findPathInNewThread(playerFeet(), true);
} }
return;
}
// at this point, we know current is in progress
if (safe) {
// a movement just ended
if (next != null) {
if (next.getPath().positions().contains(playerFeet())) {
// jump directly onto the next path
current = next;
next = null;
return;
}
}
}
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
// if we aren't calculating right now
return;
}
if (next != null) {
// and we have no plan for what to do next
return;
}
if (goal.isInGoal(current.getPath().getDest())) {
// and this path dosen't get us all the way there
return;
}
if (current.getPath().ticksRemainingFrom(current.getPosition()) < 100) {
// and this path has 5 seconds or less left
displayChatMessageRaw("Path almost over; planning ahead");
findPathInNewThread(current.getPath().getDest(), true);
}
}
}
} }
@Override @Override
@ -136,12 +199,30 @@ public class PathingBehavior extends Behavior {
* @param talkAboutIt * @param talkAboutIt
*/ */
public void findPathInNewThread(final BlockPos start, final boolean talkAboutIt) { public void findPathInNewThread(final BlockPos start, final boolean talkAboutIt) {
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
throw new IllegalStateException("Already doing it");
}
isPathCalcInProgress = true;
}
new Thread(() -> { new Thread(() -> {
if (talkAboutIt) { if (talkAboutIt) {
displayChatMessageRaw("Starting to search for path from " + start + " to " + goal); displayChatMessageRaw("Starting to search for path from " + start + " to " + goal);
} }
findPath(start).map(PathExecutor::new).ifPresent(path -> current = path); findPath(start).map(PathExecutor::new).ifPresent(path -> {
synchronized (pathPlanLock) {
if (current == null) {
current = path;
} else {
if (next == null) {
next = path;
} else {
throw new IllegalStateException("I have no idea what to do with this path");
}
}
}
});
/* /*
isThereAnythingInProgress = false; isThereAnythingInProgress = false;
if (!currentPath.goal.isInGoal(currentPath.end)) { if (!currentPath.goal.isInGoal(currentPath.end)) {
@ -156,6 +237,9 @@ public class PathingBehavior extends Behavior {
if (talkAboutIt && current != null && current.getPath() != null) { if (talkAboutIt && current != null && current.getPath() != null) {
displayChatMessageRaw("Finished finding a path from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); displayChatMessageRaw("Finished finding a path from " + start + " towards " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered");
} }
synchronized (pathCalcLock) {
isPathCalcInProgress = false;
}
}).start(); }).start();
} }

View File

@ -17,7 +17,6 @@
package baritone.bot.pathing.path; package baritone.bot.pathing.path;
import baritone.bot.pathing.movement.CalculationContext;
import baritone.bot.pathing.movement.Movement; import baritone.bot.pathing.movement.Movement;
import baritone.bot.utils.Utils; import baritone.bot.utils.Utils;
import net.minecraft.util.Tuple; import net.minecraft.util.Tuple;
@ -108,11 +107,11 @@ public interface IPath {
return pos.get(pos.size() - 1); return pos.get(pos.size() - 1);
} }
default double ticksRemaining(int pathPosition) { default double ticksRemainingFrom(int pathPosition) {
double sum = 0; double sum = 0;
CalculationContext ctx = new CalculationContext(); //this is fast because we aren't requesting recalculation, it's just cached
for (int i = pathPosition; i < movements().size(); i++) { for (int i = pathPosition; i < movements().size(); i++) {
sum += movements().get(i).getCost(ctx); sum += movements().get(i).getCost(null);
} }
return sum; return sum;
} }

View File

@ -18,12 +18,12 @@
package baritone.bot.pathing.path; package baritone.bot.pathing.path;
import baritone.bot.Baritone; import baritone.bot.Baritone;
import baritone.bot.behavior.Behavior;
import baritone.bot.event.events.TickEvent; import baritone.bot.event.events.TickEvent;
import baritone.bot.pathing.movement.ActionCosts; import baritone.bot.pathing.movement.ActionCosts;
import baritone.bot.pathing.movement.Movement; import baritone.bot.pathing.movement.Movement;
import baritone.bot.pathing.movement.MovementState; import baritone.bot.pathing.movement.MovementState;
import baritone.bot.utils.BlockStateInterface; import baritone.bot.utils.BlockStateInterface;
import baritone.bot.utils.Helper;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.Tuple; import net.minecraft.util.Tuple;
@ -41,7 +41,7 @@ import static baritone.bot.pathing.movement.MovementState.MovementStatus.*;
* *
* @author leijurv * @author leijurv
*/ */
public class PathExecutor extends Behavior { public class PathExecutor implements Helper {
private static final double MAX_DIST_FROM_PATH = 2; private static final double MAX_DIST_FROM_PATH = 2;
private static final double MAX_TICKS_AWAY = 200; // ten seconds private static final double MAX_TICKS_AWAY = 200; // ten seconds
private final IPath path; private final IPath path;
@ -61,15 +61,21 @@ public class PathExecutor extends Behavior {
this.pathPosition = 0; this.pathPosition = 0;
} }
@Override /**
public void onTick(TickEvent event) { * Tick this executor
*
* @param event
* @return True if a movement just finished (and the player is therefore in a "stable" state, like,
* not sneaking out over lava), false otherwise
*/
public boolean onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) { if (event.getType() == TickEvent.Type.OUT) {
return; throw new IllegalStateException();
} }
if (pathPosition >= path.length()) { if (pathPosition >= path.length()) {
//stop bugging me, I'm done //stop bugging me, I'm done
//TODO Baritone.INSTANCE.behaviors.remove(this) //TODO Baritone.INSTANCE.behaviors.remove(this)
return; return true;
} }
BlockPos whereShouldIBe = path.positions().get(pathPosition); BlockPos whereShouldIBe = path.positions().get(pathPosition);
EntityPlayerSP thePlayer = mc.player; EntityPlayerSP thePlayer = mc.player;
@ -77,7 +83,7 @@ public class PathExecutor extends Behavior {
if (pathPosition == path.length() - 1) { if (pathPosition == path.length() - 1) {
displayChatMessageRaw("On last position, ending this path."); displayChatMessageRaw("On last position, ending this path.");
pathPosition++; pathPosition++;
return; return true;
} }
if (!whereShouldIBe.equals(whereAmI)) { if (!whereShouldIBe.equals(whereAmI)) {
System.out.println("Should be at " + whereShouldIBe + " actually am at " + whereAmI); System.out.println("Should be at " + whereShouldIBe + " actually am at " + whereAmI);
@ -86,7 +92,7 @@ public class PathExecutor extends Behavior {
if (whereAmI.equals(path.positions().get(i))) { if (whereAmI.equals(path.positions().get(i))) {
displayChatMessageRaw("Skipping back " + (pathPosition - i) + " steps, to " + i); displayChatMessageRaw("Skipping back " + (pathPosition - i) + " steps, to " + i);
pathPosition = Math.max(i - 1, 0); // previous step might not actually be done pathPosition = Math.max(i - 1, 0); // previous step might not actually be done
return; return false;
} }
} }
for (int i = pathPosition + 2; i < path.length(); i++) { //dont check pathPosition+1. the movement tells us when it's done (e.g. sneak placing) for (int i = pathPosition + 2; i < path.length(); i++) { //dont check pathPosition+1. the movement tells us when it's done (e.g. sneak placing)
@ -95,7 +101,7 @@ public class PathExecutor extends Behavior {
displayChatMessageRaw("Skipping forward " + (i - pathPosition) + " steps, to " + i); displayChatMessageRaw("Skipping forward " + (i - pathPosition) + " steps, to " + i);
} }
pathPosition = i - 1; pathPosition = i - 1;
return; return false;
} }
} }
} }
@ -111,7 +117,7 @@ public class PathExecutor extends Behavior {
pathPosition = path.length() + 3; pathPosition = path.length() + 3;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
failed = true; failed = true;
return; return false;
} }
} else { } else {
ticksAway = 0; ticksAway = 0;
@ -194,7 +200,7 @@ public class PathExecutor extends Behavior {
pathPosition = path.length() + 3; pathPosition = path.length() + 3;
failed = true; failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return; return true;
} }
if (costEstimateIndex == null || costEstimateIndex != pathPosition) { if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
costEstimateIndex = pathPosition; costEstimateIndex = pathPosition;
@ -206,7 +212,7 @@ public class PathExecutor extends Behavior {
pathPosition = path.length() + 3; pathPosition = path.length() + 3;
failed = true; failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return; return true;
} }
if (movementStatus == SUCCESS) { if (movementStatus == SUCCESS) {
System.out.println("Movement done, next path"); System.out.println("Movement done, next path");
@ -214,6 +220,7 @@ public class PathExecutor extends Behavior {
ticksOnCurrent = 0; ticksOnCurrent = 0;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
onTick(event); onTick(event);
return true;
} else { } else {
ticksOnCurrent++; ticksOnCurrent++;
if (ticksOnCurrent > currentMovementInitialCostEstimate + 100) { if (ticksOnCurrent > currentMovementInitialCostEstimate + 100) {
@ -226,9 +233,10 @@ public class PathExecutor extends Behavior {
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
pathPosition = path.length() + 3; pathPosition = path.length() + 3;
failed = true; failed = true;
return; return true;
} }
} }
return false; // movement is in progress
} }
public int getPosition() { public int getPosition() {