diff --git a/src/main/java/baritone/builder/GreedySolver.java b/src/main/java/baritone/builder/GreedySolver.java index cccf941eb..67ec0c0fc 100644 --- a/src/main/java/baritone/builder/GreedySolver.java +++ b/src/main/java/baritone/builder/GreedySolver.java @@ -50,6 +50,69 @@ public class GreedySolver { while (!heap.isEmpty()) { Node node = heap.removeLowest(); WorldState worldState = node.coalesceState(this); + long pos = node.pos(); + BlockStateCachedData above = at((BetterBlockPos.toLong(0, 2, 0) + pos) & BetterBlockPos.POST_ADDITION_MASK, worldState); + BlockStateCachedData head = at(Face.UP.offset(pos), worldState); + if (Main.DEBUG && head.collidesWithPlayer) { + throw new IllegalStateException(); + } + BlockStateCachedData feet = at(pos, worldState); + BlockStateCachedData underneath = at(Face.DOWN.offset(pos), worldState); + int blipsWithinBlock = PlayerPhysics.determinePlayerRealSupportLevel(underneath, feet); + if (blipsWithinBlock < 0) { + throw new IllegalStateException(); + } + boolean stickingUpIntoThirdBlock = blipsWithinBlock > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE; // exactly equal means not sticking up, since overestimate means overestimate + int blips = node.y * Blip.PER_BLOCK + blipsWithinBlock; + + mid: + for (Face travel : Face.HORIZONTALS) { + long newPos = travel.offset(pos); + BlockStateCachedData newAbove = at((BetterBlockPos.toLong(0, 2, 0) + newPos) & BetterBlockPos.POST_ADDITION_MASK, worldState); + BlockStateCachedData newHead = at(Face.UP.offset(newPos), worldState); + BlockStateCachedData newFeet = at(newPos, worldState); + BlockStateCachedData newUnderneath = at(Face.DOWN.offset(newPos), worldState); + switch (PlayerPhysics.playerTravelCollides(blipsWithinBlock, above, newAbove, newHead, newFeet, newUnderneath, underneath, feet)) { + case BLOCKED: { + // TODO ascend + continue; + } + case FALL: { + // this means that there is nothing preventing us from walking forward and falling + // iterate downwards to see what we would hit + for (int descent = 0; ; descent++) { + // NOTE: you cannot do (descent*Face.DOWN.offset)&BetterBlockPos.POST_ADDITION_MASK because Y is serialized into the center of the long. but I suppose you could do it with X. hm maybe Y should be moved to the most significant bits purely to allow this :^) + long support = (BetterBlockPos.toLong(0, -descent, 0) + newPos) & BetterBlockPos.POST_ADDITION_MASK; + BlockStateCachedData data = at(support, worldState); + BlockStateCachedData under = at(Face.DOWN.offset(support), worldState); + PlayerPhysics.VoxelResidency res = PlayerPhysics.canPlayerStand(under, data); + switch (res) { + case FLOATING: + continue; // as expected + case PREVENTED_BY_UNDERNEATH: + case PREVENTED_BY_WITHIN: + continue mid; // no safe landing + case IMPOSSIBLE_WITHOUT_SUFFOCATING: + throw new IllegalStateException(); + case UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK: + case STANDARD_WITHIN_SUPPORT: + // found our landing spot + // TODO + + } + } + // descent, with a possible fallthrough to VOXEL_LEVEL if it's just a troll + + // no break, fallthrouh instead! + } // FALLTHROUGH! + case VOXEL_LEVEL: { // ^ POSSIBLE FALLTHROUGH ^ + + } + case VOXEL_UP: { + + } + } + } // consider actions: // traverse diff --git a/src/main/java/baritone/builder/PlaceOrderDependencyGraph.java b/src/main/java/baritone/builder/PlaceOrderDependencyGraph.java index 95d13d9cf..8603093c8 100644 --- a/src/main/java/baritone/builder/PlaceOrderDependencyGraph.java +++ b/src/main/java/baritone/builder/PlaceOrderDependencyGraph.java @@ -58,10 +58,12 @@ public class PlaceOrderDependencyGraph { public BlockStateCachedData data(long pos) { int state = state(pos); - if (treatAsScaffolding(state)) { + BlockStateCachedData data = BlockStateCachedData.get(state); + if (treatAsScaffolding(data)) { return BlockStateCachedData.SCAFFOLDING; + } else { + return data; } - return BlockStateCachedData.get(state); } // example: dirt at 0,0,0 torch at 0,1,0. outgoingEdge(0,0,0,UP) returns true, incomingEdge(0,1,0,DOWN) returns true @@ -88,7 +90,7 @@ public class PlaceOrderDependencyGraph { } public boolean airTreatedAsScaffolding(long pos) { - return treatAsScaffolding(state(pos)); + return treatAsScaffolding(BlockStateCachedData.get(state(pos))); } private int state(long pos) { @@ -103,7 +105,7 @@ public class PlaceOrderDependencyGraph { return states.bounds; } - private boolean treatAsScaffolding(int state) { - return BlockStateCachedData.get(state).isAir; + private boolean treatAsScaffolding(BlockStateCachedData state) { + return state.isAir; } } diff --git a/src/main/java/baritone/builder/PlayerPhysics.java b/src/main/java/baritone/builder/PlayerPhysics.java index 0ddc0952e..d3164c7e4 100644 --- a/src/main/java/baritone/builder/PlayerPhysics.java +++ b/src/main/java/baritone/builder/PlayerPhysics.java @@ -19,28 +19,67 @@ package baritone.builder; public class PlayerPhysics { + public static int determinePlayerRealSupportLevel(BlockStateCachedData underneath, BlockStateCachedData within) { + switch (canPlayerStand(underneath, within)) { + case STANDARD_WITHIN_SUPPORT: + return within.collisionHeightBlips(); + case UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK: + return underneath.collisionHeightBlips() - Blip.FULL_BLOCK; + default: + return -1; + } + } + /** * 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. + * underneath is the block underneath that, which we annoyingly also have to check due to fences and other blocks that are taller than a block */ - public static int determinePlayerRealSupport(BlockStateCachedData underneath, BlockStateCachedData within) { + public static VoxelResidency canPlayerStand(BlockStateCachedData underneath, BlockStateCachedData within) { if (within.collidesWithPlayer) { if (underneath.collidesWithPlayer && underneath.collisionHeightBlips() - Blip.FULL_BLOCK > within.collisionHeightBlips()) { // > because imagine something like slab on top of fence, we can walk on the slab even though the fence is equivalent height if (!underneath.fullyWalkableTop) { - return -1; + return VoxelResidency.PREVENTED_BY_UNDERNEATH; } - return underneath.collisionHeightBlips() - Blip.FULL_BLOCK; // this could happen if "underneath" is a fence and "within" is a carpet + return VoxelResidency.UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK; // this could happen if "underneath" is a fence and "within" is a carpet } - if (!within.fullyWalkableTop || within.collisionHeightBlips() >= Blip.FULL_BLOCK) { - return -1; + if (!within.fullyWalkableTop) { + return VoxelResidency.PREVENTED_BY_WITHIN; } - return within.collisionHeightBlips(); + if (within.collisionHeightBlips() >= Blip.FULL_BLOCK) { + return VoxelResidency.IMPOSSIBLE_WITHOUT_SUFFOCATING; + } + return VoxelResidency.STANDARD_WITHIN_SUPPORT; } else { - if (!underneath.fullyWalkableTop || underneath.collisionHeightBlips() < Blip.FULL_BLOCK) { // short circuit only calls collisionHeightBlips when fullyWalkableTop is true, so this is safe - return -1; + if (!underneath.fullyWalkableTop) { + return VoxelResidency.PREVENTED_BY_UNDERNEATH; } - return underneath.collisionHeightBlips() - Blip.FULL_BLOCK; + if (underneath.collisionHeightBlips() < Blip.FULL_BLOCK) { // short circuit only calls collisionHeightBlips when fullyWalkableTop is true, so this is safe + return VoxelResidency.FLOATING; + } + return VoxelResidency.UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK; + } + } + + public enum VoxelResidency { + UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK, // i fucking hate notch for adding fences to the game. anyway this means that the height is underneath.collisionHeightBlips minus a full block. + STANDARD_WITHIN_SUPPORT, // :innocent: emoji, the height is simply the collisionHeightBlips of the within + + IMPOSSIBLE_WITHOUT_SUFFOCATING, // aka: um we are literally underground + FLOATING, // aka: um we are literally floating in midair + + PREVENTED_BY_UNDERNEATH, // fences :woozy_face: + PREVENTED_BY_WITHIN, // what are you even thinking? + } + + public static boolean valid(VoxelResidency res) { + // FWIW this is equivalent to "return determinePlayerRealSupportLevel > 0" + switch (res) { + case UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK: + case STANDARD_WITHIN_SUPPORT: + return true; + default: + return false; } } @@ -66,7 +105,7 @@ public class PlayerPhysics { if (Main.DEBUG && (feet < 0 || feet >= Blip.FULL_BLOCK)) { throw new IllegalStateException(); } - if (Main.DEBUG && (feet != determinePlayerRealSupport(S, X))) { + if (Main.DEBUG && (feet != determinePlayerRealSupportLevel(S, X))) { throw new IllegalStateException(); } boolean alreadyWithinU = feet > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE; // > and not >= because the player height is a slight overestimate @@ -78,7 +117,7 @@ public class PlayerPhysics { } int couldStepUpTo = feet + Blip.HALF_BLOCK; // D cannot prevent us from doing anything because it cant be higher than 1.5. therefore, makes sense to check CB before DC. - int stepUp = determinePlayerRealSupport(C, B); + int stepUp = determinePlayerRealSupportLevel(C, B); if (stepUp >= 0) { // fundamentally a step upwards, from X to B instead of X to C // too high? @@ -97,7 +136,7 @@ public class PlayerPhysics { 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); + int stayLevel = determinePlayerRealSupportLevel(D, C); if (stayLevel >= 0) { // fundamentally staying within the same vertical voxel, X -> C if (stayLevel > couldStepUpTo) {