Selection shifting and such
This commit is contained in:
parent
289971557a
commit
65d2bdaf2b
@ -1,6 +1,7 @@
|
||||
package baritone.api.selection;
|
||||
|
||||
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
|
||||
@ -46,7 +47,52 @@ public interface ISelectionManager {
|
||||
* 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.
|
||||
*
|
||||
* @return The only selection.
|
||||
* @return The only selection, or null if there isn't only one.
|
||||
*/
|
||||
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.WallsSchematic;
|
||||
import baritone.api.selection.ISelection;
|
||||
import baritone.api.selection.ISelectionManager;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.BlockOptionalMeta;
|
||||
import baritone.api.utils.IRenderer;
|
||||
import baritone.api.utils.ISchematic;
|
||||
import baritone.api.utils.command.Command;
|
||||
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.exception.CommandInvalidStateException;
|
||||
import baritone.api.utils.command.exception.CommandInvalidTypeException;
|
||||
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
|
||||
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
@ -43,11 +46,13 @@ import java.awt.Color;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class SelCommand extends Command {
|
||||
private ISelectionManager manager = baritone.getSelectionManager();
|
||||
private BetterBlockPos pos1 = null;
|
||||
|
||||
public SelCommand() {
|
||||
@ -75,22 +80,36 @@ public class SelCommand extends Command {
|
||||
pos1 = pos;
|
||||
logDirect("Position 1 has been set");
|
||||
} else {
|
||||
baritone.getSelectionManager().addSelection(pos1, pos);
|
||||
manager.addSelection(pos1, pos);
|
||||
pos1 = null;
|
||||
logDirect("Selection added");
|
||||
}
|
||||
} else if (action == Action.CLEAR) {
|
||||
args.requireMax(0);
|
||||
pos1 = null;
|
||||
logDirect(String.format(
|
||||
"Removed %d selections",
|
||||
baritone.getSelectionManager().removeAllSelections().length
|
||||
));
|
||||
logDirect(String.format("Removed %d selections", manager.removeAllSelections().length));
|
||||
} else if (action == Action.UNDO) {
|
||||
args.requireMax(0);
|
||||
|
||||
if (pos1 != null) {
|
||||
pos1 = null;
|
||||
logDirect("Undid pos1");
|
||||
} 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
|
||||
? new BlockOptionalMeta(Blocks.AIR)
|
||||
: args.getDatatypeFor(ForBlockOptionalMeta.class);
|
||||
args.requireMax(0);
|
||||
ISelection[] selections = baritone.getSelectionManager().getSelections();
|
||||
ISelection[] selections = manager.getSelections();
|
||||
|
||||
if (selections.length == 0) {
|
||||
throw new CommandInvalidStateException("No selections");
|
||||
@ -125,6 +144,36 @@ public class SelCommand extends Command {
|
||||
|
||||
baritone.getBuilderProcess().build("Fill", composite, origin);
|
||||
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 == Action.POS1 || action == Action.POS2) {
|
||||
if (args.hasAtMost(3)) {
|
||||
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
|
||||
public List<String> getLongDesc() {
|
||||
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:",
|
||||
"> "
|
||||
"> 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 {
|
||||
POS1("pos1", "p1"),
|
||||
POS2("pos2", "p2"),
|
||||
POS1("pos1", "p1", "1"),
|
||||
POS2("pos2", "p2", "2"),
|
||||
|
||||
CLEAR("clear", "c"),
|
||||
UNDO("undo", "u"),
|
||||
|
||||
SET("set", "fill", "s", "f"),
|
||||
WALLS("walls", "w"),
|
||||
SHELL("shell", "sh"),
|
||||
CLEARAREA("cleararea", "ca");
|
||||
SHELL("shell", "shl"),
|
||||
CLEARAREA("cleararea", "ca"),
|
||||
|
||||
EXPAND("expand", "ex"),
|
||||
CONTRACT("contact", "ct"),
|
||||
SHIFT("shift", "sh");
|
||||
|
||||
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
|
||||
public void onRenderPass(RenderEvent event) {
|
||||
if (!settings.renderSelectionCorners.value || pos1 == null) {
|
||||
|
@ -116,9 +116,9 @@ public class Selection implements ISelection {
|
||||
@Override
|
||||
public ISelection contract(EnumFacing direction, int blocks) {
|
||||
if (isPos2(direction)) {
|
||||
return new Selection(pos1.offset(direction, -blocks), pos2);
|
||||
return new Selection(pos1.offset(direction, blocks), pos2);
|
||||
} 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.ISelectionManager;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
|
||||
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];
|
||||
|
||||
public SelectionManager() {
|
||||
@ -54,7 +55,60 @@ public class SelectionManager implements ISelectionManager {
|
||||
@Override
|
||||
public synchronized ISelection getOnlySelection() {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user