Selection shifting and such
This commit is contained in:
parent
289971557a
commit
65d2bdaf2b
@ -1,6 +1,7 @@
|
|||||||
package baritone.api.selection;
|
package baritone.api.selection;
|
||||||
|
|
||||||
import baritone.api.utils.BetterBlockPos;
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The selection manager handles setting Baritone's selections. You can set the selection here, as well as retrieving
|
* The selection manager handles setting Baritone's selections. You can set the selection here, as well as retrieving
|
||||||
@ -46,7 +47,52 @@ public interface ISelectionManager {
|
|||||||
* For anything expecting only one selection, this method is provided. However, to enforce multi-selection support,
|
* For anything expecting only one selection, this method is provided. However, to enforce multi-selection support,
|
||||||
* this method will only return a selection if there is ONLY one.
|
* this method will only return a selection if there is ONLY one.
|
||||||
*
|
*
|
||||||
* @return The only selection.
|
* @return The only selection, or null if there isn't only one.
|
||||||
*/
|
*/
|
||||||
ISelection getOnlySelection();
|
ISelection getOnlySelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method will always return the last selection. ONLY use this if you want to, for example, modify the most
|
||||||
|
* recent selection based on user input. ALWAYS use {@link #getOnlySelection()} or, ideally,
|
||||||
|
* {@link #getSelections()} for retrieving the content of selections.
|
||||||
|
*
|
||||||
|
* @return The last selection, or null if it doesn't exist.
|
||||||
|
*/
|
||||||
|
ISelection getLastSelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the specified {@link ISelection} with one expanded in the specified direction by the specified number of
|
||||||
|
* blocks. Returns the new selection.
|
||||||
|
*
|
||||||
|
* @param selection The selection to expand.
|
||||||
|
* @param direction The direction to expand the selection.
|
||||||
|
* @param blocks How many blocks to expand it.
|
||||||
|
* @return The new selection, expanded as specified.
|
||||||
|
*/
|
||||||
|
ISelection expand(ISelection selection, EnumFacing direction, int blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the specified {@link ISelection} with one contracted in the specified direction by the specified number
|
||||||
|
* of blocks.
|
||||||
|
*
|
||||||
|
* Note that, for example, if the direction specified is UP, the bottom of the selection will be shifted up. If it
|
||||||
|
* is DOWN, the top of the selection will be shifted down.
|
||||||
|
*
|
||||||
|
* @param selection The selection to contract.
|
||||||
|
* @param direction The direction to contract the selection.
|
||||||
|
* @param blocks How many blocks to contract it.
|
||||||
|
* @return The new selection, contracted as specified.
|
||||||
|
*/
|
||||||
|
ISelection contract(ISelection selection, EnumFacing direction, int blocks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the specified {@link ISelection} with one shifted in the specified direction by the specified number of
|
||||||
|
* blocks. This moves the whole selection.
|
||||||
|
*
|
||||||
|
* @param selection The selection to shift.
|
||||||
|
* @param direction The direction to shift the selection.
|
||||||
|
* @param blocks How many blocks to shift it.
|
||||||
|
* @return The new selection, shifted as specified.
|
||||||
|
*/
|
||||||
|
ISelection shift(ISelection selection, EnumFacing direction, int blocks);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
package baritone.api.utils.command.datatypes;
|
||||||
|
|
||||||
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ForEnumFacing implements IDatatypeFor<EnumFacing> {
|
||||||
|
private final EnumFacing facing;
|
||||||
|
|
||||||
|
public ForEnumFacing() {
|
||||||
|
facing = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForEnumFacing(ArgConsumer consumer) {
|
||||||
|
facing = EnumFacing.valueOf(consumer.getString().toUpperCase(Locale.US));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumFacing get() {
|
||||||
|
return facing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<String> tabComplete(ArgConsumer consumer) {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(
|
||||||
|
Arrays.stream(EnumFacing.values())
|
||||||
|
.map(EnumFacing::getName)
|
||||||
|
.map(String::toLowerCase)
|
||||||
|
)
|
||||||
|
.filterPrefix(consumer.getString())
|
||||||
|
.stream();
|
||||||
|
}
|
||||||
|
}
|
@ -24,18 +24,21 @@ import baritone.api.schematic.FillBomSchematic;
|
|||||||
import baritone.api.schematic.ShellSchematic;
|
import baritone.api.schematic.ShellSchematic;
|
||||||
import baritone.api.schematic.WallsSchematic;
|
import baritone.api.schematic.WallsSchematic;
|
||||||
import baritone.api.selection.ISelection;
|
import baritone.api.selection.ISelection;
|
||||||
|
import baritone.api.selection.ISelectionManager;
|
||||||
import baritone.api.utils.BetterBlockPos;
|
import baritone.api.utils.BetterBlockPos;
|
||||||
import baritone.api.utils.BlockOptionalMeta;
|
import baritone.api.utils.BlockOptionalMeta;
|
||||||
import baritone.api.utils.IRenderer;
|
import baritone.api.utils.IRenderer;
|
||||||
import baritone.api.utils.ISchematic;
|
import baritone.api.utils.ISchematic;
|
||||||
import baritone.api.utils.command.Command;
|
import baritone.api.utils.command.Command;
|
||||||
import baritone.api.utils.command.datatypes.ForBlockOptionalMeta;
|
import baritone.api.utils.command.datatypes.ForBlockOptionalMeta;
|
||||||
|
import baritone.api.utils.command.datatypes.ForEnumFacing;
|
||||||
import baritone.api.utils.command.datatypes.RelativeBlockPos;
|
import baritone.api.utils.command.datatypes.RelativeBlockPos;
|
||||||
import baritone.api.utils.command.exception.CommandInvalidStateException;
|
import baritone.api.utils.command.exception.CommandInvalidStateException;
|
||||||
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.Vec3i;
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
|
||||||
@ -43,11 +46,13 @@ import java.awt.Color;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
public class SelCommand extends Command {
|
public class SelCommand extends Command {
|
||||||
|
private ISelectionManager manager = baritone.getSelectionManager();
|
||||||
private BetterBlockPos pos1 = null;
|
private BetterBlockPos pos1 = null;
|
||||||
|
|
||||||
public SelCommand() {
|
public SelCommand() {
|
||||||
@ -75,22 +80,36 @@ public class SelCommand extends Command {
|
|||||||
pos1 = pos;
|
pos1 = pos;
|
||||||
logDirect("Position 1 has been set");
|
logDirect("Position 1 has been set");
|
||||||
} else {
|
} else {
|
||||||
baritone.getSelectionManager().addSelection(pos1, pos);
|
manager.addSelection(pos1, pos);
|
||||||
pos1 = null;
|
pos1 = null;
|
||||||
logDirect("Selection added");
|
logDirect("Selection added");
|
||||||
}
|
}
|
||||||
} else if (action == Action.CLEAR) {
|
} else if (action == Action.CLEAR) {
|
||||||
|
args.requireMax(0);
|
||||||
pos1 = null;
|
pos1 = null;
|
||||||
logDirect(String.format(
|
logDirect(String.format("Removed %d selections", manager.removeAllSelections().length));
|
||||||
"Removed %d selections",
|
} else if (action == Action.UNDO) {
|
||||||
baritone.getSelectionManager().removeAllSelections().length
|
args.requireMax(0);
|
||||||
));
|
|
||||||
|
if (pos1 != null) {
|
||||||
|
pos1 = null;
|
||||||
|
logDirect("Undid pos1");
|
||||||
} else {
|
} else {
|
||||||
|
ISelection[] selections = manager.getSelections();
|
||||||
|
|
||||||
|
if (selections.length < 1) {
|
||||||
|
throw new CommandInvalidStateException("Nothing to undo!");
|
||||||
|
} else {
|
||||||
|
pos1 = manager.removeSelection(selections[selections.length - 1]).pos1();
|
||||||
|
logDirect("Undid pos2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (action == Action.SET || action == Action.WALLS || action == Action.SHELL || action == Action.CLEARAREA) {
|
||||||
BlockOptionalMeta type = action == Action.CLEARAREA
|
BlockOptionalMeta type = action == Action.CLEARAREA
|
||||||
? new BlockOptionalMeta(Blocks.AIR)
|
? new BlockOptionalMeta(Blocks.AIR)
|
||||||
: args.getDatatypeFor(ForBlockOptionalMeta.class);
|
: args.getDatatypeFor(ForBlockOptionalMeta.class);
|
||||||
args.requireMax(0);
|
args.requireMax(0);
|
||||||
ISelection[] selections = baritone.getSelectionManager().getSelections();
|
ISelection[] selections = manager.getSelections();
|
||||||
|
|
||||||
if (selections.length == 0) {
|
if (selections.length == 0) {
|
||||||
throw new CommandInvalidStateException("No selections");
|
throw new CommandInvalidStateException("No selections");
|
||||||
@ -125,6 +144,36 @@ public class SelCommand extends Command {
|
|||||||
|
|
||||||
baritone.getBuilderProcess().build("Fill", composite, origin);
|
baritone.getBuilderProcess().build("Fill", composite, origin);
|
||||||
logDirect("Filling now");
|
logDirect("Filling now");
|
||||||
|
} else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) {
|
||||||
|
args.requireExactly(3);
|
||||||
|
TransformTarget transformTarget = TransformTarget.getByName(args.getString());
|
||||||
|
|
||||||
|
if (transformTarget == null) {
|
||||||
|
throw new CommandInvalidStateException("Invalid transform type");
|
||||||
|
}
|
||||||
|
|
||||||
|
EnumFacing direction = args.getDatatypeFor(ForEnumFacing.class);
|
||||||
|
int blocks = args.getAs(Integer.class);
|
||||||
|
|
||||||
|
ISelection[] selections = manager.getSelections();
|
||||||
|
|
||||||
|
if (selections.length < 1) {
|
||||||
|
throw new CommandInvalidStateException("No selections found");
|
||||||
|
}
|
||||||
|
|
||||||
|
selections = transformTarget.transform(selections);
|
||||||
|
|
||||||
|
for (ISelection selection : selections) {
|
||||||
|
if (action == Action.EXPAND) {
|
||||||
|
manager.expand(selection, direction, blocks);
|
||||||
|
} else if (action == Action.CONTRACT) {
|
||||||
|
manager.contract(selection, direction, blocks);
|
||||||
|
} else {
|
||||||
|
manager.shift(selection, direction, blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logDirect(String.format("Transformed %d selections", selections.length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,8 +190,28 @@ public class SelCommand extends Command {
|
|||||||
|
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
if (action == Action.POS1 || action == Action.POS2) {
|
if (action == Action.POS1 || action == Action.POS2) {
|
||||||
|
if (args.hasAtMost(3)) {
|
||||||
return args.tabCompleteDatatype(RelativeBlockPos.class);
|
return args.tabCompleteDatatype(RelativeBlockPos.class);
|
||||||
}
|
}
|
||||||
|
} else if (action == Action.SET || action == Action.WALLS || action == Action.CLEARAREA) {
|
||||||
|
if (args.hasExactlyOne()) {
|
||||||
|
return args.tabCompleteDatatype(ForBlockOptionalMeta.class);
|
||||||
|
}
|
||||||
|
} else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) {
|
||||||
|
if (args.hasExactlyOne()) {
|
||||||
|
return new TabCompleteHelper()
|
||||||
|
.append(TransformTarget.getAllNames())
|
||||||
|
.filterPrefix(args.getString())
|
||||||
|
.sortAlphabetically()
|
||||||
|
.stream();
|
||||||
|
} else {
|
||||||
|
TransformTarget target = TransformTarget.getByName(args.getString());
|
||||||
|
|
||||||
|
if (target != null && args.hasExactlyOne()) {
|
||||||
|
return args.tabCompleteDatatype(ForEnumFacing.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,21 +221,38 @@ public class SelCommand extends Command {
|
|||||||
@Override
|
@Override
|
||||||
public List<String> getLongDesc() {
|
public List<String> getLongDesc() {
|
||||||
return asList(
|
return asList(
|
||||||
|
"The sel command allows you to manipulate Baritone's selections, similarly to WorldEdit.",
|
||||||
"",
|
"",
|
||||||
|
"Using these selections, you can clear areas, fill them with blocks, or something else.",
|
||||||
"",
|
"",
|
||||||
"Usage:",
|
"Usage:",
|
||||||
"> "
|
"> sel pos1/p1/1 - Set position 1 to your current position.",
|
||||||
|
"> sel pos1/p1/1 <x> <y> <z> - Set position 1 to a relative position.",
|
||||||
|
"> sel pos2/p2/2 - Set position 2 to your current position.",
|
||||||
|
"> sel pos2/p2/2 <x> <y> <z> - Set position 2 to a relative position.",
|
||||||
|
"> sel clear/c - Clear the selection.",
|
||||||
|
"> sel undo/u - Undo the last action (setting positions, creating selections, etc.)",
|
||||||
|
"> sel walls/w [block] - Fill in the walls of the selection with a specified block, or the block in your hand.",
|
||||||
|
"> sel shell/sh [block] - The same as walls, but fills in a ceiling and floor too.",
|
||||||
|
"> sel cleararea/ca - Basically 'set air'."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Action {
|
enum Action {
|
||||||
POS1("pos1", "p1"),
|
POS1("pos1", "p1", "1"),
|
||||||
POS2("pos2", "p2"),
|
POS2("pos2", "p2", "2"),
|
||||||
|
|
||||||
CLEAR("clear", "c"),
|
CLEAR("clear", "c"),
|
||||||
|
UNDO("undo", "u"),
|
||||||
|
|
||||||
SET("set", "fill", "s", "f"),
|
SET("set", "fill", "s", "f"),
|
||||||
WALLS("walls", "w"),
|
WALLS("walls", "w"),
|
||||||
SHELL("shell", "sh"),
|
SHELL("shell", "shl"),
|
||||||
CLEARAREA("cleararea", "ca");
|
CLEARAREA("cleararea", "ca"),
|
||||||
|
|
||||||
|
EXPAND("expand", "ex"),
|
||||||
|
CONTRACT("contact", "ct"),
|
||||||
|
SHIFT("shift", "sh");
|
||||||
|
|
||||||
private final String[] names;
|
private final String[] names;
|
||||||
|
|
||||||
@ -197,6 +283,46 @@ public class SelCommand extends Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum TransformTarget {
|
||||||
|
ALL(sels -> sels, "all", "a"),
|
||||||
|
NEWEST(sels -> new ISelection[] {sels[0]}, "newest", "n"),
|
||||||
|
OLDEST(sels -> new ISelection[] {sels[sels.length - 1]}, "oldest", "o");
|
||||||
|
|
||||||
|
private final Function<ISelection[], ISelection[]> transform;
|
||||||
|
private final String[] names;
|
||||||
|
|
||||||
|
TransformTarget(Function<ISelection[], ISelection[]> transform, String... names) {
|
||||||
|
this.transform = transform;
|
||||||
|
this.names = names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISelection[] transform(ISelection[] selections) {
|
||||||
|
return transform.apply(selections);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransformTarget getByName(String name) {
|
||||||
|
for (TransformTarget target : TransformTarget.values()) {
|
||||||
|
for (String alias : target.names) {
|
||||||
|
if (alias.equalsIgnoreCase(name)) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] getAllNames() {
|
||||||
|
Set<String> names = new HashSet<>();
|
||||||
|
|
||||||
|
for (TransformTarget target : TransformTarget.values()) {
|
||||||
|
names.addAll(asList(target.names));
|
||||||
|
}
|
||||||
|
|
||||||
|
return names.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRenderPass(RenderEvent event) {
|
public void onRenderPass(RenderEvent event) {
|
||||||
if (!settings.renderSelectionCorners.value || pos1 == null) {
|
if (!settings.renderSelectionCorners.value || pos1 == null) {
|
||||||
|
@ -116,9 +116,9 @@ public class Selection implements ISelection {
|
|||||||
@Override
|
@Override
|
||||||
public ISelection contract(EnumFacing direction, int blocks) {
|
public ISelection contract(EnumFacing direction, int blocks) {
|
||||||
if (isPos2(direction)) {
|
if (isPos2(direction)) {
|
||||||
return new Selection(pos1.offset(direction, -blocks), pos2);
|
return new Selection(pos1.offset(direction, blocks), pos2);
|
||||||
} else {
|
} else {
|
||||||
return new Selection(pos1, pos2.offset(direction, -blocks));
|
return new Selection(pos1, pos2.offset(direction, blocks));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,13 @@ package baritone.selection;
|
|||||||
import baritone.api.selection.ISelection;
|
import baritone.api.selection.ISelection;
|
||||||
import baritone.api.selection.ISelectionManager;
|
import baritone.api.selection.ISelectionManager;
|
||||||
import baritone.api.utils.BetterBlockPos;
|
import baritone.api.utils.BetterBlockPos;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedList;
|
||||||
import java.util.Set;
|
import java.util.ListIterator;
|
||||||
|
|
||||||
public class SelectionManager implements ISelectionManager {
|
public class SelectionManager implements ISelectionManager {
|
||||||
private final Set<ISelection> selections = new LinkedHashSet<>();
|
private final LinkedList<ISelection> selections = new LinkedList<>();
|
||||||
private ISelection[] selectionsArr = new ISelection[0];
|
private ISelection[] selectionsArr = new ISelection[0];
|
||||||
|
|
||||||
public SelectionManager() {
|
public SelectionManager() {
|
||||||
@ -54,7 +55,60 @@ public class SelectionManager implements ISelectionManager {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized ISelection getOnlySelection() {
|
public synchronized ISelection getOnlySelection() {
|
||||||
if (selections.size() == 1) {
|
if (selections.size() == 1) {
|
||||||
return selections.iterator().next();
|
return selections.peekFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ISelection getLastSelection() {
|
||||||
|
return selections.peekLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized ISelection expand(ISelection selection, EnumFacing direction, int blocks) {
|
||||||
|
for (ListIterator<ISelection> it = selections.listIterator(); it.hasNext(); ) {
|
||||||
|
ISelection current = it.next();
|
||||||
|
|
||||||
|
if (current == selection) {
|
||||||
|
it.remove();
|
||||||
|
it.add(current.expand(direction, blocks));
|
||||||
|
resetSelectionsArr();
|
||||||
|
return it.previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized ISelection contract(ISelection selection, EnumFacing direction, int blocks) {
|
||||||
|
for (ListIterator<ISelection> it = selections.listIterator(); it.hasNext(); ) {
|
||||||
|
ISelection current = it.next();
|
||||||
|
|
||||||
|
if (current == selection) {
|
||||||
|
it.remove();
|
||||||
|
it.add(current.contract(direction, blocks));
|
||||||
|
resetSelectionsArr();
|
||||||
|
return it.previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized ISelection shift(ISelection selection, EnumFacing direction, int blocks) {
|
||||||
|
for (ListIterator<ISelection> it = selections.listIterator(); it.hasNext(); ) {
|
||||||
|
ISelection current = it.next();
|
||||||
|
|
||||||
|
if (current == selection) {
|
||||||
|
it.remove();
|
||||||
|
it.add(current.shift(direction, blocks));
|
||||||
|
resetSelectionsArr();
|
||||||
|
return it.previous();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
Loading…
Reference in New Issue
Block a user