diff --git a/src/main/java/baritone/builder/Blip.java b/src/main/java/baritone/builder/Blip.java index 8d83b7b49..8e64f0389 100644 --- a/src/main/java/baritone/builder/Blip.java +++ b/src/main/java/baritone/builder/Blip.java @@ -34,11 +34,22 @@ public class Blip { public static final int FULL_BLOCK = PER_BLOCK; public static final double RATIO = 0.0625; public static final int HALF_BLOCK = 8; - public static final int PLAYER_HEIGHT = 29; + public static final int PLAYER_HEIGHT_SLIGHT_UNDERESTIMATE = 28; + public static final int PLAYER_HEIGHT_SLIGHT_OVERESTIMATE = PLAYER_HEIGHT_SLIGHT_UNDERESTIMATE + 1; public static final int TWO_BLOCKS = 2 * FULL_BLOCK; public static final int FEET_TO_EYE_APPROX = (int) (IPlayerContext.eyeHeight(false) / RATIO); public static double playerEyeFromFeetBlips(int feetBlips, boolean sneaking) { return feetBlips * RATIO + IPlayerContext.eyeHeight(sneaking); } + + static { + double realPlayerHeight = 1.8; + if (PLAYER_HEIGHT_SLIGHT_OVERESTIMATE * RATIO <= realPlayerHeight || PLAYER_HEIGHT_SLIGHT_UNDERESTIMATE * RATIO >= realPlayerHeight) { + throw new IllegalStateException(); + } + if (PER_BLOCK * RATIO != 1) { + throw new IllegalStateException(); + } + } } diff --git a/src/main/java/baritone/builder/BlockStateCachedDataBuilder.java b/src/main/java/baritone/builder/BlockStateCachedDataBuilder.java index ec7588871..bad922b99 100644 --- a/src/main/java/baritone/builder/BlockStateCachedDataBuilder.java +++ b/src/main/java/baritone/builder/BlockStateCachedDataBuilder.java @@ -256,6 +256,9 @@ public class BlockStateCachedDataBuilder { if (collisionHeightBlips != null && (collisionHeightBlips > Blip.FULL_BLOCK + Blip.HALF_BLOCK || collisionHeightBlips <= 0)) { // playerphysics assumes this is never true throw new IllegalStateException(); } + if (collidesWithPlayer && collisionHeightBlips == null) { + throw new IllegalStateException(); + } if (fullyWalkableTop && !collidesWithPlayer) { throw new IllegalStateException(); } diff --git a/src/main/java/baritone/builder/BlockStatePlacementOption.java b/src/main/java/baritone/builder/BlockStatePlacementOption.java index cf6be9fff..18d3ca29a 100644 --- a/src/main/java/baritone/builder/BlockStatePlacementOption.java +++ b/src/main/java/baritone/builder/BlockStatePlacementOption.java @@ -134,6 +134,15 @@ public class BlockStatePlacementOption { } } + /** + * In EnumFacing.getDirectionFromEntityLiving, it checks if the player feet is within 2 blocks of the center of the block to be placed. + * Normally, this is a nonissue, but a problem arises because we are considering hypothetical placements where the player stands at the exact +0.5,+0.5 center of a block. + * In that case, it's possible for our hypothetical to have the player at precisely 2 blocks away, i.e. precisely on the edge of this condition being true or false. + * For that reason, we treat those exact cases as "ambiguous". So, if the distance is within this tolerance of 2 (so, 1.99 to 2.01), we treat it as a "could go either way", + * because when we really get there in-game, floating point inaccuracy could indeed actually make it go either way. + */ + private static final double ENTITY_FACING_TOLERANCE = 0.01; + private boolean directionOk(Vec3d eye, Vec3d hit) { if (playerMustBeHorizontalFacing.isPresent()) { return eye.flatDirectionTo(hit) == playerMustBeHorizontalFacing.get(); @@ -146,27 +155,25 @@ public class BlockStatePlacementOption { // see EnumFacing.getDirectionFromEntityLiving double dx = Math.abs(eye.x - 0.5); double dz = Math.abs(eye.z - 0.5); - if (dx < 1.99 && dz < 1.99) { - // both within 2 = normal - if (eye.y < 0) { + if (dx < 2 - ENTITY_FACING_TOLERANCE && dz < 2 - ENTITY_FACING_TOLERANCE) { // < 1.99 + if (eye.y < 0) { // eye below placement level = it will be facing down, so this is only okay if we wantthat return entFace == Face.DOWN; } - if (eye.y > 2) { + if (eye.y > 2) { // same for up, if y>2 then it will be facing up return entFace == Face.UP; } - } else if (!(dx > 2.01 || dz > 2.01)) { - // ambiguous case - // UP/DOWN are impossible (caught by flat check), and anything that could cause up/down instead of horizontal is also not allowed sadly + } else if (!(dx > 2 + ENTITY_FACING_TOLERANCE || dz > 2 + ENTITY_FACING_TOLERANCE)) { // > 2.01 + // this is the ambiguous case, because we are neither unambiguously both-within-2 (previous case), nor unambiguously either-above-two (this elseif condition). + // UP/DOWN are impossible, but that's caught by flat check if (eye.y < 0 || eye.y > 2) { - return false; + return false; // anything that could cause up/down instead of horizontal is also not allowed sadly } - } // else either is above 2.01, putting us in simple horizontal mode, so fallthrough to flat condition is correct, yay + } // else we are in unambiguous either-above-two, putting us in simple horizontal mode, so fallthrough to flat condition is correct, yay return eye.flatDirectionTo(hit) == entFace.opposite(); } return true; } - public static BlockStatePlacementOption get(Face against, Half half, Optional playerMustBeHorizontalFacing, Optional playerMustBeEntityFacing) { BlockStatePlacementOption ret = PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()][Face.OPTS.indexOf(playerMustBeHorizontalFacing)][Face.OPTS.indexOf(playerMustBeEntityFacing)]; if (ret == null) { diff --git a/src/main/java/baritone/builder/PlayerPhysics.java b/src/main/java/baritone/builder/PlayerPhysics.java index 145f129e8..f1df290cf 100644 --- a/src/main/java/baritone/builder/PlayerPhysics.java +++ b/src/main/java/baritone/builder/PlayerPhysics.java @@ -21,6 +21,8 @@ public class PlayerPhysics { /** * the player Y is within within. i.e. the player Y is greater than or equal within and less than within+1 + *

+ * returns a negative value if impossible. returns a >=0 value if possible. */ public static int determinePlayerRealSupport(BlockStateCachedData underneath, BlockStateCachedData within) { if (within.collidesWithPlayer) { @@ -52,7 +54,6 @@ public class PlayerPhysics { * YB * XC * SD - * */ public static Collision playerTravelCollides(int feet, BlockStateCachedData U, @@ -68,7 +69,7 @@ public class PlayerPhysics { if (Main.DEBUG && (feet != determinePlayerRealSupport(S, X))) { throw new IllegalStateException(); } - boolean alreadyWithinU = feet > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT; // > and not >= because the player height is a slight overestimate + boolean alreadyWithinU = feet > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE; // > and not >= because the player height is a slight overestimate if (Main.DEBUG && (alreadyWithinU && U.collidesWithPlayer)) { throw new IllegalStateException(); } @@ -92,27 +93,27 @@ public class PlayerPhysics { } return Collision.VOXEL_UP; // A is already checked, so that's it! } - // betweenCandB is impossible. pessimistically, this means B is colliding. optimistically, this means B and C are air. + // stepUp is impossible. pessimistically, this means B is colliding. optimistically, this means B and C are air. + if (B.collidesWithPlayer) { // we have ruled out stepping on top of B, so now if B is still colliding there is no way forward + return Collision.BLOCKED; + } int stayLevel = determinePlayerRealSupport(D, C); if (stayLevel >= 0) { // fundamentally staying within the same vertical voxel, X -> C if (stayLevel > couldStepUpTo) { return Collision.BLOCKED; } - if (stayLevel > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT && !alreadyWithinU) { // step up, combined with our height, protrudes into U and A, AND we didn't already + if (stayLevel > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE && !alreadyWithinU) { // step up, combined with our height, protrudes into U and A, AND we didn't already if (U.collidesWithPlayer) { // stayLevel could even be LESS than feet return Collision.BLOCKED; } - if (A.collidesWithPlayer) { + if (A.collidesWithPlayer) { // already checked (alreadyWithinU && A.collidesWithPlayer) earlier return Collision.BLOCKED; } } - if (B.collidesWithPlayer) { - return Collision.BLOCKED; // obv, our head will go into B - } return Collision.VOXEL_LEVEL; } - if (B.collidesWithPlayer || C.collidesWithPlayer) { + if (C.collidesWithPlayer) { return Collision.BLOCKED; } if (!D.collidesWithPlayer) { @@ -132,7 +133,7 @@ public class PlayerPhysics { } static { - if (Blip.PLAYER_HEIGHT > Blip.TWO_BLOCKS || Blip.PLAYER_HEIGHT + Blip.HALF_BLOCK <= Blip.TWO_BLOCKS) { + if (Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE >= Blip.TWO_BLOCKS || Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE + Blip.HALF_BLOCK <= Blip.TWO_BLOCKS) { throw new IllegalStateException("Assumptions made in playerTravelCollides"); } }