diff --git a/README.md b/README.md
index c2c822002..f0e17d21f 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
[![License](https://img.shields.io/github/license/cabaletta/baritone.svg)](LICENSE)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/7150d8ccf6094057b1782aa7a8f92d7d)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade)
-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.
+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 20x faster than MineBot at calculating paths).
Features
diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java
index f5c3eacd6..410b5a3fe 100644
--- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java
+++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java
@@ -24,16 +24,12 @@ import baritone.pathing.calc.openset.BinaryHeapOpenSet;
import baritone.pathing.goals.Goal;
import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.CalculationContext;
-import baritone.pathing.movement.Movement;
-import baritone.pathing.movement.MovementHelper;
-import baritone.pathing.movement.movements.*;
import baritone.pathing.path.IPath;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ChunkProviderClient;
-import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import java.util.Collection;
@@ -45,7 +41,7 @@ import java.util.Optional;
*
* @author leijurv
*/
-public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
+public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
private final Optional> favoredPositions;
@@ -104,12 +100,14 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered");
return Optional.of(new Path(startNode, currentNode, numNodes, goal));
}
- Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at currentNodePos
- for (Movement movementToGetToNeighbor : possibleMovements) {
- if (movementToGetToNeighbor == null) {
+ for (Moves moves : Moves.values()) {
+ MoveResult res = moves.apply(calcContext, currentNodePos.x, currentNodePos.y, currentNodePos.z);
+ numMovementsConsidered++;
+ double actionCost = res.cost;
+ if (actionCost >= ActionCosts.COST_INF) {
continue;
}
- BetterBlockPos dest = movementToGetToNeighbor.getDest();
+ BetterBlockPos dest = new BetterBlockPos(res.destX, res.destY, res.destZ);
int chunkX = currentNodePos.x >> 4;
int chunkZ = currentNodePos.z >> 4;
if (dest.x >> 4 != chunkX || dest.z >> 4 != chunkZ) {
@@ -122,14 +120,11 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
}
}
}
- // TODO cache cost
- double actionCost = movementToGetToNeighbor.getCost(calcContext);
- numMovementsConsidered++;
if (actionCost >= ActionCosts.COST_INF) {
continue;
}
if (actionCost <= 0) {
- throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " calculated implausible cost " + actionCost);
+ throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
}
if (favoring && favored.contains(dest)) {
// see issue #18
@@ -139,7 +134,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
double tentativeCost = currentNode.cost + actionCost;
if (tentativeCost < neighbor.cost) {
if (tentativeCost < 0) {
- throw new IllegalStateException(movementToGetToNeighbor.getClass() + " " + movementToGetToNeighbor + " overflowed into negative " + actionCost + " " + neighbor.cost + " " + tentativeCost);
+ throw new IllegalStateException(moves + " overflowed into negative " + actionCost + " " + neighbor.cost + " " + tentativeCost);
}
double improvementBy = neighbor.cost - tentativeCost;
// there are floating point errors caused by random combinations of traverse and diagonal over a flat area
@@ -150,7 +145,6 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
continue;
}
neighbor.previous = currentNode;
- neighbor.previousMovement = movementToGetToNeighbor;
neighbor.cost = tentativeCost;
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
if (neighbor.isOpen) {
@@ -203,45 +197,4 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
logDebug("No path found =(");
return Optional.empty();
}
-
-
- public static Movement[] getConnectedPositions(BetterBlockPos pos, CalculationContext calcContext) {
- int x = pos.x;
- int y = pos.y;
- int z = pos.z;
- BetterBlockPos east = new BetterBlockPos(x + 1, y, z);
- BetterBlockPos west = new BetterBlockPos(x - 1, y, z);
- BetterBlockPos south = new BetterBlockPos(x, y, z + 1);
- BetterBlockPos north = new BetterBlockPos(x, y, z - 1);
- return new Movement[]{
- new MovementDownward(pos, new BetterBlockPos(x, y - 1, z)),
-
- new MovementPillar(pos, new BetterBlockPos(x, y + 1, z)),
-
- new MovementTraverse(pos, east),
- new MovementTraverse(pos, west),
- new MovementTraverse(pos, north),
- new MovementTraverse(pos, south),
-
- new MovementAscend(pos, new BetterBlockPos(x + 1, y + 1, z)),
- new MovementAscend(pos, new BetterBlockPos(x - 1, y + 1, z)),
- new MovementAscend(pos, new BetterBlockPos(x, y + 1, z + 1)),
- new MovementAscend(pos, new BetterBlockPos(x, y + 1, z - 1)),
-
- MovementHelper.generateMovementFallOrDescend(pos, east, calcContext),
- MovementHelper.generateMovementFallOrDescend(pos, west, calcContext),
- MovementHelper.generateMovementFallOrDescend(pos, north, calcContext),
- MovementHelper.generateMovementFallOrDescend(pos, south, calcContext),
-
- new MovementDiagonal(pos, EnumFacing.NORTH, EnumFacing.EAST),
- new MovementDiagonal(pos, EnumFacing.NORTH, EnumFacing.WEST),
- new MovementDiagonal(pos, EnumFacing.SOUTH, EnumFacing.EAST),
- new MovementDiagonal(pos, EnumFacing.SOUTH, EnumFacing.WEST),
-
- MovementParkour.generate(pos, EnumFacing.EAST, calcContext),
- MovementParkour.generate(pos, EnumFacing.WEST, calcContext),
- MovementParkour.generate(pos, EnumFacing.NORTH, calcContext),
- MovementParkour.generate(pos, EnumFacing.SOUTH, calcContext),
- };
- }
}
diff --git a/src/main/java/baritone/pathing/calc/MoveResult.java b/src/main/java/baritone/pathing/calc/MoveResult.java
new file mode 100644
index 000000000..e9c6caa9e
--- /dev/null
+++ b/src/main/java/baritone/pathing/calc/MoveResult.java
@@ -0,0 +1,32 @@
+/*
+ * 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.pathing.calc;
+
+public final class MoveResult {
+ public final int destX;
+ public final int destY;
+ public final int destZ;
+ public final double cost;
+
+ public MoveResult(int x, int y, int z, double cost) {
+ this.destX = x;
+ this.destY = y;
+ this.destZ = z;
+ this.cost = cost;
+ }
+}
diff --git a/src/main/java/baritone/pathing/calc/Moves.java b/src/main/java/baritone/pathing/calc/Moves.java
new file mode 100644
index 000000000..dd9496104
--- /dev/null
+++ b/src/main/java/baritone/pathing/calc/Moves.java
@@ -0,0 +1,274 @@
+/*
+ * 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.pathing.calc;
+
+import baritone.pathing.movement.CalculationContext;
+import baritone.pathing.movement.Movement;
+import baritone.pathing.movement.movements.*;
+import baritone.utils.pathing.BetterBlockPos;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.Tuple;
+
+public enum Moves {
+ DOWNWARD() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) { // TODO specific return types
+ return new MovementDownward(src, src.down());
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y - 1, z, MovementDownward.cost(context, x, y, z));
+ }
+ },
+
+ PILLAR() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) { // TODO specific return types
+ return new MovementPillar(src, src.up());
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y + 1, z, MovementPillar.cost(context, x, y, z));
+ }
+ },
+
+ TRAVERSE_NORTH() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementTraverse(src, src.north());
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y, z - 1, MovementTraverse.cost(context, x, y, z, x, z - 1));
+ }
+ },
+
+ TRAVERSE_SOUTH() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementTraverse(src, src.south());
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y, z + 1, MovementTraverse.cost(context, x, y, z, x, z + 1));
+ }
+ },
+
+ TRAVERSE_EAST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementTraverse(src, src.east());
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x + 1, y, z, MovementTraverse.cost(context, x, y, z, x + 1, z));
+ }
+ },
+
+ TRAVERSE_WEST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementTraverse(src, src.west());
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x - 1, y, z, MovementTraverse.cost(context, x, y, z, x - 1, z));
+ }
+ },
+
+ ASCEND_NORTH() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z - 1));
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y + 1, z - 1, MovementAscend.cost(context, x, y, z, x, z - 1));
+ }
+ },
+
+ ASCEND_SOUTH() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z + 1));
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y + 1, z + 1, MovementAscend.cost(context, x, y, z, x, z + 1));
+ }
+ },
+
+ ASCEND_EAST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementAscend(src, new BetterBlockPos(src.x + 1, src.y + 1, src.z));
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y + 1, z + 1, MovementAscend.cost(context, x, y, z, x + 1, z));
+ }
+ },
+
+ ASCEND_WEST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementAscend(src, new BetterBlockPos(src.x - 1, src.y + 1, src.z));
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x, y + 1, z - 1, MovementAscend.cost(context, x, y, z, x - 1, z));
+ }
+ },
+
+ DESCEND_EAST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
+ if (res.destY == src.y - 1) {
+ return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ } else {
+ return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ }
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ Tuple res = MovementDescend.cost(context, x, y, z, x + 1, z);
+ return new MoveResult(x + 1, res.getFirst(), z, res.getSecond());
+ }
+ },
+
+ DESCEND_WEST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
+ if (res.destY == src.y - 1) {
+ return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ } else {
+ return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ }
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ Tuple res = MovementDescend.cost(context, x, y, z, x - 1, z);
+ return new MoveResult(x - 1, res.getFirst(), z, res.getSecond());
+ }
+ },
+
+ DESCEND_NORTH() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
+ if (res.destY == src.y - 1) {
+ return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ } else {
+ return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ }
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ Tuple res = MovementDescend.cost(context, x, y, z, x, z - 1);
+ return new MoveResult(x, res.getFirst(), z - 1, res.getSecond());
+ }
+ },
+
+ DESCEND_SOUTH() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
+ if (res.destY == src.y - 1) {
+ return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ } else {
+ return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
+ }
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ Tuple res = MovementDescend.cost(context, x, y, z, x, z + 1);
+ return new MoveResult(x, res.getFirst(), z + 1, res.getSecond());
+ }
+ },
+
+ DIAGONAL_NORTHEAST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.EAST);
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x + 1, y, z - 1, MovementDiagonal.cost(context, x, y, z, x + 1, z - 1));
+ }
+ },
+
+ DIAGONAL_NORTHWEST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.WEST);
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x - 1, y, z - 1, MovementDiagonal.cost(context, x, y, z, x - 1, z - 1));
+ }
+ },
+
+ DIAGONAL_SOUTHEAST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.EAST);
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x + 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x + 1, z + 1));
+ }
+ },
+
+ DIAGONAL_SOUTHWEST() {
+ @Override
+ protected Movement apply0(BetterBlockPos src) {
+ return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.WEST);
+ }
+
+ @Override
+ public MoveResult apply(CalculationContext context, int x, int y, int z) {
+ return new MoveResult(x - 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x - 1, z + 1));
+ }
+ },
+ // TODO parkour
+ ;
+
+ protected abstract Movement apply0(BetterBlockPos src);
+
+
+ public abstract MoveResult apply(CalculationContext context, int x, int y, int z);
+}
diff --git a/src/main/java/baritone/pathing/calc/Path.java b/src/main/java/baritone/pathing/calc/Path.java
index e94f2fb3e..50dd49d76 100644
--- a/src/main/java/baritone/pathing/calc/Path.java
+++ b/src/main/java/baritone/pathing/calc/Path.java
@@ -89,7 +89,7 @@ class Path implements IPath {
LinkedList tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end
while (!current.equals(start)) {
tempPath.addFirst(current.pos);
- tempMovements.addFirst(current.previousMovement);
+ tempMovements.addFirst(runBackwards(current.previous.pos, current.pos));
current = current.previous;
}
tempPath.addFirst(start.pos);
@@ -100,6 +100,16 @@ class Path implements IPath {
movements.addAll(tempMovements);
}
+ private static Movement runBackwards(BetterBlockPos src, BetterBlockPos dest) { // TODO this is horrifying
+ for (Moves moves : Moves.values()) {
+ Movement move = moves.apply0(src);
+ if (move.getDest().equals(dest)) {
+ return move;
+ }
+ }
+ throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src));
+ }
+
/**
* Performs a series of checks to ensure that the assembly of the path went as expected.
*/
diff --git a/src/main/java/baritone/pathing/calc/PathNode.java b/src/main/java/baritone/pathing/calc/PathNode.java
index 8f9895d85..50283cf98 100644
--- a/src/main/java/baritone/pathing/calc/PathNode.java
+++ b/src/main/java/baritone/pathing/calc/PathNode.java
@@ -19,7 +19,6 @@ package baritone.pathing.calc;
import baritone.pathing.goals.Goal;
import baritone.pathing.movement.ActionCosts;
-import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos;
/**
@@ -62,12 +61,6 @@ public final class PathNode {
*/
PathNode previous;
- /**
- * In the graph search, what previous movement (edge) was taken to get to here
- * Mutable and changed by PathFinder
- */
- Movement previousMovement;
-
/**
* Is this a member of the open set in A*? (only used during pathfinding)
* Instead of doing a costly member check in the open set, cache membership in each node individually too.
@@ -85,7 +78,6 @@ public final class PathNode {
this.cost = ActionCosts.COST_INF;
this.goal = goal;
this.estimatedCostToGoal = goal.heuristic(pos);
- this.previousMovement = null;
this.isOpen = false;
}
diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java
index 8c3ad4f4c..b1be71fda 100644
--- a/src/main/java/baritone/pathing/movement/MovementHelper.java
+++ b/src/main/java/baritone/pathing/movement/MovementHelper.java
@@ -47,11 +47,12 @@ import java.util.Optional;
*/
public interface MovementHelper extends ActionCosts, Helper {
- static boolean avoidBreaking(BlockPos pos, IBlockState state) {
+ static boolean avoidBreaking(BetterBlockPos pos, IBlockState state) {
+ return avoidBreaking(pos.x, pos.y, pos.z, state);
+ }
+
+ static boolean avoidBreaking(int x, int y, int z, IBlockState state) {
Block b = state.getBlock();
- int x = pos.getX();
- int y = pos.getY();
- int z = pos.getZ();
return b == Blocks.ICE // ice becomes water, and water can mess up the path
|| b instanceof BlockSilverfish // obvious reasons
// call BlockStateInterface.get directly with x,y,z. no need to make 5 new BlockPos for no reason
@@ -165,6 +166,10 @@ public interface MovementHelper extends ActionCosts, Helper {
}
static boolean isReplacable(BlockPos pos, IBlockState state) {
+ return isReplacable(pos.getX(), pos.getY(), pos.getZ(), state);
+ }
+
+ static boolean isReplacable(int x, int y, int z, IBlockState state) {
// for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case
// all other overrides just return true or false
@@ -175,13 +180,19 @@ public interface MovementHelper extends ActionCosts, Helper {
* return ((Integer)worldIn.getBlockState(pos).getValue(LAYERS)).intValue() == 1;
* }
*/
- if (state.getBlock() instanceof BlockSnow) {
+ Block block = state.getBlock();
+ if (block instanceof BlockSnow) {
// as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
- if (mc.world.getChunk(pos) instanceof EmptyChunk) {
+ if (mc.world.getChunk(x >> 4, z >> 4) instanceof EmptyChunk) {
return true;
}
+ return state.getValue(BlockSnow.LAYERS) == 1;
}
- return state.getBlock().isReplaceable(mc.world, pos);
+ if (block instanceof BlockDoublePlant) {
+ BlockDoublePlant.EnumPlantType kek = state.getValue(BlockDoublePlant.VARIANT);
+ return kek == BlockDoublePlant.EnumPlantType.FERN || kek == BlockDoublePlant.EnumPlantType.GRASS;
+ }
+ return state.getBlock().isReplaceable(null, null);
}
static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) {
@@ -314,24 +325,39 @@ public interface MovementHelper extends ActionCosts, Helper {
return canWalkOn(x, y, z, BlockStateInterface.get(x, y, z));
}
+ static boolean canPlaceAgainst(int x, int y, int z) {
+ return canPlaceAgainst(BlockStateInterface.get(x, y, z));
+ }
+
static boolean canPlaceAgainst(BlockPos pos) {
- IBlockState state = BlockStateInterface.get(pos);
+ return canPlaceAgainst(BlockStateInterface.get(pos));
+ }
+
+ static boolean canPlaceAgainst(IBlockState state) {
// TODO isBlockNormalCube isn't the best check for whether or not we can place a block against it. e.g. glass isn't normalCube but we can place against it
return state.isBlockNormalCube();
}
static double getMiningDurationTicks(CalculationContext context, BetterBlockPos position, boolean includeFalling) {
IBlockState state = BlockStateInterface.get(position);
- return getMiningDurationTicks(context, position, state, includeFalling);
+ return getMiningDurationTicks(context, position.x, position.y, position.z, state, includeFalling);
}
static double getMiningDurationTicks(CalculationContext context, BetterBlockPos position, IBlockState state, boolean includeFalling) {
+ return getMiningDurationTicks(context, position.x, position.y, position.z, state, includeFalling);
+ }
+
+ static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, boolean includeFalling) {
+ return getMiningDurationTicks(context, x, y, z, BlockStateInterface.get(x, y, z), includeFalling);
+ }
+
+ static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
Block block = state.getBlock();
- if (!canWalkThrough(position, state)) {
+ if (!canWalkThrough(x, y, z, state)) {
if (!context.allowBreak()) {
return COST_INF;
}
- if (avoidBreaking(position, state)) {
+ if (avoidBreaking(x, y, z, state)) {
return COST_INF;
}
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
@@ -342,10 +368,9 @@ public interface MovementHelper extends ActionCosts, Helper {
double result = m / strVsBlock;
if (includeFalling) {
- BetterBlockPos up = position.up();
- IBlockState above = BlockStateInterface.get(up);
+ IBlockState above = BlockStateInterface.get(x, y + 1, z);
if (above.getBlock() instanceof BlockFalling) {
- result += getMiningDurationTicks(context, up, above, true);
+ result += getMiningDurationTicks(context, x, y + 1, z, above, true);
}
}
return result;
@@ -437,15 +462,7 @@ public interface MovementHelper extends ActionCosts, Helper {
}
static Movement generateMovementFallOrDescend(BetterBlockPos pos, BetterBlockPos dest, CalculationContext calcContext) {
- // A
- //SA
- // A
- // B
- // C
- // D
- //if S is where you start, B needs to be air for a movementfall
- //A is plausibly breakable by either descend or fall
- //C, D, etc determine the length of the fall
+
int x = dest.x;
int y = dest.y;
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java
index 9d3398a21..6d313c488 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java
@@ -28,7 +28,6 @@ import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
-import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@@ -55,46 +54,54 @@ public class MovementAscend extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- IBlockState srcDown = BlockStateInterface.get(src.down());
+ return cost(context, src.x, src.y, src.z, dest.x, dest.z);
+ }
+
+ public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
+ IBlockState srcDown = BlockStateInterface.get(x, y - 1, z);
if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
return COST_INF;
}
// we can jump from soul sand, but not from a bottom slab
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
- IBlockState toPlace = BlockStateInterface.get(positionToPlace);
+ IBlockState toPlace = BlockStateInterface.get(destX, y, destZ);
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
}
- if (!MovementHelper.canWalkOn(positionToPlace, toPlace)) {
+ boolean hasToPlace = false;
+ if (!MovementHelper.canWalkOn(destX, y, z, toPlace)) {
if (!context.hasThrowaway()) {
return COST_INF;
}
- if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) {
+ if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y, destZ, toPlace)) {
return COST_INF;
}
// TODO: add ability to place against .down() as well as the cardinal directions
// useful for when you are starting a staircase without anything to place against
// Counterpoint to the above TODO ^ you should move then pillar instead of ascend
for (int i = 0; i < 4; i++) {
- BlockPos against1 = positionToPlace.offset(HORIZONTALS[i]);
- if (against1.equals(src)) {
+ int againstX = destX + HORIZONTALS[i].getXOffset();
+ int againstZ = destZ + HORIZONTALS[i].getZOffset();
+ if (againstX == x && againstZ == z) {
continue;
}
- if (MovementHelper.canPlaceAgainst(against1)) {
- return JUMP_ONE_BLOCK_COST + WALK_ONE_BLOCK_COST + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
+ if (MovementHelper.canPlaceAgainst(againstX, y, againstZ)) {
+ hasToPlace = true;
+ break;
}
}
- return COST_INF;
+ if (!hasToPlace) { // didn't find a valid place =(
+ return COST_INF;
+ }
}
- if (BlockStateInterface.get(src.up(3)).getBlock() instanceof BlockFalling) {//it would fall on us and possibly suffocate us
+ IBlockState srcUp2 = null;
+ if (BlockStateInterface.get(x, y + 3, z).getBlock() instanceof BlockFalling) {//it would fall on us and possibly suffocate us
// HOWEVER, we assume that we're standing in the start position
// that means that src and src.up(1) are both air
// maybe they aren't now, but they will be by the time this starts
- Block srcUp = BlockStateInterface.get(src.up(1)).getBlock();
- Block srcUp2 = BlockStateInterface.get(src.up(2)).getBlock();
- if (!(srcUp instanceof BlockFalling) || !(srcUp2 instanceof BlockFalling)) {
+ if (!(BlockStateInterface.getBlock(x, y + 1, z) instanceof BlockFalling) || !((srcUp2 = BlockStateInterface.get(x, y + 2, z)).getBlock() instanceof BlockFalling)) {
// if both of those are BlockFalling, that means that by standing on src
// (the presupposition of this Movement)
// we have necessarily already cleared the entire BlockFalling stack
@@ -109,15 +116,41 @@ public class MovementAscend extends Movement {
// it's possible srcUp is AIR from the start, and srcUp2 is falling
// and in that scenario, when we arrive and break srcUp2, that lets srcUp3 fall on us and suffocate us
}
- double walk = WALK_ONE_BLOCK_COST;
- if (jumpingToBottomSlab && !jumpingFromBottomSlab) {
- return walk + getTotalHardnessOfBlocksToBreak(context); // we don't hit space we just walk into the slab
+ double walk;
+ if (jumpingToBottomSlab) {
+ if (jumpingFromBottomSlab) {
+ walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST); // we hit space immediately on entering this action
+ } else {
+ walk = WALK_ONE_BLOCK_COST; // we don't hit space we just walk into the slab
+ }
+ } else {
+ if (toPlace.getBlock() == Blocks.SOUL_SAND) {
+ walk = WALK_ONE_OVER_SOUL_SAND_COST;
+ } else {
+ walk = WALK_ONE_BLOCK_COST;
+ }
}
- if (!jumpingToBottomSlab && toPlace.getBlock().equals(Blocks.SOUL_SAND)) {
- walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST;
+
+ // cracks knuckles
+
+ double totalCost = 0;
+ totalCost += walk;
+ if (hasToPlace) {
+ totalCost += context.placeBlockCost();
}
- // we hit space immediately on entering this action
- return Math.max(JUMP_ONE_BLOCK_COST, walk) + getTotalHardnessOfBlocksToBreak(context);
+ if (srcUp2 == null) {
+ srcUp2 = BlockStateInterface.get(x, y + 2, z);
+ }
+ totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false); // TODO MAKE ABSOLUTELY SURE we don't need includeFalling here, from the falling check above
+ if (totalCost >= COST_INF) {
+ return COST_INF;
+ }
+ totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, false);
+ if (totalCost >= COST_INF) {
+ return COST_INF;
+ }
+ totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 2, destZ, true);
+ return totalCost;
}
@Override
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java
index 85f7f1107..275344e4a 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java
@@ -17,6 +17,7 @@
package baritone.pathing.movement.movements;
+import baritone.Baritone;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
@@ -26,11 +27,16 @@ import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
+import net.minecraft.block.BlockFalling;
+import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
+import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
public class MovementDescend extends Movement {
+ private static final Tuple IMPOSSIBLE = new Tuple<>(0, COST_INF);
+
private int numTicks = 0;
public MovementDescend(BetterBlockPos start, BetterBlockPos end) {
@@ -45,24 +51,103 @@ public class MovementDescend extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- Block fromDown = BlockStateInterface.get(src.down()).getBlock();
+ Tuple result = cost(context, src.x, src.y, src.z, dest.x, dest.z);
+ if (result.getFirst() != dest.y) {
+ return COST_INF; // doesn't apply to us, this position is a fall not a descend
+ }
+ return result.getSecond();
+ }
+
+ public static Tuple cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
+ Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
- return COST_INF;
+ return IMPOSSIBLE;
}
- if (!MovementHelper.canWalkOn(positionToPlace)) {
- return COST_INF;
+
+ double totalCost = 0;
+ totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, false);
+ if (totalCost >= COST_INF) {
+ return IMPOSSIBLE;
}
- Block tmp1 = BlockStateInterface.get(dest).getBlock();
+ totalCost += MovementHelper.getMiningDurationTicks(context, destX, y, destZ, false);
+ if (totalCost >= COST_INF) {
+ return IMPOSSIBLE;
+ }
+ totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, true); // only the top block in the 3 we need to mine needs to consider the falling blocks above
+ if (totalCost >= COST_INF) {
+ return IMPOSSIBLE;
+ }
+
+ // A
+ //SA
+ // A
+ // B
+ // C
+ // D
+ //if S is where you start, B needs to be air for a movementfall
+ //A is plausibly breakable by either descend or fall
+ //C, D, etc determine the length of the fall
+ if (!MovementHelper.canWalkOn(destX, y - 2, destZ)) {
+ return dynamicFallCost(context, x, y, z, destX, destZ, totalCost);
+ }
+
+ Block tmp1 = BlockStateInterface.get(destX, y - 1, destZ).getBlock();
if (tmp1 == Blocks.LADDER || tmp1 == Blocks.VINE) {
- return COST_INF;
+ return IMPOSSIBLE;
}
+
// we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel)
double walk = WALK_OFF_BLOCK_COST;
if (fromDown == Blocks.SOUL_SAND) {
// use this ratio to apply the soul sand speed penalty to our 0.8 block distance
walk = WALK_ONE_OVER_SOUL_SAND_COST;
}
- return walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST) + getTotalHardnessOfBlocksToBreak(context);
+ totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST);
+ return new Tuple<>(y - 1, totalCost);
+ }
+
+ public static Tuple dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak) {
+ if (frontBreak != 0 && BlockStateInterface.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) {
+ // if frontBreak is 0 we can actually get through this without updating the falling block and making it actually fall
+ // but if frontBreak is nonzero, we're breaking blocks in front, so don't let anything fall through this column,
+ // and potentially replace the water we're going to fall into
+ return IMPOSSIBLE;
+ }
+ for (int fallHeight = 3; true; fallHeight++) {
+ int newY = y - fallHeight;
+ if (newY < 0) {
+ // when pathing in the end, where you could plausibly fall into the void
+ // this check prevents it from getting the block at y=-1 and crashing
+ return IMPOSSIBLE;
+ }
+ IBlockState ontoBlock = BlockStateInterface.get(destX, newY, destZ);
+ double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak;
+ if (ontoBlock.getBlock() == Blocks.WATER) { // TODO flowing check required here?
+ if (Baritone.settings().assumeWalkOnWater.get()) {
+ return IMPOSSIBLE; // TODO fix
+ }
+ // found a fall into water
+ return new Tuple<>(newY, tentativeCost); // TODO incorporate water swim up cost?
+ }
+ if (MovementHelper.canWalkThrough(destX, newY, destZ, ontoBlock)) {
+ continue;
+ }
+ if (!MovementHelper.canWalkOn(destX, newY, destZ, ontoBlock)) {
+ return IMPOSSIBLE;
+ }
+ if (MovementHelper.isBottomSlab(ontoBlock)) {
+ return IMPOSSIBLE; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
+ }
+ if (context.hasWaterBucket() && fallHeight <= context.maxFallHeightBucket() + 1) {
+ return new Tuple<>(newY + 1, tentativeCost + context.placeBlockCost()); // this is the block we're falling onto, so dest is +1
+ }
+ if (fallHeight <= context.maxFallHeightNoWater() + 1) {
+ // fallHeight = 4 means onto.up() is 3 blocks down, which is the max
+ return new Tuple<>(newY + 1, tentativeCost);
+ } else {
+ return IMPOSSIBLE;
+ }
+ }
}
@Override
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java
index d092b66ea..5a5b736a6 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java
@@ -53,40 +53,43 @@ public class MovementDiagonal extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- Block fromDown = BlockStateInterface.get(src.down()).getBlock();
+ return cost(context, src.x, src.y, src.z, dest.x, dest.z);
+ }
+
+ public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
+ Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF;
}
- if (!MovementHelper.canWalkThrough(positionsToBreak[4]) || !MovementHelper.canWalkThrough(positionsToBreak[5])) {
+ if (!MovementHelper.canWalkThrough(destX, y, destZ) || !MovementHelper.canWalkThrough(destX, y + 1, destZ)) {
return COST_INF;
}
- BetterBlockPos destDown = dest.down();
- IBlockState destWalkOn = BlockStateInterface.get(destDown);
- if (!MovementHelper.canWalkOn(destDown, destWalkOn)) {
+ IBlockState destWalkOn = BlockStateInterface.get(destX, y - 1, destZ);
+ if (!MovementHelper.canWalkOn(destX, y - 1, destZ, destWalkOn)) {
return COST_INF;
}
double multiplier = WALK_ONE_BLOCK_COST;
// For either possible soul sand, that affects half of our walking
- if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) {
+ if (destWalkOn.getBlock() == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
if (fromDown == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
- Block cuttingOver1 = BlockStateInterface.get(positionsToBreak[2].down()).getBlock();
+ Block cuttingOver1 = BlockStateInterface.get(x, y - 1, destZ).getBlock();
if (cuttingOver1 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver1)) {
return COST_INF;
}
- Block cuttingOver2 = BlockStateInterface.get(positionsToBreak[4].down()).getBlock();
+ Block cuttingOver2 = BlockStateInterface.get(destX, y - 1, z).getBlock();
if (cuttingOver2 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver2)) {
return COST_INF;
}
- IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
- IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]);
- IBlockState pb2 = BlockStateInterface.get(positionsToBreak[2]);
- IBlockState pb3 = BlockStateInterface.get(positionsToBreak[3]);
- double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, true);
- double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], pb2, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], pb3, true);
+ IBlockState pb0 = BlockStateInterface.get(x, y, destZ);
+ IBlockState pb1 = BlockStateInterface.get(x, y + 1, destZ);
+ IBlockState pb2 = BlockStateInterface.get(destX, y, z);
+ IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z);
+ double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false) + MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true);
+ double optionB = MovementHelper.getMiningDurationTicks(context, destX, y, z, pb2, false) + MovementHelper.getMiningDurationTicks(context, destX, y + 1, z, pb3, true);
if (optionA != 0 && optionB != 0) {
return COST_INF;
}
@@ -100,7 +103,7 @@ public class MovementDiagonal extends Movement {
return COST_INF;
}
}
- if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) {
+ if (BlockStateInterface.isWater(BlockStateInterface.getBlock(x, y, z)) || BlockStateInterface.isWater(BlockStateInterface.getBlock(destX, y, destZ))) {
// Ignore previous multiplier
// Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// Not even touching the blocks below
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java
index b265ddd71..148dc3b38 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java
@@ -43,17 +43,21 @@ public class MovementDownward extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- if (!MovementHelper.canWalkOn(dest.down())) {
+ return cost(context, src.x, src.y, src.z);
+ }
+
+ public static double cost(CalculationContext context, int x, int y, int z) {
+ if (!MovementHelper.canWalkOn(x, y - 2, z)) {
return COST_INF;
}
- IBlockState d = BlockStateInterface.get(dest);
+ IBlockState d = BlockStateInterface.get(x, y - 1, z);
Block td = d.getBlock();
boolean ladder = td == Blocks.LADDER || td == Blocks.VINE;
if (ladder) {
return LADDER_DOWN_ONE_COST;
} else {
// we're standing on it, while it might be block falling, it'll be air by the time we get here in the movement
- return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, dest, d, false);
+ return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, x, y - 1, z, d, false);
}
}
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementFall.java b/src/main/java/baritone/pathing/movement/movements/MovementFall.java
index a6a9e9f6f..8ff115911 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementFall.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementFall.java
@@ -26,13 +26,10 @@ import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos;
-import net.minecraft.block.Block;
-import net.minecraft.block.BlockFalling;
-import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.InventoryPlayer;
-import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
@@ -48,58 +45,11 @@ public class MovementFall extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- Block fromDown = BlockStateInterface.get(src.down()).getBlock();
- if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
- return COST_INF;
+ Tuple result = MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z);
+ if (result.getFirst() != dest.y) {
+ return COST_INF; // doesn't apply to us, this position is a descend not a fall
}
- IBlockState fallOnto = BlockStateInterface.get(dest.down());
- if (!MovementHelper.canWalkOn(dest.down(), fallOnto)) {
- return COST_INF;
- }
- if (MovementHelper.isBottomSlab(fallOnto)) {
- return COST_INF; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
- }
- double placeBucketCost = 0.0;
- boolean destIsWater = BlockStateInterface.isWater(dest);
- if (!destIsWater && src.getY() - dest.getY() > context.maxFallHeightNoWater()) {
- if (!context.hasWaterBucket()) {
- return COST_INF;
- }
- if (src.getY() - dest.getY() > context.maxFallHeightBucket()) {
- return COST_INF;
- }
- placeBucketCost = context.placeBlockCost();
- }
- double frontThree = 0;
- for (int i = 0; i < 3; i++) {
- frontThree += MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false);
- // don't include falling because we will check falling right after this, and if it's there it's COST_INF
- if (frontThree >= COST_INF) {
- return COST_INF;
- }
- }
- if (BlockStateInterface.get(positionsToBreak[0].up()).getBlock() instanceof BlockFalling) {
- return COST_INF;
- }
- for (int i = 3; i < positionsToBreak.length; i++) {
- // TODO is this the right check here?
- // MiningDurationTicks is all right, but shouldn't it be canWalkThrough instead?
- // Lilypads (i think?) are 0 ticks to mine, but they definitely cause fall damage
- // Same thing for falling through water... we can't actually do that
- // And falling through signs is possible, but they do have a mining duration, right?
- if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false) > 0) {
- //can't break while falling
-
- if (i != positionsToBreak.length - 1 || !destIsWater) {
- // if we're checking the very last block to mine
- // and it's water (so this is a water fall)
- // don't consider the cost of "mining" it
- // (if assumeWalkOnWater is true, water isn't canWalkThrough)
- return COST_INF;
- }
- }
- }
- return WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[positionsToBreak.length - 1] + placeBucketCost + frontThree;
+ return result.getSecond();
}
@Override
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java
index 15e7d52c0..bf77855d3 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java
@@ -48,9 +48,13 @@ public class MovementPillar extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- Block fromDown = BlockStateInterface.get(src).getBlock();
+ return cost(context, src.x, src.y, src.z);
+ }
+
+ public static double cost(CalculationContext context, int x, int y, int z) {
+ Block fromDown = BlockStateInterface.get(x, y, z).getBlock();
boolean ladder = fromDown instanceof BlockLadder || fromDown instanceof BlockVine;
- IBlockState fromDownDown = BlockStateInterface.get(src.down());
+ IBlockState fromDownDown = BlockStateInterface.get(x, y - 1, z);
if (!ladder) {
if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) {
return COST_INF;
@@ -65,24 +69,23 @@ public class MovementPillar extends Movement {
return COST_INF;
}
if (fromDown instanceof BlockVine) {
- if (getAgainst(src) == null) {
+ if (!hasAgainst(x, y, z)) {
return COST_INF;
}
}
- BetterBlockPos toBreakPos = src.up(2);
- IBlockState toBreak = BlockStateInterface.get(toBreakPos);
+ IBlockState toBreak = BlockStateInterface.get(x, y + 2, z);
Block toBreakBlock = toBreak.getBlock();
if (toBreakBlock instanceof BlockFenceGate) {
return COST_INF;
}
Block srcUp = null;
if (BlockStateInterface.isWater(toBreakBlock) && BlockStateInterface.isWater(fromDown)) {
- srcUp = BlockStateInterface.get(dest).getBlock();
+ srcUp = BlockStateInterface.get(x, y + 1, z).getBlock();
if (BlockStateInterface.isWater(srcUp)) {
return LADDER_UP_ONE_COST;
}
}
- double hardness = MovementHelper.getMiningDurationTicks(context, toBreakPos, toBreak, true);
+ double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true);
if (hardness >= COST_INF) {
return COST_INF;
}
@@ -90,12 +93,11 @@ public class MovementPillar extends Movement {
if (toBreakBlock instanceof BlockLadder || toBreakBlock instanceof BlockVine) {
hardness = 0; // we won't actually need to break the ladder / vine because we're going to use it
} else {
- BlockPos chkPos = src.up(3);
- IBlockState check = BlockStateInterface.get(chkPos);
+ IBlockState check = BlockStateInterface.get(x, y + 3, z);
if (check.getBlock() instanceof BlockFalling) {
// see MovementAscend's identical check for breaking a falling block above our head
if (srcUp == null) {
- srcUp = BlockStateInterface.get(dest).getBlock();
+ srcUp = BlockStateInterface.get(x, y + 1, z).getBlock();
}
if (!(toBreakBlock instanceof BlockFalling) || !(srcUp instanceof BlockFalling)) {
return COST_INF;
@@ -120,6 +122,13 @@ public class MovementPillar extends Movement {
}
}
+ public static boolean hasAgainst(int x, int y, int z) {
+ return BlockStateInterface.get(x + 1, y, z).isBlockNormalCube() ||
+ BlockStateInterface.get(x - 1, y, z).isBlockNormalCube() ||
+ BlockStateInterface.get(x, y, z + 1).isBlockNormalCube() ||
+ BlockStateInterface.get(x, y, z - 1).isBlockNormalCube();
+ }
+
public static BlockPos getAgainst(BlockPos vine) {
if (BlockStateInterface.get(vine.north()).isBlockNormalCube()) {
return vine.north();
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java
index a2d643772..232a8376e 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java
@@ -57,11 +57,15 @@ public class MovementTraverse extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
- IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
- IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]);
- IBlockState destOn = BlockStateInterface.get(positionToPlace);
- Block srcDown = BlockStateInterface.getBlock(src.down());
- if (MovementHelper.canWalkOn(positionToPlace, destOn)) {//this is a walk, not a bridge
+ return cost(context, src.x, src.y, src.z, dest.x, dest.z);
+ }
+
+ public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
+ IBlockState pb0 = BlockStateInterface.get(destX, y + 1, destZ);
+ IBlockState pb1 = BlockStateInterface.get(destX, y, destZ);
+ IBlockState destOn = BlockStateInterface.get(destX, y - 1, destZ);
+ Block srcDown = BlockStateInterface.getBlock(x, y - 1, z);
+ if (MovementHelper.canWalkOn(destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
double WC = WALK_ONE_BLOCK_COST;
if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) {
WC = WALK_ONE_IN_WATER_COST;
@@ -73,11 +77,11 @@ public class MovementTraverse extends Movement {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
}
}
- double hardness1 = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, true);
+ double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true);
if (hardness1 >= COST_INF) {
return COST_INF;
}
- double hardness2 = MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, false);
+ double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
if (hardness1 == 0 && hardness2 == 0) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) {
// If there's nothing in the way, and this isn't water or soul sand, and we aren't sneak placing
@@ -95,7 +99,7 @@ public class MovementTraverse extends Movement {
if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
return COST_INF;
}
- if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(positionToPlace, destOn)) {
+ if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(destX, y - 1, destZ, destOn)) {
boolean throughWater = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock());
if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) {
return COST_INF;
@@ -103,15 +107,21 @@ public class MovementTraverse extends Movement {
if (!context.hasThrowaway()) {
return COST_INF;
}
+ double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb0, false);
+ if (hardness1 >= COST_INF) {
+ return COST_INF;
+ }
+ double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb1, true);
+
double WC = throughWater ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST;
for (int i = 0; i < 4; i++) {
- BlockPos against1 = dest.offset(HORIZONTALS[i]);
- if (against1.equals(src)) {
+ int againstX = destX + HORIZONTALS[i].getXOffset();
+ int againstZ = destZ + HORIZONTALS[i].getZOffset();
+ if (againstX == x && againstZ == z) {
continue;
}
- against1 = against1.down();
- if (MovementHelper.canPlaceAgainst(against1)) {
- return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
+ if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) {
+ return WC + context.placeBlockCost() + hardness1 + hardness2;
}
}
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) {
@@ -121,7 +131,7 @@ public class MovementTraverse extends Movement {
return COST_INF; // this is obviously impossible
}
WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking
- return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
+ return WC + context.placeBlockCost() + hardness1 + hardness2;
}
return COST_INF;
// Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock());
diff --git a/src/main/java/baritone/utils/BlockStateInterface.java b/src/main/java/baritone/utils/BlockStateInterface.java
index 6e0c7297b..ff55c7d89 100644
--- a/src/main/java/baritone/utils/BlockStateInterface.java
+++ b/src/main/java/baritone/utils/BlockStateInterface.java
@@ -98,6 +98,9 @@ public class BlockStateInterface implements Helper {
return get(pos).getBlock();
}
+ public static Block getBlock(int x, int y, int z) {
+ return get(x, y, z).getBlock();
+ }
/**
* Returns whether or not the specified block is
diff --git a/src/main/java/baritone/utils/ExampleBaritoneControl.java b/src/main/java/baritone/utils/ExampleBaritoneControl.java
index 6cd2655aa..19a33f32f 100644
--- a/src/main/java/baritone/utils/ExampleBaritoneControl.java
+++ b/src/main/java/baritone/utils/ExampleBaritoneControl.java
@@ -27,14 +27,9 @@ import baritone.behavior.PathingBehavior;
import baritone.cache.ChunkPacker;
import baritone.cache.Waypoint;
import baritone.cache.WorldProvider;
-import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.goals.*;
-import baritone.pathing.movement.ActionCosts;
-import baritone.pathing.movement.CalculationContext;
-import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
-import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.entity.Entity;
@@ -433,7 +428,8 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
event.cancel();
return;
}
- if (msg.equals("costs")) {
+ // TODO
+ /*if (msg.equals("costs")) {
Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext());
List moves = new ArrayList<>(Arrays.asList(movements));
while (moves.contains(null)) {
@@ -451,6 +447,6 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
}
event.cancel();
return;
- }
+ }*/
}
}
diff --git a/src/main/java/baritone/utils/pathing/BetterBlockPos.java b/src/main/java/baritone/utils/pathing/BetterBlockPos.java
index e46b27dc7..09727b846 100644
--- a/src/main/java/baritone/utils/pathing/BetterBlockPos.java
+++ b/src/main/java/baritone/utils/pathing/BetterBlockPos.java
@@ -134,4 +134,24 @@ public final class BetterBlockPos extends BlockPos {
Vec3i vec = dir.getDirectionVec();
return new BetterBlockPos(x + vec.getX() * dist, y + vec.getY() * dist, z + vec.getZ() * dist);
}
+
+ @Override
+ public BetterBlockPos north() {
+ return new BetterBlockPos(x, y, z - 1);
+ }
+
+ @Override
+ public BetterBlockPos south() {
+ return new BetterBlockPos(x, y, z + 1);
+ }
+
+ @Override
+ public BetterBlockPos east() {
+ return new BetterBlockPos(x + 1, y, z);
+ }
+
+ @Override
+ public BetterBlockPos west() {
+ return new BetterBlockPos(x - 1, y, z);
+ }
}