hollow-cube/sender-in-command-arg-parsing

Signed-off-by: mworzala <mattheworzala@gmail.com>

fix default argument issue

(cherry picked from commit a7440639c8541faeb91155c53ce3a1f4d60df127)

Add sender to command parse chain

(cherry picked from commit 853307891d178abdc7036f8c809c52909cdca327)

(cherry picked from commit 1268cf16c0)
This commit is contained in:
mworzala 2023-03-25 09:29:20 -04:00 committed by Matt Worzala
parent 351000e2cb
commit 8335afdf47
38 changed files with 158 additions and 99 deletions

View File

@ -11,3 +11,7 @@ Some of these are pending, some deserve PRs, others are just minor tweaks
* **breaking** Remove tinylog and MinestomTerminal implementation
* Add `Tag.Transient`
* Optionally allow multiple parents in event nodes
* **breaking** Add sender to argument parsing chain
* This allows for argument parsing based on the sender, such as in argument map. This was already present for suggestions, but not for parsing.
* This is a breaking change because it changes the signature of `Argument#parse`, but most use cases should not be affected.
Support has been maintained for the old argument map signature, so only completely custom arguments will be affected.

View File

@ -108,7 +108,7 @@ public final class CommandManager {
command = playerCommandEvent.getCommand();
}
// Process the command
final CommandParser.Result parsedCommand = parseCommand(command);
final CommandParser.Result parsedCommand = parseCommand(sender, command);
final ExecutableCommand executable = parsedCommand.executable();
final ExecutableCommand.Result executeResult = executable.execute(sender);
final CommandResult result = resultConverter(executable, executeResult, command);
@ -184,8 +184,8 @@ public final class CommandManager {
* @param input commands string without prefix
* @return the parsing result
*/
public CommandParser.Result parseCommand(String input) {
return parser.parse(getGraph(), input);
public CommandParser.Result parseCommand(@NotNull CommandSender sender, String input) {
return parser.parse(sender, getGraph(), input);
}
private Graph getGraph() {

View File

@ -24,7 +24,7 @@ public interface CommandParser {
* @return the parsed command which can be executed and cached
*/
@Contract("_, _ -> new")
@NotNull Result parse(@NotNull Graph graph, @NotNull String input);
@NotNull Result parse(@NotNull CommandSender sender, @NotNull Graph graph, @NotNull String input);
sealed interface Result {
@NotNull ExecutableCommand executable();

View File

@ -1,10 +1,7 @@
package net.minestom.server.command;
import net.minestom.server.command.Graph.Node;
import net.minestom.server.command.builder.ArgumentCallback;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.CommandData;
import net.minestom.server.command.builder.CommandExecutor;
import net.minestom.server.command.builder.*;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.condition.CommandCondition;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
@ -98,12 +95,12 @@ final class CommandParserImpl implements CommandParser {
}
@Override
public @NotNull CommandParser.Result parse(@NotNull Graph graph, @NotNull String input) {
public @NotNull CommandParser.Result parse(@NotNull CommandSender sender, @NotNull Graph graph, @NotNull String input) {
final CommandStringReader reader = new CommandStringReader(input);
Chain chain = new Chain();
Node parent = graph.root();
NodeResult result = parseNode(parent, chain, reader);
NodeResult result = parseNode(sender, parent, chain, reader);
chain = result.chain;
NodeResult lastNodeResult = chain.nodeResults.peekLast();
@ -130,13 +127,13 @@ final class CommandParserImpl implements CommandParser {
return obj == null ? null : getter.apply(obj);
}
private static NodeResult parseNode(Node node, Chain chain, CommandStringReader reader) {
private static NodeResult parseNode(@NotNull CommandSender sender, Node node, Chain chain, CommandStringReader reader) {
chain = chain.fork();
Argument<?> argument = node.argument();
int start = reader.cursor();
if (reader.hasRemaining()) {
ArgumentResult<?> result = parseArgument(argument, reader);
ArgumentResult<?> result = parseArgument(sender, argument, reader);
SuggestionCallback suggestionCallback = argument.getSuggestionCallback();
NodeResult nodeResult = new NodeResult(node, chain, (ArgumentResult<Object>) result, suggestionCallback);
chain.append(nodeResult);
@ -418,18 +415,18 @@ final class CommandParserImpl implements CommandParser {
// ARGUMENT
private static <T> ArgumentResult<T> parseArgument(Argument<T> argument, CommandStringReader reader) {
private static <T> ArgumentResult<T> parseArgument(@NotNull CommandSender sender, Argument<T> argument, CommandStringReader reader) {
// Handle specific type without loop
try {
// Single word argument
if (!argument.allowSpace()) {
final String word = reader.readWord();
return new ArgumentResult.Success<>(argument.parse(word), word);
return new ArgumentResult.Success<>(argument.parse(sender, word), word);
}
// Complete input argument
if (argument.useRemaining()) {
final String remaining = reader.readRemaining();
return new ArgumentResult.Success<>(argument.parse(remaining), remaining);
return new ArgumentResult.Success<>(argument.parse(sender, remaining), remaining);
}
} catch (ArgumentSyntaxException ignored) {
return new ArgumentResult.IncompatibleType<>();
@ -440,7 +437,7 @@ final class CommandParserImpl implements CommandParser {
while (true) {
try {
final String input = current.toString();
return new ArgumentResult.Success<>(argument.parse(input), input);
return new ArgumentResult.Success<>(argument.parse(sender, input), input);
} catch (ArgumentSyntaxException ignored) {
if (!reader.hasRemaining()) break;
current.append(" ");

View File

@ -1,5 +1,6 @@
package net.minestom.server.command;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.arguments.*;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
@ -77,7 +78,8 @@ final class GraphConverter {
redirects.add((graph, root) -> node.redirectedNode = root);
} else {
redirects.add((graph, root) -> {
final List<Argument<?>> args = CommandParser.parser().parse(graph, shortcut).args();
var sender = player == null ? MinecraftServer.getCommandManager().getConsoleSender() : player;
final List<Argument<?>> args = CommandParser.parser().parse(sender, graph, shortcut).args();
final Argument<?> last = args.get(args.size() - 1);
if (last.allowSpace()) {
node.redirectedNode = argToPacketId.get(args.get(args.size()-2));

View File

@ -16,10 +16,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.*;
import java.util.stream.Stream;
/**
@ -167,14 +164,14 @@ public class Command {
// the 'args' array starts by all the required arguments, followed by the optional ones
List<Argument<?>> requiredArguments = new ArrayList<>();
Map<String, Supplier<Object>> defaultValuesMap = new HashMap<>();
Map<String, Function<CommandSender, Object>> defaultValuesMap = new HashMap<>();
boolean optionalBranch = false;
int i = 0;
for (Argument<?> argument : args) {
final boolean isLast = ++i == args.length;
if (argument.isOptional()) {
// Set default value
defaultValuesMap.put(argument.getId(), (Supplier<Object>) argument.getDefaultValue());
defaultValuesMap.put(argument.getId(), (Function<CommandSender, Object>) argument.getDefaultValue());
if (!optionalBranch && !requiredArguments.isEmpty()) {
// First optional argument, create a syntax with current cached arguments

View File

@ -74,8 +74,8 @@ public class CommandDispatcher {
* @param commandString the command (containing the command name and the args if any)
* @return the parsing result
*/
public @NotNull CommandResult parse(@NotNull String commandString) {
final net.minestom.server.command.CommandParser.Result test = manager.parseCommand(commandString);
public @NotNull CommandResult parse(@NotNull CommandSender sender, @NotNull String commandString) {
final net.minestom.server.command.CommandParser.Result test = manager.parseCommand(sender, commandString);
return resultConverter(test, commandString);
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.condition.CommandCondition;
import net.minestom.server.entity.Player;
@ -9,6 +10,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
/**
@ -20,14 +22,14 @@ public class CommandSyntax {
private CommandCondition commandCondition;
private CommandExecutor executor;
private final Map<String, Supplier<Object>> defaultValuesMap;
private final Map<String, Function<CommandSender, Object>> defaultValuesMap;
private final Argument<?>[] args;
private final boolean suggestion;
protected CommandSyntax(@Nullable CommandCondition commandCondition,
@NotNull CommandExecutor commandExecutor,
@Nullable Map<String, Supplier<Object>> defaultValuesMap,
@Nullable Map<String, Function<CommandSender, Object>> defaultValuesMap,
@NotNull Argument<?>... args) {
this.commandCondition = commandCondition;
this.executor = commandExecutor;
@ -87,7 +89,7 @@ public class CommandSyntax {
}
@Nullable
protected Map<String, Supplier<Object>> getDefaultValuesMap() {
protected Map<String, Function<CommandSender, Object>> getDefaultValuesMap() {
return defaultValuesMap;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.ArgumentCallback;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandExecutor;
@ -13,6 +14,7 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
@ -22,7 +24,7 @@ import java.util.function.Supplier;
* <p>
* You can create your own with your own special conditions.
* <p>
* Arguments are parsed using {@link #parse(String)}.
* Arguments are parsed using {@link #parse(CommandSender, String)}.
*
* @param <T> the type of this parsed argument
*/
@ -44,7 +46,7 @@ public abstract class Argument<T> {
private ArgumentCallback callback;
private Supplier<T> defaultValue;
private Function<CommandSender, T> defaultValue;
private SuggestionCallback suggestionCallback;
protected SuggestionType suggestionType;
@ -90,8 +92,8 @@ public abstract class Argument<T> {
* @throws ArgumentSyntaxException if the argument cannot be parsed due to a fault input (argument id)
*/
@ApiStatus.Experimental
public static <T> @NotNull T parse(@NotNull Argument<T> argument) throws ArgumentSyntaxException {
return argument.parse(argument.getId());
public static <T> @NotNull T parse(@NotNull CommandSender sender, @NotNull Argument<T> argument) throws ArgumentSyntaxException {
return argument.parse(sender, argument.getId());
}
/**
@ -102,7 +104,7 @@ public abstract class Argument<T> {
* @return the parsed argument
* @throws ArgumentSyntaxException if {@code value} is not valid
*/
public abstract @NotNull T parse(@NotNull String input) throws ArgumentSyntaxException;
public abstract @NotNull T parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException;
public abstract String parser();
@ -187,7 +189,7 @@ public abstract class Argument<T> {
}
@Nullable
public Supplier<T> getDefaultValue() {
public Function<CommandSender, T> getDefaultValue() {
return defaultValue;
}
@ -202,6 +204,12 @@ public abstract class Argument<T> {
*/
@NotNull
public Argument<T> setDefaultValue(@Nullable Supplier<T> defaultValue) {
this.defaultValue = unused -> defaultValue.get();
return this;
}
@NotNull
public Argument<T> setDefaultValue(@Nullable Function<CommandSender, T> defaultValue) {
this.defaultValue = defaultValue;
return this;
}
@ -214,7 +222,7 @@ public abstract class Argument<T> {
*/
@NotNull
public Argument<T> setDefaultValue(@NotNull T defaultValue) {
this.defaultValue = () -> defaultValue;
this.defaultValue = unused -> defaultValue;
return this;
}
@ -261,6 +269,11 @@ public abstract class Argument<T> {
*/
@ApiStatus.Experimental
public <O> @NotNull Argument<O> map(@NotNull Function<T, O> mapper) {
return new ArgumentMap<>(this, (p, i) -> mapper.apply(i));
}
@ApiStatus.Experimental
public <O> @NotNull Argument<O> map(@NotNull BiFunction<CommandSender, T, O> mapper) {
return new ArgumentMap<>(this, mapper);
}
@ -293,22 +306,22 @@ public abstract class Argument<T> {
private static final class ArgumentMap<I, O> extends Argument<O> {
public static final int INVALID_MAP = 555;
final Argument<I> argument;
final Function<I, O> mapper;
final BiFunction<@NotNull CommandSender, I, O> mapper;
private ArgumentMap(@NotNull Argument<I> argument, @NotNull Function<I, O> mapper) {
private ArgumentMap(@NotNull Argument<I> argument, @NotNull BiFunction<@NotNull CommandSender, I, O> mapper) {
super(argument.getId(), argument.allowSpace(), argument.useRemaining());
if (argument.getSuggestionCallback() != null)
this.setSuggestionCallback(argument.getSuggestionCallback());
if (argument.getDefaultValue() != null)
this.setDefaultValue(() -> mapper.apply(argument.getDefaultValue().get()));
this.setDefaultValue(sender -> mapper.apply(sender, argument.getDefaultValue().apply(sender)));
this.argument = argument;
this.mapper = mapper;
}
@Override
public @NotNull O parse(@NotNull String input) throws ArgumentSyntaxException {
final I value = argument.parse(input);
final O mappedValue = mapper.apply(value);
public @NotNull O parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
final I value = argument.parse(sender, input);
final O mappedValue = mapper.apply(sender, value);
if (mappedValue == null)
throw new ArgumentSyntaxException("Couldn't be converted to map type", input, INVALID_MAP);
return mappedValue;
@ -341,8 +354,8 @@ public abstract class Argument<T> {
}
@Override
public @NotNull T parse(@NotNull String input) throws ArgumentSyntaxException {
final T result = argument.parse(input);
public @NotNull T parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
final T result = argument.parse(sender, input);
if (!predicate.test(result))
throw new ArgumentSyntaxException("Predicate failed", input, INVALID_FILTER);
return result;

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -18,7 +19,7 @@ public class ArgumentBoolean extends Argument<Boolean> {
@NotNull
@Override
public Boolean parse(@NotNull String input) throws ArgumentSyntaxException {
public Boolean parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
if (input.equalsIgnoreCase("true"))
return true;
if (input.equalsIgnoreCase("false"))

View File

@ -1,6 +1,7 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.CommandDispatcher;
import net.minestom.server.command.builder.CommandResult;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
@ -21,12 +22,12 @@ public class ArgumentCommand extends Argument<CommandResult> {
@NotNull
@Override
public CommandResult parse(@NotNull String input) throws ArgumentSyntaxException {
public CommandResult parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
final String commandString = !shortcut.isEmpty() ?
shortcut + StringUtils.SPACE + input
: input;
CommandDispatcher dispatcher = MinecraftServer.getCommandManager().getDispatcher();
CommandResult result = dispatcher.parse(commandString);
CommandResult result = dispatcher.parse(sender, commandString);
if (onlyCorrect && result.getType() != CommandResult.Type.SUCCESS)
throw new ArgumentSyntaxException("Invalid command", input, INVALID_COMMAND_ERROR);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -30,7 +31,7 @@ public class ArgumentEnum<E extends Enum> extends Argument<E> {
@NotNull
@Override
public E parse(@NotNull String input) throws ArgumentSyntaxException {
public E parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
for (E value : this.values) {
if (this.format.formatter.apply(value.name()).equals(input)) {
return value;

View File

@ -1,11 +1,13 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.command.builder.parser.CommandParser;
import net.minestom.server.command.builder.parser.ValidSyntaxHolder;
import net.minestom.server.utils.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
@ -23,9 +25,9 @@ public class ArgumentGroup extends Argument<CommandContext> {
@NotNull
@Override
public CommandContext parse(@NotNull String input) throws ArgumentSyntaxException {
public CommandContext parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
List<ValidSyntaxHolder> validSyntaxes = new ArrayList<>();
CommandParser.parse(null, group, input.split(StringUtils.SPACE), input, validSyntaxes, null);
CommandParser.parse(sender, null, group, input.split(StringUtils.SPACE), input, validSyntaxes, null);
CommandContext context = new CommandContext(input);
CommandParser.findMostCorrectSyntax(validSyntaxes, context);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -13,7 +14,7 @@ public class ArgumentLiteral extends Argument<String> {
@NotNull
@Override
public String parse(@NotNull String input) throws ArgumentSyntaxException {
public String parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
if (!input.equals(getId()))
throw new ArgumentSyntaxException("Invalid literal value", input, INVALID_VALUE_ERROR);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.StringUtils;
import org.jetbrains.annotations.NotNull;
@ -22,7 +23,7 @@ public class ArgumentLoop<T> extends Argument<List<T>> {
@NotNull
@Override
public List<T> parse(@NotNull String input) throws ArgumentSyntaxException {
public List<T> parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
List<T> result = new ArrayList<>();
final String[] split = input.split(StringUtils.SPACE);
@ -34,7 +35,7 @@ public class ArgumentLoop<T> extends Argument<List<T>> {
for (Argument<T> argument : arguments) {
try {
final String inputString = builder.toString();
final T value = argument.parse(inputString);
final T value = argument.parse(sender, inputString);
success = true;
result.add(value);
break;

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.StringUtils;
import net.minestom.server.utils.binary.BinaryWriter;
@ -25,7 +26,7 @@ public class ArgumentString extends Argument<String> {
@NotNull
@Override
public String parse(@NotNull String input) throws ArgumentSyntaxException {
public String parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
return staticParse(input);
}
@ -42,7 +43,7 @@ public class ArgumentString extends Argument<String> {
}
/**
* @deprecated use {@link Argument#parse(Argument)}
* @deprecated use {@link Argument#parse(CommandSender, Argument)}
*/
@Deprecated
public static String staticParse(@NotNull String input) throws ArgumentSyntaxException {

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.utils.StringUtils;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
@ -20,7 +21,7 @@ public class ArgumentStringArray extends Argument<String[]> {
@NotNull
@Override
public String[] parse(@NotNull String input) {
public String[] parse(@NotNull CommandSender sender, @NotNull String input) {
return input.split(Pattern.quote(StringUtils.SPACE));
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.StringUtils;
import net.minestom.server.utils.binary.BinaryWriter;
@ -51,7 +52,7 @@ public class ArgumentWord extends Argument<String> {
@NotNull
@Override
public String parse(@NotNull String input) throws ArgumentSyntaxException {
public String parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
if (input.contains(StringUtils.SPACE))
throw new ArgumentSyntaxException("Word cannot contain space character", input, SPACE_ERROR);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.instance.block.Block;
@ -18,7 +19,7 @@ public class ArgumentBlockState extends Argument<Block> {
}
@Override
public @NotNull Block parse(@NotNull String input) throws ArgumentSyntaxException {
public @NotNull Block parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
return staticParse(input);
}
@ -28,7 +29,7 @@ public class ArgumentBlockState extends Argument<Block> {
}
/**
* @deprecated use {@link Argument#parse(Argument)}
* @deprecated use {@link Argument#parse(CommandSender, Argument)}
*/
@Deprecated
public static Block staticParse(@NotNull String input) throws ArgumentSyntaxException {

View File

@ -2,6 +2,7 @@ package net.minestom.server.command.builder.arguments.minecraft;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -22,7 +23,7 @@ public class ArgumentColor extends Argument<Style> {
@NotNull
@Override
public Style parse(@NotNull String input) throws ArgumentSyntaxException {
public Style parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
// check for colour
NamedTextColor color = NamedTextColor.NAMES.value(input);

View File

@ -3,6 +3,7 @@ package net.minestom.server.command.builder.arguments.minecraft;
import com.google.gson.JsonParseException;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -17,7 +18,7 @@ public class ArgumentComponent extends Argument<Component> {
@NotNull
@Override
public Component parse(@NotNull String input) throws ArgumentSyntaxException {
public Component parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try {
return GsonComponentSerializer.gson().deserialize(input);
} catch (JsonParseException e) {

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.entity.EntityType;
@ -66,8 +67,8 @@ public class ArgumentEntity extends Argument<EntityFinder> {
@NotNull
@Override
public EntityFinder parse(@NotNull String input) throws ArgumentSyntaxException {
return staticParse(input, onlySingleEntity, onlyPlayers);
public EntityFinder parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
return staticParse(sender, input, onlySingleEntity, onlyPlayers);
}
@Override
@ -90,11 +91,11 @@ public class ArgumentEntity extends Argument<EntityFinder> {
}
/**
* @deprecated use {@link Argument#parse(Argument)}
* @deprecated use {@link Argument#parse(CommandSender, Argument)}
*/
@Deprecated
@NotNull
public static EntityFinder staticParse(@NotNull String input,
public static EntityFinder staticParse(@NotNull CommandSender sender, @NotNull String input,
boolean onlySingleEntity, boolean onlyPlayers) throws ArgumentSyntaxException {
// Check for raw player name or UUID
if (!input.contains(SELECTOR_PREFIX) && !input.contains(StringUtils.SPACE)) {
@ -148,11 +149,12 @@ public class ArgumentEntity extends Argument<EntityFinder> {
// START PARSING THE STRUCTURE
final String structure = input.substring(2);
return parseStructure(input, entityFinder, structure);
return parseStructure(sender, input, entityFinder, structure);
}
@NotNull
private static EntityFinder parseStructure(@NotNull String input,
private static EntityFinder parseStructure(@NotNull CommandSender sender,
@NotNull String input,
@NotNull EntityFinder entityFinder,
@NotNull String structure) throws ArgumentSyntaxException {
// The structure isn't opened or closed properly
@ -174,7 +176,7 @@ public class ArgumentEntity extends Argument<EntityFinder> {
if (!VALID_ARGUMENTS.contains(currentArgument))
throw new ArgumentSyntaxException("Argument name '" + currentArgument + "' does not exist", input, INVALID_ARGUMENT_NAME);
i = parseArgument(entityFinder, currentArgument, input, structureData, i);
i = parseArgument(sender, entityFinder, currentArgument, input, structureData, i);
currentArgument = ""; // Reset current argument
} else {
currentArgument += c;
@ -184,7 +186,8 @@ public class ArgumentEntity extends Argument<EntityFinder> {
return entityFinder;
}
private static int parseArgument(@NotNull EntityFinder entityFinder,
private static int parseArgument(@NotNull CommandSender sender,
@NotNull EntityFinder entityFinder,
@NotNull String argumentName,
@NotNull String input,
@NotNull String structureData, int beginIndex) throws ArgumentSyntaxException {
@ -249,7 +252,7 @@ public class ArgumentEntity extends Argument<EntityFinder> {
break;
case "level":
try {
final IntRange level = Argument.parse(new ArgumentIntRange(value));
final IntRange level = Argument.parse(sender, new ArgumentIntRange(value));
entityFinder.setLevel(level);
} catch (ArgumentSyntaxException e) {
throw new ArgumentSyntaxException("Invalid level number", input, INVALID_ARGUMENT_VALUE);
@ -257,7 +260,7 @@ public class ArgumentEntity extends Argument<EntityFinder> {
break;
case "distance":
try {
final IntRange distance = Argument.parse(new ArgumentIntRange(value));
final IntRange distance = Argument.parse(sender, new ArgumentIntRange(value));
entityFinder.setDistance(distance);
} catch (ArgumentSyntaxException e) {
throw new ArgumentSyntaxException("Invalid level number", input, INVALID_ARGUMENT_VALUE);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.item.ItemStack;
@ -30,7 +31,7 @@ public class ArgumentItemStack extends Argument<ItemStack> {
@NotNull
@Override
public ItemStack parse(@NotNull String input) throws ArgumentSyntaxException {
public ItemStack parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
return staticParse(input);
}
@ -40,7 +41,7 @@ public class ArgumentItemStack extends Argument<ItemStack> {
}
/**
* @deprecated use {@link Argument#parse(Argument)}
* @deprecated use {@link Argument#parse(CommandSender, Argument)}
*/
@Deprecated
public static ItemStack staticParse(@NotNull String input) throws ArgumentSyntaxException {

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -25,7 +26,7 @@ public class ArgumentNbtCompoundTag extends Argument<NBTCompound> {
@NotNull
@Override
public NBTCompound parse(@NotNull String input) throws ArgumentSyntaxException {
public NBTCompound parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try {
NBT nbt = new SNBTParser(new StringReader(input)).parse();

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -26,7 +27,7 @@ public class ArgumentNbtTag extends Argument<NBT> {
@NotNull
@Override
public NBT parse(@NotNull String input) throws ArgumentSyntaxException {
public NBT parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try {
return new SNBTParser(new StringReader(input)).parse();
} catch (NBTException e) {

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.math.Range;
@ -32,7 +33,7 @@ public abstract class ArgumentRange<T extends Range<N>, N extends Number> extend
@NotNull
@Override
public T parse(@NotNull String input) throws ArgumentSyntaxException {
public T parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try {
final String[] split = input.split(Pattern.quote(".."), -1);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.StringUtils;
@ -15,7 +16,7 @@ public class ArgumentResourceLocation extends Argument<String> {
@NotNull
@Override
public String parse(@NotNull String input) throws ArgumentSyntaxException {
public String parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
if (input.contains(StringUtils.SPACE))
throw new ArgumentSyntaxException("Resource location cannot contain space character", input, SPACE_ERROR);

View File

@ -2,6 +2,7 @@ package net.minestom.server.command.builder.arguments.minecraft;
import it.unimi.dsi.fastutil.chars.CharArrayList;
import it.unimi.dsi.fastutil.chars.CharList;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.time.TimeUnit;
@ -28,7 +29,7 @@ public class ArgumentTime extends Argument<Duration> {
@NotNull
@Override
public Duration parse(@NotNull String input) throws ArgumentSyntaxException {
public Duration parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
final char lastChar = input.charAt(input.length() - 1);
TemporalUnit timeUnit;

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -16,7 +17,7 @@ public class ArgumentUUID extends Argument<UUID> {
@NotNull
@Override
public UUID parse(@NotNull String input) throws ArgumentSyntaxException {
public UUID parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try {
return UUID.fromString(input);
} catch (IllegalArgumentException exception) {

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft.registry;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
@ -16,7 +17,7 @@ public abstract class ArgumentRegistry<T> extends Argument<T> {
@NotNull
@Override
public T parse(@NotNull String input) throws ArgumentSyntaxException {
public T parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
final T registryValue = getRegistry(input);
if (registryValue == null)
throw new ArgumentSyntaxException("Registry value is invalid", input, INVALID_NAME);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.number;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.binary.BinaryWriter;
@ -40,7 +41,7 @@ public class ArgumentNumber<T extends Number> extends Argument<T> {
}
@Override
public @NotNull T parse(@NotNull String input) throws ArgumentSyntaxException {
public @NotNull T parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
try {
final T value;
final int radix = getRadix(input);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.relative;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.coordinate.Vec;
@ -38,7 +39,7 @@ abstract class ArgumentRelativeVec extends Argument<RelativeVec> {
@NotNull
@Override
public RelativeVec parse(@NotNull String input) throws ArgumentSyntaxException {
public RelativeVec parse(@NotNull CommandSender sender, @NotNull String input) throws ArgumentSyntaxException {
final String[] split = input.split(StringUtils.SPACE);
if (split.length != getNumberCount()) {
throw new ArgumentSyntaxException("Invalid number of values", input, INVALID_NUMBER_COUNT_ERROR);

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.parser;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.*;
import net.minestom.server.command.builder.arguments.minecraft.*;
import net.minestom.server.command.builder.arguments.minecraft.registry.ArgumentEnchantment;
@ -139,7 +140,8 @@ public class ArgumentParser {
}
@Nullable
public static ArgumentResult validate(@NotNull Argument<?> argument,
public static ArgumentResult validate(@NotNull CommandSender sender,
@NotNull Argument<?> argument,
@NotNull Argument<?>[] arguments, int argIndex,
@NotNull String[] inputArguments, int inputIndex) {
final boolean end = inputIndex == inputArguments.length;
@ -171,7 +173,7 @@ public class ArgumentParser {
rawArg = builder.toString();
try {
parsedValue = argument.parse(rawArg);
parsedValue = argument.parse(sender, rawArg);
correct = true;
} catch (ArgumentSyntaxException exception) {
argumentSyntaxException = exception;
@ -186,7 +188,7 @@ public class ArgumentParser {
rawArg = builder.toString();
try {
parsedValue = argument.parse(rawArg);
parsedValue = argument.parse(sender, rawArg);
// Prevent quitting the parsing too soon if the argument
// does not allow space

View File

@ -1,6 +1,7 @@
package net.minestom.server.command.builder.parser;
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.CommandDispatcher;
@ -51,7 +52,8 @@ public final class CommandParser {
return recursiveCommandQuery(dispatcher, parents, null, commandName, args);
}
public static void parse(@Nullable CommandSyntax syntax, @NotNull Argument<?>[] commandArguments, @NotNull String[] inputArguments,
public static void parse(@NotNull CommandSender sender, @Nullable CommandSyntax syntax,
@NotNull Argument<?>[] commandArguments, @NotNull String[] inputArguments,
@NotNull String commandString,
@Nullable List<ValidSyntaxHolder> validSyntaxes,
@Nullable Int2ObjectRBTreeMap<CommandSuggestionHolder> syntaxesSuggestions) {
@ -65,7 +67,7 @@ public final class CommandParser {
// Check the validity of the arguments...
for (int argIndex = 0; argIndex < commandArguments.length; argIndex++) {
final Argument<?> argument = commandArguments[argIndex];
ArgumentParser.ArgumentResult argumentResult = validate(argument, commandArguments, argIndex, inputArguments, inputIndex);
ArgumentParser.ArgumentResult argumentResult = validate(sender, argument, commandArguments, argIndex, inputArguments, inputIndex);
if (argumentResult == null) {
break;
}
@ -145,7 +147,8 @@ public final class CommandParser {
}
@Nullable
public static ArgumentQueryResult findEligibleArgument(@NotNull Command command, String[] args, String commandString,
public static ArgumentQueryResult findEligibleArgument(@NotNull CommandSender sender,
@NotNull Command command, String[] args, String commandString,
boolean trailingSpace, boolean forceCorrect,
Predicate<CommandSyntax> syntaxPredicate,
Predicate<Argument<?>> argumentPredicate) {
@ -167,7 +170,7 @@ public final class CommandParser {
int maxArgIndex = 0;
for (int argIndex = 0; argIndex < commandArguments.length; argIndex++) {
Argument<?> argument = commandArguments[argIndex];
ArgumentParser.ArgumentResult argumentResult = validate(argument, commandArguments, argIndex, args, inputIndex);
ArgumentParser.ArgumentResult argumentResult = validate(sender, argument, commandArguments, argIndex, args, inputIndex);
if (argumentResult == null) {
// Nothing to analyze, create a dummy object
argumentResult = new ArgumentParser.ArgumentResult();

View File

@ -35,6 +35,6 @@ public class TabCompleteListener {
// it works as intended :)
text = text + '\00';
}
return MinecraftServer.getCommandManager().parseCommand(text).suggestion(commandSender);
return MinecraftServer.getCommandManager().parseCommand(commandSender, text).suggestion(commandSender);
}
}

View File

@ -15,8 +15,8 @@ public class ArgumentTest {
@Test
public void testParseSelf() {
assertEquals("example", Argument.parse(ArgumentType.String("example")));
assertEquals(55, Argument.parse(ArgumentType.Integer("55")));
assertEquals("example", Argument.parse(new ServerSender(), ArgumentType.String("example")));
assertEquals(55, Argument.parse(new ServerSender(), ArgumentType.Integer("55")));
}
@Test
@ -36,7 +36,7 @@ public class ArgumentTest {
assertFalse(arg.isOptional());
arg.setDefaultValue("default value");
assertTrue(arg.isOptional());
assertEquals("default value", arg.getDefaultValue().get());
assertEquals("default value", arg.getDefaultValue().apply(new ServerSender()));
}
@Test

View File

@ -379,13 +379,13 @@ public class ArgumentTypeTest {
var arg = ArgumentType.Group("group", ArgumentType.Integer("integer"), ArgumentType.String("string"), ArgumentType.Double("double"));
// Test normal input
var context1 = arg.parse("1234 1234 1234");
var context1 = arg.parse(new ServerSender(), "1234 1234 1234");
assertEquals(1234, context1.<Integer>get("integer"));
assertEquals("1234", context1.<String>get("string"));
assertEquals(1234.0, context1.<Double>get("double"));
// Test different input + trailing spaces
var context2 = arg.parse("1234 abcd 1234.5678 ");
var context2 = arg.parse(new ServerSender(), "1234 abcd 1234.5678 ");
assertEquals(1234, context2.<Integer>get("integer"));
assertEquals("abcd", context2.<String>get("string"));
assertEquals(1234.5678, context2.<Double>get("double"));
@ -450,19 +450,32 @@ public class ArgumentTypeTest {
assertInvalidArg(arg, "word4");
}
@Test
public void testArgumentMapWithSender() {
var serverSender = new ServerSender();
var arg = ArgumentType.Word("word").from("word1", "word2", "word3")
.map((sender, s) -> {
assertEquals(serverSender, sender);
return s;
});
assertEquals("word1", arg.parse(serverSender, "word1"));
}
private static <T> void assertArg(Argument<T> arg, T expected, String input) {
assertEquals(expected, arg.parse(input));
assertEquals(expected, arg.parse(new ServerSender(), input));
}
private static <T> void assertArrayArg(Argument<T[]> arg, T[] expected, String input) {
assertArrayEquals(expected, arg.parse(input));
assertArrayEquals(expected, arg.parse(new ServerSender(), input));
}
private static <T> void assertValidArg(Argument<T> arg, String input) {
assertDoesNotThrow(() -> arg.parse(input));
assertDoesNotThrow(() -> arg.parse(new ServerSender(), input));
}
private static <T> void assertInvalidArg(Argument<T> arg, String input) {
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(input));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(new ServerSender(), input));
}
}

View File

@ -143,7 +143,7 @@ public class CommandParseTest {
}
private static CommandParser.Result parseCommand(Graph graph, String input) {
return CommandParser.parser().parse(graph, input);
return CommandParser.parser().parse(new ServerSender(), graph, input);
}
@NotNull