a much needed path executor overhaul

This commit is contained in:
Leijurv 2018-09-14 18:29:35 -07:00
parent 13cfb8e369
commit 12b64ead5c
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
6 changed files with 119 additions and 108 deletions

View File

@ -31,7 +31,7 @@ public enum EventState {
/** /**
* Indicates that whatever movement the event is being * Indicates that whatever movement the event is being
* dispatched as a result of has already occured. * dispatched as a result of has already occurred.
*/ */
POST POST
} }

View File

@ -102,6 +102,7 @@ public abstract class Movement implements Helper, MovementHelper {
* @return Status * @return Status
*/ */
public MovementStatus update() { public MovementStatus update() {
player().capabilities.allowFlying = false;
MovementState latestState = updateState(currentState); MovementState latestState = updateState(currentState);
if (BlockStateInterface.isLiquid(playerFeet())) { if (BlockStateInterface.isLiquid(playerFeet())) {
latestState.setInput(Input.JUMP, true); latestState.setInput(Input.JUMP, true);

View File

@ -71,11 +71,11 @@ public interface IPath extends Helper {
*/ */
Goal getGoal(); Goal getGoal();
default Tuple<Double, BlockPos> closestPathPos(double x, double y, double z) { default Tuple<Double, BlockPos> closestPathPos() {
double best = -1; double best = -1;
BlockPos bestPos = null; BlockPos bestPos = null;
for (BlockPos pos : positions()) { for (BlockPos pos : positions()) {
double dist = Utils.distanceToCenter(pos, x, y, z); double dist = Utils.playerDistanceToCenter(pos);
if (dist < best || best == -1) { if (dist < best || best == -1) {
best = dist; best = dist;
bestPos = pos; bestPos = pos;

View File

@ -26,7 +26,7 @@ import baritone.pathing.movement.movements.MovementFall;
import baritone.pathing.movement.movements.MovementTraverse; import baritone.pathing.movement.movements.MovementTraverse;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import net.minecraft.client.entity.EntityPlayerSP; import baritone.utils.Utils;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.Tuple; import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -75,18 +75,11 @@ public class PathExecutor implements Helper {
if (event.getType() == TickEvent.Type.OUT) { if (event.getType() == TickEvent.Type.OUT) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
if (pathPosition >= path.length()) { if (pathPosition >= path.length() - 1) {
//stop bugging me, I'm done return true; // stop bugging me, I'm done
//TODO Baritone.INSTANCE.behaviors.remove(this)
return true;
} }
BlockPos whereShouldIBe = path.positions().get(pathPosition); BlockPos whereShouldIBe = path.positions().get(pathPosition);
EntityPlayerSP thePlayer = mc.player;
BlockPos whereAmI = playerFeet(); BlockPos whereAmI = playerFeet();
if (pathPosition == path.length() - 1) {
pathPosition++;
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);
if (!Blocks.AIR.equals(BlockStateInterface.getBlock(whereAmI.down()))) {//do not skip if standing on air, because our position isn't stable to skip if (!Blocks.AIR.equals(BlockStateInterface.getBlock(whereAmI.down()))) {//do not skip if standing on air, because our position isn't stable to skip
@ -98,7 +91,7 @@ public class PathExecutor implements Helper {
for (int j = pathPosition; j <= previousPos; j++) { for (int j = pathPosition; j <= previousPos; j++) {
path.movements().get(j).reset(); path.movements().get(j).reset();
} }
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); clearKeys();
return false; return false;
} }
} }
@ -109,39 +102,29 @@ public class PathExecutor implements Helper {
} }
System.out.println("Double skip sundae"); System.out.println("Double skip sundae");
pathPosition = i - 1; pathPosition = i - 1;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); clearKeys();
return false; return false;
} }
} }
} }
} }
Tuple<Double, BlockPos> status = path.closestPathPos(thePlayer.posX, thePlayer.posY, thePlayer.posZ); Tuple<Double, BlockPos> status = path.closestPathPos();
double distanceFromPath = status.getFirst(); if (possiblyOffPath(status, MAX_DIST_FROM_PATH)) {
if (distanceFromPath > MAX_DIST_FROM_PATH) {
ticksAway++; ticksAway++;
System.out.println("FAR AWAY FROM PATH FOR " + ticksAway + " TICKS. Current distance: " + distanceFromPath + ". Threshold: " + MAX_DIST_FROM_PATH); System.out.println("FAR AWAY FROM PATH FOR " + ticksAway + " TICKS. Current distance: " + status.getFirst() + ". Threshold: " + MAX_DIST_FROM_PATH);
if (ticksAway > MAX_TICKS_AWAY) { if (ticksAway > MAX_TICKS_AWAY) {
logDebug("Too far away from path for too long, cancelling path"); logDebug("Too far away from path for too long, cancelling path");
System.out.println("Too many ticks"); cancel();
pathPosition = path.length() + 3;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
failed = true;
return false; return false;
} }
} else { } else {
ticksAway = 0; ticksAway = 0;
} }
if (distanceFromPath > MAX_MAX_DIST_FROM_PATH) { if (possiblyOffPath(status, MAX_MAX_DIST_FROM_PATH)) { // ok, stop right away, we're way too far.
if (!(path.movements().get(pathPosition) instanceof MovementFall)) { // might be midair
if (pathPosition == 0 || !(path.movements().get(pathPosition - 1) instanceof MovementFall)) { // might have overshot the landing
logDebug("too far from path"); logDebug("too far from path");
pathPosition = path.length() + 3; cancel();
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
failed = true;
return false; return false;
} }
}
}
//this commented block is literally cursed. //this commented block is literally cursed.
/*Out.log(actions.get(pathPosition)); /*Out.log(actions.get(pathPosition));
if (pathPosition < actions.size() - 1) {//if there are two ActionBridges in a row and they are at right angles, walk diagonally. This makes it so you walk at 45 degrees along a zigzag path instead of doing inefficient zigging and zagging if (pathPosition < actions.size() - 1) {//if there are two ActionBridges in a row and they are at right angles, walk diagonally. This makes it so you walk at 45 degrees along a zigzag path instead of doing inefficient zigging and zagging
@ -176,7 +159,9 @@ public class PathExecutor implements Helper {
}*/ }*/
long start = System.nanoTime() / 1000000L; long start = System.nanoTime() / 1000000L;
for (int i = pathPosition - 10; i < pathPosition + 10; i++) { for (int i = pathPosition - 10; i < pathPosition + 10; i++) {
if (i >= 0 && i < path.movements().size()) { if (i < 0 || i >= path.movements().size()) {
continue;
}
Movement m = path.movements().get(i); Movement m = path.movements().get(i);
HashSet<BlockPos> prevBreak = new HashSet<>(m.toBreak()); HashSet<BlockPos> prevBreak = new HashSet<>(m.toBreak());
HashSet<BlockPos> prevPlace = new HashSet<>(m.toPlace()); HashSet<BlockPos> prevPlace = new HashSet<>(m.toPlace());
@ -194,7 +179,6 @@ public class PathExecutor implements Helper {
recalcBP = true; recalcBP = true;
} }
} }
}
if (recalcBP) { if (recalcBP) {
HashSet<BlockPos> newBreak = new HashSet<>(); HashSet<BlockPos> newBreak = new HashSet<>();
HashSet<BlockPos> newPlace = new HashSet<>(); HashSet<BlockPos> newPlace = new HashSet<>();
@ -221,9 +205,7 @@ public class PathExecutor implements Helper {
for (int i = 1; i < Baritone.settings().costVerificationLookahead.get() && pathPosition + i < path.length() - 1; i++) { for (int i = 1; i < Baritone.settings().costVerificationLookahead.get() && pathPosition + i < path.length() - 1; i++) {
if (path.movements().get(pathPosition + i).calculateCostWithoutCaching() >= ActionCosts.COST_INF) { if (path.movements().get(pathPosition + i).calculateCostWithoutCaching() >= ActionCosts.COST_INF) {
logDebug("Something has changed in the world and a future movement has become impossible. Cancelling."); logDebug("Something has changed in the world and a future movement has become impossible. Cancelling.");
pathPosition = path.length() + 3; cancel();
failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true; return true;
} }
} }
@ -231,108 +213,98 @@ public class PathExecutor implements Helper {
double currentCost = movement.recalculateCost(); double currentCost = movement.recalculateCost();
if (currentCost >= ActionCosts.COST_INF) { if (currentCost >= ActionCosts.COST_INF) {
logDebug("Something has changed in the world and this movement has become impossible. Cancelling."); logDebug("Something has changed in the world and this movement has become impossible. Cancelling.");
pathPosition = path.length() + 3; cancel();
failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true; return true;
} }
if (!movement.calculatedWhileLoaded() && currentCost - currentMovementInitialCostEstimate > Baritone.settings().maxCostIncrease.get()) { if (!movement.calculatedWhileLoaded() && currentCost - currentMovementInitialCostEstimate > Baritone.settings().maxCostIncrease.get()) {
logDebug("Original cost " + currentMovementInitialCostEstimate + " current cost " + currentCost + ". Cancelling."); logDebug("Original cost " + currentMovementInitialCostEstimate + " current cost " + currentCost + ". Cancelling.");
pathPosition = path.length() + 3; cancel();
failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true; return true;
} }
player().capabilities.allowFlying = false;
MovementState.MovementStatus movementStatus = movement.update(); MovementState.MovementStatus movementStatus = movement.update();
if (movementStatus == UNREACHABLE || movementStatus == FAILED) { if (movementStatus == UNREACHABLE || movementStatus == FAILED) {
logDebug("Movement returns status " + movementStatus); logDebug("Movement returns status " + movementStatus);
pathPosition = path.length() + 3; cancel();
failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true; return true;
} }
if (movementStatus == SUCCESS) { if (movementStatus == SUCCESS) {
//System.out.println("Movement done, next path"); //System.out.println("Movement done, next path");
pathPosition++; pathPosition++;
ticksOnCurrent = 0; ticksOnCurrent = 0;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); clearKeys();
onTick(event); onTick(event);
return true; return true;
} else { } else {
sprintIfRequested(); sprintIfRequested();
ticksOnCurrent++; ticksOnCurrent++;
if (ticksOnCurrent > currentMovementInitialCostEstimate + Baritone.settings().movementTimeoutTicks.get()) { if (ticksOnCurrent > currentMovementInitialCostEstimate + Baritone.settings().movementTimeoutTicks.get()) {
// only fail if the total time has exceeded the initial estimate // only cancel if the total time has exceeded the initial estimate
// as you break the blocks required, the remaining cost goes down, to the point where // as you break the blocks required, the remaining cost goes down, to the point where
// ticksOnCurrent is greater than recalculateCost + 100 // ticksOnCurrent is greater than recalculateCost + 100
// this is why we cache cost at the beginning, and don't recalculate for this comparison every tick // this is why we cache cost at the beginning, and don't recalculate for this comparison every tick
logDebug("This movement has taken too long (" + ticksOnCurrent + " ticks, expected " + currentMovementInitialCostEstimate + "). Cancelling."); logDebug("This movement has taken too long (" + ticksOnCurrent + " ticks, expected " + currentMovementInitialCostEstimate + "). Cancelling.");
movement.cancel(); cancel();
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
pathPosition = path.length() + 3;
failed = true;
return true; return true;
} }
} }
return false; // movement is in progress return false; // movement is in progress
} }
private boolean possiblyOffPath(Tuple<Double, BlockPos> status, double leniency) {
double distanceFromPath = status.getFirst();
if (distanceFromPath > leniency) {
// when we're midair in the middle of a fall, we're very far from both the beginning and the end, but we aren't actually off path
if (path.movements().get(pathPosition) instanceof MovementFall) {
BlockPos fallDest = path.positions().get(pathPosition + 1); // .get(pathPosition) is the block we fell off of
if (Utils.playerFlatDistanceToCenter(fallDest) < 0.5) {
return false;
}
return true;
} else {
return true;
}
} else {
return false;
}
}
private void sprintIfRequested() { private void sprintIfRequested() {
// first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint
if (!new CalculationContext().canSprint()) { if (!new CalculationContext().canSprint()) {
player().setSprinting(false); player().setSprinting(false);
return; return;
} }
// if the movement requested sprinting, then we're done
if (Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindSprint)) { if (Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindSprint)) {
if (!player().isSprinting()) { if (!player().isSprinting()) {
player().setSprinting(true); player().setSprinting(true);
} }
return; return;
} }
Movement movement = path.movements().get(pathPosition);
if (movement instanceof MovementDescend && pathPosition < path.length() - 2) { // however, descend doesn't request sprinting, beceause it doesn't know the context of what movement comes after it
BlockPos descendStart = movement.getSrc(); Movement current = path.movements().get(pathPosition);
BlockPos descendEnd = movement.getDest(); if (current instanceof MovementDescend && pathPosition < path.length() - 2) {
BlockPos into = descendEnd.subtract(descendStart.down()).add(descendEnd);
if (into.getY() != descendEnd.getY()) { // (dest - src) + dest is offset 1 more in the same direction
throw new IllegalStateException(); // sanity check // so it's the block we'd need to worry about running into if we decide to sprint straight through this descend
}
for (int i = 0; i <= 2; i++) { BlockPos into = current.getDest().subtract(current.getSrc().down()).add(current.getDest());
if (MovementHelper.avoidWalkingInto(BlockStateInterface.getBlock(into.up(i)))) { for (int y = 0; y <= 2; y++) { // we could hit any of the three blocks
if (MovementHelper.avoidWalkingInto(BlockStateInterface.getBlock(into.up(y)))) {
logDebug("Sprinting would be unsafe"); logDebug("Sprinting would be unsafe");
player().setSprinting(false); player().setSprinting(false);
return; return;
} }
} }
Movement next = path.movements().get(pathPosition + 1); Movement next = path.movements().get(pathPosition + 1);
if (next instanceof MovementDescend) { if (canSprintInto(current, next)) {
if (next.getDirection().equals(movement.getDirection())) { if (playerFeet().equals(current.getDest())) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++; pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); clearKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
if (next instanceof MovementTraverse) {
if (next.getDirection().down().equals(movement.getDirection()) && MovementHelper.canWalkOn(next.getDest().down())) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
if (next instanceof MovementDiagonal && Baritone.settings().allowOvershootDiagonalDescend.get()) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
} }
if (!player().isSprinting()) { if (!player().isSprinting()) {
player().setSprinting(true); player().setSprinting(true);
@ -344,6 +316,34 @@ public class PathExecutor implements Helper {
player().setSprinting(false); player().setSprinting(false);
} }
private static boolean canSprintInto(Movement current, Movement next) {
if (next instanceof MovementDescend) {
if (next.getDirection().equals(current.getDirection())) {
return true;
}
}
if (next instanceof MovementTraverse) {
if (next.getDirection().down().equals(current.getDirection()) && MovementHelper.canWalkOn(next.getDest().down())) {
return true;
}
}
if (next instanceof MovementDiagonal && Baritone.settings().allowOvershootDiagonalDescend.get()) {
return true;
}
return false;
}
private static void clearKeys() {
// i'm just sick and tired of this snippet being everywhere lol
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
private void cancel() {
clearKeys();
pathPosition = path.length() + 3;
failed = true;
}
public int getPosition() { public int getPosition() {
return pathPosition; return pathPosition;
} }

View File

@ -35,7 +35,6 @@
package baritone.utils; package baritone.utils;
import net.minecraft.client.settings.KeyBinding; import net.minecraft.client.settings.KeyBinding;
import org.lwjgl.input.Keyboard;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -134,7 +133,7 @@ public final class InputOverrideHandler implements Helper {
/** /**
* The actual game {@link KeyBinding} being forced. * The actual game {@link KeyBinding} being forced.
*/ */
private KeyBinding keyBinding; private final KeyBinding keyBinding;
Input(KeyBinding keyBinding) { Input(KeyBinding keyBinding) {
this.keyBinding = keyBinding; this.keyBinding = keyBinding;

View File

@ -19,6 +19,7 @@ package baritone.utils;
import net.minecraft.block.BlockFire; import net.minecraft.block.BlockFire;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -112,6 +113,16 @@ public final class Utils {
return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff); return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff);
} }
public static double playerDistanceToCenter(BlockPos pos) {
EntityPlayerSP player = (new Helper() {}).player();
return distanceToCenter(pos, player.posX, player.posY, player.posZ);
}
public static double playerFlatDistanceToCenter(BlockPos pos) {
EntityPlayerSP player = (new Helper() {}).player();
return distanceToCenter(pos, player.posX, pos.getY() + 0.5, player.posZ);
}
public static double degToRad(double deg) { public static double degToRad(double deg) {
return deg * DEG_TO_RAD; return deg * DEG_TO_RAD;
} }