parkour
This commit is contained in:
parent
a05d3269a3
commit
59b4e1a993
@ -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++;
|
||||
|
@ -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<Tuple<Integer, Integer>, 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<Tuple<Integer, Integer>, 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<Tuple<Integer, Integer>, 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<Tuple<Integer, Integer>, 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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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<Tuple<Integer, Integer>, 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<Tuple<Integer, Integer>, 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<Tuple<Integer, Integer>, 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<Tuple<Integer, Integer>, 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user