s a n i k

This commit is contained in:
Leijurv 2018-09-22 22:00:28 -07:00
parent 1b576eca28
commit 0d0eefec9c
No known key found for this signature in database
GPG Key ID: 44A3EA646EADAC6A
13 changed files with 489 additions and 182 deletions

View File

@ -24,16 +24,12 @@ import baritone.pathing.calc.openset.BinaryHeapOpenSet;
import baritone.pathing.goals.Goal; import baritone.pathing.goals.Goal;
import baritone.pathing.movement.ActionCosts; import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.CalculationContext; 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.pathing.path.IPath;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.Collection; import java.util.Collection;
@ -45,7 +41,7 @@ import java.util.Optional;
* *
* @author leijurv * @author leijurv
*/ */
public class AStarPathFinder extends AbstractNodeCostSearch implements Helper { public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
private final Optional<HashSet<BetterBlockPos>> favoredPositions; private final Optional<HashSet<BetterBlockPos>> favoredPositions;
@ -104,12 +100,14 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered"); logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered");
return Optional.of(new Path(startNode, currentNode, numNodes, goal)); return Optional.of(new Path(startNode, currentNode, numNodes, goal));
} }
Movement[] possibleMovements = getConnectedPositions(currentNodePos, calcContext);//movement that we could take that start at currentNodePos for (Moves moves : Moves.values()) {
for (Movement movementToGetToNeighbor : possibleMovements) { MoveResult res = moves.apply(calcContext, currentNodePos.x, currentNodePos.y, currentNodePos.z);
if (movementToGetToNeighbor == null) { numMovementsConsidered++;
double actionCost = res.cost;
if (actionCost >= ActionCosts.COST_INF) {
continue; continue;
} }
BetterBlockPos dest = movementToGetToNeighbor.getDest(); BetterBlockPos dest = new BetterBlockPos(res.destX, res.destY, res.destZ);
int chunkX = currentNodePos.x >> 4; int chunkX = currentNodePos.x >> 4;
int chunkZ = currentNodePos.z >> 4; int chunkZ = currentNodePos.z >> 4;
if (dest.x >> 4 != chunkX || dest.z >> 4 != chunkZ) { 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) { if (actionCost >= ActionCosts.COST_INF) {
continue; continue;
} }
if (actionCost <= 0) { 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)) { if (favoring && favored.contains(dest)) {
// see issue #18 // see issue #18
@ -139,7 +134,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
double tentativeCost = currentNode.cost + actionCost; double tentativeCost = currentNode.cost + actionCost;
if (tentativeCost < neighbor.cost) { if (tentativeCost < neighbor.cost) {
if (tentativeCost < 0) { 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; double improvementBy = neighbor.cost - tentativeCost;
// there are floating point errors caused by random combinations of traverse and diagonal over a flat area // 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; continue;
} }
neighbor.previous = currentNode; neighbor.previous = currentNode;
neighbor.previousMovement = movementToGetToNeighbor;
neighbor.cost = tentativeCost; neighbor.cost = tentativeCost;
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal; neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
if (neighbor.isOpen) { if (neighbor.isOpen) {
@ -203,45 +197,4 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
logDebug("No path found =("); logDebug("No path found =(");
return Optional.empty(); 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),
};
}
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<Integer, Double> 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<Integer, Double> 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<Integer, Double> 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<Integer, Double> 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);
}

View File

@ -89,7 +89,7 @@ class Path implements IPath {
LinkedList<Movement> tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end LinkedList<Movement> tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end
while (!current.equals(start)) { while (!current.equals(start)) {
tempPath.addFirst(current.pos); tempPath.addFirst(current.pos);
tempMovements.addFirst(current.previousMovement); tempMovements.addFirst(runBackwards(current.previous.pos, current.pos));
current = current.previous; current = current.previous;
} }
tempPath.addFirst(start.pos); tempPath.addFirst(start.pos);
@ -100,6 +100,16 @@ class Path implements IPath {
movements.addAll(tempMovements); 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. * Performs a series of checks to ensure that the assembly of the path went as expected.
*/ */

View File

@ -19,7 +19,6 @@ package baritone.pathing.calc;
import baritone.pathing.goals.Goal; import baritone.pathing.goals.Goal;
import baritone.pathing.movement.ActionCosts; import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
/** /**
@ -62,12 +61,6 @@ public final class PathNode {
*/ */
PathNode previous; 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) * 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. * 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.cost = ActionCosts.COST_INF;
this.goal = goal; this.goal = goal;
this.estimatedCostToGoal = goal.heuristic(pos); this.estimatedCostToGoal = goal.heuristic(pos);
this.previousMovement = null;
this.isOpen = false; this.isOpen = false;
} }

View File

@ -462,15 +462,7 @@ public interface MovementHelper extends ActionCosts, Helper {
} }
static Movement generateMovementFallOrDescend(BetterBlockPos pos, BetterBlockPos dest, CalculationContext calcContext) { 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 x = dest.x;
int y = dest.y; int y = dest.y;

View File

@ -17,6 +17,7 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
@ -26,11 +27,16 @@ import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
public class MovementDescend extends Movement { public class MovementDescend extends Movement {
private static final Tuple<Integer, Double> IMPOSSIBLE = new Tuple<>(0, COST_INF);
private int numTicks = 0; private int numTicks = 0;
public MovementDescend(BetterBlockPos start, BetterBlockPos end) { public MovementDescend(BetterBlockPos start, BetterBlockPos end) {
@ -45,38 +51,103 @@ public class MovementDescend extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
return cost(context, src.x, src.y, src.z, dest.x, dest.z); Tuple<Integer, Double> 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 double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) { public static Tuple<Integer, Double> cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock(); Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF; return IMPOSSIBLE;
} }
double totalCost = 0;
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, false);
if (totalCost >= COST_INF) {
return IMPOSSIBLE;
}
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)) { if (!MovementHelper.canWalkOn(destX, y - 2, destZ)) {
return COST_INF; return dynamicFallCost(context, x, y, z, destX, destZ, totalCost);
} }
Block tmp1 = BlockStateInterface.get(destX, y - 1, destZ).getBlock(); Block tmp1 = BlockStateInterface.get(destX, y - 1, destZ).getBlock();
if (tmp1 == Blocks.LADDER || tmp1 == Blocks.VINE) { 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) // 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; double walk = WALK_OFF_BLOCK_COST;
if (fromDown == Blocks.SOUL_SAND) { if (fromDown == Blocks.SOUL_SAND) {
// use this ratio to apply the soul sand speed penalty to our 0.8 block distance // use this ratio to apply the soul sand speed penalty to our 0.8 block distance
walk = WALK_ONE_OVER_SOUL_SAND_COST; walk = WALK_ONE_OVER_SOUL_SAND_COST;
} }
double totalCost = walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST); totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST);
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, false); return new Tuple<>(y - 1, totalCost);
if (totalCost >= COST_INF) { }
return COST_INF;
public static Tuple<Integer, Double> 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;
} }
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y, destZ, false); for (int fallHeight = 3; true; fallHeight++) {
if (totalCost >= COST_INF) { int newY = y - fallHeight;
return COST_INF; 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;
}
} }
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
return totalCost;
} }
@Override @Override

View File

@ -53,40 +53,43 @@ public class MovementDiagonal extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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) { if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return COST_INF; 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; return COST_INF;
} }
BetterBlockPos destDown = dest.down(); IBlockState destWalkOn = BlockStateInterface.get(destX, y - 1, destZ);
IBlockState destWalkOn = BlockStateInterface.get(destDown); if (!MovementHelper.canWalkOn(destX, y - 1, destZ, destWalkOn)) {
if (!MovementHelper.canWalkOn(destDown, destWalkOn)) {
return COST_INF; return COST_INF;
} }
double multiplier = WALK_ONE_BLOCK_COST; double multiplier = WALK_ONE_BLOCK_COST;
// For either possible soul sand, that affects half of our walking // 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; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} }
if (fromDown == Blocks.SOUL_SAND) { if (fromDown == Blocks.SOUL_SAND) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; 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)) { if (cuttingOver1 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver1)) {
return COST_INF; 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)) { if (cuttingOver2 instanceof BlockMagma || BlockStateInterface.isLava(cuttingOver2)) {
return COST_INF; return COST_INF;
} }
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); IBlockState pb0 = BlockStateInterface.get(x, y, destZ);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); IBlockState pb1 = BlockStateInterface.get(x, y + 1, destZ);
IBlockState pb2 = BlockStateInterface.get(positionsToBreak[2]); IBlockState pb2 = BlockStateInterface.get(destX, y, z);
IBlockState pb3 = BlockStateInterface.get(positionsToBreak[3]); IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z);
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], pb0, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], pb1, true); double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false) + MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], pb2, false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], pb3, 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) { if (optionA != 0 && optionB != 0) {
return COST_INF; return COST_INF;
} }
@ -100,7 +103,7 @@ public class MovementDiagonal extends Movement {
return COST_INF; 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 // Ignore previous multiplier
// Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water // Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// Not even touching the blocks below // Not even touching the blocks below

View File

@ -43,17 +43,21 @@ public class MovementDownward extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { 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; return COST_INF;
} }
IBlockState d = BlockStateInterface.get(dest); IBlockState d = BlockStateInterface.get(x, y - 1, z);
Block td = d.getBlock(); Block td = d.getBlock();
boolean ladder = td == Blocks.LADDER || td == Blocks.VINE; boolean ladder = td == Blocks.LADDER || td == Blocks.VINE;
if (ladder) { if (ladder) {
return LADDER_DOWN_ONE_COST; return LADDER_DOWN_ONE_COST;
} else { } 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 // 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);
} }
} }

View File

@ -26,13 +26,10 @@ import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.*; import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos; 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.entity.player.InventoryPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items; import net.minecraft.init.Items;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@ -48,58 +45,11 @@ public class MovementFall extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
Block fromDown = BlockStateInterface.get(src.down()).getBlock(); Tuple<Integer, Double> result = MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z);
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) { if (result.getFirst() != dest.y) {
return COST_INF; return COST_INF; // doesn't apply to us, this position is a descend not a fall
} }
IBlockState fallOnto = BlockStateInterface.get(dest.down()); return result.getSecond();
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;
} }
@Override @Override

View File

@ -57,11 +57,15 @@ public class MovementTraverse extends Movement {
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); return cost(context, src.x, src.y, src.z, dest.x, dest.z);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); }
IBlockState destOn = BlockStateInterface.get(positionToPlace);
Block srcDown = BlockStateInterface.getBlock(src.down()); public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
if (MovementHelper.canWalkOn(positionToPlace, destOn)) {//this is a walk, not a bridge 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; double WC = WALK_ONE_BLOCK_COST;
if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) { if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) {
WC = WALK_ONE_IN_WATER_COST; 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; 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) { if (hardness1 >= COST_INF) {
return 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 (hardness1 == 0 && hardness2 == 0) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) { 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 // 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) { if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
return COST_INF; 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()); boolean throughWater = BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock());
if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) { if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) {
return COST_INF; return COST_INF;
@ -103,15 +107,21 @@ public class MovementTraverse extends Movement {
if (!context.hasThrowaway()) { if (!context.hasThrowaway()) {
return COST_INF; 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; double WC = throughWater ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
BlockPos against1 = dest.offset(HORIZONTALS[i]); int againstX = destX + HORIZONTALS[i].getXOffset();
if (against1.equals(src)) { int againstZ = destZ + HORIZONTALS[i].getZOffset();
if (againstX == x && againstZ == z) {
continue; continue;
} }
against1 = against1.down(); if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) {
if (MovementHelper.canPlaceAgainst(against1)) { return WC + context.placeBlockCost() + hardness1 + hardness2;
return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
} }
} }
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) { 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 return COST_INF; // this is obviously impossible
} }
WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking 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; return COST_INF;
// Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock()); // Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock());

View File

@ -27,14 +27,9 @@ import baritone.behavior.PathingBehavior;
import baritone.cache.ChunkPacker; import baritone.cache.ChunkPacker;
import baritone.cache.Waypoint; import baritone.cache.Waypoint;
import baritone.cache.WorldProvider; import baritone.cache.WorldProvider;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch; import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.goals.*; 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.pathing.movement.MovementHelper;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.multiplayer.ChunkProviderClient; import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
@ -433,7 +428,8 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
event.cancel(); event.cancel();
return; return;
} }
if (msg.equals("costs")) { // TODO
/*if (msg.equals("costs")) {
Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext()); Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext());
List<Movement> moves = new ArrayList<>(Arrays.asList(movements)); List<Movement> moves = new ArrayList<>(Arrays.asList(movements));
while (moves.contains(null)) { while (moves.contains(null)) {
@ -451,6 +447,6 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
} }
event.cancel(); event.cancel();
return; return;
} }*/
} }
} }

View File

@ -134,4 +134,24 @@ public final class BetterBlockPos extends BlockPos {
Vec3i vec = dir.getDirectionVec(); Vec3i vec = dir.getDirectionVec();
return new BetterBlockPos(x + vec.getX() * dist, y + vec.getY() * dist, z + vec.getZ() * dist); 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);
}
} }