Datatype Singletons

This commit is contained in:
Brady 2019-09-26 18:49:26 -05:00
parent 7292245b55
commit 595f5a35e0
No known key found for this signature in database
GPG Key ID: 73A788379A197567
35 changed files with 447 additions and 645 deletions

View File

@ -35,6 +35,8 @@ import javax.annotation.Nonnull;
*/
public final class BetterBlockPos extends BlockPos {
public static final BetterBlockPos ORIGIN = new BetterBlockPos(0, 0, 0);
public final int x;
public final int y;
public final int z;

View File

@ -25,7 +25,6 @@ import baritone.api.event.events.ChatEvent;
import baritone.api.event.events.TabCompleteEvent;
import baritone.api.event.listener.AbstractGameEventListener;
import baritone.api.utils.Helper;
import baritone.api.utils.IPlayerContext;
import baritone.api.utils.SettingsUtil;
import baritone.api.utils.command.argument.CommandArgument;
import baritone.api.utils.command.exception.CommandNotEnoughArgumentsException;
@ -33,6 +32,7 @@ import baritone.api.utils.command.exception.CommandNotFoundException;
import baritone.api.utils.command.execution.CommandExecution;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
import baritone.api.utils.command.manager.ICommandManager;
import com.mojang.realmsclient.util.Pair;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
@ -49,9 +49,8 @@ import java.util.stream.Stream;
public class BaritoneChatControl implements Helper, AbstractGameEventListener {
public final IBaritone baritone;
public final IPlayerContext ctx;
public final Settings settings = BaritoneAPI.getSettings();
private static final Settings settings = BaritoneAPI.getSettings();
private final ICommandManager manager;
/**
* In certain cases chat components need to execute commands for you. For example, the paginator automatically runs
@ -67,8 +66,7 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener {
public static String FORCE_COMMAND_PREFIX = String.format("<<%s>>", UUID.randomUUID().toString());
public BaritoneChatControl(IBaritone baritone) {
this.baritone = baritone;
this.ctx = baritone.getPlayerContext();
this.manager = baritone.getCommandManager();
baritone.getGameEventHandler().registerEventListener(this);
}
@ -123,15 +121,15 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener {
Pair<String, List<CommandArgument>> pair = CommandExecution.expand(msg);
String command = pair.first();
String rest = msg.substring(pair.first().length());
ArgConsumer argc = new ArgConsumer(pair.second());
ArgConsumer argc = new ArgConsumer(this.manager, pair.second());
if (!argc.hasAny()) {
Settings.Setting setting = settings.byLowerName.get(command.toLowerCase(Locale.US));
if (setting != null) {
logRanCommand(command, rest);
if (setting.getValueClass() == Boolean.class) {
this.baritone.getCommandManager().execute(String.format("set toggle %s", setting.getName()));
this.manager.execute(String.format("set toggle %s", setting.getName()));
} else {
this.baritone.getCommandManager().execute(String.format("set %s", setting.getName()));
this.manager.execute(String.format("set %s", setting.getName()));
}
return true;
}
@ -143,18 +141,18 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener {
if (setting.getName().equalsIgnoreCase(pair.first())) {
logRanCommand(command, rest);
try {
this.baritone.getCommandManager().execute(String.format("set %s %s", setting.getName(), argc.getString()));
this.manager.execute(String.format("set %s %s", setting.getName(), argc.getString()));
} catch (CommandNotEnoughArgumentsException ignored) {} // The operation is safe
return true;
}
}
}
CommandExecution execution = CommandExecution.from(this.baritone.getCommandManager(), pair);
CommandExecution execution = CommandExecution.from(this.manager, pair);
if (execution == null) {
return false;
}
logRanCommand(command, rest);
this.baritone.getCommandManager().execute(execution);
this.manager.execute(execution);
return true;
}
@ -180,11 +178,11 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener {
public Stream<String> tabComplete(String msg) {
try {
List<CommandArgument> args = CommandArgument.from(msg, true);
ArgConsumer argc = new ArgConsumer(args);
ArgConsumer argc = new ArgConsumer(this.manager, args);
if (argc.hasAtMost(2)) {
if (argc.hasExactly(1)) {
return new TabCompleteHelper()
.addCommands(this.baritone.getCommandManager())
.addCommands(this.manager)
.addSettings()
.filterPrefix(argc.getString())
.stream();
@ -204,7 +202,7 @@ public class BaritoneChatControl implements Helper, AbstractGameEventListener {
}
}
}
return this.baritone.getCommandManager().tabComplete(msg);
return this.manager.tabComplete(msg);
} catch (CommandNotEnoughArgumentsException ignored) { // Shouldn't happen, the operation is safe
return Stream.empty();
}

View File

@ -18,8 +18,6 @@
package baritone.api.utils.command.datatypes;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.exception.CommandNotEnoughArgumentsException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
@ -27,35 +25,28 @@ import net.minecraft.util.ResourceLocation;
import java.util.stream.Stream;
public class BlockById implements IDatatypeFor<Block> {
public enum BlockById implements IDatatypeFor<Block> {
INSTANCE;
public final Block block;
public BlockById() {
block = null;
}
public BlockById(ArgConsumer consumer) throws CommandNotEnoughArgumentsException {
ResourceLocation id = new ResourceLocation(consumer.getString());
@Override
public Block get(IDatatypeContext ctx) throws CommandException {
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
Block block;
if ((block = Block.REGISTRY.getObject(id)) == Blocks.AIR) {
throw new IllegalArgumentException("no block found by that id");
}
}
@Override
public Block get() {
return block;
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
return new TabCompleteHelper()
.append(
Block.REGISTRY.getKeys()
.stream()
.map(Object::toString)
)
.filterPrefixNamespaced(consumer.getString())
.filterPrefixNamespaced(ctx.getConsumer().getString())
.sortAlphabetically()
.stream();
}

View File

@ -26,35 +26,24 @@ import net.minecraft.util.ResourceLocation;
import java.util.stream.Stream;
public class EntityClassById implements IDatatypeFor<Class<? extends Entity>> {
public enum EntityClassById implements IDatatypeFor<Class<? extends Entity>> {
INSTANCE;
public final Class<? extends Entity> entity;
public EntityClassById() {
entity = null;
}
public EntityClassById(ArgConsumer consumer) throws CommandException {
ResourceLocation id = new ResourceLocation(consumer.getString());
@Override
public Class<? extends Entity> get(IDatatypeContext ctx) throws CommandException {
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
Class<? extends Entity> entity;
if ((entity = EntityList.REGISTRY.getObject(id)) == null) {
throw new IllegalArgumentException("no entity found by that id");
}
}
@Override
public Class<? extends Entity> get() {
return entity;
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
return new TabCompleteHelper()
.append(
EntityList.getEntityNameList()
.stream()
.map(Object::toString)
)
.filterPrefixNamespaced(consumer.getString())
.append(EntityList.getEntityNameList().stream().map(Object::toString))
.filterPrefixNamespaced(ctx.getConsumer().getString())
.sortAlphabetically()
.stream();
}

View File

@ -19,29 +19,19 @@ package baritone.api.utils.command.datatypes;
import baritone.api.utils.BlockOptionalMeta;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import java.util.stream.Stream;
public class ForBlockOptionalMeta implements IDatatypeFor<BlockOptionalMeta> {
public enum ForBlockOptionalMeta implements IDatatypeFor<BlockOptionalMeta> {
INSTANCE;
public final BlockOptionalMeta selector;
public ForBlockOptionalMeta() {
selector = null;
}
public ForBlockOptionalMeta(ArgConsumer consumer) throws CommandException {
selector = new BlockOptionalMeta(consumer.getString());
@Override
public BlockOptionalMeta get(IDatatypeContext ctx) throws CommandException {
return new BlockOptionalMeta(ctx.getConsumer().getString());
}
@Override
public BlockOptionalMeta get() {
return selector;
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) {
return consumer.tabCompleteDatatype(BlockById.class);
public Stream<String> tabComplete(IDatatypeContext ctx) {
return ctx.getConsumer().tabCompleteDatatype(BlockById.INSTANCE);
}
}

View File

@ -23,36 +23,23 @@ 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> {
public enum ForEnumFacing implements IDatatypeFor<EnumFacing> {
INSTANCE;
private final EnumFacing facing;
public ForEnumFacing() {
facing = null;
}
public ForEnumFacing(ArgConsumer consumer) throws CommandNotEnoughArgumentsException {
facing = EnumFacing.valueOf(consumer.getString().toUpperCase(Locale.US));
@Override
public EnumFacing get(IDatatypeContext ctx) throws CommandException {
return EnumFacing.valueOf(ctx.getConsumer().getString().toUpperCase(Locale.US));
}
@Override
public EnumFacing get() {
return facing;
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
return new TabCompleteHelper()
.append(
Stream.of(EnumFacing.values())
.map(EnumFacing::getName)
.map(String::toLowerCase)
)
.filterPrefix(consumer.getString())
.append(Stream.of(EnumFacing.values())
.map(EnumFacing::getName).map(String::toLowerCase))
.filterPrefix(ctx.getConsumer().getString())
.stream();
}
}

View File

@ -17,79 +17,64 @@
package baritone.api.utils.command.datatypes;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.cache.IWaypoint;
import baritone.api.cache.IWaypointCollection;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.exception.CommandNotEnoughArgumentsException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.Stream;
public class ForWaypoints implements IDatatypeFor<IWaypoint[]> {
public enum ForWaypoints implements IDatatypeFor<IWaypoint[]> {
INSTANCE;
private final IWaypoint[] waypoints;
@Override
public IWaypoint[] get(IDatatypeContext ctx) throws CommandException {
final String input = ctx.getConsumer().getString();
final IWaypoint.Tag tag = IWaypoint.Tag.getByName(input);
public ForWaypoints() {
waypoints = null;
}
public ForWaypoints(String arg) {
IWaypoint.Tag tag = IWaypoint.Tag.getByName(arg);
waypoints = tag == null ? getWaypointsByName(arg) : getWaypointsByTag(tag);
}
public ForWaypoints(ArgConsumer consumer) throws CommandNotEnoughArgumentsException {
this(consumer.getString());
// If the input doesn't resolve to a valid tag, resolve by name
return tag == null
? getWaypointsByName(ctx.getBaritone(), input)
: getWaypointsByTag(ctx.getBaritone(), tag);
}
@Override
public IWaypoint[] get() {
return waypoints;
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
return new TabCompleteHelper()
.append(getWaypointNames())
.append(getWaypointNames(ctx.getBaritone()))
.sortAlphabetically()
.prepend(IWaypoint.Tag.getAllNames())
.filterPrefix(consumer.getString())
.filterPrefix(ctx.getConsumer().getString())
.stream();
}
public static IWaypointCollection waypoints() {
return BaritoneAPI.getProvider()
.getPrimaryBaritone()
.getWorldProvider()
.getCurrentWorld()
.getWaypoints();
public static IWaypointCollection waypoints(IBaritone baritone) {
return baritone.getWorldProvider().getCurrentWorld().getWaypoints();
}
public static IWaypoint[] getWaypoints() {
return waypoints().getAllWaypoints().stream()
public static IWaypoint[] getWaypoints(IBaritone baritone) {
return waypoints(baritone).getAllWaypoints().stream()
.sorted(Comparator.comparingLong(IWaypoint::getCreationTimestamp).reversed())
.toArray(IWaypoint[]::new);
}
public static String[] getWaypointNames() {
return Stream.of(getWaypoints())
public static String[] getWaypointNames(IBaritone baritone) {
return Stream.of(getWaypoints(baritone))
.map(IWaypoint::getName)
.filter(name -> !name.isEmpty())
.toArray(String[]::new);
}
public static IWaypoint[] getWaypointsByTag(IWaypoint.Tag tag) {
return waypoints().getByTag(tag).stream()
public static IWaypoint[] getWaypointsByTag(IBaritone baritone, IWaypoint.Tag tag) {
return waypoints(baritone).getByTag(tag).stream()
.sorted(Comparator.comparingLong(IWaypoint::getCreationTimestamp).reversed())
.toArray(IWaypoint[]::new);
}
public static IWaypoint[] getWaypointsByName(String name) {
return Stream.of(getWaypoints())
public static IWaypoint[] getWaypointsByName(IBaritone baritone, String name) {
return Stream.of(getWaypoints(baritone))
.filter(waypoint -> waypoint.getName().equalsIgnoreCase(name))
.toArray(IWaypoint[]::new);
}

View File

@ -19,17 +19,14 @@ package baritone.api.utils.command.datatypes;
import baritone.api.utils.command.argparser.IArgParser;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.exception.CommandInvalidArgumentException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import java.util.stream.Stream;
/**
* Since interfaces cannot enforce the presence of a constructor, it's on you to make sure there is a constructor that
* accepts a single {@link ArgConsumer} argument. The constructor will perform all needed validation, and {@link
* ArgConsumer#getDatatype(Class)} will handle RuntimeExceptions and translate them into {@link
* CommandInvalidArgumentException}s. There must always be a constructor with no arguments so that {@link ArgConsumer}
* can create an instance for tab completion.
* @see IDatatypeContext
* @see IDatatypeFor
* @see IDatatypePost
*/
public interface IDatatype {
@ -41,9 +38,9 @@ public interface IDatatype {
* See {@link RelativeFile} for a very advanced example of tab completion. You wouldn't want this pasted into every
* command that uses files - right? Right?
*
* @param consumer The argument consumer to tab complete
* @param ctx The argument consumer to tab complete
* @return A stream representing the strings that can be tab completed. DO NOT INCLUDE SPACES IN ANY STRINGS.
* @see ArgConsumer#tabCompleteDatatype(Class)
* @see ArgConsumer#tabCompleteDatatype(IDatatype)
*/
Stream<String> tabComplete(ArgConsumer consumer) throws CommandException;
Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException;
}

View File

@ -0,0 +1,47 @@
/*
* 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.command.datatypes;
import baritone.api.IBaritone;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
/**
* Provides an {@link IDatatype} with contextual information so
* that it can perform the desired operation on the target level.
*
* @see IDatatype
*
* @author Brady
* @since 9/26/2019
*/
public interface IDatatypeContext {
/**
* Provides the {@link IBaritone} instance that is associated with the action relating to datatype handling.
*
* @return The context {@link IBaritone} instance.
*/
IBaritone getBaritone();
/**
* Provides the {@link ArgConsumer} to fetch input information from.
*
* @return The context {@link ArgConsumer}.
*/
ArgConsumer getConsumer();
}

View File

@ -17,7 +17,9 @@
package baritone.api.utils.command.datatypes;
import baritone.api.utils.command.exception.CommandException;
public interface IDatatypeFor<T> extends IDatatype {
T get();
T get(IDatatypeContext ctx) throws CommandException;
}

View File

@ -17,7 +17,18 @@
package baritone.api.utils.command.datatypes;
import baritone.api.utils.command.exception.CommandException;
public interface IDatatypePost<T, O> extends IDatatype {
T apply(O original);
/**
* Takes the expected input and transforms it based on the value held by {@code original}. If {@code original}
* is null, it is expected that the implementation of this method has a case to handle it, such that a
* {@link NullPointerException} will never be thrown as a result.
*
* @param ctx The datatype context
* @param original The transformable value
* @return The transformed value
*/
T apply(IDatatypeContext ctx, O original) throws CommandException;
}

View File

@ -0,0 +1,29 @@
/*
* 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.command.datatypes;
import baritone.api.utils.command.exception.CommandException;
/**
* @author Brady
* @since 9/26/2019
*/
public interface IDatatypePostFunction<T, O> {
T apply(O original) throws CommandException;
}

View File

@ -17,10 +17,8 @@
package baritone.api.utils.command.datatypes;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import baritone.api.utils.command.helpers.tabcomplete.TabCompleteHelper;
import net.minecraft.entity.player.EntityPlayer;
@ -31,43 +29,27 @@ import java.util.stream.Stream;
* An {@link IDatatype} used to resolve nearby players, those within
* render distance of the target {@link IBaritone} instance.
*/
public class NearbyPlayer implements IDatatypeFor<EntityPlayer> {
public enum NearbyPlayer implements IDatatypeFor<EntityPlayer> {
INSTANCE;
private final List<EntityPlayer> players =
BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext().world().playerEntities;
public final EntityPlayer player;
public NearbyPlayer() {
player = null;
}
public NearbyPlayer(ArgConsumer consumer) throws CommandException {
String username = consumer.getString();
player = players
.stream()
@Override
public EntityPlayer get(IDatatypeContext ctx) throws CommandException {
final String username = ctx.getConsumer().getString();
return getPlayers(ctx).stream()
.filter(s -> s.getName().equalsIgnoreCase(username))
.findFirst()
.orElse(null);
if (player == null) {
throw new IllegalArgumentException("no player found by that username");
}
.findFirst().orElse(null);
}
@Override
public EntityPlayer get() {
return player;
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
return new TabCompleteHelper()
.append(
players
.stream()
.map(EntityPlayer::getName)
)
.filterPrefix(consumer.getString())
.append(getPlayers(ctx).stream().map(EntityPlayer::getName))
.filterPrefix(ctx.getConsumer().getString())
.sortAlphabetically()
.stream();
}
private static List<EntityPlayer> getPlayers(IDatatypeContext ctx) {
return ctx.getBaritone().getPlayerContext().world().playerEntities;
}
}

View File

@ -23,43 +23,34 @@ import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import java.util.stream.Stream;
public class RelativeBlockPos implements IDatatypePost<BetterBlockPos, BetterBlockPos> {
final RelativeCoordinate x;
final RelativeCoordinate y;
final RelativeCoordinate z;
public RelativeBlockPos() {
x = null;
y = null;
z = null;
}
public RelativeBlockPos(ArgConsumer consumer) throws CommandException {
x = consumer.getDatatype(RelativeCoordinate.class);
y = consumer.getDatatype(RelativeCoordinate.class);
z = consumer.getDatatype(RelativeCoordinate.class);
}
public enum RelativeBlockPos implements IDatatypePost<BetterBlockPos, BetterBlockPos> {
INSTANCE;
@Override
public BetterBlockPos apply(BetterBlockPos origin) {
public BetterBlockPos apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
if (origin == null) {
origin = BetterBlockPos.ORIGIN;
}
final ArgConsumer consumer = ctx.getConsumer();
return new BetterBlockPos(
x.apply((double) origin.x),
y.apply((double) origin.y),
z.apply((double) origin.z)
consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x),
consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y),
consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.z)
);
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
final ArgConsumer consumer = ctx.getConsumer();
if (consumer.hasAny() && !consumer.has(4)) {
while (consumer.has(2)) {
if (consumer.peekDatatypeOrNull(RelativeCoordinate.class) == null) {
if (consumer.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) == null) {
break;
}
consumer.get();
}
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
}
return Stream.empty();
}

View File

@ -18,7 +18,6 @@
package baritone.api.utils.command.datatypes;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.exception.CommandNotEnoughArgumentsException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import net.minecraft.util.math.MathHelper;
@ -26,40 +25,37 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class RelativeCoordinate implements IDatatypePost<Double, Double> {
public enum RelativeCoordinate implements IDatatypePost<Double, Double> {
INSTANCE;
public static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$");
final boolean isRelative;
final double offset;
private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|)$");
public RelativeCoordinate() {
isRelative = true;
offset = 0;
}
@Override
public Double apply(IDatatypeContext ctx, Double origin) throws CommandException {
if (origin == null) {
origin = 0.0D;
}
public RelativeCoordinate(ArgConsumer consumer) throws CommandNotEnoughArgumentsException {
Matcher matcher = PATTERN.matcher(consumer.getString());
System.out.println(ctx.getConsumer().args);
new Throwable().printStackTrace();
Matcher matcher = PATTERN.matcher(ctx.getConsumer().getString());
if (!matcher.matches()) {
throw new IllegalArgumentException("pattern doesn't match");
}
isRelative = !matcher.group(1).isEmpty();
offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2));
}
@Override
public Double apply(Double origin) {
boolean isRelative = !matcher.group(1).isEmpty();
double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2));
if (isRelative) {
return origin + offset;
}
return offset;
}
public int applyFloor(double origin) {
return MathHelper.floor(apply(origin));
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) throws CommandException {
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
final ArgConsumer consumer = ctx.getConsumer();
if (!consumer.has(2) && consumer.getString().matches("^(~|$)")) {
return Stream.of("~");
}

View File

@ -18,7 +18,6 @@
package baritone.api.utils.command.datatypes;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.exception.CommandNotEnoughArgumentsException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import java.io.File;
@ -27,31 +26,32 @@ import java.io.UncheckedIOException;
import java.nio.file.FileSystems;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Stream;
import static baritone.api.utils.Helper.HELPER;
public class RelativeFile implements IDatatypePost<File, File> {
public enum RelativeFile implements IDatatypePost<File, File> {
INSTANCE;
private final Path path;
@Override
public File apply(IDatatypeContext ctx, File original) throws CommandException {
if (original == null) {
original = new File("./");
}
public RelativeFile() {
path = null;
}
public RelativeFile(ArgConsumer consumer) throws CommandNotEnoughArgumentsException {
Path path;
try {
path = FileSystems.getDefault().getPath(consumer.getString());
path = FileSystems.getDefault().getPath(ctx.getConsumer().getString());
} catch (InvalidPathException e) {
throw new IllegalArgumentException("invalid path");
}
return getCanonicalFileUnchecked(original.toPath().resolve(path).toFile());
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) {
public Stream<String> tabComplete(IDatatypeContext ctx) {
return Stream.empty();
}
@ -93,11 +93,6 @@ public class RelativeFile implements IDatatypePost<File, File> {
.filter(s -> !s.contains(" "));
}
@Override
public File apply(File original) {
return getCanonicalFileUnchecked(original.toPath().resolve(path).toFile());
}
public static File gameDir() {
File gameDir = HELPER.mc.gameDir.getAbsoluteFile();
if (gameDir.getName().equals(".")) {

View File

@ -24,56 +24,56 @@ import baritone.api.pathing.goals.GoalYLevel;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import net.minecraft.util.math.MathHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class RelativeGoal implements IDatatypePost<Goal, BetterBlockPos> {
final RelativeCoordinate[] coords;
public RelativeGoal() {
coords = new RelativeCoordinate[0];
}
public RelativeGoal(ArgConsumer consumer) throws CommandException {
List<RelativeCoordinate> coordsList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
if (consumer.peekDatatypeOrNull(RelativeCoordinate.class) != null) {
coordsList.add(consumer.getDatatype(RelativeCoordinate.class));
}
}
coords = coordsList.toArray(new RelativeCoordinate[0]);
}
public enum RelativeGoal implements IDatatypePost<Goal, BetterBlockPos> {
INSTANCE;
@Override
public Goal apply(BetterBlockPos origin) {
switch (coords.length) {
public Goal apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
if (origin == null) {
origin = BetterBlockPos.ORIGIN;
}
final ArgConsumer consumer = ctx.getConsumer();
List<IDatatypePostFunction<Double, Double>> coords = new ArrayList<>();
final ArgConsumer copy = consumer.copy(); // This is a hack and should be fixed in the future probably
for (int i = 0; i < 3; i++) {
if (copy.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) {
coords.add(o -> consumer.getDatatypePost(RelativeCoordinate.INSTANCE, o));
copy.get(); // Consume so we actually decrement the remaining arguments
}
}
switch (coords.size()) {
case 0:
return new GoalBlock(origin);
case 1:
return new GoalYLevel(
coords[0].applyFloor(origin.y)
MathHelper.floor(coords.get(0).apply((double) origin.y))
);
case 2:
return new GoalXZ(
coords[0].applyFloor(origin.x),
coords[1].applyFloor(origin.z)
MathHelper.floor(coords.get(0).apply((double) origin.x)),
MathHelper.floor(coords.get(1).apply((double) origin.z))
);
case 3:
return new GoalBlock(
coords[0].applyFloor(origin.x),
coords[1].applyFloor(origin.y),
coords[2].applyFloor(origin.z)
MathHelper.floor(coords.get(0).apply((double) origin.x)),
MathHelper.floor(coords.get(1).apply((double) origin.y)),
MathHelper.floor(coords.get(2).apply((double) origin.z))
);
default:
throw new IllegalStateException("Unexpected coords size: " + coords.length);
throw new IllegalStateException("Unexpected coords size: " + coords.size());
}
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) {
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
public Stream<String> tabComplete(IDatatypeContext ctx) {
return ctx.getConsumer().tabCompleteDatatype(RelativeCoordinate.INSTANCE);
}
}

View File

@ -20,40 +20,29 @@ package baritone.api.utils.command.datatypes;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.exception.CommandInvalidTypeException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import net.minecraft.util.math.MathHelper;
import java.util.stream.Stream;
public class RelativeGoalBlock implements IDatatypePost<GoalBlock, BetterBlockPos> {
final RelativeCoordinate[] coords;
public RelativeGoalBlock() {
coords = new RelativeCoordinate[0];
}
public RelativeGoalBlock(ArgConsumer consumer) throws CommandException {
coords = new RelativeCoordinate[]{
consumer.getDatatype(RelativeCoordinate.class),
consumer.getDatatype(RelativeCoordinate.class),
consumer.getDatatype(RelativeCoordinate.class)
};
}
public enum RelativeGoalBlock implements IDatatypePost<GoalBlock, BetterBlockPos> {
INSTANCE;
@Override
public GoalBlock apply(BetterBlockPos origin) {
public GoalBlock apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
final ArgConsumer consumer = ctx.getConsumer();
return new GoalBlock(
coords[0].applyFloor(origin.x),
coords[1].applyFloor(origin.y),
coords[2].applyFloor(origin.z)
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x)),
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y)),
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.z))
);
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) {
public Stream<String> tabComplete(IDatatypeContext ctx) {
final ArgConsumer consumer = ctx.getConsumer();
if (consumer.hasAtMost(3)) {
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
}
return Stream.empty();
}

View File

@ -21,36 +21,27 @@ import baritone.api.pathing.goals.GoalXZ;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import net.minecraft.util.math.MathHelper;
import java.util.stream.Stream;
public class RelativeGoalXZ implements IDatatypePost<GoalXZ, BetterBlockPos> {
final RelativeCoordinate[] coords;
public RelativeGoalXZ() {
coords = new RelativeCoordinate[0];
}
public RelativeGoalXZ(ArgConsumer consumer) throws CommandException {
coords = new RelativeCoordinate[]{
consumer.getDatatype(RelativeCoordinate.class),
consumer.getDatatype(RelativeCoordinate.class)
};
}
public enum RelativeGoalXZ implements IDatatypePost<GoalXZ, BetterBlockPos> {
INSTANCE;
@Override
public GoalXZ apply(BetterBlockPos origin) {
public GoalXZ apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
final ArgConsumer consumer = ctx.getConsumer();
return new GoalXZ(
coords[0].applyFloor(origin.x),
coords[1].applyFloor(origin.z)
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x)),
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y))
);
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) {
public Stream<String> tabComplete(IDatatypeContext ctx) {
final ArgConsumer consumer = ctx.getConsumer();
if (consumer.hasAtMost(2)) {
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
}
return Stream.empty();
}

View File

@ -21,30 +21,25 @@ import baritone.api.pathing.goals.GoalYLevel;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.command.exception.CommandException;
import baritone.api.utils.command.helpers.arguments.ArgConsumer;
import net.minecraft.util.math.MathHelper;
import java.util.stream.Stream;
public class RelativeGoalYLevel implements IDatatypePost<GoalYLevel, BetterBlockPos> {
public enum RelativeGoalYLevel implements IDatatypePost<GoalYLevel, BetterBlockPos> {
INSTANCE;
final RelativeCoordinate coord;
public RelativeGoalYLevel() {
coord = null;
}
public RelativeGoalYLevel(ArgConsumer consumer) throws CommandException {
coord = consumer.getDatatype(RelativeCoordinate.class);
@Override
public GoalYLevel apply(IDatatypeContext ctx, BetterBlockPos origin) throws CommandException {
return new GoalYLevel(
MathHelper.floor(ctx.getConsumer().getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y))
);
}
@Override
public GoalYLevel apply(BetterBlockPos origin) {
return new GoalYLevel(coord.applyFloor(origin.y));
}
@Override
public Stream<String> tabComplete(ArgConsumer consumer) {
public Stream<String> tabComplete(IDatatypeContext ctx) {
final ArgConsumer consumer = ctx.getConsumer();
if (consumer.hasAtMost(1)) {
return consumer.tabCompleteDatatype(RelativeCoordinate.class);
return consumer.tabCompleteDatatype(RelativeCoordinate.INSTANCE);
}
return Stream.empty();
}

View File

@ -93,7 +93,7 @@ public class CommandExecution {
}
public static CommandExecution from(ICommandManager manager, Pair<String, List<CommandArgument>> pair) {
return from(manager, pair.first(), new ArgConsumer(pair.second()));
return from(manager, pair.first(), new ArgConsumer(manager, pair.second()));
}
public static CommandExecution from(ICommandManager manager, String string) {

View File

@ -17,15 +17,14 @@
package baritone.api.utils.command.helpers.arguments;
import baritone.api.IBaritone;
import baritone.api.utils.Helper;
import baritone.api.utils.command.Command;
import baritone.api.utils.command.argparser.IArgParser;
import baritone.api.utils.command.argument.CommandArgument;
import baritone.api.utils.command.datatypes.IDatatype;
import baritone.api.utils.command.datatypes.IDatatypeFor;
import baritone.api.utils.command.datatypes.IDatatypePost;
import baritone.api.utils.command.datatypes.RelativeFile;
import baritone.api.utils.command.datatypes.*;
import baritone.api.utils.command.exception.*;
import baritone.api.utils.command.manager.ICommandManager;
import net.minecraft.util.EnumFacing;
import java.lang.reflect.InvocationTargetException;
@ -56,22 +55,39 @@ import java.util.stream.Stream;
*/
public class ArgConsumer {
/**
* The parent {@link ICommandManager} for this {@link ArgConsumer}. Used by {@link #context}.
*/
private final ICommandManager manager;
/**
* The {@link IDatatypeContext} instance for this {@link ArgConsumer}, passed to
* datatypes when an operation is performed upon them.
*
* @see IDatatype
* @see IDatatypeContext
*/
private final IDatatypeContext context;
/**
* The list of arguments in this ArgConsumer
*/
public final LinkedList<CommandArgument> args;
/**
* The list of consumed arguments for this ArgConsumer. The most recently consumed argument is the last one
*/
public final Deque<CommandArgument> consumed;
private ArgConsumer(Deque<CommandArgument> args, Deque<CommandArgument> consumed) {
private ArgConsumer(ICommandManager manager, Deque<CommandArgument> args, Deque<CommandArgument> consumed) {
this.manager = manager;
this.context = this.new Context();
this.args = new LinkedList<>(args);
this.consumed = new LinkedList<>(consumed);
}
public ArgConsumer(List<CommandArgument> args) {
this(new LinkedList<>(args), new LinkedList<>());
public ArgConsumer(ICommandManager manager, List<CommandArgument> args) {
this(manager, new LinkedList<>(args), new LinkedList<>());
}
/**
@ -156,9 +172,6 @@ public class ArgConsumer {
* @see #peek(int)
* @see #peekString()
* @see #peekAs(Class)
* @see #peekDatatype(Class)
* @see #peekDatatypeFor(Class)
* @see #peekDatatypePost(Class, Object)
* @see #get()
*/
public CommandArgument peek() throws CommandNotEnoughArgumentsException {
@ -390,92 +403,35 @@ public class ArgConsumer {
return peekAsOrNull(type, 0);
}
/**
* Attempts to get the specified datatype from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
*
* @param datatype The datatype to get
* @return The datatype instance
* @see IDatatype
*/
public <T extends IDatatype> T peekDatatype(Class<T> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return copy().getDatatype(datatype);
public <T> T peekDatatype(IDatatypeFor<T> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return copy().getDatatypeFor(datatype);
}
/**
* Attempts to get the specified datatype from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
*
* @param datatype The datatype to get
* @return The datatype instance, or {@code null} if it throws an exception
* @see IDatatype
*/
public <T extends IDatatype> T peekDatatypeOrNull(Class<T> datatype) throws CommandNotEnoughArgumentsException {
return copy().getDatatypeOrNull(datatype);
public <T, O> T peekDatatype(IDatatypePost<T, O> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return this.peekDatatype(datatype, null);
}
/**
* Attempts to get the specified {@link IDatatypePost} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
*
* @param datatype The datatype to get
* @return The datatype instance
* @see IDatatype
* @see IDatatypePost
*/
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePost(Class<D> datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
public <T, O> T peekDatatype(IDatatypePost<T, O> datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return copy().getDatatypePost(datatype, original);
}
/**
* Attempts to get the specified {@link IDatatypePost} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
*
* @param datatype The datatype to get
* @param def The default value
* @return The datatype instance, or {@code def} if it throws an exception
* @see IDatatype
* @see IDatatypePost
*/
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePostOrDefault(Class<D> datatype, O original, T def) {
public <T> T peekDatatypeOrNull(IDatatypeFor<T> datatype) {
return copy().getDatatypeForOrNull(datatype);
}
public <T, O> T peekDatatypeOrNull(IDatatypePost<T, O> datatype) {
return copy().getDatatypePostOrNull(datatype, null);
}
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePost(D datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return copy().getDatatypePost(datatype, original);
}
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePostOrDefault(D datatype, O original, T def) {
return copy().getDatatypePostOrDefault(datatype, original, def);
}
/**
* Attempts to get the specified {@link IDatatypePost} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* Since this is a peek operation, this ArgConsumer will not be mutated by any call to this method.
*
* @param datatype The datatype to get
* @return The datatype instance, or {@code null} if it throws an exception
* @see IDatatype
* @see IDatatypePost
*/
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePostOrNull(Class<D> datatype, O original) {
public <T, O, D extends IDatatypePost<T, O>> T peekDatatypePostOrNull(D datatype, O original) {
return peekDatatypePostOrDefault(datatype, original, null);
}
@ -689,198 +645,65 @@ public class ArgConsumer {
return getAsOrDefault(type, null);
}
/**
* Attempts to get the specified datatype from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
*
* @param datatype The datatype to get
* @return The datatype instance
* @see IDatatype
*/
public <T extends IDatatype> T getDatatype(Class<T> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePost(D datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
try {
return datatype.getConstructor(ArgConsumer.class).newInstance(this);
} catch (InvocationTargetException e) {
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getSimpleName());
} catch (NoSuchMethodException | IllegalAccessException | InstantiationException e) {
throw new CommandUnhandledException(e);
}
}
/**
* Attempts to get the specified datatype from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* The state of this {@link ArgConsumer} is restored if the datatype could not be gotten.
*
* @param datatype The datatype to get
* @return The datatype instance, or {@code null} if it throws an exception
* @see IDatatype
*/
public <T extends IDatatype> T getDatatypeOrNull(Class<T> datatype) throws CommandNotEnoughArgumentsException {
List<CommandArgument> argsSnapshot = new ArrayList<>(args);
List<CommandArgument> consumedSnapshot = new ArrayList<>(consumed);
try {
return getDatatype(datatype);
} catch (CommandInvalidTypeException e) {
args.clear();
args.addAll(argsSnapshot);
consumed.clear();
consumed.addAll(consumedSnapshot);
return null;
}
}
/**
* Attempts to get the specified {@link IDatatypePost} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
*
* @param datatype The datatype to get
* @return The datatype instance
* @see IDatatype
* @see IDatatypePost
*/
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePost(Class<D> datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return getDatatype(datatype).apply(original);
}
/**
* Attempts to get the specified {@link IDatatypePost} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* The state of this {@link ArgConsumer} is restored if the datatype could not be gotten.
*
* @param datatype The datatype to get
* @param def The default value
* @return The datatype instance, or {@code def} if it throws an exception
* @see IDatatype
* @see IDatatypePost
*/
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePostOrDefault(Class<D> datatype, O original, T def) {
List<CommandArgument> argsSnapshot = new ArrayList<>(args);
List<CommandArgument> consumedSnapshot = new ArrayList<>(consumed);
try {
return getDatatypePost(datatype, original);
} catch (CommandException e) {
args.clear();
args.addAll(argsSnapshot);
consumed.clear();
consumed.addAll(consumedSnapshot);
return def;
}
}
/**
* Attempts to get the specified {@link IDatatypePost} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* The state of this {@link ArgConsumer} is restored if the datatype could not be gotten.
*
* @param datatype The datatype to get
* @return The datatype instance, or {@code null} if it throws an exception
* @see IDatatype
* @see IDatatypePost
*/
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePostOrNull(Class<D> datatype, O original) {
return getDatatypePostOrDefault(datatype, original, null);
}
/**
* Attempts to get the specified {@link IDatatypeFor} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
*
* @param datatype The datatype to get
* @return The datatype instance
* @see IDatatype
* @see IDatatypeFor
*/
public <T, D extends IDatatypeFor<T>> T getDatatypeFor(Class<D> datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
return getDatatype(datatype).get();
}
/**
* Attempts to get the specified {@link IDatatypeFor} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* The state of this {@link ArgConsumer} is restored if the datatype could not be gotten.
*
* @param datatype The datatype to get
* @param def The default value
* @return The datatype instance, or {@code def} if it throws an exception
* @see IDatatype
* @see IDatatypeFor
*/
public <T, D extends IDatatypeFor<T>> T getDatatypeForOrDefault(Class<D> datatype, T def) throws CommandNotEnoughArgumentsException {
List<CommandArgument> argsSnapshot = new ArrayList<>(args);
List<CommandArgument> consumedSnapshot = new ArrayList<>(consumed);
try {
return getDatatypeFor(datatype);
} catch (CommandInvalidTypeException e) {
args.clear();
args.addAll(argsSnapshot);
consumed.clear();
consumed.addAll(consumedSnapshot);
return def;
}
}
/**
* Attempts to get the specified {@link IDatatypeFor} from this ArgConsumer
* <p>
* A critical difference between {@link IDatatype}s and {@link IArgParser}s is how many arguments they can take.
* While {@link IArgParser}s always operate on a single argument's value, {@link IDatatype}s get access to the entire
* {@link ArgConsumer}.
* <p>
* The state of this {@link ArgConsumer} is restored if the datatype could not be gotten.
*
* @param datatype The datatype to get
* @return The datatype instance, or {@code null} if it throws an exception
* @see IDatatype
* @see IDatatypeFor
*/
public <T, D extends IDatatypeFor<T>> T getDatatypeForOrNull(Class<D> datatype) throws CommandNotEnoughArgumentsException {
return getDatatypeForOrDefault(datatype, null);
}
/**
* One benefit over datatypes over {@link IArgParser}s is that instead of each command trying to guess what values
* the datatype will accept, or simply not tab completing at all, datatypes that support tab completion can provide
* accurate information using the same methods used to parse arguments in the first place.
* <p>
* See {@link RelativeFile} for a very advanced example of tab completion. You wouldn't want this pasted into every
* command that uses files - right? Right?
*
* @param datatype The datatype to get tab completions from
* @return A stream representing the strings that can be tab completed. DO NOT INCLUDE SPACES IN ANY STRINGS.
* @see IDatatype#tabComplete(ArgConsumer)
*/
public <T extends IDatatype> Stream<String> tabCompleteDatatype(Class<T> datatype) {
try {
return datatype.getConstructor().newInstance().tabComplete(this);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
return datatype.apply(this.context, original);
} catch (Exception e) {
e.printStackTrace();
} catch (CommandException ignored) {}
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName());
}
}
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePostOrDefault(D datatype, O original, T _default) {
final List<CommandArgument> argsSnapshot = new ArrayList<>(this.args);
final List<CommandArgument> consumedSnapshot = new ArrayList<>(this.consumed);
try {
return this.getDatatypePost(datatype, original);
} catch (Exception e) {
this.args.clear();
this.args.addAll(argsSnapshot);
this.consumed.clear();
this.consumed.addAll(consumedSnapshot);
return _default;
}
}
public <T, O, D extends IDatatypePost<T, O>> T getDatatypePostOrNull(D datatype, O original) {
return this.getDatatypePostOrDefault(datatype, original, null);
}
public <T, D extends IDatatypeFor<T>> T getDatatypeFor(D datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException {
try {
return datatype.get(this.context);
} catch (Exception e) {
throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName());
}
}
public <T, D extends IDatatypeFor<T>> T getDatatypeForOrDefault(D datatype, T def) {
final List<CommandArgument> argsSnapshot = new ArrayList<>(this.args);
final List<CommandArgument> consumedSnapshot = new ArrayList<>(this.consumed);
try {
return this.getDatatypeFor(datatype);
} catch (Exception e) {
this.args.clear();
this.args.addAll(argsSnapshot);
this.consumed.clear();
this.consumed.addAll(consumedSnapshot);
return def;
}
}
public <T, D extends IDatatypeFor<T>> T getDatatypeForOrNull(D datatype) {
return this.getDatatypeForOrDefault(datatype, null);
}
public <T extends IDatatype> Stream<String> tabCompleteDatatype(T datatype) {
try {
return datatype.tabComplete(this.context);
} catch (Exception e) {
e.printStackTrace();
}
return Stream.empty();
}
@ -972,15 +795,19 @@ public class ArgConsumer {
* affect or mutate this instance. Useful for the various {@code peek} functions
*/
public ArgConsumer copy() {
return new ArgConsumer(args, consumed);
return new ArgConsumer(manager, args, consumed);
}
/**
* @param string The string to split
* @return A new {@link ArgConsumer} constructed from the specified string
* @see CommandArgument#from(String)
*/
public static ArgConsumer from(String string) {
return new ArgConsumer(CommandArgument.from(string));
private final class Context implements IDatatypeContext {
@Override
public final IBaritone getBaritone() {
return ArgConsumer.this.manager.getBaritone();
}
@Override
public final ArgConsumer getConsumer() {
return ArgConsumer.this;
}
}
}

View File

@ -17,6 +17,7 @@
package baritone.api.utils.command.manager;
import baritone.api.IBaritone;
import baritone.api.utils.command.Command;
import baritone.api.utils.command.argument.CommandArgument;
import baritone.api.utils.command.execution.CommandExecution;
@ -32,6 +33,8 @@ import java.util.stream.Stream;
*/
public interface ICommandManager {
IBaritone getBaritone();
Registry<Command> getRegistry();
/**

View File

@ -44,7 +44,7 @@ public class BuildCommand extends Command {
@Override
protected void executed(String label, ArgConsumer args) throws CommandException {
File file = args.getDatatypePost(RelativeFile.class, schematicsDir).getAbsoluteFile();
File file = args.getDatatypePost(RelativeFile.INSTANCE, schematicsDir).getAbsoluteFile();
if (!file.getName().toLowerCase(Locale.US).endsWith(".schematic")) {
file = new File(file.getAbsolutePath() + ".schematic");
}
@ -52,7 +52,7 @@ public class BuildCommand extends Command {
BetterBlockPos buildOrigin;
if (args.hasAny()) {
args.requireMax(3);
buildOrigin = args.getDatatype(RelativeBlockPos.class).apply(origin);
buildOrigin = args.getDatatypePost(RelativeBlockPos.INSTANCE, origin);
} else {
args.requireMax(0);
buildOrigin = origin;
@ -70,7 +70,7 @@ public class BuildCommand extends Command {
return RelativeFile.tabComplete(args, schematicsDir);
} else if (args.has(2)) {
args.get();
return args.tabCompleteDatatype(RelativeBlockPos.class);
return args.tabCompleteDatatype(RelativeBlockPos.INSTANCE);
}
return Stream.empty();
}

View File

@ -44,7 +44,7 @@ public class ClearareaCommand extends Command {
BetterBlockPos pos2;
if (args.hasAny()) {
args.requireMax(3);
pos2 = args.getDatatype(RelativeBlockPos.class).apply(pos1);
pos2 = args.getDatatypePost(RelativeBlockPos.INSTANCE, pos1);
} else {
args.requireMax(0);
Goal goal = baritone.getCustomGoalProcess().getGoal();
@ -60,7 +60,7 @@ public class ClearareaCommand extends Command {
@Override
protected Stream<String> tabCompleted(String label, ArgConsumer args) {
return args.tabCompleteDatatype(RelativeBlockPos.class);
return args.tabCompleteDatatype(RelativeBlockPos.INSTANCE);
}
@Override

View File

@ -43,7 +43,7 @@ public class ExploreCommand extends Command {
args.requireMax(0);
}
GoalXZ goal = args.hasAny()
? args.getDatatypePost(RelativeGoalXZ.class, ctx.playerFeet())
? args.getDatatypePost(RelativeGoalXZ.INSTANCE, ctx.playerFeet())
: new GoalXZ(ctx.playerFeet());
baritone.getExploreProcess().explore(goal.getX(), goal.getZ());
logDirect(String.format("Exploring from %s", goal.toString()));
@ -52,7 +52,7 @@ public class ExploreCommand extends Command {
@Override
protected Stream<String> tabCompleted(String label, ArgConsumer args) {
if (args.hasAtMost(2)) {
return args.tabCompleteDatatype(RelativeGoalXZ.class);
return args.tabCompleteDatatype(RelativeGoalXZ.INSTANCE);
}
return Stream.empty();
}

View File

@ -42,7 +42,7 @@ public class ExploreFilterCommand extends Command {
@Override
protected void executed(String label, ArgConsumer args) throws CommandException {
args.requireMax(2);
File file = args.getDatatypePost(RelativeFile.class, mc.gameDir.getAbsoluteFile().getParentFile());
File file = args.getDatatypePost(RelativeFile.INSTANCE, mc.gameDir.getAbsoluteFile().getParentFile());
boolean invert = false;
if (args.hasAny()) {
if (args.getString().equalsIgnoreCase("invert")) {

View File

@ -41,7 +41,7 @@ public class FindCommand extends Command {
protected void executed(String label, ArgConsumer args) throws CommandException {
List<Block> toFind = new ArrayList<>();
while (args.hasAny()) {
toFind.add(args.getDatatypeFor(BlockById.class));
toFind.add(args.getDatatypeFor(BlockById.INSTANCE));
}
BetterBlockPos origin = ctx.playerFeet();
toFind.stream()
@ -61,7 +61,7 @@ public class FindCommand extends Command {
@Override
protected Stream<String> tabCompleted(String label, ArgConsumer args) {
return args.tabCompleteDatatype(BlockById.class);
return args.tabCompleteDatatype(BlockById.INSTANCE);
}
@Override

View File

@ -56,7 +56,6 @@ public class FollowCommand extends Command {
group = null;
list = args.getEnum(FollowList.class);
while (args.hasAny()) {
//noinspection unchecked
Object gotten = args.getDatatypeFor(list.datatype);
if (gotten instanceof Class) {
//noinspection unchecked
@ -98,7 +97,7 @@ public class FollowCommand extends Command {
.filterPrefix(args.getString())
.stream();
} else {
Class<? extends IDatatype> followType;
IDatatypeFor followType;
try {
followType = args.getEnum(FollowList.class).datatype;
} catch (NullPointerException e) {
@ -145,11 +144,12 @@ public class FollowCommand extends Command {
}
private enum FollowList {
ENTITY(EntityClassById.class),
PLAYER(NearbyPlayer.class);
final Class<? extends IDatatypeFor> datatype;
ENTITY(EntityClassById.INSTANCE),
PLAYER(NearbyPlayer.INSTANCE);
FollowList(Class<? extends IDatatypeFor> datatype) {
final IDatatypeFor datatype;
FollowList(IDatatypeFor datatype) {
this.datatype = datatype;
}
}

View File

@ -53,7 +53,7 @@ public class GoalCommand extends Command {
} else {
args.requireMax(3);
BetterBlockPos origin = baritone.getPlayerContext().playerFeet();
Goal goal = args.getDatatype(RelativeGoal.class).apply(origin);
Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin);
goalProcess.setGoal(goal);
logDirect(String.format("Goal: %s", goal.toString()));
}
@ -67,7 +67,7 @@ public class GoalCommand extends Command {
} else {
if (args.hasAtMost(3)) {
while (args.has(2)) {
if (args.peekDatatypeOrNull(RelativeCoordinate.class) == null) {
if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) == null) {
break;
}
args.get();

View File

@ -18,7 +18,6 @@
package baritone.utils.command.defaults;
import baritone.api.IBaritone;
import baritone.api.Settings;
import baritone.api.utils.BlockOptionalMeta;
import baritone.api.utils.command.Command;
import baritone.api.utils.command.datatypes.BlockById;
@ -44,7 +43,7 @@ public class MineCommand extends Command {
args.requireMin(1);
List<BlockOptionalMeta> boms = new ArrayList<>();
while (args.hasAny()) {
boms.add(args.getDatatypeFor(ForBlockOptionalMeta.class));
boms.add(args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE));
}
WorldScanner.INSTANCE.repack(ctx);
logDirect(String.format("Mining %s", boms.toString()));
@ -53,7 +52,7 @@ public class MineCommand extends Command {
@Override
protected Stream<String> tabCompleted(String label, ArgConsumer args) {
return args.tabCompleteDatatype(BlockById.class);
return args.tabCompleteDatatype(BlockById.INSTANCE);
}
@Override

View File

@ -46,7 +46,7 @@ public class PathCommand extends Command {
Goal goal;
if (args.hasAny()) {
args.requireMax(3);
goal = args.getDatatype(RelativeGoal.class).apply(ctx.playerFeet());
goal = args.getDatatypePost(RelativeGoal.INSTANCE, ctx.playerFeet());
} else if ((goal = customGoalProcess.getGoal()) == null) {
throw new CommandInvalidStateException("No goal");
}
@ -60,7 +60,7 @@ public class PathCommand extends Command {
protected Stream<String> tabCompleted(String label, ArgConsumer args) throws CommandException {
if (args.hasAny() && !args.has(4)) {
while (args.has(2)) {
if (args.peekDatatypeOrNull(RelativeCoordinate.class) == null) {
if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) == null) {
break;
}
args.get();

View File

@ -86,7 +86,7 @@ public class SelCommand extends Command {
throw new CommandInvalidStateException("Set pos1 first before using pos2");
}
BetterBlockPos playerPos = mc.getRenderViewEntity() != null ? BetterBlockPos.from(new BlockPos(mc.getRenderViewEntity())) : ctx.playerFeet();
BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.class, playerPos) : playerPos;
BetterBlockPos pos = args.hasAny() ? args.getDatatypePost(RelativeBlockPos.INSTANCE, playerPos) : playerPos;
args.requireMax(0);
if (action == Action.POS1) {
pos1 = pos;
@ -117,16 +117,16 @@ public class SelCommand extends Command {
} else if (action == Action.SET || action == Action.WALLS || action == Action.SHELL || action == Action.CLEARAREA || action == Action.REPLACE) {
BlockOptionalMeta type = action == Action.CLEARAREA
? new BlockOptionalMeta(Blocks.AIR)
: args.getDatatypeFor(ForBlockOptionalMeta.class);
: args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE);
BlockOptionalMetaLookup replaces = null;
if (action == Action.REPLACE) {
args.requireMin(1);
List<BlockOptionalMeta> replacesList = new ArrayList<>();
replacesList.add(type);
while (args.has(2)) {
replacesList.add(args.getDatatypeFor(ForBlockOptionalMeta.class));
replacesList.add(args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE));
}
type = args.getDatatypeFor(ForBlockOptionalMeta.class);
type = args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE);
replaces = new BlockOptionalMetaLookup(replacesList.toArray(new BlockOptionalMeta[0]));
} else {
args.requireMax(0);
@ -166,7 +166,7 @@ public class SelCommand extends Command {
if (transformTarget == null) {
throw new CommandInvalidStateException("Invalid transform type");
}
EnumFacing direction = args.getDatatypeFor(ForEnumFacing.class);
EnumFacing direction = args.getDatatypeFor(ForEnumFacing.INSTANCE);
int blocks = args.getAs(Integer.class);
ISelection[] selections = manager.getSelections();
if (selections.length < 1) {
@ -199,14 +199,14 @@ public class SelCommand extends Command {
if (action != null) {
if (action == Action.POS1 || action == Action.POS2) {
if (args.hasAtMost(3)) {
return args.tabCompleteDatatype(RelativeBlockPos.class);
return args.tabCompleteDatatype(RelativeBlockPos.INSTANCE);
}
} else if (action == Action.SET || action == Action.WALLS || action == Action.CLEARAREA || action == Action.REPLACE) {
if (args.hasExactlyOne() || action == Action.REPLACE) {
while (args.has(2)) {
args.get();
}
return args.tabCompleteDatatype(ForBlockOptionalMeta.class);
return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE);
}
} else if (action == Action.EXPAND || action == Action.CONTRACT || action == Action.SHIFT) {
if (args.hasExactlyOne()) {
@ -218,7 +218,7 @@ public class SelCommand extends Command {
} else {
TransformTarget target = TransformTarget.getByName(args.getString());
if (target != null && args.hasExactlyOne()) {
return args.tabCompleteDatatype(ForEnumFacing.class);
return args.tabCompleteDatatype(ForEnumFacing.INSTANCE);
}
}
}

View File

@ -96,8 +96,8 @@ public class WaypointsCommand extends Command {
args.get();
}
IWaypoint[] waypoints = tag != null
? ForWaypoints.getWaypointsByTag(tag)
: ForWaypoints.getWaypoints();
? ForWaypoints.getWaypointsByTag(this.baritone, tag)
: ForWaypoints.getWaypoints(this.baritone);
if (waypoints.length > 0) {
args.requireMax(1);
Paginator.paginate(
@ -132,11 +132,11 @@ public class WaypointsCommand extends Command {
}
String name = args.hasAny() ? args.getString() : "";
BetterBlockPos pos = args.hasAny()
? args.getDatatypePost(RelativeBlockPos.class, ctx.playerFeet())
? args.getDatatypePost(RelativeBlockPos.INSTANCE, ctx.playerFeet())
: ctx.playerFeet();
args.requireMax(0);
IWaypoint waypoint = new Waypoint(name, tag, pos);
ForWaypoints.waypoints().addWaypoint(waypoint);
ForWaypoints.waypoints(this.baritone).addWaypoint(waypoint);
ITextComponent component = new TextComponentString("Waypoint added: ");
component.getStyle().setColor(TextFormatting.GRAY);
component.appendSibling(toComponent.apply(waypoint, Action.INFO));
@ -144,13 +144,13 @@ public class WaypointsCommand extends Command {
} else if (action == Action.CLEAR) {
args.requireMax(1);
IWaypoint.Tag tag = IWaypoint.Tag.getByName(args.getString());
IWaypoint[] waypoints = ForWaypoints.getWaypointsByTag(tag);
IWaypoint[] waypoints = ForWaypoints.getWaypointsByTag(this.baritone, tag);
for (IWaypoint waypoint : waypoints) {
ForWaypoints.waypoints().removeWaypoint(waypoint);
ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint);
}
logDirect(String.format("Cleared %d waypoints", waypoints.length));
} else {
IWaypoint[] waypoints = args.getDatatypeFor(ForWaypoints.class);
IWaypoint[] waypoints = args.getDatatypeFor(ForWaypoints.INSTANCE);
IWaypoint waypoint = null;
if (args.hasAny() && args.peekString().equals("@")) {
args.requireExactly(2);
@ -230,7 +230,7 @@ public class WaypointsCommand extends Command {
logDirect(goalComponent);
logDirect(backComponent);
} else if (action == Action.DELETE) {
ForWaypoints.waypoints().removeWaypoint(waypoint);
ForWaypoints.waypoints(this.baritone).removeWaypoint(waypoint);
logDirect("That waypoint has successfully been deleted");
} else if (action == Action.GOAL) {
Goal goal = new GoalBlock(waypoint.getLocation());
@ -260,12 +260,12 @@ public class WaypointsCommand extends Command {
.filterPrefix(args.getString())
.stream();
} else {
return args.tabCompleteDatatype(ForWaypoints.class);
return args.tabCompleteDatatype(ForWaypoints.INSTANCE);
}
} else if (args.has(3) && action == Action.SAVE) {
args.get();
args.get();
return args.tabCompleteDatatype(RelativeBlockPos.class);
return args.tabCompleteDatatype(RelativeBlockPos.INSTANCE);
}
}
}

View File

@ -18,6 +18,7 @@
package baritone.utils.command.manager;
import baritone.Baritone;
import baritone.api.IBaritone;
import baritone.api.utils.command.Command;
import baritone.api.utils.command.argument.CommandArgument;
import baritone.api.utils.command.execution.CommandExecution;
@ -45,6 +46,11 @@ public class CommandManager implements ICommandManager {
DefaultCommands.commands(baritone).forEach(this.registry::register);
}
@Override
public IBaritone getBaritone() {
return this.baritone;
}
@Override
public Registry<Command> getRegistry() {
return this.registry;