From 59b4e1a993095165e4060afb9d0fe35afa8831f9 Mon Sep 17 00:00:00 2001 From: Leijurv Date: Sun, 23 Sep 2018 12:24:07 -0700 Subject: [PATCH] parkour --- .../pathing/calc/AStarPathFinder.java | 2 +- .../java/baritone/pathing/calc/Moves.java | 63 +++++++- .../pathing/movement/MovementHelper.java | 50 +------ .../movement/movements/MovementParkour.java | 140 +++++++----------- .../pathing/calc/openset/OpenSetsTest.java | 2 +- 5 files changed, 116 insertions(+), 141 deletions(-) diff --git a/src/main/java/baritone/pathing/calc/AStarPathFinder.java b/src/main/java/baritone/pathing/calc/AStarPathFinder.java index d733931f..6ca58e6b 100644 --- a/src/main/java/baritone/pathing/calc/AStarPathFinder.java +++ b/src/main/java/baritone/pathing/calc/AStarPathFinder.java @@ -102,7 +102,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel } } MoveResult res = moves.apply(calcContext, currentNode.x, currentNode.y, currentNode.z); - if (res.destX != newX || res.destZ != newZ) { + if (!moves.dynamicXZ && (res.destX != newX || res.destZ != newZ)) { throw new IllegalStateException(moves + " " + res.destX + " " + newX + " " + res.destZ + " " + newZ); } numMovementsConsidered++; diff --git a/src/main/java/baritone/pathing/calc/Moves.java b/src/main/java/baritone/pathing/calc/Moves.java index 1ff78351..0a30199a 100644 --- a/src/main/java/baritone/pathing/calc/Moves.java +++ b/src/main/java/baritone/pathing/calc/Moves.java @@ -264,19 +264,76 @@ public enum Moves { return new MoveResult(x - 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x - 1, z + 1)); } }, - // TODO parkour - ; + + PARKOUR_NORTH(0, -4, true) { + @Override + protected Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.NORTH); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + Tuple, Double> res = MovementParkour.cost(context, x, y, z, EnumFacing.NORTH); + return new MoveResult(res.getFirst().getFirst(), y, res.getFirst().getSecond(), res.getSecond()); + } + }, + + PARKOUR_SOUTH(0, +4, true) { + @Override + protected Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.SOUTH); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + Tuple, Double> res = MovementParkour.cost(context, x, y, z, EnumFacing.SOUTH); + return new MoveResult(res.getFirst().getFirst(), y, res.getFirst().getSecond(), res.getSecond()); + } + }, + + PARKOUR_EAST(+4, 0, true) { + @Override + protected Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.EAST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + Tuple, Double> res = MovementParkour.cost(context, x, y, z, EnumFacing.EAST); + return new MoveResult(res.getFirst().getFirst(), y, res.getFirst().getSecond(), res.getSecond()); + } + }, + + PARKOUR_WEST(-4, 0, true) { + @Override + protected Movement apply0(BetterBlockPos src) { + return MovementParkour.cost(new CalculationContext(), src, EnumFacing.WEST); + } + + @Override + public MoveResult apply(CalculationContext context, int x, int y, int z) { + Tuple, Double> res = MovementParkour.cost(context, x, y, z, EnumFacing.WEST); + return new MoveResult(res.getFirst().getFirst(), y, res.getFirst().getSecond(), res.getSecond()); + } + }; protected abstract Movement apply0(BetterBlockPos src); public abstract MoveResult apply(CalculationContext context, int x, int y, int z); + public final boolean dynamicXZ; + public final int xOffset; public final int zOffset; - Moves(int x, int z) { + Moves(int x, int z, boolean dynamicXZ) { this.xOffset = x; this.zOffset = z; + this.dynamicXZ = dynamicXZ; + } + + Moves(int x, int z) { + this(x, z, false); } } diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java index fea40a02..df16879c 100644 --- a/src/main/java/baritone/pathing/movement/MovementHelper.java +++ b/src/main/java/baritone/pathing/movement/MovementHelper.java @@ -20,8 +20,6 @@ package baritone.pathing.movement; import baritone.Baritone; import baritone.behavior.LookBehaviorUtils; import baritone.pathing.movement.MovementState.MovementTarget; -import baritone.pathing.movement.movements.MovementDescend; -import baritone.pathing.movement.movements.MovementFall; import baritone.utils.*; import baritone.utils.pathing.BetterBlockPos; import net.minecraft.block.*; @@ -142,6 +140,10 @@ public interface MovementHelper extends ActionCosts, Helper { return fullyPassable(BlockStateInterface.get(pos)); } + static boolean fullyPassable(int x, int y, int z) { + return fullyPassable(BlockStateInterface.get(x, y, z)); + } + static boolean fullyPassable(IBlockState state) { Block block = state.getBlock(); if (block == Blocks.AIR) { // early return for most common case @@ -463,48 +465,4 @@ public interface MovementHelper extends ActionCosts, Helper { false )).setInput(InputOverrideHandler.Input.MOVE_FORWARD, true); } - - static Movement generateMovementFallOrDescend(BetterBlockPos pos, BetterBlockPos dest, CalculationContext calcContext) { - - - int x = dest.x; - int y = dest.y; - int z = dest.z; - if (!canWalkThrough(x, y - 2, z)) { - //if B in the diagram aren't air - //have to do a descend, because fall is impossible - - //this doesn't guarantee descend is possible, it just guarantees fall is impossible - return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1 - // we can't cost shortcut descend because !canWalkThrough doesn't mean canWalkOn - } - - // we're clear for a fall 2 - // let's see how far we can fall - 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 - break; - } - IBlockState ontoBlock = BlockStateInterface.get(x, newY, z); - if (ontoBlock.getBlock() == Blocks.WATER) { - return new MovementFall(pos, new BetterBlockPos(x, newY, z)); - } - if (canWalkThrough(x, newY, z, ontoBlock)) { - continue; - } - if (!canWalkOn(x, newY, z, ontoBlock)) { - break; - } - if ((calcContext.hasWaterBucket() && fallHeight <= calcContext.maxFallHeightBucket() + 1) || fallHeight <= calcContext.maxFallHeightNoWater() + 1) { - // fallHeight = 4 means onto.up() is 3 blocks down, which is the max - return new MovementFall(pos, new BetterBlockPos(x, newY + 1, z)); - } else { - return null; - } - } - return null; - } } diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java index 0093539f..4d4cef08 100644 --- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java +++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java @@ -27,19 +27,20 @@ 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.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.util.EnumFacing; +import net.minecraft.util.Tuple; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import java.util.Objects; public class MovementParkour extends Movement { - private static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN}; + private static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN}; private static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{}; + private static final Tuple, Double> IMPOSSIBLE = new Tuple<>(new Tuple<>(0, 0), COST_INF); private final EnumFacing direction; private final int dist; @@ -48,79 +49,81 @@ public class MovementParkour extends Movement { super(src, src.offset(dir, dist), EMPTY); this.direction = dir; this.dist = dist; - super.override(costFromJumpDistance(dist)); } - public static MovementParkour generate(BetterBlockPos src, EnumFacing dir, CalculationContext context) { - // MUST BE KEPT IN SYNC WITH calculateCost + public static MovementParkour cost(CalculationContext context, BetterBlockPos src, EnumFacing direction) { + Tuple, Double> res = cost(context, src.x, src.y, src.z, direction); + int dist = Math.abs(res.getFirst().getFirst() - src.x) + Math.abs(res.getFirst().getSecond() - src.z); + return new MovementParkour(src, dist, direction); + } + + public static Tuple, Double> cost(CalculationContext context, int x, int y, int z, EnumFacing dir) { if (!Baritone.settings().allowParkour.get()) { - return null; + return IMPOSSIBLE; } - IBlockState standingOn = BlockStateInterface.get(src.down()); + IBlockState standingOn = BlockStateInterface.get(x, y - 1, z); if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || MovementHelper.isBottomSlab(standingOn)) { - return null; + return IMPOSSIBLE; } - BetterBlockPos adjBlock = src.down().offset(dir); - IBlockState adj = BlockStateInterface.get(adjBlock); + int xDiff = dir.getXOffset(); + int zDiff = dir.getZOffset(); + IBlockState adj = BlockStateInterface.get(x + xDiff, y - 1, z + zDiff); if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks - return null; + return IMPOSSIBLE; } - if (MovementHelper.canWalkOn(adjBlock, adj)) { // don't parkour if we could just traverse (for now) - return null; + if (MovementHelper.canWalkOn(x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now) + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.offset(dir))) { - return null; + if (!MovementHelper.fullyPassable(x + xDiff, y, z + zDiff)) { + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.up().offset(dir))) { - return null; + if (!MovementHelper.fullyPassable(x + xDiff, y + 1, z + zDiff)) { + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.up(2).offset(dir))) { - return null; + if (!MovementHelper.fullyPassable(x + xDiff, y + 2, z + zDiff)) { + return IMPOSSIBLE; } - if (!MovementHelper.fullyPassable(src.up(2))) { - return null; + if (!MovementHelper.fullyPassable(x, y + 2, z)) { + return IMPOSSIBLE; } for (int i = 2; i <= (context.canSprint() ? 4 : 3); i++) { - BetterBlockPos dest = src.offset(dir, i); // TODO perhaps dest.up(3) doesn't need to be fullyPassable, just canWalkThrough, possibly? - for (int y = 0; y < 4; y++) { - if (!MovementHelper.fullyPassable(dest.up(y))) { - return null; + for (int y2 = 0; y2 < 4; y2++) { + if (!MovementHelper.fullyPassable(x + xDiff * i, y + y2, z + zDiff * i)) { + return IMPOSSIBLE; } } - if (MovementHelper.canWalkOn(dest.down())) { - return new MovementParkour(src, i, dir); + if (MovementHelper.canWalkOn(x + xDiff * i, y - 1, z + zDiff * i)) { + return new Tuple<>(new Tuple<>(x + xDiff * i, z + zDiff * i), costFromJumpDistance(i)); } } if (!context.canSprint()) { - return null; + return IMPOSSIBLE; } if (!Baritone.settings().allowParkourPlace.get()) { - return null; + return IMPOSSIBLE; } - BlockPos dest = src.offset(dir, 4); - BlockPos positionToPlace = dest.down(); - IBlockState toPlace = BlockStateInterface.get(positionToPlace); + int destX = x + 4 * xDiff; + int destZ = z + 4 * zDiff; + IBlockState toPlace = BlockStateInterface.get(destX, y - 1, destZ); if (!context.hasThrowaway()) { - return null; + return IMPOSSIBLE; } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) { - return null; + if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace)) { + return IMPOSSIBLE; } for (int i = 0; i < 5; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); - if (against1.up().equals(src.offset(dir, 3))) { // we can't turn around that fast + int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset(); + int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset(); + if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast continue; } - if (MovementHelper.canPlaceAgainst(against1)) { - // holy jesus we gonna do it - MovementParkour ret = new MovementParkour(src, 4, dir); - ret.override(costFromJumpDistance(4) + context.placeBlockCost()); - return ret; + if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) { + return new Tuple<>(new Tuple<>(destX, destZ), costFromJumpDistance(i) + context.placeBlockCost()); } } - return null; + return IMPOSSIBLE; } private static double costFromJumpDistance(int dist) { @@ -139,54 +142,11 @@ public class MovementParkour extends Movement { @Override protected double calculateCost(CalculationContext context) { - // MUST BE KEPT IN SYNC WITH generate - if (!context.canSprint() && dist >= 4) { + Tuple, Double> res = cost(context, src.x, src.y, src.z, direction); + if (res.getFirst().getFirst() != dest.x || res.getFirst().getSecond() != dest.z) { return COST_INF; } - boolean placing = false; - if (!MovementHelper.canWalkOn(dest.down())) { - if (dist != 4) { - return COST_INF; - } - if (!Baritone.settings().allowParkourPlace.get()) { - return COST_INF; - } - BlockPos positionToPlace = dest.down(); - IBlockState toPlace = BlockStateInterface.get(positionToPlace); - if (!context.hasThrowaway()) { - return COST_INF; - } - if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionToPlace, toPlace)) { - return COST_INF; - } - for (int i = 0; i < 5; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); - if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast - continue; - } - if (MovementHelper.canPlaceAgainst(against1)) { - // holy jesus we gonna do it - placing = true; - break; - } - } - } - Block walkOff = BlockStateInterface.get(src.down().offset(direction)).getBlock(); - if (MovementHelper.avoidWalkingInto(walkOff) && walkOff != Blocks.WATER && walkOff != Blocks.FLOWING_WATER) { - return COST_INF; - } - for (int i = 1; i <= 4; i++) { - BlockPos d = src.offset(direction, i); - for (int y = 0; y < (i == 1 ? 3 : 4); y++) { - if (!MovementHelper.fullyPassable(d.up(y))) { - return COST_INF; - } - } - if (d.equals(dest)) { - return costFromJumpDistance(i) + (placing ? context.placeBlockCost() : 0); - } - } - throw new IllegalStateException("invalid jump distance?"); + return res.getSecond(); } @Override @@ -209,7 +169,7 @@ public class MovementParkour extends Movement { if (!MovementHelper.canWalkOn(dest.down())) { BlockPos positionToPlace = dest.down(); for (int i = 0; i < 5; i++) { - BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN_SO_EVERY_DIRECTION_EXCEPT_UP[i]); + BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]); if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast continue; } diff --git a/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java b/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java index 5f7b98d0..4fa88735 100644 --- a/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java +++ b/src/test/java/baritone/pathing/calc/openset/OpenSetsTest.java @@ -83,7 +83,7 @@ public class OpenSetsTest { assertTrue(set.isEmpty()); } - // generate the pathnodes that we'll be testing the sets on + // cost the pathnodes that we'll be testing the sets on PathNode[] toInsert = new PathNode[size]; for (int i = 0; i < size; i++) { // can't use an existing goal