refactors and begin on sneak nodes
This commit is contained in:
@@ -30,6 +30,7 @@ public final class BlockStateCachedData {
|
||||
private static final BlockStateCachedData[] PER_STATE = Main.DATA_PROVIDER.allNullable();
|
||||
public static final BlockStateCachedData SCAFFOLDING = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).fullyWalkableTop().collisionHeight(1).canPlaceAgainstMe());
|
||||
public static final BlockStateCachedData AIR = PER_STATE[0];
|
||||
public static final BlockStateCachedData OUT_OF_BOUNDS = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).collisionHeight(1));
|
||||
|
||||
static {
|
||||
if (!AIR.isAir) {
|
||||
|
||||
@@ -86,7 +86,7 @@ public class BlockStateCachedDataBuilder {
|
||||
* Should be 1 for trapdoors because when they're open, they touch the top face of the voxel
|
||||
*/
|
||||
public BlockStateCachedDataBuilder collisionHeight(double y) {
|
||||
for (int h = 1; h <= Blip.PER_BLOCK + Blip.HALF_BLOCK; h++) {
|
||||
for (int h = 0; h <= Blip.PER_BLOCK + Blip.HALF_BLOCK; h++) {
|
||||
if (y == h * Blip.RATIO) {
|
||||
collisionHeightBlips = h;
|
||||
return this;
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.Optional;
|
||||
public enum Face {
|
||||
DOWN, UP, NORTH, SOUTH, WEST, EAST;
|
||||
public final int index = ordinal();
|
||||
public final int oppositeIndex = index ^ 1;
|
||||
public final int oppositeIndex = opposite(index);
|
||||
public final int x = toMC().getXOffset();
|
||||
public final int y = toMC().getYOffset();
|
||||
public final int z = toMC().getZOffset();
|
||||
@@ -44,11 +44,13 @@ public enum Face {
|
||||
public static final Face[] VALUES = new Face[NUM_FACES];
|
||||
public static final Face[] HORIZONTALS;
|
||||
public static final List<Optional<Face>> OPTS;
|
||||
public static final long[] OFFSETS = new long[NUM_FACES];
|
||||
|
||||
static {
|
||||
List<Optional<Face>> lst = new ArrayList<>();
|
||||
for (Face face : values()) {
|
||||
VALUES[face.index] = face;
|
||||
OFFSETS[face.index] = face.offset;
|
||||
lst.add(Optional.of(face));
|
||||
}
|
||||
lst.add(Optional.empty());
|
||||
@@ -71,4 +73,12 @@ public enum Face {
|
||||
public final long offset(long pos) {
|
||||
return (pos + offset) & BetterBlockPos.POST_ADDITION_MASK;
|
||||
}
|
||||
|
||||
public static long offset(long pos, int face) {
|
||||
return (pos + OFFSETS[face]) & BetterBlockPos.POST_ADDITION_MASK;
|
||||
}
|
||||
|
||||
public static int opposite(int face) {
|
||||
return face ^ 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,13 +22,15 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
|
||||
public class GreedySolver {
|
||||
|
||||
SolverEngineInput engineInput;
|
||||
NodeBinaryHeap heap = new NodeBinaryHeap();
|
||||
Long2ObjectOpenHashMap<Node> nodes = new Long2ObjectOpenHashMap<>();
|
||||
Long2ObjectOpenHashMap<WorldState> zobristWorldStateCache = new Long2ObjectOpenHashMap<>();
|
||||
private final SolverEngineInput engineInput;
|
||||
private final NodeBinaryHeap heap = new NodeBinaryHeap();
|
||||
private final Long2ObjectOpenHashMap<Node> nodes = new Long2ObjectOpenHashMap<>();
|
||||
final Long2ObjectOpenHashMap<WorldState> zobristWorldStateCache = new Long2ObjectOpenHashMap<>();
|
||||
private final Bounds bounds;
|
||||
|
||||
public GreedySolver(SolverEngineInput input) {
|
||||
this.engineInput = input;
|
||||
this.bounds = engineInput.graph.bounds();
|
||||
}
|
||||
|
||||
synchronized SolverEngineOutput search() {
|
||||
@@ -44,7 +46,7 @@ public class GreedySolver {
|
||||
|
||||
private void expandNode(Node node) {
|
||||
WorldState worldState = node.coalesceState(this);
|
||||
long pos = node.pos;
|
||||
long pos = node.pos();
|
||||
BlockStateCachedData aboveAbove = at(BetterBlockPos.offsetBy(pos, 0, 3, 0), worldState);
|
||||
BlockStateCachedData above = at(BetterBlockPos.offsetBy(pos, 0, 2, 0), worldState);
|
||||
BlockStateCachedData head = at(Face.UP.offset(pos), worldState);
|
||||
@@ -53,53 +55,46 @@ public class GreedySolver {
|
||||
}
|
||||
BlockStateCachedData feet = at(pos, worldState);
|
||||
BlockStateCachedData underneath = at(Face.DOWN.offset(pos), worldState);
|
||||
int blipsWithinBlock = PlayerPhysics.determinePlayerRealSupportLevel(underneath, feet);
|
||||
|
||||
PlayerPhysics.VoxelResidency residency = PlayerPhysics.canPlayerStand(underneath, feet);
|
||||
if (!PlayerPhysics.valid(residency)) {
|
||||
throw new UnsupportedOperationException("sneaking off the edge of a block is not yet supported");
|
||||
}
|
||||
boolean standingWithinCollidableVoxel = residency == PlayerPhysics.VoxelResidency.STANDARD_WITHIN_SUPPORT;
|
||||
long playerIsActuallySupportedBy = standingWithinCollidableVoxel ? pos : Face.DOWN.offset(pos);
|
||||
int blipsWithinBlock = standingWithinCollidableVoxel ? feet.collisionHeightBlips() : underneath.collisionHeightBlips() - Blip.FULL_BLOCK;
|
||||
if (blipsWithinBlock < 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
cardinals:
|
||||
// pillar up
|
||||
{
|
||||
long maybePlaceAt = Face.UP.offset(playerIsActuallySupportedBy);
|
||||
if (!worldState.blockExists(maybePlaceAt)) {
|
||||
engineInput.graph.data(maybePlaceAt);
|
||||
} else {
|
||||
if (Main.DEBUG && at(maybePlaceAt, worldState).collidesWithPlayer) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// walk sideways and either stay level, ascend, or descend
|
||||
for (Face travel : Face.HORIZONTALS) {
|
||||
long newPos = travel.offset(pos);
|
||||
BlockStateCachedData newAboveAbove = at(BetterBlockPos.offsetBy(newPos, 0, 3, 0), worldState);
|
||||
BlockStateCachedData newAbove = at(BetterBlockPos.offsetBy(newPos, 0, 2, 0), 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, aboveAbove, newAboveAbove)) {
|
||||
switch (PlayerPhysics.playerTravelCollides(blipsWithinBlock, underneath, feet, above, aboveAbove, newPos, worldState, engineInput)) {
|
||||
case BLOCKED: {
|
||||
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.offsetBy(newPos, 0, -descent, 0);
|
||||
long under = Face.DOWN.offset(support);
|
||||
if (Main.DEBUG && !engineInput.graph.bounds().inRangePos(under)) {
|
||||
throw new IllegalStateException(); // should be caught by PREVENTED_BY_UNDERNEATH
|
||||
}
|
||||
PlayerPhysics.VoxelResidency res = PlayerPhysics.canPlayerStand(at(under, worldState), at(support, worldState));
|
||||
if (Main.DEBUG && descent == 0 && res != PlayerPhysics.VoxelResidency.FLOATING) {
|
||||
throw new IllegalStateException(); // CD shouldn't collide, it should be D and the one beneath...
|
||||
}
|
||||
switch (res) {
|
||||
case FLOATING:
|
||||
continue; // as expected
|
||||
case PREVENTED_BY_UNDERNEATH:
|
||||
case PREVENTED_BY_WITHIN:
|
||||
continue cardinals; // 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
|
||||
upsertEdge(node, worldState, support, -1, fallCost(descent));
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
int descendBy = PlayerPhysics.playerFalls(newPos, worldState, engineInput);
|
||||
if (descendBy != -1) {
|
||||
if (Main.DEBUG && descendBy <= 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
upsertEdge(node, worldState, BetterBlockPos.offsetBy(newPos, 0, -descendBy, 0), -1, fallCost(descendBy));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VOXEL_LEVEL: {
|
||||
upsertEdge(node, worldState, newPos, -1, flatCost());
|
||||
@@ -143,6 +138,9 @@ public class GreedySolver {
|
||||
}
|
||||
|
||||
private void upsertEdge(Node node, WorldState worldState, long newPlayerPosition, long blockPlacement, int edgeCost) {
|
||||
if (Main.DEBUG && blockPlacement == -1 && PlayerPhysics.determinePlayerRealSupportLevel(at(Face.DOWN.offset(newPlayerPosition), worldState), at(newPlayerPosition, worldState)) < 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Node neighbor = getNode(newPlayerPosition, node, worldState, blockPlacement);
|
||||
if (Main.SLOW_DEBUG && blockPlacement != -1 && !neighbor.coalesceState(this).blockExists(blockPlacement)) { // only in slow_debug because this force-allocates a WorldState for every neighbor of every node!
|
||||
throw new IllegalStateException();
|
||||
@@ -217,6 +215,6 @@ public class GreedySolver {
|
||||
}
|
||||
|
||||
public BlockStateCachedData at(long pos, WorldState inWorldState) {
|
||||
return inWorldState.blockExists(pos) ? engineInput.graph.data(pos) : BlockStateCachedData.AIR;
|
||||
return engineInput.at(pos, inWorldState);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
|
||||
package baritone.builder;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
|
||||
public class Node {
|
||||
|
||||
public final long pos;
|
||||
private final long posAndSneak;
|
||||
public final long worldStateZobristHash;
|
||||
|
||||
public final int heuristic;
|
||||
@@ -67,8 +69,29 @@ public class Node {
|
||||
return myState;
|
||||
}
|
||||
|
||||
public static long encode(long pos, int sneak) {
|
||||
if (Main.DEBUG && (sneak < 0 || sneak > 3)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (Main.DEBUG && ((pos & BetterBlockPos.POST_ADDITION_MASK) != pos)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
long ret = pos
|
||||
| (sneak & 0x1L) << 26 // snugly and cozily fit into the two bits left between X and Y and between Y and Z
|
||||
| (sneak & 0x2L) << 35
|
||||
| 1L << 63; // and turn on the top bit as a signal
|
||||
if (Main.DEBUG && ((ret & BetterBlockPos.POST_ADDITION_MASK) != pos)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public long pos() {
|
||||
return posAndSneak & BetterBlockPos.POST_ADDITION_MASK;
|
||||
}
|
||||
|
||||
public long nodeMapKey() {
|
||||
return pos ^ worldStateZobristHash;
|
||||
return posAndSneak ^ worldStateZobristHash;
|
||||
}
|
||||
|
||||
public boolean inHeap() {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package baritone.builder;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
|
||||
public class PlayerPhysics {
|
||||
|
||||
public static int determinePlayerRealSupportLevel(BlockStateCachedData underneath, BlockStateCachedData within) {
|
||||
@@ -86,6 +88,24 @@ public class PlayerPhysics {
|
||||
}
|
||||
}
|
||||
|
||||
public static Collision playerTravelCollides(int feetBlips,
|
||||
BlockStateCachedData underneath,
|
||||
BlockStateCachedData feet,
|
||||
BlockStateCachedData above,
|
||||
BlockStateCachedData aboveAbove,
|
||||
long newPos, WorldState worldState, SolverEngineInput engineInput) {
|
||||
return playerTravelCollides(feetBlips,
|
||||
above,
|
||||
engineInput.at(BetterBlockPos.offsetBy(newPos, 0, 2, 0), worldState),
|
||||
engineInput.at(Face.UP.offset(newPos), worldState),
|
||||
engineInput.at(newPos, worldState),
|
||||
engineInput.at(Face.DOWN.offset(newPos), worldState),
|
||||
underneath,
|
||||
feet,
|
||||
aboveAbove,
|
||||
engineInput.at(BetterBlockPos.offsetBy(newPos, 0, 3, 0), worldState));
|
||||
}
|
||||
|
||||
/**
|
||||
* "Can the player walk forwards without needing to break anything?"
|
||||
* <p>
|
||||
@@ -98,7 +118,7 @@ public class PlayerPhysics {
|
||||
* XC
|
||||
* SD
|
||||
*/
|
||||
public static Collision playerTravelCollides(int feet,
|
||||
public static Collision playerTravelCollides(int feetBlips,
|
||||
BlockStateCachedData U,
|
||||
BlockStateCachedData A,
|
||||
BlockStateCachedData B,
|
||||
@@ -108,24 +128,24 @@ public class PlayerPhysics {
|
||||
BlockStateCachedData X,
|
||||
BlockStateCachedData E,
|
||||
BlockStateCachedData F) {
|
||||
if (Main.DEBUG && (feet < 0 || feet >= Blip.FULL_BLOCK)) {
|
||||
if (Main.DEBUG && (feetBlips < 0 || feetBlips >= Blip.FULL_BLOCK)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (Main.DEBUG && (feet != determinePlayerRealSupportLevel(S, X))) {
|
||||
if (Main.DEBUG && (feetBlips != 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
|
||||
boolean alreadyWithinU = protrudesIntoThirdBlock(feetBlips);
|
||||
if (Main.DEBUG && (alreadyWithinU && U.collidesWithPlayer)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
int couldJumpUpTo = feet + Blip.JUMP;
|
||||
int couldStepUpTo = feet + Blip.HALF_BLOCK;
|
||||
int couldJumpUpTo = feetBlips + Blip.JUMP;
|
||||
int couldStepUpTo = feetBlips + Blip.HALF_BLOCK;
|
||||
if (couldJumpUpTo >= Blip.TWO_BLOCKS && !E.collidesWithPlayer && !F.collidesWithPlayer) {
|
||||
// probably blocked, but maybe could we stand on A?
|
||||
// imagine X is soul sand, A is carpet. that jump is possible
|
||||
int jumpUpTwo = determinePlayerRealSupportLevel(B, A);
|
||||
if (jumpUpTwo >= 0 && jumpUpTwo <= couldJumpUpTo - Blip.TWO_BLOCKS) {
|
||||
if (Main.DEBUG && (!alreadyWithinU || jumpUpTwo > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE)) {
|
||||
if (Main.DEBUG && (!alreadyWithinU || protrudesIntoThirdBlock(jumpUpTwo))) {
|
||||
throw new IllegalStateException(); // numeric impossibilities
|
||||
}
|
||||
return Collision.JUMP_TO_VOXEL_TWO_UP;
|
||||
@@ -139,7 +159,7 @@ public class PlayerPhysics {
|
||||
if (voxelUp >= 0) {
|
||||
// fundamentally a step upwards, from X to B instead of X to C
|
||||
// too high?
|
||||
if (voxelUp > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE && (E.collidesWithPlayer || F.collidesWithPlayer)) {
|
||||
if (protrudesIntoThirdBlock(voxelUp) && (E.collidesWithPlayer || F.collidesWithPlayer)) {
|
||||
return Collision.BLOCKED;
|
||||
}
|
||||
int heightRelativeToStartVoxel = voxelUp + Blip.FULL_BLOCK;
|
||||
@@ -164,7 +184,7 @@ public class PlayerPhysics {
|
||||
int stayLevel = determinePlayerRealSupportLevel(D, C);
|
||||
if (stayLevel >= 0) {
|
||||
// fundamentally staying within the same vertical voxel, X -> C
|
||||
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 (protrudesIntoThirdBlock(stayLevel) && !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;
|
||||
}
|
||||
@@ -172,7 +192,7 @@ public class PlayerPhysics {
|
||||
return Collision.BLOCKED;
|
||||
}
|
||||
}
|
||||
if (stayLevel > couldStepUpTo) {
|
||||
if (stayLevel > couldStepUpTo) { // staying within the same voxel means that a jump will always succeed
|
||||
return Collision.JUMP_TO_VOXEL_LEVEL;
|
||||
}
|
||||
return Collision.VOXEL_LEVEL;
|
||||
@@ -186,13 +206,17 @@ public class PlayerPhysics {
|
||||
if (Main.DEBUG && D.collisionHeightBlips() >= Blip.FULL_BLOCK && D.fullyWalkableTop) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (D.collisionHeightBlips() < Blip.FULL_BLOCK + feet) {
|
||||
if (D.collisionHeightBlips() < Blip.FULL_BLOCK + feetBlips) {
|
||||
return Collision.FALL;
|
||||
} else {
|
||||
return Collision.BLOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean protrudesIntoThirdBlock(int feet) {
|
||||
return feet > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE; // > and not >= because the player height is a slight overestimate
|
||||
}
|
||||
|
||||
static {
|
||||
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");
|
||||
@@ -200,7 +224,7 @@ public class PlayerPhysics {
|
||||
int maxFeet = Blip.FULL_BLOCK - 1;
|
||||
int couldJumpUpTo = maxFeet + Blip.JUMP;
|
||||
int maxWithinAB = couldJumpUpTo - Blip.TWO_BLOCKS;
|
||||
if (maxWithinAB > Blip.TWO_BLOCKS - Blip.PLAYER_HEIGHT_SLIGHT_OVERESTIMATE) {
|
||||
if (protrudesIntoThirdBlock(maxWithinAB)) {
|
||||
throw new IllegalStateException("Oh no, if this is true then playerTravelCollides needs to check another layer above EF");
|
||||
}
|
||||
}
|
||||
@@ -215,4 +239,34 @@ public class PlayerPhysics {
|
||||
FALL // if you hit W, you will not immediately collide with anything, at all, to the front or to the bottom (example: walking off a cliff)
|
||||
// TODO maybe we need another option that is like "you could do it, but you shouldn't". like, "if you hit W, you would walk forward, but you wouldn't like the outcome" such as cactus or lava or something
|
||||
}
|
||||
|
||||
public static int playerFalls(long newPos, WorldState worldState, SolverEngineInput engineInput) {
|
||||
// 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.offsetBy(newPos, 0, -descent, 0);
|
||||
long under = Face.DOWN.offset(support);
|
||||
if (Main.DEBUG && !engineInput.bounds.inRangePos(under)) {
|
||||
throw new IllegalStateException(); // should be caught by PREVENTED_BY_UNDERNEATH
|
||||
}
|
||||
VoxelResidency res = canPlayerStand(engineInput.at(under, worldState), engineInput.at(support, worldState));
|
||||
if (Main.DEBUG && descent == 0 && res != VoxelResidency.FLOATING) {
|
||||
throw new IllegalStateException(); // CD shouldn't collide, it should be D and the one beneath...
|
||||
}
|
||||
switch (res) {
|
||||
case FLOATING:
|
||||
continue; // as expected
|
||||
case PREVENTED_BY_UNDERNEATH:
|
||||
case PREVENTED_BY_WITHIN:
|
||||
return -1; // no safe landing
|
||||
case UNDERNEATH_PROTRUDES_AT_OR_ABOVE_FULL_BLOCK:
|
||||
case STANDARD_WITHIN_SUPPORT:
|
||||
// found our landing spot
|
||||
return descent;
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class PlayerReachSphere {
|
||||
/**
|
||||
* Bring closer to 0 by one if not already zero
|
||||
*/
|
||||
private static int lower(int v) {
|
||||
private static int lowerBranchy(int v) {
|
||||
if (v > 0) {
|
||||
return v - 1;
|
||||
} else if (v < 0) {
|
||||
@@ -62,4 +62,16 @@ public class PlayerReachSphere {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
private static int lower(int v) {
|
||||
return v + (v >>> 31) - ((-v) >>> 31);
|
||||
}
|
||||
|
||||
static {
|
||||
for (int i = -10; i <= 10; i++) {
|
||||
if (lowerBranchy(i) != lower(i)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ public class SolverEngineInput {
|
||||
public final LongSet alreadyPlaced;
|
||||
public final LongSet allToPlaceNow;
|
||||
private final List<LongOpenHashSet> toPlaceNow;
|
||||
public final Bounds bounds;
|
||||
public final long player;
|
||||
|
||||
/**
|
||||
@@ -48,18 +49,19 @@ public class SolverEngineInput {
|
||||
this.toPlaceNow = toPlaceNow;
|
||||
this.player = player;
|
||||
this.allToPlaceNow = combine(toPlaceNow);
|
||||
this.bounds = graph.bounds();
|
||||
if (Main.DEBUG) {
|
||||
sanityCheck();
|
||||
}
|
||||
}
|
||||
|
||||
private void sanityCheck() {
|
||||
if (!graph.bounds().inRangePos(player)) {
|
||||
if (!bounds.inRangePos(player)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
for (LongSet toVerify : new LongSet[]{intendedScaffolding, alreadyPlaced}) {
|
||||
for (long pos : toVerify) {
|
||||
if (!graph.bounds().inRangePos(pos)) {
|
||||
if (!bounds.inRangePos(pos)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
@@ -69,7 +71,7 @@ public class SolverEngineInput {
|
||||
if (alreadyPlaced.contains(pos)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!graph.bounds().inRangePos(pos)) {
|
||||
if (!bounds.inRangePos(pos)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (intendedScaffolding.contains(pos) ^ graph.airTreatedAsScaffolding(pos)) {
|
||||
@@ -121,4 +123,16 @@ public class SolverEngineInput {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public BlockStateCachedData at(long pos, WorldState inWorldState) {
|
||||
if (bounds.inRangePos(pos)) {
|
||||
if (inWorldState.blockExists(pos)) {
|
||||
return graph.data(pos);
|
||||
} else {
|
||||
return BlockStateCachedData.AIR;
|
||||
}
|
||||
} else {
|
||||
return BlockStateCachedData.OUT_OF_BOUNDS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user