diff --git a/src/api/java/baritone/api/schematic/CylinderSchematic.java b/src/api/java/baritone/api/schematic/CylinderSchematic.java
new file mode 100644
index 000000000..3ba8bc9b8
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/CylinderSchematic.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import net.minecraft.block.state.IBlockState;
+
+/**
+ * @author Brady
+ */
+public class CylinderSchematic extends MaskSchematic {
+
+ private final double cx, cz, rx, rz;
+ private final boolean filled;
+
+ public CylinderSchematic(ISchematic schematic, boolean filled) {
+ super(schematic);
+ this.cx = schematic.widthX() / 2.0;
+ this.cz = schematic.lengthZ() / 2.0;
+ this.rx = this.cx * this.cx;
+ this.rz = this.cz * this.cz;
+ this.filled = filled;
+ }
+
+ @Override
+ protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
+ double dx = Math.abs((x + 0.5) - this.cx);
+ double dz = Math.abs((z + 0.5) - this.cz);
+ return !this.outside(dx, dz)
+ && (this.filled || outside(dx + 1, dz) || outside(dx, dz + 1));
+ }
+
+ private boolean outside(double dx, double dz) {
+ return dx * dx / this.rx + dz * dz / this.rz > 1;
+ }
+}
diff --git a/src/api/java/baritone/api/schematic/SphereSchematic.java b/src/api/java/baritone/api/schematic/SphereSchematic.java
new file mode 100644
index 000000000..0ca987760
--- /dev/null
+++ b/src/api/java/baritone/api/schematic/SphereSchematic.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.util.math.Vec3d;
+
+/**
+ * @author Brady
+ */
+public class SphereSchematic extends MaskSchematic {
+
+ private final double cx, cy, cz, rx, ry, rz;
+ private final boolean filled;
+
+ public SphereSchematic(ISchematic schematic, boolean filled) {
+ super(schematic);
+ this.cx = schematic.widthX() / 2.0;
+ this.cy = schematic.heightY() / 2.0;
+ this.cz = schematic.lengthZ() / 2.0;
+ this.rx = this.cx * this.cx;
+ this.ry = this.cy * this.cy;
+ this.rz = this.cz * this.cz;
+ this.filled = filled;
+ }
+
+ @Override
+ protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
+ double dx = Math.abs((x + 0.5) - this.cx);
+ double dy = Math.abs((y + 0.5) - this.cy);
+ double dz = Math.abs((z + 0.5) - this.cz);
+ return !this.outside(dx, dy, dz)
+ && (this.filled || outside(dx + 1, dy, dz) || outside(dx, dy + 1, dz) || outside(dx, dy, dz + 1));
+ }
+
+ private boolean outside(double dx,double dy, double dz) {
+ return dx * dx / this.rx + dy * dy / this.ry + dz * dz / this.rz > 1;
+ }
+}
diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java
index 5677eec3c..dcdd05b74 100644
--- a/src/main/java/baritone/command/defaults/SelCommand.java
+++ b/src/main/java/baritone/command/defaults/SelCommand.java
@@ -117,7 +117,7 @@ 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);
@@ -151,14 +151,10 @@ 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);
- }
+ ISchematic schematic = action.createFillMask(
+ new FillSchematic(size.getX(), size.getY(), size.getZ(), type),
+ replaces
+ );
composite.put(schematic, min.x - origin.x, min.y - origin.y, min.z - origin.z);
}
baritone.getBuilderProcess().build("Fill", composite, origin);
@@ -254,7 +250,7 @@ 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();
@@ -305,6 +301,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.",
+ "> 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 +324,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 +359,39 @@ 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;
+ }
+
+ public final ISchematic createFillMask(ISchematic fill, BlockOptionalMetaLookup replaces) {
+ switch (this) {
+ case WALLS:
+ return new WallsSchematic(fill);
+ case SHELL:
+ return new ShellSchematic(fill);
+ case REPLACE:
+ return new ReplaceSchematic(fill, replaces);
+ case SPHERE:
+ return new SphereSchematic(fill, true);
+ case HSPHERE:
+ return new SphereSchematic(fill, false);
+ case CYLINDER:
+ return new CylinderSchematic(fill, true);
+ case HCYLINDER:
+ return new CylinderSchematic(fill, false);
+ }
+ // Silent fail
+ return fill;
+ }
}
enum TransformTarget {