Merge pull request #3974 from cabaletta/pr/sel-shape-masks

Add sphere and cylinder build commands to sel
This commit is contained in:
leijurv
2023-06-12 12:57:01 -07:00
committed by GitHub
13 changed files with 682 additions and 11 deletions

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<EnumFacing.Axis> {
INSTANCE;
@Override
public EnumFacing.Axis get(IDatatypeContext ctx) throws CommandException {
return EnumFacing.Axis.valueOf(ctx.getConsumer().getString().toUpperCase(Locale.US));
}
@Override
public Stream<String> 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();
}
}

View File

@@ -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<IBlockState> 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);
}
};
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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];
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 <b><u>NOT</u></b> 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);
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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)
);
}
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
/**
* @author Brady
*/
@FunctionalInterface
public interface BooleanBinaryOperator {
boolean applyAsBoolean(boolean a, boolean b);
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@@ -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<BlockOptionalMeta> 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<ISchematic> 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] <axis> - Fills the selection with a cylinder bounded by the sides, oriented about the given axis. (default=y)",
"> sel hcylinder/hcyl [block] <axis> - The same as cylinder, but hollow.",
"> sel cleararea/ca - Basically 'set air'.",
"> sel replace/r <blocks...> <with> - Replaces blocks with another block.",
"> sel copy/cp <x> <y> <z> - 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 {