Selection shifting and such

This commit is contained in:
Logan Darklock 2019-09-03 06:09:02 -07:00
parent 289971557a
commit 65d2bdaf2b
No known key found for this signature in database
GPG Key ID: B8C37CEDE1AC60EA
5 changed files with 284 additions and 20 deletions

View File

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

View File

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

View File

@ -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) {

View File

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

View File

@ -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;