cool vine and ladder descending, fixes #159
This commit is contained in:
@@ -121,7 +121,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||||||
if (actionCost >= ActionCosts.COST_INF) {
|
if (actionCost >= ActionCosts.COST_INF) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (actionCost <= 0) {
|
if (actionCost <= 0 || Double.isNaN(actionCost)) {
|
||||||
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
|
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
|
||||||
}
|
}
|
||||||
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
|
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
|
||||||
|
@@ -73,6 +73,9 @@ public final class PathNode {
|
|||||||
this.previous = null;
|
this.previous = null;
|
||||||
this.cost = ActionCosts.COST_INF;
|
this.cost = ActionCosts.COST_INF;
|
||||||
this.estimatedCostToGoal = goal.heuristic(x, y, z);
|
this.estimatedCostToGoal = goal.heuristic(x, y, z);
|
||||||
|
if (Double.isNaN(estimatedCostToGoal)) {
|
||||||
|
throw new IllegalStateException(goal + " calculated implausible heuristic");
|
||||||
|
}
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
@@ -115,66 +115,84 @@ public class MovementDescend extends Movement {
|
|||||||
res.cost = totalCost;
|
res.cost = totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) {
|
public static boolean dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) {
|
||||||
if (frontBreak != 0 && context.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) {
|
if (frontBreak != 0 && context.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
|
// 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,
|
// 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
|
// and potentially replace the water we're going to fall into
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (!MovementHelper.canWalkThrough(context.bsi(), destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) {
|
if (!MovementHelper.canWalkThrough(context.bsi(), destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
double costSoFar = 0;
|
||||||
|
int effectiveStartHeight = y;
|
||||||
for (int fallHeight = 3; true; fallHeight++) {
|
for (int fallHeight = 3; true; fallHeight++) {
|
||||||
int newY = y - fallHeight;
|
int newY = y - fallHeight;
|
||||||
if (newY < 0) {
|
if (newY < 0) {
|
||||||
// when pathing in the end, where you could plausibly fall into the void
|
// 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
|
// this check prevents it from getting the block at y=-1 and crashing
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
IBlockState ontoBlock = context.get(destX, newY, destZ);
|
IBlockState ontoBlock = context.get(destX, newY, destZ);
|
||||||
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak;
|
int unprotectedFallHeight = fallHeight - (y - effectiveStartHeight); // equal to fallHeight - y + effectiveFallHeight, which is equal to -newY + effectiveFallHeight, which is equal to effectiveFallHeight - newY
|
||||||
if (ontoBlock.getBlock() == Blocks.WATER && !MovementHelper.isFlowing(ontoBlock) && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) { // TODO flowing check required here?
|
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar;
|
||||||
|
if (ontoBlock.getBlock() == Blocks.WATER && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) {
|
||||||
// lilypads are canWalkThrough, but we can't end a fall that should be broken by water if it's covered by a lilypad
|
// lilypads are canWalkThrough, but we can't end a fall that should be broken by water if it's covered by a lilypad
|
||||||
// however, don't return impossible in the lilypad scenario, because we could still jump right on it (water that's below a lilypad is canWalkOn so it works)
|
// however, don't return impossible in the lilypad scenario, because we could still jump right on it (water that's below a lilypad is canWalkOn so it works)
|
||||||
if (context.assumeWalkOnWater()) {
|
if (context.assumeWalkOnWater()) {
|
||||||
return; // TODO fix
|
return false; // TODO fix
|
||||||
|
}
|
||||||
|
if (MovementHelper.isFlowing(ontoBlock)) {
|
||||||
|
return false; // TODO flowing check required here?
|
||||||
|
}
|
||||||
|
if (!MovementHelper.canWalkOn(context.bsi(), destX, newY - 1, destZ)) {
|
||||||
|
// we could punch right through the water into something else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
// found a fall into water
|
// found a fall into water
|
||||||
res.x = destX;
|
res.x = destX;
|
||||||
res.y = newY;
|
res.y = newY;
|
||||||
res.z = destZ;
|
res.z = destZ;
|
||||||
res.cost = tentativeCost;// TODO incorporate water swim up cost?
|
res.cost = tentativeCost;// TODO incorporate water swim up cost?
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) {
|
if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) {
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
if (unprotectedFallHeight <= 11 && (ontoBlock.getBlock() == Blocks.VINE || ontoBlock.getBlock() == Blocks.LADDER)) {
|
||||||
|
// if fall height is greater than or equal to 11, we don't actually grab on to vines or ladders. the more you know
|
||||||
|
// this effectively "resets" our falling speed
|
||||||
|
costSoFar += FALL_N_BLOCKS_COST[unprotectedFallHeight - 1];// we fall until the top of this block (not including this block)
|
||||||
|
costSoFar += LADDER_DOWN_ONE_COST;
|
||||||
|
effectiveStartHeight = newY;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (MovementHelper.canWalkThrough(context.bsi(), destX, newY, destZ, ontoBlock)) {
|
if (MovementHelper.canWalkThrough(context.bsi(), destX, newY, destZ, ontoBlock)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!MovementHelper.canWalkOn(context.bsi(), destX, newY, destZ, ontoBlock)) {
|
if (!MovementHelper.canWalkOn(context.bsi(), destX, newY, destZ, ontoBlock)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (MovementHelper.isBottomSlab(ontoBlock)) {
|
if (MovementHelper.isBottomSlab(ontoBlock)) {
|
||||||
return; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
|
return false; // 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) {
|
if (context.hasWaterBucket() && unprotectedFallHeight <= context.maxFallHeightBucket() + 1) {
|
||||||
res.x = destX;
|
res.x = destX;
|
||||||
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
|
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
|
||||||
res.z = destZ;
|
res.z = destZ;
|
||||||
res.cost = tentativeCost + context.placeBlockCost();
|
res.cost = tentativeCost + context.placeBlockCost();
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if (fallHeight <= context.maxFallHeightNoWater() + 1) {
|
if (unprotectedFallHeight <= context.maxFallHeightNoWater() + 1) {
|
||||||
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max
|
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max
|
||||||
res.x = destX;
|
res.x = destX;
|
||||||
res.y = newY + 1;
|
res.y = newY + 1;
|
||||||
res.z = destZ;
|
res.z = destZ;
|
||||||
res.cost = tentativeCost;
|
res.cost = tentativeCost;
|
||||||
return;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package baritone.pathing.movement.movements;
|
package baritone.pathing.movement.movements;
|
||||||
|
|
||||||
import baritone.Baritone;
|
|
||||||
import baritone.api.IBaritone;
|
import baritone.api.IBaritone;
|
||||||
import baritone.api.pathing.movement.MovementStatus;
|
import baritone.api.pathing.movement.MovementStatus;
|
||||||
import baritone.api.utils.BetterBlockPos;
|
import baritone.api.utils.BetterBlockPos;
|
||||||
@@ -31,12 +30,19 @@ import baritone.pathing.movement.MovementHelper;
|
|||||||
import baritone.pathing.movement.MovementState;
|
import baritone.pathing.movement.MovementState;
|
||||||
import baritone.pathing.movement.MovementState.MovementTarget;
|
import baritone.pathing.movement.MovementState.MovementTarget;
|
||||||
import baritone.utils.pathing.MutableMoveResult;
|
import baritone.utils.pathing.MutableMoveResult;
|
||||||
|
import net.minecraft.block.BlockLadder;
|
||||||
|
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.EnumFacing;
|
||||||
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;
|
||||||
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class MovementFall extends Movement {
|
public class MovementFall extends Movement {
|
||||||
|
|
||||||
@@ -57,6 +63,12 @@ public class MovementFall extends Movement {
|
|||||||
return result.cost;
|
return result.cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean willPlaceBucket() {
|
||||||
|
CalculationContext context = new CalculationContext(baritone);
|
||||||
|
MutableMoveResult result = new MutableMoveResult();
|
||||||
|
return MovementDescend.dynamicFallCost(context, src.x, src.y, src.z, dest.x, dest.z, 0, context.get(dest.x, src.y - 2, dest.z), result);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MovementState updateState(MovementState state) {
|
public MovementState updateState(MovementState state) {
|
||||||
super.updateState(state);
|
super.updateState(state);
|
||||||
@@ -67,7 +79,7 @@ public class MovementFall extends Movement {
|
|||||||
BlockPos playerFeet = ctx.playerFeet();
|
BlockPos playerFeet = ctx.playerFeet();
|
||||||
Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest));
|
Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest));
|
||||||
Rotation targetRotation = null;
|
Rotation targetRotation = null;
|
||||||
if (!MovementHelper.isWater(ctx, dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) {
|
if (!MovementHelper.isWater(ctx, dest) && willPlaceBucket() && !playerFeet.equals(dest)) {
|
||||||
if (!InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_WATER)) || ctx.world().provider.isNether()) {
|
if (!InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_WATER)) || ctx.world().provider.isNether()) {
|
||||||
return state.setStatus(MovementStatus.UNREACHABLE);
|
return state.setStatus(MovementStatus.UNREACHABLE);
|
||||||
}
|
}
|
||||||
@@ -78,7 +90,7 @@ public class MovementFall extends Movement {
|
|||||||
targetRotation = new Rotation(toDest.getYaw(), 90.0F);
|
targetRotation = new Rotation(toDest.getYaw(), 90.0F);
|
||||||
|
|
||||||
RayTraceResult trace = ctx.objectMouseOver();
|
RayTraceResult trace = ctx.objectMouseOver();
|
||||||
if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && ctx.player().rotationPitch > 89.0F) {
|
if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && (trace.getBlockPos().equals(dest) || trace.getBlockPos().equals(dest.down()))) {
|
||||||
state.setInput(Input.CLICK_RIGHT, true);
|
state.setInput(Input.CLICK_RIGHT, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,12 +119,40 @@ public class MovementFall extends Movement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vec3d destCenter = VecUtils.getBlockPosCenter(dest); // we are moving to the 0.5 center not the edge (like if we were falling on a ladder)
|
Vec3d destCenter = VecUtils.getBlockPosCenter(dest); // we are moving to the 0.5 center not the edge (like if we were falling on a ladder)
|
||||||
if (Math.abs(ctx.player().posX - destCenter.x) > 0.15 || Math.abs(ctx.player().posZ - destCenter.z) > 0.15) {
|
if (Math.abs(ctx.player().posX + ctx.player().motionX - destCenter.x) > 0.1 || Math.abs(ctx.player().posZ + ctx.player().motionZ - destCenter.z) > 0.1) {
|
||||||
|
if (!ctx.player().onGround && Math.abs(ctx.player().motionY) > 0.4) {
|
||||||
|
state.setInput(Input.SNEAK, true);
|
||||||
|
}
|
||||||
state.setInput(Input.MOVE_FORWARD, true);
|
state.setInput(Input.MOVE_FORWARD, true);
|
||||||
}
|
}
|
||||||
|
Vec3i avoid = Optional.ofNullable(avoid()).map(EnumFacing::getDirectionVec).orElse(null);
|
||||||
|
if (avoid == null) {
|
||||||
|
avoid = src.subtract(dest);
|
||||||
|
} else {
|
||||||
|
double dist = Math.abs(avoid.getX() * (destCenter.x - avoid.getX() / 2.0 - ctx.player().posX)) + Math.abs(avoid.getZ() * (destCenter.z - avoid.getZ() / 2.0 - ctx.player().posZ));
|
||||||
|
if (dist < 0.6) {
|
||||||
|
state.setInput(Input.MOVE_FORWARD, true);
|
||||||
|
} else {
|
||||||
|
state.setInput(Input.SNEAK, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetRotation == null) {
|
||||||
|
Vec3d destCenterOffset = new Vec3d(destCenter.x + 0.125 * avoid.getX(), destCenter.y, destCenter.z + 0.125 * avoid.getZ());
|
||||||
|
state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), destCenterOffset), false));
|
||||||
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EnumFacing avoid() {
|
||||||
|
for (int i = 0; i < 15; i++) {
|
||||||
|
IBlockState state = ctx.world().getBlockState(ctx.playerFeet().down(i));
|
||||||
|
if (state.getBlock() == Blocks.LADDER) {
|
||||||
|
return state.getValue(BlockLadder.FACING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean safeToCancel(MovementState state) {
|
public boolean safeToCancel(MovementState state) {
|
||||||
// if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall
|
// if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall
|
||||||
|
Reference in New Issue
Block a user