progress on properties and entity oriented blocks
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.builder;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -27,10 +28,10 @@ import java.util.List;
|
||||
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().height(1).canPlaceAgainstMe());
|
||||
public static final BlockStateCachedData SCAFFOLDING = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).fullyWalkableTop().collisionHeight(1).canPlaceAgainstMe());
|
||||
|
||||
public final boolean fullyWalkableTop;
|
||||
public final Integer supportedPlayerY;
|
||||
public final Integer collisionHeightBlips;
|
||||
public final boolean isAir;
|
||||
|
||||
public final boolean collidesWithPlayer;
|
||||
@@ -40,7 +41,7 @@ public final class BlockStateCachedData {
|
||||
|
||||
public final List<BlockStatePlacementOption> options;
|
||||
|
||||
private final PlaceAgainstData[] againstMe;
|
||||
public final PlaceAgainstData[] againstMe;
|
||||
|
||||
public static BlockStateCachedData get(int state) {
|
||||
return PER_STATE[state];
|
||||
@@ -51,10 +52,10 @@ public final class BlockStateCachedData {
|
||||
this.isAir = builder.isAir();
|
||||
this.fullyWalkableTop = builder.isFullyWalkableTop();
|
||||
this.collidesWithPlayer = builder.isCollidesWithPlayer();
|
||||
this.supportedPlayerY = builder.supportedPlayerY();
|
||||
this.collisionHeightBlips = builder.collisionHeightBlips();
|
||||
|
||||
this.mustSneakWhenPlacingAgainstMe = builder.isMustSneakWhenPlacingAgainstMe();
|
||||
this.options = builder.howCanIBePlaced();
|
||||
this.options = Collections.unmodifiableList(builder.howCanIBePlaced());
|
||||
|
||||
this.againstMe = builder.placeAgainstMe();
|
||||
}
|
||||
|
||||
@@ -41,8 +41,12 @@ public class BlockStateCachedDataBuilder {
|
||||
* Normal blocks must be placed against EITHER
|
||||
*/
|
||||
private Half mustBePlacedAgainst = Half.EITHER;
|
||||
private Face playerMustBeFacingInOrderToPlaceMe;
|
||||
private Integer height;
|
||||
private Face playerMustBeHorizontalFacingInOrderToPlaceMe;
|
||||
private Integer collisionHeightBlips;
|
||||
private Face canOnlyPlaceAgainst;
|
||||
private boolean fakeLessThanFullHeight; // snow layers and soul sand
|
||||
private boolean placementLogicNotImplementedYet;
|
||||
private Face playerMustBeEntityFacingInOrderToPlaceMe;
|
||||
|
||||
public BlockStateCachedDataBuilder() {
|
||||
}
|
||||
@@ -72,18 +76,18 @@ public class BlockStateCachedDataBuilder {
|
||||
return fullyWalkableTop;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder height(double y) {
|
||||
public BlockStateCachedDataBuilder collisionHeight(double y) {
|
||||
for (int h = 1; h <= Blip.PER_BLOCK + Blip.HALF_BLOCK; h++) {
|
||||
if (y == h * Blip.RATIO) {
|
||||
height = h;
|
||||
collisionHeightBlips = h;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public Integer supportedPlayerY() { // e.g. slabs are 0.5, soul sand is 0.875, normal blocks are 1, fences are 1.5
|
||||
return height;
|
||||
public Integer collisionHeightBlips() { // e.g. slabs are 0.5, soul sand is 0.875, normal blocks are 1, fences are 1.5
|
||||
return collisionHeightBlips;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder mustSneakWhenPlacingAgainstMe() {
|
||||
@@ -109,12 +113,20 @@ public class BlockStateCachedDataBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder playerMustBeFacingInOrderToPlaceMe(Face face) {
|
||||
playerMustBeFacingInOrderToPlaceMe = face;
|
||||
public BlockStateCachedDataBuilder playerMustBeHorizontalFacingInOrderToPlaceMe(Face face) {
|
||||
playerMustBeHorizontalFacingInOrderToPlaceMe = face;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder playerMustBeEntityFacingInOrderToPlaceMe(Face face) {
|
||||
playerMustBeEntityFacingInOrderToPlaceMe = face;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder mustBePlacedAgainst(Half half) {
|
||||
if (half == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
mustBePlacedAgainst = half;
|
||||
return this;
|
||||
}
|
||||
@@ -124,16 +136,40 @@ public class BlockStateCachedDataBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder canOnlyPlaceAgainst(Face face) {
|
||||
canOnlyPlaceAgainst = face;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder placementLogicNotImplementedYet() {
|
||||
placementLogicNotImplementedYet = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockStateCachedDataBuilder fakeLessThanFullHeight() {
|
||||
fakeLessThanFullHeight = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<BlockStatePlacementOption> howCanIBePlaced() {
|
||||
if (mustBePlacedAgainst == null) {
|
||||
if (mustBePlacedAgainst == null || placementLogicNotImplementedYet) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<BlockStatePlacementOption> ret = new ArrayList<>();
|
||||
for (Face face : Face.VALUES) {
|
||||
if (Main.STRICT_Y && face == Face.UP) {
|
||||
continue; // TODO don't do this...
|
||||
}
|
||||
if (playerMustBeHorizontalFacingInOrderToPlaceMe == face.opposite()) { // obv, this won't happen if playerMustBeHorizontalFacing is null
|
||||
continue;
|
||||
}
|
||||
if (playerMustBeFacingInOrderToPlaceMe == face.opposite()) { // obv, this won't happen if playerMustBeFacing is null
|
||||
if (playerMustBeEntityFacingInOrderToPlaceMe == face) {
|
||||
continue;
|
||||
}
|
||||
if (falling && face != Face.DOWN) {
|
||||
continue;
|
||||
}
|
||||
if (canOnlyPlaceAgainst != null && face != canOnlyPlaceAgainst) {
|
||||
continue;
|
||||
}
|
||||
Half overrideHalf = mustBePlacedAgainst;
|
||||
@@ -151,9 +187,9 @@ public class BlockStateCachedDataBuilder {
|
||||
overrideHalf = Half.EITHER;
|
||||
}
|
||||
}
|
||||
ret.add(BlockStatePlacementOption.get(face, overrideHalf, Optional.ofNullable(playerMustBeFacingInOrderToPlaceMe)));
|
||||
ret.add(BlockStatePlacementOption.get(face, overrideHalf, Optional.ofNullable(playerMustBeHorizontalFacingInOrderToPlaceMe), Optional.ofNullable(playerMustBeEntityFacingInOrderToPlaceMe)));
|
||||
}
|
||||
return Collections.unmodifiableList(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public PlaceAgainstData[] placeAgainstMe() {
|
||||
@@ -168,6 +204,7 @@ public class BlockStateCachedDataBuilder {
|
||||
}
|
||||
|
||||
protected PlaceAgainstData placeAgainstFace(Face face) {
|
||||
// TODO this makes the stair/slab assumption that the same half is the mustBePlacedAgainst as the faces offered for placement... counterexample is daylight sensor
|
||||
if (mustBePlacedAgainst == Half.TOP && face == Face.DOWN) {
|
||||
return null;
|
||||
}
|
||||
@@ -192,23 +229,31 @@ public class BlockStateCachedDataBuilder {
|
||||
if (mustBePlacedAgainst == null ^ isAir()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (mustBePlacedAgainst == null ^ howCanIBePlaced().isEmpty()) {
|
||||
throw new IllegalStateException();
|
||||
if (howCanIBePlaced().isEmpty()) {
|
||||
if (mustBePlacedAgainst != null && !placementLogicNotImplementedYet) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (playerMustBeHorizontalFacingInOrderToPlaceMe != null || playerMustBeEntityFacingInOrderToPlaceMe != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (canOnlyPlaceAgainst != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
if (isMustSneakWhenPlacingAgainstMe() && mustBePlacedAgainst != Half.EITHER) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (playerMustBeFacingInOrderToPlaceMe != null && mustBePlacedAgainst == null) {
|
||||
if ((playerMustBeHorizontalFacingInOrderToPlaceMe != null || playerMustBeEntityFacingInOrderToPlaceMe != null) && mustBePlacedAgainst == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (isFullyWalkableTop() ^ height != null) {
|
||||
if (!isFullyWalkableTop() && height > Blip.PER_BLOCK) {
|
||||
if (isFullyWalkableTop() ^ collisionHeightBlips != null) {
|
||||
if (!isFullyWalkableTop() && collisionHeightBlips > Blip.PER_BLOCK) {
|
||||
// exception for fences, walls
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
if (height != null && height > Blip.FULL_BLOCK + Blip.HALF_BLOCK) { // playerphysics assumes this is never true
|
||||
if (collisionHeightBlips != null && (collisionHeightBlips > Blip.FULL_BLOCK + Blip.HALF_BLOCK || collisionHeightBlips <= 0)) { // playerphysics assumes this is never true
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (fullyWalkableTop && !collidesWithPlayer) {
|
||||
@@ -217,7 +262,7 @@ public class BlockStateCachedDataBuilder {
|
||||
if (canPlaceAgainstMe && !collidesWithPlayer) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (playerMustBeFacingInOrderToPlaceMe != null && playerMustBeFacingInOrderToPlaceMe.vertical) {
|
||||
if (playerMustBeHorizontalFacingInOrderToPlaceMe != null && playerMustBeHorizontalFacingInOrderToPlaceMe.vertical) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (Main.STRICT_Y && howCanIBePlaced().stream().anyMatch(opt -> opt.against == Face.UP)) {
|
||||
@@ -227,9 +272,31 @@ public class BlockStateCachedDataBuilder {
|
||||
if (data.length != Face.NUM_FACES) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
boolean any = false;
|
||||
for (int i = 0; i < Face.NUM_FACES; i++) {
|
||||
if (data[i] != null && data[i].against != Face.VALUES[i]) {
|
||||
throw new IllegalStateException();
|
||||
if (data[i] != null) {
|
||||
if (data[i].against != Face.VALUES[i]) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!canPlaceAgainstMe) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
if (canPlaceAgainstMe && !any) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (collisionHeightBlips != null && !fakeLessThanFullHeight) {
|
||||
for (PlaceAgainstData d : data) {
|
||||
if (d == null) {
|
||||
continue;
|
||||
}
|
||||
d.streamRelativeToMyself().forEach(hit -> {
|
||||
if (hit.y > collisionHeightBlips * Blip.RATIO) {
|
||||
throw new IllegalStateException(d.against + " " + hit.y + " " + collisionHeightBlips * Blip.RATIO);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import java.util.stream.Collectors;
|
||||
* For a block like a slab or a stair, this will contain the information that the placement must be against the top or bottom half of the face
|
||||
* <p>
|
||||
* For a block like a furnace, this will contain the information that the player must be facing a specific horizontal direction in order to get the desired orientation
|
||||
* <p>
|
||||
* For a block like a piston, dispenser, or observer, this will contain the information that be player must pass a combination of: specific relative eye coordinate, specific relative X Z, and specific horizontal facing
|
||||
*/
|
||||
public class BlockStatePlacementOption {
|
||||
|
||||
@@ -40,15 +42,20 @@ public class BlockStatePlacementOption {
|
||||
*/
|
||||
public final Face against;
|
||||
public final Half half;
|
||||
public final Optional<Face> playerMustBeFacing;
|
||||
public final Optional<Face> playerMustBeHorizontalFacing; // getHorizontalFacing
|
||||
/**
|
||||
* IMPORTANT this is the RAW getDirectionFromEntityLiving meaning that it is the OPPOSITE of getHorizontalFacing (when in the horizontal plane)
|
||||
*/
|
||||
public final Optional<Face> playerMustBeEntityFacing; // EnumFacing.getDirectionFromEntityLiving, used by piston, dispenser, observer
|
||||
|
||||
private BlockStatePlacementOption(Face against, Half half, Optional<Face> playerMustBeFacing) {
|
||||
private BlockStatePlacementOption(Face against, Half half, Optional<Face> playerMustBeHorizontalFacing, Optional<Face> playerMustBeEntityFacing) {
|
||||
Objects.requireNonNull(against);
|
||||
Objects.requireNonNull(half);
|
||||
this.against = against;
|
||||
this.half = half;
|
||||
this.playerMustBeFacing = playerMustBeFacing;
|
||||
validate(against, half, playerMustBeFacing);
|
||||
this.playerMustBeHorizontalFacing = playerMustBeHorizontalFacing;
|
||||
this.playerMustBeEntityFacing = playerMustBeEntityFacing;
|
||||
validate(against, half, playerMustBeHorizontalFacing, playerMustBeEntityFacing);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +69,7 @@ public class BlockStatePlacementOption {
|
||||
if (!BlockStateCachedData.possible(this, placingAgainst)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (Main.DEBUG && placingAgainst.stream().noneMatch(hit -> hitOk(half, hit))) {
|
||||
if (Main.DEBUG && placingAgainst.streamRelativeToPlace().noneMatch(hit -> hitOk(half, hit))) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
List<Vec2d> acceptableVantages = new ArrayList<>();
|
||||
@@ -98,7 +105,7 @@ public class BlockStatePlacementOption {
|
||||
.stream()
|
||||
.map(playerEyeXZ -> new Vec3d(playerEyeXZ.x, Blip.playerEyeFromFeetBlips(playerFeetBlips, placingAgainst.mustSneak), playerEyeXZ.z))
|
||||
.flatMap(eye ->
|
||||
placingAgainst.stream()
|
||||
placingAgainst.streamRelativeToPlace()
|
||||
.filter(hit -> hitOk(half, hit))
|
||||
.filter(hit -> eye.distSq(hit) < blockReachDistance * blockReachDistance)
|
||||
.filter(hit -> directionOk(eye, hit))
|
||||
@@ -128,51 +135,85 @@ public class BlockStatePlacementOption {
|
||||
}
|
||||
|
||||
private boolean directionOk(Vec3d eye, Vec3d hit) {
|
||||
if (playerMustBeFacing.isPresent()) {
|
||||
return eye.flatDirectionTo(hit) == playerMustBeFacing.get();
|
||||
if (playerMustBeHorizontalFacing.isPresent()) {
|
||||
return eye.flatDirectionTo(hit) == playerMustBeHorizontalFacing.get();
|
||||
}
|
||||
if (playerMustBeEntityFacing.isPresent()) { // handle piston, dispenser, observer
|
||||
if (!hit.inOriginUnitVoxel()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Face entFace = playerMustBeEntityFacing.get();
|
||||
// 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) {
|
||||
return entFace == Face.DOWN;
|
||||
}
|
||||
if (eye.y > 2) {
|
||||
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
|
||||
if (eye.y < 0 || eye.y > 2) {
|
||||
return false;
|
||||
}
|
||||
} // else either is above 2.01, putting us in simple horizontal mode, so fallthrough to flat condition is correct, yay
|
||||
return eye.flatDirectionTo(hit) == entFace.opposite();
|
||||
}
|
||||
// TODO include the other conditions for stupid blocks like pistons
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static BlockStatePlacementOption get(Face against, Half half, Optional<Face> playerMustBeFacing) {
|
||||
BlockStatePlacementOption ret = PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()][playerMustBeFacing.map(face -> face.index).orElse(Face.NUM_FACES)];
|
||||
public static BlockStatePlacementOption get(Face against, Half half, Optional<Face> playerMustBeHorizontalFacing, Optional<Face> playerMustBeEntityFacing) {
|
||||
BlockStatePlacementOption ret = PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()][Face.OPTS.indexOf(playerMustBeHorizontalFacing)][Face.OPTS.indexOf(playerMustBeEntityFacing)];
|
||||
if (ret == null) {
|
||||
throw new IllegalStateException(against + " " + half + " " + playerMustBeFacing);
|
||||
throw new IllegalStateException(against + " " + half + " " + playerMustBeHorizontalFacing + " " + playerMustBeEntityFacing);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static final BlockStatePlacementOption[][][] PLACEMENT_OPTION_SINGLETON_CACHE;
|
||||
private static final BlockStatePlacementOption[][][][] PLACEMENT_OPTION_SINGLETON_CACHE;
|
||||
|
||||
static {
|
||||
PLACEMENT_OPTION_SINGLETON_CACHE = new BlockStatePlacementOption[Face.NUM_FACES][Half.values().length][Face.NUM_FACES + 1];
|
||||
PLACEMENT_OPTION_SINGLETON_CACHE = new BlockStatePlacementOption[Face.NUM_FACES][Half.values().length][Face.OPTS.size()][Face.OPTS.size()];
|
||||
for (Face against : Face.VALUES) {
|
||||
for (Half half : Half.values()) {
|
||||
BlockStatePlacementOption[] saveInto = PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()];
|
||||
for (Face player : Face.VALUES) {
|
||||
try {
|
||||
saveInto[player.index] = new BlockStatePlacementOption(against, half, Optional.of(player));
|
||||
} catch (RuntimeException ex) {
|
||||
for (Optional<Face> horizontalFacing : Face.OPTS) {
|
||||
for (Optional<Face> entityFacing : Face.OPTS) {
|
||||
try {
|
||||
PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()][Face.OPTS.indexOf(horizontalFacing)][Face.OPTS.indexOf(entityFacing)] = new BlockStatePlacementOption(against, half, horizontalFacing, entityFacing);
|
||||
} catch (RuntimeException ex) {}
|
||||
}
|
||||
}
|
||||
try {
|
||||
saveInto[Face.NUM_FACES] = new BlockStatePlacementOption(against, half, Optional.empty());
|
||||
} catch (RuntimeException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validate(Face against, Half half, Optional<Face> playerMustBeFacing) {
|
||||
static {
|
||||
for (int i = 0; i < Face.OPTS.size(); i++) {
|
||||
if (Face.OPTS.indexOf(Face.OPTS.get(i)) != i) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (Face.OPTS.get(i).map(face -> face.index).orElse(Face.NUM_FACES) != i) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validate(Face against, Half half, Optional<Face> playerMustBeHorizontalFacing, Optional<Face> playerMustBeEntityFacing) {
|
||||
if (playerMustBeEntityFacing.isPresent() && playerMustBeHorizontalFacing.isPresent()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (against.vertical && half != Half.EITHER) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (Main.STRICT_Y && against == Face.UP) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
playerMustBeFacing.ifPresent(face -> {
|
||||
playerMustBeHorizontalFacing.ifPresent(face -> {
|
||||
if (face.vertical) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
@@ -180,6 +221,14 @@ public class BlockStatePlacementOption {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
});
|
||||
playerMustBeEntityFacing.ifPresent(face -> {
|
||||
if (half != Half.EITHER) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (against == face) { // impossible because EnumFacing inverts the horizontal facing AND because the down and up require the eye to be <0 and >2 respectively
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static {
|
||||
@@ -200,7 +249,7 @@ public class BlockStatePlacementOption {
|
||||
for (PlayerVantage vantage : new PlayerVantage[]{PlayerVantage.STRICT_CENTER, PlayerVantage.LOOSE_CENTER}) {
|
||||
for (Face playerFacing : new Face[]{Face.NORTH, Face.EAST, Face.WEST}) {
|
||||
sanity.append(vantage).append(playerFacing);
|
||||
List<Raytracer.Raytrace> traces = BlockStatePlacementOption.get(Face.NORTH, Half.BOTTOM, Optional.of(playerFacing)).computeTraceOptions(new PlaceAgainstData(Face.SOUTH, Half.EITHER, false), 1, 0, 0, vantage, 4);
|
||||
List<Raytracer.Raytrace> traces = BlockStatePlacementOption.get(Face.NORTH, Half.BOTTOM, Optional.of(playerFacing), Optional.empty()).computeTraceOptions(new PlaceAgainstData(Face.SOUTH, Half.EITHER, false), 1, 0, 0, vantage, 4);
|
||||
sanity.append(traces.size());
|
||||
sanity.append(" ");
|
||||
if (!traces.isEmpty()) {
|
||||
|
||||
@@ -20,6 +20,11 @@ package baritone.builder;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* I hate porting things to new versions of Minecraft
|
||||
* <p>
|
||||
@@ -38,11 +43,16 @@ public enum Face {
|
||||
public static final int NUM_FACES = 6;
|
||||
public static final Face[] VALUES = new Face[NUM_FACES];
|
||||
public static final Face[] HORIZONTALS;
|
||||
public static final List<Optional<Face>> OPTS;
|
||||
|
||||
static {
|
||||
List<Optional<Face>> lst = new ArrayList<>();
|
||||
for (Face face : values()) {
|
||||
VALUES[face.index] = face;
|
||||
lst.add(Optional.of(face));
|
||||
}
|
||||
lst.add(Optional.empty());
|
||||
OPTS = Collections.unmodifiableList(lst);
|
||||
HORIZONTALS = new Face[]{Face.SOUTH, Face.WEST, Face.NORTH, Face.EAST};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
package baritone.builder;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.builder.mc.DebugStates;
|
||||
import baritone.builder.mc.VanillaBlockStateDataProvider;
|
||||
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
@@ -163,7 +164,7 @@ public class Main {
|
||||
{
|
||||
BlockStatePlacementOption.sanityCheck();
|
||||
}
|
||||
{
|
||||
for (int aaaa = 0; aaaa < 0; aaaa++) {
|
||||
/*Raytracer.raytraceMode++;
|
||||
Raytracer.raytraceMode %= 3;*/
|
||||
Random rand = new Random(5021);
|
||||
@@ -262,6 +263,9 @@ public class Main {
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
DebugStates.debug();
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class PlaceAgainstData {
|
||||
|
||||
public final Face against;
|
||||
public final boolean mustSneak; // like if its a crafting table
|
||||
public final Vec3d[] hits;
|
||||
private final Vec3d[] hits;
|
||||
private final boolean top;
|
||||
private final boolean bottom;
|
||||
|
||||
@@ -61,10 +61,14 @@ public class PlaceAgainstData {
|
||||
}
|
||||
}
|
||||
|
||||
public Stream<Vec3d> stream() {
|
||||
public Stream<Vec3d> streamRelativeToPlace() {
|
||||
return Stream.of(hits);
|
||||
}
|
||||
|
||||
public Stream<Vec3d> streamRelativeToMyself() {
|
||||
return streamRelativeToPlace().map(v -> v.plus(against.x, against.y, against.z));
|
||||
}
|
||||
|
||||
private boolean validatePossibleHit(Vec3d hit) {
|
||||
double[] h = {hit.x, hit.y, hit.z};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
@@ -92,7 +96,7 @@ public class PlaceAgainstData {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO for playerMustBeFacing, do i need something like andThatOptionExtendsTheFullHorizontalSpaceOfTheVoxel()?
|
||||
// TODO for playerMustBeHorizontalFacing, do i need something like andThatOptionExtendsTheFullHorizontalSpaceOfTheVoxel()?
|
||||
|
||||
public boolean presentsAnOptionStrictlyInTheTopHalfOfTheStandardVoxelPlane() {
|
||||
if (Main.DEBUG && against.vertical) {
|
||||
|
||||
@@ -24,21 +24,21 @@ public class PlayerPhysics {
|
||||
*/
|
||||
public static int determinePlayerRealSupport(BlockStateCachedData underneath, BlockStateCachedData within) {
|
||||
if (within.collidesWithPlayer) {
|
||||
if (underneath.supportedPlayerY != null && underneath.supportedPlayerY - Blip.FULL_BLOCK > within.supportedPlayerY) { // TODO > or >=
|
||||
if (underneath.collisionHeightBlips != null && underneath.collisionHeightBlips - Blip.FULL_BLOCK > within.collisionHeightBlips) { // TODO > or >=
|
||||
if (!underneath.fullyWalkableTop) {
|
||||
return -1;
|
||||
}
|
||||
return underneath.supportedPlayerY - Blip.FULL_BLOCK; // this could happen if "underneath" is a fence and "within" is a carpet
|
||||
return underneath.collisionHeightBlips - Blip.FULL_BLOCK; // this could happen if "underneath" is a fence and "within" is a carpet
|
||||
}
|
||||
if (!within.fullyWalkableTop || within.supportedPlayerY >= Blip.FULL_BLOCK) {
|
||||
if (!within.fullyWalkableTop || within.collisionHeightBlips >= Blip.FULL_BLOCK) {
|
||||
return -1;
|
||||
}
|
||||
return within.supportedPlayerY;
|
||||
return within.collisionHeightBlips;
|
||||
} else {
|
||||
if (!underneath.fullyWalkableTop || underneath.supportedPlayerY < Blip.FULL_BLOCK) {
|
||||
if (!underneath.fullyWalkableTop || underneath.collisionHeightBlips < Blip.FULL_BLOCK) {
|
||||
return -1;
|
||||
}
|
||||
return underneath.supportedPlayerY - Blip.FULL_BLOCK;
|
||||
return underneath.collisionHeightBlips - Blip.FULL_BLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,13 +118,13 @@ public class PlayerPhysics {
|
||||
if (!D.collidesWithPlayer) {
|
||||
return Collision.FALL;
|
||||
}
|
||||
if (Main.DEBUG && D.supportedPlayerY == null) {
|
||||
if (Main.DEBUG && D.collisionHeightBlips == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (Main.DEBUG && D.supportedPlayerY >= Blip.FULL_BLOCK && D.fullyWalkableTop) {
|
||||
if (Main.DEBUG && D.collisionHeightBlips >= Blip.FULL_BLOCK && D.fullyWalkableTop) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (D.supportedPlayerY < Blip.FULL_BLOCK + feet) {
|
||||
if (D.collisionHeightBlips < Blip.FULL_BLOCK + feet) {
|
||||
return Collision.FALL;
|
||||
} else {
|
||||
return Collision.BLOCKED;
|
||||
|
||||
@@ -25,4 +25,13 @@ I'm not sure how to think about performance for this. Obviously there are copes
|
||||
|
||||
One particularly annoying thing is needing to reimplement portions of Minecraft. For example, there is a bit of code that I can easily call that says "If I looked in this direction right now, and right clicked, what block precisely would it place". Because, well, Minecraft needs to decide what block appears if and when I right click. This works great for current Baritone and I can just call it without needing to worry. For this builder though, I need to do hypotheticals. "If I were standing here on top of this block (that doesn't exist yet), looking at this face of this block (which doesn't exist yet), and right clicked while holding this item (which I don't have), what block would appear?". Minecraft code isn't built like that. There are so many conditions based on Y hit, face hit, player orientation, etc. Just look at the trapdoor place logic to instantly die. So I need to reimplement all the code for "I desire this block state (northward facing upside down acacia stairs). How can I make this coordinate contain that block? (well, you need to be facing north and right click the top face of an adjacent block with such a stair)". That code needs to be written for every block that has custom placement like that. The question of "If block X is at coordinate Y, could I right click against that to place block Z on face D" is incredibly frustratingly not easily answerable. It all depends on external variables like the horizontal orientation of the player, and even the Y coordinate of the player (for some blocks like pistons and dispensers).
|
||||
|
||||
I'm trying my best to minimize floating point calculations as much as possible. The fast case for the graph search should never use floating point. I'm too annoyed by even simple things like `> 1` being randomly wrong (with `0.99999` or `1.000001`). Also, no need to have path costs be floating point. Both path costs and player Y will be fixed point integers. Costs have a to-be-determined denominator, for player Y it's sixteen.
|
||||
I'm trying my best to minimize floating point calculations as much as possible. The fast case for the graph search should never use floating point. I'm too annoyed by even simple things like `> 1` being randomly wrong (with `0.99999` or `1.000001`). Also, no need to have path costs be floating point. Both path costs and player Y will be fixed point integers. Costs have a to-be-determined denominator, for player Y it's sixteen.
|
||||
|
||||
I'm going to list stupid things about Minecraft that have pissed me off during this:
|
||||
* Every `IBlockState` in the game has an entry in `Block.BLOCK_STATE_IDS`. Except for some variants of tripwire. Nothing else. Just tripwire is the exception. And it isn't even for a good or elegant reason. It's just hardcoded in the thing that constructs the block state registry to skip some of the tripwire states. No idea why.
|
||||
* `Block.BLOCK_STATE_IDS` has double entries. There are many states that map to the same integer ID, when you go back to states it sets certain properties to default. Such as `BlockStairs.SHAPE`.
|
||||
|
||||
Things about old Baritone builder that are stupid and that I will do better:
|
||||
* The thing I mentioned above about left and right clicking
|
||||
* Complete nonunderstanding of orientable blocks. It has no idea that in order to place a stair / a torch it has to go walk around and look at the block from the other side.
|
||||
* Instead of just placing blocks normally, it sneaks before EVERY right click. This makes it look unnatural, stupid, and jittery, for no reason.
|
||||
|
||||
@@ -94,8 +94,9 @@ public class Scaffolder {
|
||||
}
|
||||
|
||||
private ScaffoldingSearchNode dijkstra(CollapsedDependencyGraphComponent root) {
|
||||
Set<CollapsedDependencyGraphComponent> descendents = new ObjectOpenHashSet<>();
|
||||
walkAllDescendents(root, descendents);
|
||||
Set<CollapsedDependencyGraphComponent> exclusiveDescendents = new ObjectOpenHashSet<>();
|
||||
walkAllDescendents(root, exclusiveDescendents);
|
||||
exclusiveDescendents.remove(root);
|
||||
PriorityQueue<ScaffoldingSearchNode> openSet = new PriorityQueue<>(Comparator.comparingInt(node -> node.costSoFar));
|
||||
Long2ObjectOpenHashMap<ScaffoldingSearchNode> nodeMap = new Long2ObjectOpenHashMap<>();
|
||||
LongIterator it = root.getPositions().iterator();
|
||||
@@ -108,12 +109,15 @@ public class Scaffolder {
|
||||
ScaffoldingSearchNode node = openSet.poll();
|
||||
CollapsedDependencyGraphComponent tentativeComponent = componentLocations.get(node.pos);
|
||||
if (tentativeComponent != null) {
|
||||
if (descendents.contains(tentativeComponent)) {
|
||||
if (exclusiveDescendents.contains(tentativeComponent)) {
|
||||
// have gone back onto a descendent of this node
|
||||
// sadly this can happen even at the same Y level even in Y_STRICT mode due to orientable blocks forming a loop
|
||||
continue; // TODO does this need to be here? can I expand THROUGH an unrelated component? probably requires testing, this is quite a mind bending possibility
|
||||
} else {
|
||||
return node; // all done! found a path to a component unrelated to this one, meaning we have successfully connected this part of the build with scaffolding back to the rest of it
|
||||
// found a path to a component that isn't a descendent of the root
|
||||
if (tentativeComponent != root) { // but if it IS the root, then we're just on our first loop iteration, we are far from done
|
||||
return node; // all done! found a path to a component unrelated to this one, meaning we have successfully connected this part of the build with scaffolding back to the rest of it
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Face face : Face.VALUES) {
|
||||
@@ -127,7 +131,7 @@ public class Scaffolder {
|
||||
// we can accomplish this and kill two birds with one stone by skipping all nodes already in the node map
|
||||
// any position in the initial frontier is clearly in the node map, but also any node that has already been considered
|
||||
// this prevents useless cycling of equivalent paths
|
||||
// this is okay because our search has no heuristic so this is a uniform cost search
|
||||
// this is okay because all paths are equivalent, so there is no possible way to find a better path (because currently it's a fixed value for horizontal / vertical movements)
|
||||
if (existingNode.costSoFar < newCost) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@@ -157,7 +161,7 @@ public class Scaffolder {
|
||||
return 2;
|
||||
}
|
||||
|
||||
private class ScaffoldingSearchNode {
|
||||
private static class ScaffoldingSearchNode {
|
||||
|
||||
private final long pos;
|
||||
private int costSoFar;
|
||||
|
||||
@@ -38,6 +38,14 @@ public class Vec3d {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean inOriginUnitVoxel() {
|
||||
return x >= 0 && x <= 1 && y >= 0 && y <= 1 && z >= 0 && z <= 1;
|
||||
}
|
||||
|
||||
public Vec3d plus(double x, double y, double z) {
|
||||
return new Vec3d(this.x + x, this.y + y, this.z + z);
|
||||
}
|
||||
|
||||
public long getRoundedToZeroPositionUnsafeDontUse() {
|
||||
return BetterBlockPos.toLong((int) x, (int) y, (int) z);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,9 @@ package baritone.builder.mc;
|
||||
import baritone.builder.*;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -38,9 +37,12 @@ public class BlockStatePropertiesExtractor {
|
||||
Block block = state.getBlock();
|
||||
BlockStateCachedDataBuilder builder = new BlockStateCachedDataBuilder();
|
||||
|
||||
// returns null only if we don't know how to walk on / walk around / place against this block
|
||||
// if we don't know how to place the block, get everything else but add .placementLogicNotImplementedYe
|
||||
|
||||
// special cases
|
||||
{
|
||||
if (block instanceof BlockAir) {
|
||||
if (block instanceof BlockAir || block instanceof BlockStructureVoid) {
|
||||
return builder.setAir();
|
||||
}
|
||||
if (block instanceof BlockStairs) {
|
||||
@@ -58,30 +60,23 @@ public class BlockStatePropertiesExtractor {
|
||||
};
|
||||
if (!rightsideUp) {
|
||||
stairBuilder.fullyWalkableTop();
|
||||
stairBuilder.height(1);
|
||||
stairBuilder.collisionHeight(1);
|
||||
}
|
||||
return stairBuilder.mustBePlacedAgainst(rightsideUp ? Half.BOTTOM : Half.TOP)
|
||||
.collidesWithPlayer(true)
|
||||
.canPlaceAgainstMe()
|
||||
.playerMustBeFacingInOrderToPlaceMe(facing);
|
||||
.playerMustBeHorizontalFacingInOrderToPlaceMe(facing);
|
||||
}
|
||||
if (block instanceof BlockSlab) {
|
||||
double height;
|
||||
Half mustBePlacedAgainst;
|
||||
if (((BlockSlab) block).isDouble()) {
|
||||
height = 1;
|
||||
mustBePlacedAgainst = Half.EITHER;
|
||||
builder.placementLogicNotImplementedYet().collisionHeight(1);
|
||||
} else if (state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) {
|
||||
height = 0.5;
|
||||
mustBePlacedAgainst = Half.BOTTOM;
|
||||
builder.mustBePlacedAgainst(Half.BOTTOM).collisionHeight(0.5);
|
||||
} else {
|
||||
height = 1;
|
||||
mustBePlacedAgainst = Half.TOP;
|
||||
builder.mustBePlacedAgainst(Half.TOP).collisionHeight(1);
|
||||
}
|
||||
return builder
|
||||
.mustBePlacedAgainst(mustBePlacedAgainst)
|
||||
.fullyWalkableTop()
|
||||
.height(height)
|
||||
.canPlaceAgainstMe()
|
||||
.collidesWithPlayer(true);
|
||||
}
|
||||
@@ -93,12 +88,52 @@ public class BlockStatePropertiesExtractor {
|
||||
public List<BlockStatePlacementOption> howCanIBePlaced() {
|
||||
List<BlockStatePlacementOption> ret = new ArrayList<>();
|
||||
if (!(Main.STRICT_Y && !bottom)) {
|
||||
ret.add(BlockStatePlacementOption.get(bottom ? Face.DOWN : Face.UP, Half.EITHER, Optional.ofNullable(facing.opposite())));
|
||||
ret.add(BlockStatePlacementOption.get(bottom ? Face.DOWN : Face.UP, Half.EITHER, Optional.ofNullable(facing.opposite()), Optional.empty()));
|
||||
}
|
||||
ret.add(BlockStatePlacementOption.get(facing.opposite(), bottom ? Half.BOTTOM : Half.TOP, Optional.empty()));
|
||||
return Collections.unmodifiableList(ret);
|
||||
ret.add(BlockStatePlacementOption.get(facing.opposite(), bottom ? Half.BOTTOM : Half.TOP, Optional.empty(), Optional.empty()));
|
||||
return ret;
|
||||
}
|
||||
}.collidesWithPlayer(true); // TODO allow walking on top of closed top-half trapdoor? lol
|
||||
}.collidesWithPlayer(true); // dont allow walking on top of closed top-half trapdoor because redstone activation is scary and im not gonna predict it
|
||||
}
|
||||
if (block instanceof BlockLog) {
|
||||
BlockLog.EnumAxis axis = state.getValue(BlockLog.LOG_AXIS);
|
||||
BlockStateCachedDataBuilder logBuilder = new BlockStateCachedDataBuilder() {
|
||||
@Override
|
||||
public List<BlockStatePlacementOption> howCanIBePlaced() {
|
||||
List<BlockStatePlacementOption> ret = super.howCanIBePlaced();
|
||||
ret.removeIf(place -> BlockLog.EnumAxis.fromFacingAxis(place.against.toMC().getAxis()) != axis);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
if (axis == BlockLog.EnumAxis.NONE) {
|
||||
logBuilder.placementLogicNotImplementedYet(); // ugh
|
||||
}
|
||||
return logBuilder
|
||||
.fullyWalkableTop()
|
||||
.collisionHeight(1)
|
||||
.canPlaceAgainstMe()
|
||||
.collidesWithPlayer(true);
|
||||
}
|
||||
if (block instanceof BlockRotatedPillar) { // hay block, bone block
|
||||
// even though blocklog inherits from blockrotatedpillar it uses its own stupid enum, ugh
|
||||
// this is annoying because this is pretty much identical
|
||||
EnumFacing.Axis axis = state.getValue(BlockRotatedPillar.AXIS);
|
||||
BlockStateCachedDataBuilder rotatedPillarBuilder = new BlockStateCachedDataBuilder() {
|
||||
@Override
|
||||
public List<BlockStatePlacementOption> howCanIBePlaced() {
|
||||
List<BlockStatePlacementOption> ret = super.howCanIBePlaced();
|
||||
ret.removeIf(place -> place.against.toMC().getAxis() != axis);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
return rotatedPillarBuilder
|
||||
.fullyWalkableTop()
|
||||
.collisionHeight(1)
|
||||
.canPlaceAgainstMe()
|
||||
.collidesWithPlayer(true);
|
||||
}
|
||||
if (block instanceof BlockStructure) {
|
||||
return null; // truly an error to encounter this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,14 +142,14 @@ public class BlockStatePropertiesExtractor {
|
||||
|
||||
// rotated clockwise about the Y axis
|
||||
if (block instanceof BlockAnvil) {
|
||||
builder.playerMustBeFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockAnvil.FACING).rotateYCCW()));
|
||||
builder.playerMustBeHorizontalFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockAnvil.FACING).rotateYCCW()));
|
||||
}
|
||||
|
||||
// unchanged
|
||||
if (block instanceof BlockChest
|
||||
// it is not right || block instanceof BlockSkull // TODO is this right?? skull can be any facing?
|
||||
) { // TODO fence gate and lever
|
||||
builder.playerMustBeFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockHorizontal.FACING)));
|
||||
builder.playerMustBeHorizontalFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockHorizontal.FACING)));
|
||||
}
|
||||
|
||||
// opposite
|
||||
@@ -126,12 +161,27 @@ public class BlockStatePropertiesExtractor {
|
||||
|| block instanceof BlockPumpkin
|
||||
|| block instanceof BlockRedstoneDiode // both repeater and comparator
|
||||
) {
|
||||
builder.playerMustBeFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockHorizontal.FACING)).opposite());
|
||||
builder.playerMustBeHorizontalFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockHorizontal.FACING)).opposite());
|
||||
}
|
||||
}
|
||||
// getStateForPlacement.against is the against face. placing a torch will have it as UP. placing a bottom slab will have it as UP. placing a top slab will have it as DOWN.
|
||||
// ladder
|
||||
|
||||
{
|
||||
if (block instanceof BlockContainer || block instanceof BlockWorkbench) {
|
||||
builder.mustSneakWhenPlacingAgainstMe();
|
||||
}
|
||||
}
|
||||
|
||||
if (block instanceof BlockCommandBlock
|
||||
|| block instanceof BlockDispenser // dropper extends from dispenser
|
||||
|| block instanceof BlockPistonBase) {
|
||||
builder.playerMustBeEntityFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockDirectional.FACING)));
|
||||
}
|
||||
|
||||
if (block instanceof BlockObserver) {
|
||||
builder.playerMustBeEntityFacingInOrderToPlaceMe(Face.fromMC(state.getValue(BlockDirectional.FACING)).opposite());
|
||||
}
|
||||
|
||||
// fully passable blocks
|
||||
{
|
||||
// some ways of determining this list that don't work:
|
||||
@@ -159,39 +209,75 @@ public class BlockStatePropertiesExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO getDirectionFromEntityLiving
|
||||
if (block instanceof BlockFalling) {
|
||||
builder.falling();
|
||||
}
|
||||
|
||||
|
||||
// TODO multiblocks like door and bed and double plant
|
||||
|
||||
|
||||
boolean fullyUnderstood = false; // set this flag to true for any state for which we have fully and completely described it
|
||||
|
||||
// getStateForPlacement.against is the against face. placing a torch will have it as UP. placing a bottom slab will have it as UP. placing a top slab will have it as DOWN.
|
||||
|
||||
if (block instanceof BlockTorch) { // includes redstone torch
|
||||
builder.canOnlyPlaceAgainst(Face.fromMC(state.getValue(BlockTorch.FACING)).opposite());
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
if (block instanceof BlockShulkerBox) {
|
||||
builder.canOnlyPlaceAgainst(Face.fromMC(state.getValue(BlockShulkerBox.FACING)).opposite());
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
if (block instanceof BlockFenceGate // because if we place it we need to think about hypothetically walking through it
|
||||
|| block instanceof BlockLever
|
||||
|| block instanceof BlockButton
|
||||
|| block instanceof BlockBanner) {
|
||||
builder.placementLogicNotImplementedYet();
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
if (block instanceof BlockSapling
|
||||
|| block instanceof BlockRedstoneWire
|
||||
|| block instanceof BlockRailBase
|
||||
|| block instanceof BlockFlower
|
||||
|| block instanceof BlockDeadBush
|
||||
) {
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
//isBlockNormalCube=true implies isFullCube=true
|
||||
if (state.isBlockNormalCube() || state.isFullBlock() || block instanceof BlockGlass || block instanceof BlockStainedGlass) {
|
||||
builder.canPlaceAgainstMe();
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
if (state.isBlockNormalCube()) {
|
||||
builder.fullyWalkableTop().height(1);
|
||||
if ((state.isBlockNormalCube() || block instanceof BlockGlass || block instanceof BlockStainedGlass) && !(block instanceof BlockMagma || block instanceof BlockSlime)) {
|
||||
builder.fullyWalkableTop().collisionHeight(1);
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
if (block instanceof BlockSnow) {
|
||||
fullyUnderstood = true;
|
||||
if (state.getValue(BlockSnow.LAYERS) > 1) { // collidesWithPlayer false from earlier
|
||||
builder.fullyWalkableTop().height(0.125 * (state.getValue(BlockSnow.LAYERS) - 1));
|
||||
builder.fullyWalkableTop().collisionHeight(0.125 * (state.getValue(BlockSnow.LAYERS) - 1));
|
||||
// funny - if you have snow layers packed 8 high, it only supports the player to a height of 0.875, but it still counts as "isTopSolid" for placing stuff like torches on it
|
||||
}
|
||||
}
|
||||
|
||||
if (block instanceof BlockSoulSand) {
|
||||
builder.height(0.875);
|
||||
builder.collisionHeight(0.875).fakeLessThanFullHeight();
|
||||
fullyUnderstood = true;
|
||||
}
|
||||
|
||||
|
||||
// TODO fully walkable top and height
|
||||
|
||||
return builder;
|
||||
if (fullyUnderstood) {
|
||||
return builder;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
108
src/main/java/baritone/builder/mc/DebugStates.java
Normal file
108
src/main/java/baritone/builder/mc/DebugStates.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.builder.mc;
|
||||
|
||||
import baritone.builder.BlockStateCachedData;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DebugStates {
|
||||
|
||||
public static void debug() {
|
||||
Map<Block, List<IBlockState>> bts = new HashMap<>();
|
||||
Map<String, List<IBlockState>> byString = new HashMap<>();
|
||||
for (IBlockState state : Block.BLOCK_STATE_IDS) {
|
||||
//System.out.println(state);
|
||||
bts.computeIfAbsent(state.getBlock(), $ -> new ArrayList<>()).add(state);
|
||||
String str = toString(BlockStateCachedData.get(Block.BLOCK_STATE_IDS.get(state)));
|
||||
byString.computeIfAbsent(str, $ -> new ArrayList<>()).add(state);
|
||||
}
|
||||
for (String key : (Iterable<String>) byString.keySet().stream().sorted()::iterator) {
|
||||
System.out.println("\n");
|
||||
System.out.println(key);
|
||||
Set<Block> skip = new HashSet<>();
|
||||
List<IBlockState> matches = byString.get(key);
|
||||
for (IBlockState state : matches) {
|
||||
if (skip.contains(state.getBlock())) {
|
||||
continue;
|
||||
}
|
||||
if (matches.containsAll(bts.get(state.getBlock()))) {
|
||||
System.out.println("All " + bts.get(state.getBlock()).size() + " variants of " + state.getBlock());
|
||||
skip.add(state.getBlock());
|
||||
} else {
|
||||
System.out.println(state);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*System.out.println(Blocks.OAK_STAIRS.getDefaultState());
|
||||
System.out.println(Block.BLOCK_STATE_IDS.get(Blocks.OAK_STAIRS.getDefaultState()));
|
||||
System.out.println(Block.BLOCK_STATE_IDS.getByValue(Block.BLOCK_STATE_IDS.get(Blocks.OAK_STAIRS.getDefaultState())));*/
|
||||
Set<Block> normal = new HashSet<>();
|
||||
Block.REGISTRY.iterator().forEachRemaining(normal::add);
|
||||
Set<Block> alternate = new HashSet<>();
|
||||
for (IBlockState state : Block.BLOCK_STATE_IDS) {
|
||||
alternate.add(state.getBlock());
|
||||
}
|
||||
if (!alternate.equals(normal)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
outer:
|
||||
for (Block block : normal) {
|
||||
for (IBlockState state : block.getBlockState().getValidStates()) {
|
||||
if (Block.BLOCK_STATE_IDS.get(state) == -1) {
|
||||
System.out.println(state + " doesn't exist?!");
|
||||
continue;
|
||||
}
|
||||
if (block == Blocks.TRIPWIRE) {
|
||||
System.out.println(state + " does exist");
|
||||
}
|
||||
if (!Block.BLOCK_STATE_IDS.getByValue(Block.BLOCK_STATE_IDS.get(state)).equals(state)) {
|
||||
System.out.println(block + " is weird");
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String toString(BlockStateCachedData data) {
|
||||
if (data == null) {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
Map<String, String> props = new LinkedHashMap<>();
|
||||
props(data, props);
|
||||
return props.toString();
|
||||
}
|
||||
|
||||
private static void props(BlockStateCachedData data, Map<String, String> props) {
|
||||
if (data.isAir) {
|
||||
props.put("air", "true");
|
||||
return;
|
||||
}
|
||||
props.put("collides", "" + data.collidesWithPlayer);
|
||||
props.put("walkabletop", "" + data.fullyWalkableTop);
|
||||
props.put("placeme", "" + data.options.size());
|
||||
props.put("sneak", "" + data.mustSneakWhenPlacingAgainstMe);
|
||||
props.put("againstme", "" + Stream.of(data.againstMe).filter(Objects::nonNull).count());
|
||||
props.put("y", "" + data.collisionHeightBlips);
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
package baritone.builder.mc;
|
||||
|
||||
import baritone.builder.BlockStateCachedData;
|
||||
import baritone.builder.BlockStateCachedDataBuilder;
|
||||
import baritone.builder.IBlockStateDataProvider;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
@@ -36,7 +37,12 @@ public class VanillaBlockStateDataProvider implements IBlockStateDataProvider {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BlockStateCachedData(BlockStatePropertiesExtractor.getData(state));
|
||||
BlockStateCachedDataBuilder builder = BlockStatePropertiesExtractor.getData(state);
|
||||
if (builder == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new BlockStateCachedData(builder);
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
throw new RuntimeException("Exception while extracting " + state + " ID " + i, th);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user