diff --git a/src/api/java/baritone/api/command/datatypes/ForAxis.java b/src/api/java/baritone/api/command/datatypes/ForAxis.java
new file mode 100644
index 000000000..48efb39b7
--- /dev/null
+++ b/src/api/java/baritone/api/command/datatypes/ForAxis.java
@@ -0,0 +1,43 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.command.datatypes;
+
+import baritone.api.command.exception.CommandException;
+import baritone.api.command.helpers.TabCompleteHelper;
+import net.minecraft.util.EnumFacing;
+
+import java.util.Locale;
+import java.util.stream.Stream;
+
+public enum ForAxis implements IDatatypeFor {
+ INSTANCE;
+
+ @Override
+ public EnumFacing.Axis get(IDatatypeContext ctx) throws CommandException {
+ return EnumFacing.Axis.valueOf(ctx.getConsumer().getString().toUpperCase(Locale.US));
+ }
+
+ @Override
+ public Stream tabComplete(IDatatypeContext ctx) throws CommandException {
+ return new TabCompleteHelper()
+ .append(Stream.of(EnumFacing.Axis.values())
+ .map(EnumFacing.Axis::getName).map(String::toLowerCase))
+ .filterPrefix(ctx.getConsumer().getString())
+ .stream();
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/MaskSchematic.java b/src/api/java/baritone/api/schematic/MaskSchematic.java
index 229f58d5b..2853c6e58 100644
--- a/src/api/java/baritone/api/schematic/MaskSchematic.java
+++ b/src/api/java/baritone/api/schematic/MaskSchematic.java
@@ -17,6 +17,7 @@
package baritone.api.schematic;
+import baritone.api.schematic.mask.Mask;
import net.minecraft.block.state.IBlockState;
import java.util.List;
@@ -41,4 +42,14 @@ public abstract class MaskSchematic extends AbstractSchematic {
public IBlockState desiredState(int x, int y, int z, IBlockState current, List approxPlaceable) {
return schematic.desiredState(x, y, z, current, approxPlaceable);
}
+
+ public static MaskSchematic create(ISchematic schematic, Mask function) {
+ return new MaskSchematic(schematic) {
+
+ @Override
+ protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
+ return function.partOfMask(x, y, z, currentState);
+ }
+ };
+ }
}
diff --git a/src/api/java/baritone/api/schematic/mask/AbstractMask.java b/src/api/java/baritone/api/schematic/mask/AbstractMask.java
new file mode 100644
index 000000000..ce92af0ec
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/AbstractMask.java
@@ -0,0 +1,49 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask;
+
+/**
+ * @author Brady
+ */
+public abstract class AbstractMask implements Mask {
+
+ private final int widthX;
+ private final int heightY;
+ private final int lengthZ;
+
+ public AbstractMask(int widthX, int heightY, int lengthZ) {
+ this.widthX = widthX;
+ this.heightY = heightY;
+ this.lengthZ = lengthZ;
+ }
+
+ @Override
+ public int widthX() {
+ return this.widthX;
+ }
+
+ @Override
+ public int heightY() {
+ return this.heightY;
+ }
+
+ @Override
+ public int lengthZ() {
+ return this.lengthZ;
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/Mask.java b/src/api/java/baritone/api/schematic/mask/Mask.java
new file mode 100644
index 000000000..7df6f8f04
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/Mask.java
@@ -0,0 +1,60 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask;
+
+import baritone.api.schematic.mask.operator.BinaryOperatorMask;
+import baritone.api.schematic.mask.operator.NotMask;
+import baritone.api.utils.BooleanBinaryOperators;
+import net.minecraft.block.state.IBlockState;
+
+/**
+ * @author Brady
+ */
+public interface Mask {
+
+ /**
+ * @param x The relative x position of the block
+ * @param y The relative y position of the block
+ * @param z The relative z position of the block
+ * @param currentState The current state of that block in the world, may be {@code null}
+ * @return Whether the given position is included in this mask
+ */
+ boolean partOfMask(int x, int y, int z, IBlockState currentState);
+
+ int widthX();
+
+ int heightY();
+
+ int lengthZ();
+
+ default Mask not() {
+ return new NotMask(this);
+ }
+
+ default Mask union(Mask other) {
+ return new BinaryOperatorMask(this, other, BooleanBinaryOperators.OR);
+ }
+
+ default Mask intersection(Mask other) {
+ return new BinaryOperatorMask(this, other, BooleanBinaryOperators.AND);
+ }
+
+ default Mask xor(Mask other) {
+ return new BinaryOperatorMask(this, other, BooleanBinaryOperators.XOR);
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/PreComputedMask.java b/src/api/java/baritone/api/schematic/mask/PreComputedMask.java
new file mode 100644
index 000000000..aed26cc94
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/PreComputedMask.java
@@ -0,0 +1,44 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask;
+
+/**
+ * @author Brady
+ */
+final class PreComputedMask extends AbstractMask implements StaticMask {
+
+ private final boolean[][][] mask;
+
+ public PreComputedMask(StaticMask mask) {
+ super(mask.widthX(), mask.heightY(), mask.lengthZ());
+
+ this.mask = new boolean[this.heightY()][this.lengthZ()][this.widthX()];
+ for (int y = 0; y < this.heightY(); y++) {
+ for (int z = 0; z < this.lengthZ(); z++) {
+ for (int x = 0; x < this.widthX(); x++) {
+ this.mask[y][z][x] = mask.partOfMask(x, y, z);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ return this.mask[y][z][x];
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/StaticMask.java b/src/api/java/baritone/api/schematic/mask/StaticMask.java
new file mode 100644
index 000000000..220a94828
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/StaticMask.java
@@ -0,0 +1,82 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask;
+
+import baritone.api.schematic.mask.operator.BinaryOperatorMask;
+import baritone.api.schematic.mask.operator.NotMask;
+import baritone.api.utils.BooleanBinaryOperators;
+import net.minecraft.block.state.IBlockState;
+
+/**
+ * A mask that is context-free. In other words, it doesn't require the current block state to determine if a relative
+ * position is a part of the mask.
+ *
+ * @author Brady
+ */
+public interface StaticMask extends Mask {
+
+ /**
+ * Determines if a given relative coordinate is included in this mask, without the need for the current block state.
+ *
+ * @param x The relative x position of the block
+ * @param y The relative y position of the block
+ * @param z The relative z position of the block
+ * @return Whether the given position is included in this mask
+ */
+ boolean partOfMask(int x, int y, int z);
+
+ /**
+ * Implements the parent {@link Mask#partOfMask partOfMask function} by calling the static function
+ * provided in this functional interface without needing the {@link IBlockState} argument. This {@code default}
+ * implementation should NOT be overriden.
+ *
+ * @param x The relative x position of the block
+ * @param y The relative y position of the block
+ * @param z The relative z position of the block
+ * @param currentState The current state of that block in the world, may be {@code null}
+ * @return Whether the given position is included in this mask
+ */
+ @Override
+ default boolean partOfMask(int x, int y, int z, IBlockState currentState) {
+ return this.partOfMask(x, y, z);
+ }
+
+ @Override
+ default StaticMask not() {
+ return new NotMask.Static(this);
+ }
+
+ default StaticMask union(StaticMask other) {
+ return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.OR);
+ }
+
+ default StaticMask intersection(StaticMask other) {
+ return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.AND);
+ }
+
+ default StaticMask xor(StaticMask other) {
+ return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.XOR);
+ }
+
+ /**
+ * Returns a pre-computed mask using {@code this} function, with the specified size parameters.
+ */
+ default StaticMask compute() {
+ return new PreComputedMask(this);
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java b/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java
new file mode 100644
index 000000000..e591c7873
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/operator/BinaryOperatorMask.java
@@ -0,0 +1,71 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask.operator;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.Mask;
+import baritone.api.schematic.mask.StaticMask;
+import baritone.api.utils.BooleanBinaryOperator;
+import net.minecraft.block.state.IBlockState;
+
+/**
+ * @author Brady
+ */
+public final class BinaryOperatorMask extends AbstractMask {
+
+ private final Mask a;
+ private final Mask b;
+ private final BooleanBinaryOperator operator;
+
+ public BinaryOperatorMask(Mask a, Mask b, BooleanBinaryOperator operator) {
+ super(a.widthX(), a.heightY(), a.lengthZ());
+ this.a = a;
+ this.b = b;
+ this.operator = operator;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z, IBlockState currentState) {
+ return this.operator.applyAsBoolean(
+ this.a.partOfMask(x, y, z, currentState),
+ this.b.partOfMask(x, y, z, currentState)
+ );
+ }
+
+ public static final class Static extends AbstractMask implements StaticMask {
+
+ private final StaticMask a;
+ private final StaticMask b;
+ private final BooleanBinaryOperator operator;
+
+ public Static(StaticMask a, StaticMask b, BooleanBinaryOperator operator) {
+ super(a.widthX(), a.heightY(), a.lengthZ());
+ this.a = a;
+ this.b = b;
+ this.operator = operator;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ return this.operator.applyAsBoolean(
+ this.a.partOfMask(x, y, z),
+ this.b.partOfMask(x, y, z)
+ );
+ }
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/operator/NotMask.java b/src/api/java/baritone/api/schematic/mask/operator/NotMask.java
new file mode 100644
index 000000000..f9f770b82
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/operator/NotMask.java
@@ -0,0 +1,56 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask.operator;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.Mask;
+import baritone.api.schematic.mask.StaticMask;
+import net.minecraft.block.state.IBlockState;
+
+/**
+ * @author Brady
+ */
+public final class NotMask extends AbstractMask {
+
+ private final Mask source;
+
+ public NotMask(Mask source) {
+ super(source.widthX(), source.heightY(), source.lengthZ());
+ this.source = source;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z, IBlockState currentState) {
+ return !this.source.partOfMask(x, y, z, currentState);
+ }
+
+ public static final class Static extends AbstractMask implements StaticMask {
+
+ private final StaticMask source;
+
+ public Static(StaticMask source) {
+ super(source.widthX(), source.heightY(), source.lengthZ());
+ this.source = source;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ return !this.source.partOfMask(x, y, z);
+ }
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java b/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java
new file mode 100644
index 000000000..71b0d43c9
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/shape/CylinderMask.java
@@ -0,0 +1,69 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask.shape;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.StaticMask;
+import net.minecraft.util.EnumFacing;
+
+/**
+ * @author Brady
+ */
+public final class CylinderMask extends AbstractMask implements StaticMask {
+
+ private final double centerA;
+ private final double centerB;
+ private final double radiusSqA;
+ private final double radiusSqB;
+ private final boolean filled;
+ private final EnumFacing.Axis alignment;
+
+ public CylinderMask(int widthX, int heightY, int lengthZ, boolean filled, EnumFacing.Axis alignment) {
+ super(widthX, heightY, lengthZ);
+ this.centerA = this.getA(widthX, heightY) / 2.0;
+ this.centerB = this.getB(heightY, lengthZ) / 2.0;
+ this.radiusSqA = (this.centerA - 1) * (this.centerA - 1);
+ this.radiusSqB = (this.centerB - 1) * (this.centerB - 1);
+ this.filled = filled;
+ this.alignment = alignment;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ double da = Math.abs((this.getA(x, y) + 0.5) - this.centerA);
+ double db = Math.abs((this.getB(y, z) + 0.5) - this.centerB);
+ if (this.outside(da, db)) {
+ return false;
+ }
+ return this.filled
+ || this.outside(da + 1, db)
+ || this.outside(da, db + 1);
+ }
+
+ private boolean outside(double da, double db) {
+ return da * da / this.radiusSqA + db * db / this.radiusSqB > 1;
+ }
+
+ private int getA(int x, int y) {
+ return this.alignment == EnumFacing.Axis.X ? y : x;
+ }
+
+ private int getB(int y, int z) {
+ return this.alignment == EnumFacing.Axis.Z ? y : z;
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/mask/shape/SphereMask.java b/src/api/java/baritone/api/schematic/mask/shape/SphereMask.java
new file mode 100644
index 000000000..d805c98a8
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/mask/shape/SphereMask.java
@@ -0,0 +1,64 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.schematic.mask.shape;
+
+import baritone.api.schematic.mask.AbstractMask;
+import baritone.api.schematic.mask.StaticMask;
+
+/**
+ * @author Brady
+ */
+public final class SphereMask extends AbstractMask implements StaticMask {
+
+ private final double centerX;
+ private final double centerY;
+ private final double centerZ;
+ private final double radiusSqX;
+ private final double radiusSqY;
+ private final double radiusSqZ;
+ private final boolean filled;
+
+ public SphereMask(int widthX, int heightY, int lengthZ, boolean filled) {
+ super(widthX, heightY, lengthZ);
+ this.centerX = widthX / 2.0;
+ this.centerY = heightY / 2.0;
+ this.centerZ = lengthZ / 2.0;
+ this.radiusSqX = this.centerX * this.centerX;
+ this.radiusSqY = this.centerY * this.centerY;
+ this.radiusSqZ = this.centerZ * this.centerZ;
+ this.filled = filled;
+ }
+
+ @Override
+ public boolean partOfMask(int x, int y, int z) {
+ double dx = Math.abs((x + 0.5) - this.centerX);
+ double dy = Math.abs((y + 0.5) - this.centerY);
+ double dz = Math.abs((z + 0.5) - this.centerZ);
+ if (this.outside(dx, dy, dz)) {
+ return false;
+ }
+ return this.filled
+ || this.outside(dx + 1, dy, dz)
+ || this.outside(dx, dy + 1, dz)
+ || this.outside(dx, dy, dz + 1);
+ }
+
+ private boolean outside(double dx, double dy, double dz) {
+ return dx * dx / this.radiusSqX + dy * dy / this.radiusSqY + dz * dz / this.radiusSqZ > 1;
+ }
+}
diff --git a/src/api/java/baritone/api/utils/BooleanBinaryOperator.java b/src/api/java/baritone/api/utils/BooleanBinaryOperator.java
new file mode 100644
index 000000000..cfb85e644
--- /dev/null
+++ b/src/api/java/baritone/api/utils/BooleanBinaryOperator.java
@@ -0,0 +1,27 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.utils;
+
+/**
+ * @author Brady
+ */
+@FunctionalInterface
+public interface BooleanBinaryOperator {
+
+ boolean applyAsBoolean(boolean a, boolean b);
+}
diff --git a/src/api/java/baritone/api/utils/BooleanBinaryOperators.java b/src/api/java/baritone/api/utils/BooleanBinaryOperators.java
new file mode 100644
index 000000000..11605c965
--- /dev/null
+++ b/src/api/java/baritone/api/utils/BooleanBinaryOperators.java
@@ -0,0 +1,38 @@
+/*
+ * 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 .
+ */
+
+package baritone.api.utils;
+
+/**
+ * @author Brady
+ */
+public enum BooleanBinaryOperators implements BooleanBinaryOperator {
+ OR((a, b) -> a || b),
+ AND((a, b) -> a && b),
+ XOR((a, b) -> a ^ b);
+
+ private final BooleanBinaryOperator op;
+
+ BooleanBinaryOperators(BooleanBinaryOperator op) {
+ this.op = op;
+ }
+
+ @Override
+ public boolean applyAsBoolean(boolean a, boolean b) {
+ return this.op.applyAsBoolean(a, b);
+ }
+}
diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java
index d6c2e890d..9abe417ac 100644
--- a/src/main/java/baritone/command/defaults/SelCommand.java
+++ b/src/main/java/baritone/command/defaults/SelCommand.java
@@ -21,6 +21,7 @@ import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.command.Command;
import baritone.api.command.argument.IArgConsumer;
+import baritone.api.command.datatypes.ForAxis;
import baritone.api.command.datatypes.ForBlockOptionalMeta;
import baritone.api.command.datatypes.ForEnumFacing;
import baritone.api.command.datatypes.RelativeBlockPos;
@@ -31,6 +32,8 @@ import baritone.api.command.helpers.TabCompleteHelper;
import baritone.api.event.events.RenderEvent;
import baritone.api.event.listener.AbstractGameEventListener;
import baritone.api.schematic.*;
+import baritone.api.schematic.mask.shape.CylinderMask;
+import baritone.api.schematic.mask.shape.SphereMask;
import baritone.api.selection.ISelection;
import baritone.api.selection.ISelectionManager;
import baritone.api.utils.BetterBlockPos;
@@ -50,6 +53,7 @@ import java.awt.*;
import java.util.List;
import java.util.*;
import java.util.function.Function;
+import java.util.function.UnaryOperator;
import java.util.stream.Stream;
public class SelCommand extends Command {
@@ -117,11 +121,13 @@ public class SelCommand extends Command {
logDirect("Undid pos2");
}
}
- } else if (action == Action.SET || action == Action.WALLS || action == Action.SHELL || action == Action.CLEARAREA || action == Action.REPLACE) {
+ } else if (action.isFillAction()) {
BlockOptionalMeta type = action == Action.CLEARAREA
? new BlockOptionalMeta(Blocks.AIR)
: args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE);
- BlockOptionalMetaLookup replaces = null;
+
+ final BlockOptionalMetaLookup replaces; // Action.REPLACE
+ final EnumFacing.Axis alignment; // Action.(H)CYLINDER
if (action == Action.REPLACE) {
args.requireMin(1);
List replacesList = new ArrayList<>();
@@ -131,8 +137,15 @@ public class SelCommand extends Command {
}
type = args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE);
replaces = new BlockOptionalMetaLookup(replacesList.toArray(new BlockOptionalMeta[0]));
+ alignment = null;
+ } else if (action == Action.CYLINDER || action == Action.HCYLINDER) {
+ args.requireMax(1);
+ alignment = args.hasAny() ? args.getDatatypeFor(ForAxis.INSTANCE) : EnumFacing.Axis.Y;
+ replaces = null;
} else {
args.requireMax(0);
+ replaces = null;
+ alignment = null;
}
ISelection[] selections = manager.getSelections();
if (selections.length == 0) {
@@ -151,14 +164,35 @@ public class SelCommand extends Command {
for (ISelection selection : selections) {
Vec3i size = selection.size();
BetterBlockPos min = selection.min();
- ISchematic schematic = new FillSchematic(size.getX(), size.getY(), size.getZ(), type);
- if (action == Action.WALLS) {
- schematic = new WallsSchematic(schematic);
- } else if (action == Action.SHELL) {
- schematic = new ShellSchematic(schematic);
- } else if (action == Action.REPLACE) {
- schematic = new ReplaceSchematic(schematic, replaces);
- }
+
+ // Java 8 so no switch expressions 😿
+ UnaryOperator create = fill -> {
+ final int w = fill.widthX();
+ final int h = fill.heightY();
+ final int l = fill.lengthZ();
+
+ switch (action) {
+ case WALLS:
+ return new WallsSchematic(fill);
+ case SHELL:
+ return new ShellSchematic(fill);
+ case REPLACE:
+ return new ReplaceSchematic(fill, replaces);
+ case SPHERE:
+ return MaskSchematic.create(fill, new SphereMask(w, h, l, true).compute());
+ case HSPHERE:
+ return MaskSchematic.create(fill, new SphereMask(w, h, l, false).compute());
+ case CYLINDER:
+ return MaskSchematic.create(fill, new CylinderMask(w, h, l, true, alignment).compute());
+ case HCYLINDER:
+ return MaskSchematic.create(fill, new CylinderMask(w, h, l, false, alignment).compute());
+ default:
+ // Silent fail
+ return fill;
+ }
+ };
+
+ ISchematic schematic = create.apply(new FillSchematic(size.getX(), size.getY(), size.getZ(), type));
composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z);
}
baritone.getBuilderProcess().build("Fill", composite, origin);
@@ -254,12 +288,15 @@ public class SelCommand extends Command {
if (args.hasAtMost(3)) {
return args.tabCompleteDatatype(RelativeBlockPos.INSTANCE);
}
- } else if (action == Action.SET || action == Action.WALLS || action == Action.CLEARAREA || action == Action.REPLACE) {
+ } else if (action.isFillAction()) {
if (args.hasExactlyOne() || action == Action.REPLACE) {
while (args.has(2)) {
args.get();
}
return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE);
+ } else if (args.hasExactly(2) && (action == Action.CYLINDER || action == Action.HCYLINDER)) {
+ args.get();
+ return args.tabCompleteDatatype(ForAxis.INSTANCE);
}
} else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) {
if (args.hasExactlyOne()) {
@@ -305,6 +342,10 @@ public class SelCommand extends Command {
"> sel set/fill/s/f [block] - Completely fill all selections with a block.",
"> sel walls/w [block] - Fill in the walls of the selection with a specified block.",
"> sel shell/shl [block] - The same as walls, but fills in a ceiling and floor too.",
+ "> sel sphere/sph [block] - Fills the selection with a sphere bounded by the sides.",
+ "> sel hsphere/hsph [block] - The same as sphere, but hollow.",
+ "> sel cylinder/cyl [block] - Fills the selection with a cylinder bounded by the sides, oriented about the given axis. (default=y)",
+ "> sel hcylinder/hcyl [block] - The same as cylinder, but hollow.",
"> sel cleararea/ca - Basically 'set air'.",
"> sel replace/r - Replaces blocks with another block.",
"> sel copy/cp - Copy the selected area relative to the specified or your position.",
@@ -324,6 +365,10 @@ public class SelCommand extends Command {
SET("set", "fill", "s", "f"),
WALLS("walls", "w"),
SHELL("shell", "shl"),
+ SPHERE("sphere", "sph"),
+ HSPHERE("hsphere", "hsph"),
+ CYLINDER("cylinder", "cyl"),
+ HCYLINDER("hcylinder", "hcyl"),
CLEARAREA("cleararea", "ca"),
REPLACE("replace", "r"),
EXPAND("expand", "ex"),
@@ -355,6 +400,18 @@ public class SelCommand extends Command {
}
return names.toArray(new String[0]);
}
+
+ public final boolean isFillAction() {
+ return this == SET
+ || this == WALLS
+ || this == SHELL
+ || this == SPHERE
+ || this == HSPHERE
+ || this == CYLINDER
+ || this == HCYLINDER
+ || this == CLEARAREA
+ || this == REPLACE;
+ }
}
enum TransformTarget {