/* * 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 . */ package baritone.command.argument; import baritone.Baritone; import baritone.api.IBaritone; import baritone.api.command.argument.IArgConsumer; import baritone.api.command.argument.ICommandArgument; import baritone.api.command.datatypes.IDatatype; import baritone.api.command.datatypes.IDatatypeContext; import baritone.api.command.datatypes.IDatatypeFor; import baritone.api.command.datatypes.IDatatypePost; import baritone.api.command.exception.CommandException; import baritone.api.command.exception.CommandInvalidTypeException; import baritone.api.command.exception.CommandNotEnoughArgumentsException; import baritone.api.command.exception.CommandTooManyArgumentsException; import baritone.api.command.manager.ICommandManager; import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.stream.Stream; public class ArgConsumer implements IArgConsumer { /** * The parent {@link ICommandManager} for this {@link IArgConsumer}}. Used by {@link #context}. */ private final ICommandManager manager; /** * The {@link IDatatypeContext} instance for this {@link IArgConsumer}}, 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 */ private final LinkedList args; /** * The list of consumed arguments for this ArgConsumer. The most recently consumed argument is the last one */ private final Deque consumed; private ArgConsumer(ICommandManager manager, Deque args, Deque consumed) { this.manager = manager; this.context = this.new Context(); this.args = new LinkedList<>(args); this.consumed = new LinkedList<>(consumed); } public ArgConsumer(ICommandManager manager, List args) { this(manager, new LinkedList<>(args), new LinkedList<>()); } @Override public LinkedList getArgs() { return this.args; } @Override public Deque getConsumed() { return this.consumed; } @Override public boolean has(int num) { return args.size() >= num; } @Override public boolean hasAny() { return has(1); } @Override public boolean hasAtMost(int num) { return args.size() <= num; } @Override public boolean hasAtMostOne() { return hasAtMost(1); } @Override public boolean hasExactly(int num) { return args.size() == num; } @Override public boolean hasExactlyOne() { return hasExactly(1); } @Override public ICommandArgument peek(int index) throws CommandNotEnoughArgumentsException { requireMin(index + 1); return args.get(index); } @Override public ICommandArgument peek() throws CommandNotEnoughArgumentsException { return peek(0); } @Override public boolean is(Class type, int index) throws CommandNotEnoughArgumentsException { return peek(index).is(type); } @Override public boolean is(Class type) throws CommandNotEnoughArgumentsException { return is(type, 0); } @Override public String peekString(int index) throws CommandNotEnoughArgumentsException { return peek(index).getValue(); } @Override public String peekString() throws CommandNotEnoughArgumentsException { return peekString(0); } @Override public > E peekEnum(Class enumClass, int index) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return peek(index).getEnum(enumClass); } @Override public > E peekEnum(Class enumClass) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return peekEnum(enumClass, 0); } @Override public > E peekEnumOrNull(Class enumClass, int index) throws CommandNotEnoughArgumentsException { try { return peekEnum(enumClass, index); } catch (CommandInvalidTypeException e) { return null; } } @Override public > E peekEnumOrNull(Class enumClass) throws CommandNotEnoughArgumentsException { return peekEnumOrNull(enumClass, 0); } @Override public T peekAs(Class type, int index) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return peek(index).getAs(type); } @Override public T peekAs(Class type) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return peekAs(type, 0); } @Override public T peekAsOrDefault(Class type, T def, int index) throws CommandNotEnoughArgumentsException { try { return peekAs(type, index); } catch (CommandInvalidTypeException e) { return def; } } @Override public T peekAsOrDefault(Class type, T def) throws CommandNotEnoughArgumentsException { return peekAsOrDefault(type, def, 0); } @Override public T peekAsOrNull(Class type, int index) throws CommandNotEnoughArgumentsException { return peekAsOrDefault(type, null, index); } @Override public T peekAsOrNull(Class type) throws CommandNotEnoughArgumentsException { return peekAsOrNull(type, 0); } @Override public T peekDatatype(IDatatypeFor datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return copy().getDatatypeFor(datatype); } @Override public T peekDatatype(IDatatypePost datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return this.peekDatatype(datatype, null); } @Override public T peekDatatype(IDatatypePost datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return copy().getDatatypePost(datatype, original); } @Override public T peekDatatypeOrNull(IDatatypeFor datatype) { return copy().getDatatypeForOrNull(datatype); } @Override public T peekDatatypeOrNull(IDatatypePost datatype) { return copy().getDatatypePostOrNull(datatype, null); } @Override public > T peekDatatypePost(D datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return copy().getDatatypePost(datatype, original); } @Override public > T peekDatatypePostOrDefault(D datatype, O original, T def) { return copy().getDatatypePostOrDefault(datatype, original, def); } @Override public > T peekDatatypePostOrNull(D datatype, O original) { return peekDatatypePostOrDefault(datatype, original, null); } @Override public > T peekDatatypeFor(Class datatype) { return copy().peekDatatypeFor(datatype); } @Override public > T peekDatatypeForOrDefault(Class datatype, T def) { return copy().peekDatatypeForOrDefault(datatype, def); } @Override public > T peekDatatypeForOrNull(Class datatype) { return peekDatatypeForOrDefault(datatype, null); } @Override public ICommandArgument get() throws CommandNotEnoughArgumentsException { requireMin(1); ICommandArgument arg = args.removeFirst(); consumed.add(arg); return arg; } @Override public String getString() throws CommandNotEnoughArgumentsException { return get().getValue(); } @Override public > E getEnum(Class enumClass) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return get().getEnum(enumClass); } @Override public > E getEnumOrDefault(Class enumClass, E def) throws CommandNotEnoughArgumentsException { try { peekEnum(enumClass); return getEnum(enumClass); } catch (CommandInvalidTypeException e) { return def; } } @Override public > E getEnumOrNull(Class enumClass) throws CommandNotEnoughArgumentsException { return getEnumOrDefault(enumClass, null); } @Override public T getAs(Class type) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { return get().getAs(type); } @Override public T getAsOrDefault(Class type, T def) throws CommandNotEnoughArgumentsException { try { T val = peek().getAs(type); get(); return val; } catch (CommandInvalidTypeException e) { return def; } } @Override public T getAsOrNull(Class type) throws CommandNotEnoughArgumentsException { return getAsOrDefault(type, null); } @Override public > T getDatatypePost(D datatype, O original) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { try { return datatype.apply(this.context, original); } catch (Exception e) { if (Baritone.settings().verboseCommandExceptions.value) { e.printStackTrace(); } throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName(), e); } } @Override public > T getDatatypePostOrDefault(D datatype, O original, T _default) { final List argsSnapshot = new ArrayList<>(this.args); final List 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; } } @Override public > T getDatatypePostOrNull(D datatype, O original) { return this.getDatatypePostOrDefault(datatype, original, null); } @Override public > T getDatatypeFor(D datatype) throws CommandInvalidTypeException, CommandNotEnoughArgumentsException { try { return datatype.get(this.context); } catch (Exception e) { if (Baritone.settings().verboseCommandExceptions.value) { e.printStackTrace(); } throw new CommandInvalidTypeException(hasAny() ? peek() : consumed(), datatype.getClass().getSimpleName(), e); } } @Override public > T getDatatypeForOrDefault(D datatype, T def) { final List argsSnapshot = new ArrayList<>(this.args); final List 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; } } @Override public > T getDatatypeForOrNull(D datatype) { return this.getDatatypeForOrDefault(datatype, null); } @Override public Stream tabCompleteDatatype(T datatype) { try { return datatype.tabComplete(this.context); } catch (CommandException ignored) { // NOP } catch (Exception e) { e.printStackTrace(); } return Stream.empty(); } @Override public String rawRest() { return args.size() > 0 ? args.getFirst().getRawRest() : ""; } @Override public void requireMin(int min) throws CommandNotEnoughArgumentsException { if (args.size() < min) { throw new CommandNotEnoughArgumentsException(min + consumed.size()); } } @Override public void requireMax(int max) throws CommandTooManyArgumentsException { if (args.size() > max) { throw new CommandTooManyArgumentsException(max + consumed.size()); } } @Override public void requireExactly(int args) throws CommandException { requireMin(args); requireMax(args); } @Override public boolean hasConsumed() { return !consumed.isEmpty(); } @Override public ICommandArgument consumed() { return consumed.size() > 0 ? consumed.getLast() : CommandArguments.unknown(); } @Override public String consumedString() { return consumed().getValue(); } @Override public ArgConsumer copy() { return new ArgConsumer(manager, args, consumed); } /** * Implementation of {@link IDatatypeContext} which adapts to the parent {@link IArgConsumer}} */ private final class Context implements IDatatypeContext { @Override public final IBaritone getBaritone() { return ArgConsumer.this.manager.getBaritone(); } @Override public final ArgConsumer getConsumer() { return ArgConsumer.this; } } }