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/CylinderSchematic.java b/src/api/java/baritone/api/schematic/CylinderSchematic.java index 055f12875..342c6e373 100644 --- a/src/api/java/baritone/api/schematic/CylinderSchematic.java +++ b/src/api/java/baritone/api/schematic/CylinderSchematic.java @@ -17,29 +17,39 @@ package baritone.api.schematic; +import net.minecraft.util.EnumFacing; + /** * @author Brady */ public final class CylinderSchematic extends CachedMaskSchematic { - public CylinderSchematic(ISchematic schematic, boolean filled) { + public CylinderSchematic(ISchematic schematic, boolean filled, EnumFacing.Axis alignment) { super(schematic, new StaticMaskFunction() { - private final double centerX = schematic.widthX() / 2.0; - private final double centerZ = schematic.lengthZ() / 2.0; - private final double radiusSqX = this.centerX * this.centerX; - private final double radiusSqZ = this.centerZ * this.centerZ; + private final double centerA = this.getA(schematic.widthX(), schematic.heightY()) / 2.0; + private final double centerB = this.getB(schematic.heightY(), schematic.lengthZ()) / 2.0; + private final double radiusSqA = this.centerA * this.centerA; + private final double radiusSqB = this.centerB * this.centerB; @Override public boolean partOfMask(int x, int y, int z) { - double dx = Math.abs((x + 0.5) - this.centerX); - double dz = Math.abs((z + 0.5) - this.centerZ); - return !this.outside(dx, dz) - && (filled || outside(dx + 1, dz) || outside(dx, dz + 1)); + double da = Math.abs((this.getA(x, y) + 0.5) - this.centerA); + double db = Math.abs((this.getB(y, z) + 0.5) - this.centerB); + return !this.outside(da, db) + && (filled || outside(da + 1, db) || outside(da, db + 1)); } - private boolean outside(double dx, double dz) { - return dx * dx / this.radiusSqX + dz * dz / this.radiusSqZ > 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 alignment == EnumFacing.Axis.X ? y : x; + } + + private int getB(int y, int z) { + return alignment == EnumFacing.Axis.Z ? y : z; } }); } diff --git a/src/main/java/baritone/command/defaults/SelCommand.java b/src/main/java/baritone/command/defaults/SelCommand.java index 85b3e4307..72c5cd1c0 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; @@ -122,7 +123,9 @@ public class SelCommand extends Command { BlockOptionalMeta type = action == Action.CLEARAREA ? new BlockOptionalMeta(Blocks.AIR) : args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE); - BlockOptionalMetaLookup replaces; + + final BlockOptionalMetaLookup replaces; // Action.REPLACE + final EnumFacing.Axis alignment; // Action.(H)CYLINDER if (action == Action.REPLACE) { args.requireMin(1); List replacesList = new ArrayList<>(); @@ -132,9 +135,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) { @@ -168,9 +177,9 @@ public class SelCommand extends Command { case HSPHERE: return new SphereSchematic(fill, false); case CYLINDER: - return new CylinderSchematic(fill, true); + return new CylinderSchematic(fill, true, alignment); case HCYLINDER: - return new CylinderSchematic(fill, false); + return new CylinderSchematic(fill, false, alignment); default: // Silent fail return fill; @@ -279,6 +288,12 @@ public class SelCommand extends Command { args.get(); } return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE); + } else if (action == Action.CYLINDER || action == Action.HCYLINDER) { + if (args.hasExactly(2)) { + if (args.getDatatypeForOrNull(ForBlockOptionalMeta.INSTANCE) != null) { + return args.tabCompleteDatatype(ForAxis.INSTANCE); + } + } } } else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) { if (args.hasExactlyOne()) { @@ -326,8 +341,8 @@ public class SelCommand extends Command { "> 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 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.",