Rework of ArgumentCallback to be more robust, allowing to simplify all argument types in order to be used out of the command framework for general parsing.

Also removed magic space string, replaced with constant from commons apache library
This commit is contained in:
themode 2021-01-08 03:07:37 +01:00
parent d0e94f0ee5
commit 1c65b36087
41 changed files with 535 additions and 779 deletions

View File

@ -22,6 +22,7 @@ import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.callback.CommandCallback;
import net.minestom.server.utils.validate.Check;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -209,7 +210,7 @@ public final class CommandManager {
return true;
} else {
// Check for legacy-command
final String[] splitCommand = command.split(" ");
final String[] splitCommand = command.split(StringUtils.SPACE);
final String commandName = splitCommand[0];
final CommandProcessor commandProcessor = commandProcessorMap.get(commandName.toLowerCase());
if (commandProcessor == null) {
@ -220,7 +221,7 @@ public final class CommandManager {
}
// Execute the legacy-command
final String[] args = command.substring(command.indexOf(" ") + 1).split(" ");
final String[] args = command.substring(command.indexOf(StringUtils.SPACE) + 1).split(StringUtils.SPACE);
return commandProcessor.process(sender, commandName, args);
}

View File

@ -75,7 +75,7 @@ public interface CommandProcessor {
*
* @param sender the command sender
* @param text the whole player text
* @return the array containing all the suggestions for the current arg (split " "), can be null
* @return the array containing all the suggestions for the current arg (split SPACE), can be null
* @see #enableWritingTracking()
*/
@Nullable

View File

@ -2,6 +2,7 @@ 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.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
/**
@ -13,9 +14,8 @@ public interface ArgumentCallback {
/**
* Executed when an error is found.
*
* @param source the sender which executed the command
* @param value the raw string argument which is responsible for the error
* @param error the error id (you can check its meaning in the specific argument class or ask the developer about it)
* @param sender the sender which executed the command
* @param exception the exception containing the message, input and error code related to the issue
*/
void apply(@NotNull CommandSender source, @NotNull String value, int error);
void apply(@NotNull CommandSender sender, @NotNull ArgumentSyntaxException exception);
}

View File

@ -256,7 +256,7 @@ public class Command {
*
* @param sender the command sender
* @param text the whole player's text
* @return the array containing all the suggestion for the current arg (split " "), can be null
* @return the array containing all the suggestion for the current arg (split SPACE), can be null
*/
@Nullable
public String[] onDynamicWrite(@NotNull CommandSender sender, @NotNull String text) {

View File

@ -3,6 +3,8 @@ 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.command.builder.exception.ArgumentSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -60,11 +62,10 @@ public class CommandDispatcher {
commandString = commandString.trim();
// Split space
final String spaceRegex = " ";
final String[] parts = commandString.split(spaceRegex);
final String[] parts = commandString.split(StringUtils.SPACE);
final String commandName = parts[0];
final String[] args = commandString.replaceFirst(Pattern.quote(commandName), "").trim().split(spaceRegex);
final String[] args = commandString.replaceFirst(Pattern.quote(commandName), "").trim().split(StringUtils.SPACE);
final Command command = findCommand(commandName);
// Check if the command exists
@ -126,10 +127,7 @@ public class CommandDispatcher {
// All the registered syntaxes of the command
final Collection<CommandSyntax> syntaxes = command.getSyntaxes();
// Contains all the fully validated syntaxes (we later find the one with the most amount of arguments)
List<CommandSyntax> validSyntaxes = new ArrayList<>();
// Contains the raw string value of each argument that has been validated
// CommandSyntax - (Argument index/Raw string value)
Map<CommandSyntax, String[]> syntaxesValues = new HashMap<>();
List<ValidSyntaxHolder> validSyntaxes = new ArrayList<>();
// Contains all the syntaxes that are not fully correct, used to later, retrieve the "most correct syntax"
// Number of correct argument - The data about the failing argument
@ -137,64 +135,81 @@ public class CommandDispatcher {
for (CommandSyntax syntax : syntaxes) {
final Argument<?>[] arguments = syntax.getArguments();
final String[] argsValues = new String[Byte.MAX_VALUE];
final List<Object> argsValues = new ArrayList<>(arguments.length);
boolean syntaxCorrect = true;
// The current index in the raw command string arguments
int argIndex = 0;
int splitIndex = 0;
boolean useRemaining = false;
// Check the validity of the arguments...
for (int argCount = 0; argCount < arguments.length; argCount++) {
final boolean lastArgumentIteration = argCount + 1 == arguments.length;
final Argument<?> argument = arguments[argCount];
useRemaining = argument.useRemaining();
// the correction result of the argument
int correctionResult = Argument.SUCCESS;
// the parsed argument value, null if incorrect
Object parsedValue;
// the argument exception, null if the input is correct
ArgumentSyntaxException argumentSyntaxException = null;
// true if the arg is valid, false otherwise
boolean correct = false;
// the raw string representing the correct argument syntax
StringBuilder argValue = new StringBuilder();
if (useRemaining) {
final boolean hasArgs = args.length > argIndex;
final boolean hasArgs = args.length > splitIndex;
// Verify if there is any string part available
if (hasArgs) {
// Argument is supposed to take the rest of the command input
for (int i = argIndex; i < args.length; i++) {
for (int i = splitIndex; i < args.length; i++) {
final String arg = args[i];
if (argValue.length() > 0)
argValue.append(" ");
argValue.append(StringUtils.SPACE);
argValue.append(arg);
}
final String argValueString = argValue.toString();
correctionResult = argument.getCorrectionResult(argValueString);
if (correctionResult == Argument.SUCCESS) {
try {
parsedValue = argument.parse(argValueString);
correct = true;
argsValues[argCount] = argValueString;
argsValues.add(parsedValue);
} catch (ArgumentSyntaxException exception) {
argumentSyntaxException = exception;
}
}
} else {
// Argument is either single-word or can accept optional delimited space(s)
for (int i = argIndex; i < args.length; i++) {
for (int i = splitIndex; i < args.length; i++) {
final String rawArg = args[i];
argValue.append(rawArg);
final String argValueString = argValue.toString();
correctionResult = argument.getCorrectionResult(argValueString);
if (correctionResult == Argument.SUCCESS) {
try {
parsedValue = argument.parse(argValueString);
// Prevent quitting the parsing too soon if the argument
// does not allow space
if (lastArgumentIteration && i + 1 < args.length) {
if (!argument.allowSpace())
break;
argValue.append(StringUtils.SPACE);
continue;
}
correct = true;
argsValues[argCount] = argValueString;
argIndex = i + 1;
argsValues.add(parsedValue);
splitIndex = i + 1;
break;
} else {
} catch (ArgumentSyntaxException exception) {
argumentSyntaxException = exception;
if (!argument.allowSpace())
break;
argValue.append(" ");
argValue.append(StringUtils.SPACE);
}
}
}
@ -205,8 +220,7 @@ public class CommandDispatcher {
syntaxCorrect = false;
CommandSuggestionHolder suggestionHolder = new CommandSuggestionHolder();
suggestionHolder.syntax = syntax;
suggestionHolder.argValue = argValue.toString();
suggestionHolder.correctionResult = correctionResult;
suggestionHolder.argumentSyntaxException = argumentSyntaxException;
suggestionHolder.argIndex = argCount;
syntaxesSuggestions.put(argCount, suggestionHolder);
break;
@ -215,9 +229,12 @@ public class CommandDispatcher {
// Add the syntax to the list of valid syntaxes if correct
if (syntaxCorrect) {
if (args.length == argIndex || useRemaining) {
validSyntaxes.add(syntax);
syntaxesValues.put(syntax, argsValues);
if (arguments.length == argsValues.size() || useRemaining) {
ValidSyntaxHolder validSyntaxHolder = new ValidSyntaxHolder();
validSyntaxHolder.syntax = syntax;
validSyntaxHolder.argumentsValue = argsValues;
validSyntaxes.add(validSyntaxHolder);
}
}
}
@ -225,7 +242,7 @@ public class CommandDispatcher {
// Check if there is at least one correct syntax
if (!validSyntaxes.isEmpty()) {
// Search the syntax with all perfect args
final CommandSyntax finalSyntax = findMostCorrectSyntax(validSyntaxes, syntaxesValues, executorArgs);
final CommandSyntax finalSyntax = findMostCorrectSyntax(validSyntaxes, executorArgs);
if (finalSyntax != null) {
// A fully correct syntax has been found, use it
result.syntax = finalSyntax;
@ -234,29 +251,6 @@ public class CommandDispatcher {
return result;
}
// Otherwise, search for the first syntax with an incorrect argument
for (CommandSyntax syntax : validSyntaxes) {
final Argument[] arguments = syntax.getArguments();
final String[] argsValues = syntaxesValues.get(syntax);
for (int i = 0; i < arguments.length; i++) {
final Argument argument = arguments[i];
final String argValue = argsValues[i];
// Finally parse it
final Object parsedValue = argument.parse(argValue);
final int conditionResult = argument.getConditionResult(parsedValue);
if (conditionResult != Argument.SUCCESS) {
// Condition of an argument not correct, use the argument callback if any
if (argument.hasErrorCallback()) {
result.callback = argument.getCallback();
result.value = argValue;
result.error = conditionResult;
return result;
}
}
}
}
}
// No all-correct syntax, find the closest one to use the argument callback
@ -269,16 +263,14 @@ public class CommandDispatcher {
// Get the data of the closest syntax
final CommandSuggestionHolder suggestionHolder = syntaxesSuggestions.get(max);
final CommandSyntax syntax = suggestionHolder.syntax;
final String argValue = suggestionHolder.argValue;
final int correctionResult = suggestionHolder.correctionResult;
final ArgumentSyntaxException argumentSyntaxException = suggestionHolder.argumentSyntaxException;
final int argIndex = suggestionHolder.argIndex;
// Found the closest syntax with at least 1 correct argument
final Argument<?> argument = syntax.getArguments()[argIndex];
if (argument.hasErrorCallback()) {
result.callback = argument.getCallback();
result.value = argValue;
result.error = correctionResult;
result.argumentSyntaxException = argumentSyntaxException;
return result;
}
@ -297,60 +289,67 @@ public class CommandDispatcher {
* Retrieves from the valid syntax map the arguments condition result and get the one with the most
* valid arguments.
*
* @param validSyntaxes the list containing all the valid syntaxes
* @param syntaxesValues the map containing the argument raw string values
* @param executorArgs the recipient of the argument parsed values
* @param validSyntaxes the list containing all the valid syntaxes
* @param executorArgs the recipient of the argument parsed values
* @return the command syntax with all of its arguments correct and with the most arguments count, null if not any
*/
@Nullable
private CommandSyntax findMostCorrectSyntax(@NotNull List<CommandSyntax> validSyntaxes,
@NotNull Map<CommandSyntax, String[]> syntaxesValues,
private CommandSyntax findMostCorrectSyntax(@NotNull List<ValidSyntaxHolder> validSyntaxes,
@NotNull Arguments executorArgs) {
Map<CommandSyntax, Arguments> argumentsValueMap = new HashMap<>();
CommandSyntax finalSyntax = null;
int maxArguments = 0;
for (CommandSyntax syntax : validSyntaxes) {
Arguments syntaxValues = new Arguments();
boolean fullyCorrect = true;
Arguments finalArguments = null;
for (ValidSyntaxHolder validSyntaxHolder : validSyntaxes) {
final CommandSyntax syntax = validSyntaxHolder.syntax;
final Argument<?>[] arguments = syntax.getArguments();
final String[] argsValues = syntaxesValues.get(syntax);
for (int i = 0; i < arguments.length; i++) {
final Argument argument = arguments[i];
final String argValue = argsValues[i];
// Finally parse it
final Object parsedValue = argument.parse(argValue);
final int conditionResult = argument.getConditionResult(parsedValue);
if (conditionResult == Argument.SUCCESS) {
syntaxValues.setArg(argument.getId(), parsedValue);
} else {
// One argument is incorrect, stop the whole syntax check
fullyCorrect = false;
break;
}
}
final int argumentsCount = arguments.length;
final List<Object> argsValues = validSyntaxHolder.argumentsValue;
final int argumentLength = arguments.length;
if (fullyCorrect && argumentLength > maxArguments) {
final int argsSize = argsValues.size();
if (argsSize > maxArguments) {
finalSyntax = syntax;
maxArguments = argumentLength;
argumentsValueMap.put(syntax, syntaxValues);
maxArguments = argsSize;
// Fill arguments map
Arguments syntaxValues = new Arguments();
for (int i = 0; i < argumentsCount; i++) {
final Argument<?> argument = arguments[i];
final Object argumentValue = argsValues.get(i);
syntaxValues.setArg(argument.getId(), argumentValue);
}
finalArguments = syntaxValues;
}
}
// Get the arguments values
if (finalSyntax != null) {
executorArgs.copy(argumentsValueMap.get(finalSyntax));
executorArgs.copy(finalArguments);
}
return finalSyntax;
}
/**
* Holds the data of a validated syntax.
*/
private static class ValidSyntaxHolder {
private CommandSyntax syntax;
/**
* (Argument index/Argument parsed object)
*/
private List<Object> argumentsValue;
}
/**
* Holds the data of an invalidated syntax.
*/
private static class CommandSuggestionHolder {
private CommandSyntax syntax;
private String argValue;
private int correctionResult;
private ArgumentSyntaxException argumentSyntaxException;
private int argIndex;
}
@ -370,8 +369,7 @@ public class CommandDispatcher {
// Argument Callback
private ArgumentCallback callback;
private String value;
private int error;
private ArgumentSyntaxException argumentSyntaxException;
/**
* Executes the command for the given source.
@ -407,10 +405,10 @@ public class CommandDispatcher {
// The executor is probably the default one
executor.apply(source, arguments);
}
} else if (callback != null) {
} else if (callback != null && argumentSyntaxException != null) {
// No syntax has been validated but the faulty argument with a callback has been found
// Execute the faulty argument callback
callback.apply(source, value, error);
callback.apply(source, argumentSyntaxException);
}
}

View File

@ -3,7 +3,7 @@ package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.builder.ArgumentCallback;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandExecutor;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -12,18 +12,12 @@ import org.jetbrains.annotations.Nullable;
* <p>
* You can create your own with your own special conditions.
* <p>
* Here in order, how is parsed an argument: {@link #getCorrectionResult(String)} to check
* if the syntax is correct, {@link #parse(String)} to convert the correct argument
* and {@link #getConditionResult(Object)} to verify that the parsed object validate the additional
* conditions.
* Arguments are parsed using {@link #parse(String)}.
*
* @param <T> the type of this parsed argument
*/
public abstract class Argument<T> {
public static final int SUCCESS = 0;
public static final int UNDEFINED_ERROR = -1;
private final String id;
private final boolean allowSpace;
private final boolean useRemaining;
@ -65,38 +59,15 @@ public abstract class Argument<T> {
}
/**
* First method called to check the validity of an input.
* <p>
* If {@link #allowSpace()} is enabled, the value will be incremented by the next word until it returns {@link #SUCCESS},
* meaning that you need to be sure to check the inexpensive operations first (eg the number of brackets, the first and last char, etc...).
* Parses the given input, and throw an {@link ArgumentSyntaxException}
* if the input cannot be convert to {@code T}
*
* @param value The received argument
* @return the error code or {@link #SUCCESS}
*/
public abstract int getCorrectionResult(@NotNull String value);
/**
* Called after {@link #getCorrectionResult(String)} returned {@link #SUCCESS}.
* <p>
* The correction being correct means that {@code value} shouldn't be verified again, you can assume that no exception will occur
* when converting it to the correct type.
*
* @param value The correct argument which does not need to be verified again
* @return The parsed argument
* @param input the argument to parse
* @return the parsed argument
* @throws ArgumentSyntaxException if {@code value} is not valid
*/
@NotNull
public abstract T parse(@NotNull String value);
/**
* Called after {@link #parse(String)} meaning that {@code value} should already represent a valid representation of the input.
* <p>
* The condition result has for goal to check the optional conditions that are user configurable (eg min/max values for a number, a specific material
* for an item, etc...).
*
* @param value The parsed argument
* @return the error code or {@link #SUCCESS}
*/
public abstract int getConditionResult(@NotNull T value);
public abstract T parse(@NotNull String input) throws ArgumentSyntaxException;
/**
* Gets the ID of the argument, showed in-game above the chat bar
@ -179,12 +150,9 @@ public abstract class Argument<T> {
*
* @param defaultValue the default argument value, null to make the argument non-optional
* @return 'this' for chaining
* @throws IllegalArgumentException if {@code defaultValue} does not validate {@link #getConditionResult(Object)}
*/
@NotNull
public Argument<T> setDefaultValue(@Nullable T defaultValue) {
Check.argCondition(defaultValue != null && getConditionResult(defaultValue) != SUCCESS,
"The default value needs to validate the argument condition!");
this.defaultValue = defaultValue;
return this;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
/**
@ -15,21 +16,15 @@ public class ArgumentBoolean extends Argument<Boolean> {
super(id);
}
@Override
public int getCorrectionResult(@NotNull String value) {
return (value.equalsIgnoreCase("true")
|| value.equalsIgnoreCase("false")) ? SUCCESS : NOT_BOOLEAN_ERROR;
}
@NotNull
@Override
public Boolean parse(@NotNull String value) {
return Boolean.parseBoolean(value);
}
public Boolean parse(@NotNull String input) throws ArgumentSyntaxException {
if (input.equalsIgnoreCase("true"))
return true;
if (input.equalsIgnoreCase("false"))
return false;
@Override
public int getConditionResult(@NotNull Boolean value) {
return SUCCESS;
throw new ArgumentSyntaxException("Not a boolean", input, NOT_BOOLEAN_ERROR);
}
}

View File

@ -1,12 +1,12 @@
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.callback.validator.StringArrayValidator;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.regex.Pattern;
/**
* Same as {@link ArgumentStringArray} with the exception
* that this argument can trigger {@link net.minestom.server.command.builder.Command#onDynamicWrite(CommandSender, String)}.
@ -21,28 +21,19 @@ public class ArgumentDynamicStringArray extends Argument<String[]> {
super(id, true, true);
}
@Override
public int getCorrectionResult(@NotNull String value) {
return SUCCESS;
}
@NotNull
@Override
public String[] parse(@NotNull String value) {
return value.split(Pattern.quote(" "));
}
@Override
public int getConditionResult(@NotNull String[] value) {
public String[] parse(@NotNull String input) throws ArgumentSyntaxException {
final String[] value = input.split(StringUtils.SPACE);
// true if 'value' is valid based on the dynamic restriction
final boolean restrictionCheck = dynamicRestriction == null || dynamicRestriction.isValid(value);
if (!restrictionCheck) {
return RESTRICTION_ERROR;
throw new ArgumentSyntaxException("Argument does not respect the dynamic restriction", input, RESTRICTION_ERROR);
}
return SUCCESS;
return value;
}
/**

View File

@ -2,7 +2,9 @@ package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.arguments.minecraft.SuggestionType;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.callback.validator.StringValidator;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -25,31 +27,20 @@ public class ArgumentDynamicWord extends Argument<String> {
this.suggestionType = suggestionType;
}
@Override
public int getCorrectionResult(@NotNull String value) {
if (value.contains(" "))
return SPACE_ERROR;
return SUCCESS;
}
@NotNull
@Override
public String parse(@NotNull String value) {
return value;
}
@Override
public int getConditionResult(@NotNull String value) {
public String parse(@NotNull String input) throws ArgumentSyntaxException {
if (input.contains(StringUtils.SPACE))
throw new ArgumentSyntaxException("Word cannot contain space characters", input, SPACE_ERROR);
// true if 'value' is valid based on the dynamic restriction
final boolean restrictionCheck = dynamicRestriction == null || dynamicRestriction.isValid(value);
final boolean restrictionCheck = dynamicRestriction == null || dynamicRestriction.isValid(input);
if (!restrictionCheck) {
return RESTRICTION_ERROR;
throw new ArgumentSyntaxException("Word does not respect the dynamic restriction", input, RESTRICTION_ERROR);
}
return SUCCESS;
return input;
}
/**

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
/**
@ -15,45 +16,36 @@ public class ArgumentString extends Argument<String> {
super(id, true);
}
@NotNull
@Override
public int getCorrectionResult(@NotNull String value) {
public String parse(@NotNull String input) throws ArgumentSyntaxException {
// Check if value start and end with quote
final char first = value.charAt(0);
final char last = value.charAt(value.length() - 1);
final char first = input.charAt(0);
final char last = input.charAt(input.length() - 1);
final boolean quote = first == '\"' && last == '\"';
if (!quote)
return QUOTE_ERROR;
throw new ArgumentSyntaxException("String argument needs to start and end with quotes", input, QUOTE_ERROR);
for (int i = 1; i < value.length(); i++) {
final char c = value.charAt(i);
// Verify backslashes
for (int i = 1; i < input.length(); i++) {
final char c = input.charAt(i);
if (c == '\"') {
final char lastChar = value.charAt(i - 1);
final char lastChar = input.charAt(i - 1);
if (lastChar == '\\') {
continue;
} else if (i == value.length() - 1) {
return SUCCESS;
} else if (i == input.length() - 1) {
// Remove first and last characters (quote)
input = input.substring(1, input.length() - 1);
// Remove all backslashes
input = input.replace("\\", "");
return input;
}
}
}
// Last quote is written like \"
return QUOTE_ERROR;
}
@NotNull
@Override
public String parse(@NotNull String value) {
// Remove first and last characters (quote)
value = value.substring(1, value.length() - 1);
// Remove all backslashes
value = value.replace("\\", "");
return value;
}
@Override
public int getConditionResult(@NotNull String value) {
return SUCCESS;
throw new ArgumentSyntaxException("Last quote is escaped", input, QUOTE_ERROR);
}
}

View File

@ -1,5 +1,7 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Pattern;
@ -15,19 +17,9 @@ public class ArgumentStringArray extends Argument<String[]> {
super(id, true, true);
}
@Override
public int getCorrectionResult(@NotNull String value) {
return SUCCESS;
}
@NotNull
@Override
public String[] parse(@NotNull String value) {
return value.split(Pattern.quote(" "));
}
@Override
public int getConditionResult(@NotNull String[] value) {
return SUCCESS;
public String[] parse(@NotNull String input) throws ArgumentSyntaxException {
return input.split(Pattern.quote(StringUtils.SPACE));
}
}

View File

@ -1,5 +1,7 @@
package net.minestom.server.command.builder.arguments;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -37,32 +39,22 @@ public class ArgumentWord extends Argument<String> {
return this;
}
@NotNull
@Override
public int getCorrectionResult(@NotNull String value) {
if (value.contains(" "))
return SPACE_ERROR;
public String parse(@NotNull String input) throws ArgumentSyntaxException {
if (input.contains(StringUtils.SPACE))
throw new ArgumentSyntaxException("Word cannot contain space character", input, SPACE_ERROR);
// Check restrictions (acting as literal)
if (hasRestrictions()) {
for (String r : restrictions) {
if (value.equalsIgnoreCase(r))
return SUCCESS;
if (input.equalsIgnoreCase(r))
return input;
}
return RESTRICTION_ERROR;
throw new ArgumentSyntaxException("Word needs to be in the restriction list", input, RESTRICTION_ERROR);
}
return SUCCESS;
}
@NotNull
@Override
public String parse(@NotNull String value) {
return value;
}
@Override
public int getConditionResult(@NotNull String value) {
return SUCCESS;
return input;
}
/**

View File

@ -2,6 +2,7 @@ package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
/**
@ -17,20 +18,13 @@ public class ArgumentColor extends Argument<ChatColor> {
super(id);
}
@Override
public int getCorrectionResult(@NotNull String value) {
final ChatColor color = ChatColor.fromName(value);
return color == ChatColor.NO_COLOR ? UNDEFINED_COLOR : SUCCESS;
}
@NotNull
@Override
public ChatColor parse(@NotNull String value) {
return ChatColor.fromName(value);
}
public ChatColor parse(@NotNull String input) throws ArgumentSyntaxException {
final ChatColor color = ChatColor.fromName(input);
if (color == ChatColor.NO_COLOR)
throw new ArgumentSyntaxException("Undefined color", input, UNDEFINED_COLOR);
@Override
public int getConditionResult(@NotNull ChatColor value) {
return SUCCESS;
return color;
}
}

View File

@ -6,7 +6,6 @@ import net.minestom.server.entity.Entity;
import net.minestom.server.network.ConnectionManager;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -18,6 +17,8 @@ import java.util.List;
*/
public class ArgumentEntities extends Argument<List<Entity>> {
private static final int SUCCESS = 0;
public static final int INVALID_SYNTAX = -2;
public static final int ONLY_SINGLE_ENTITY_ERROR = -3;
public static final int ONLY_PLAYERS_ERROR = -4;
@ -46,7 +47,6 @@ public class ArgumentEntities extends Argument<List<Entity>> {
return this;
}
@Override
public int getCorrectionResult(@NotNull String value) {
System.out.println("check: " + value);
@ -119,11 +119,6 @@ public class ArgumentEntities extends Argument<List<Entity>> {
return null;
}
@Override
public int getConditionResult(@NotNull List<Entity> value) {
return SUCCESS;
}
public boolean isOnlySingleEntity() {
return onlySingleEntity;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.math.FloatRange;
import org.jetbrains.annotations.NotNull;
@ -16,63 +17,39 @@ public class ArgumentFloatRange extends ArgumentRange<FloatRange> {
super(id);
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
Float.valueOf(value);
return SUCCESS; // Is a single number
} catch (NumberFormatException e) {
String[] split = value.split(Pattern.quote(".."));
if (split.length == 1) {
try {
Float.valueOf(split[0]);
return SUCCESS;
} catch (NumberFormatException e2) {
return FORMAT_ERROR;
}
} else if (split.length == 2) {
try {
Float.valueOf(split[0]); // min
Float.valueOf(split[1]); // max
return SUCCESS;
} catch (NumberFormatException e2) {
return FORMAT_ERROR;
}
} else {
return FORMAT_ERROR;
}
}
}
@NotNull
@Override
public FloatRange parse(@NotNull String value) {
if (value.contains("..")) {
final int index = value.indexOf('.');
final String[] split = value.split(Pattern.quote(".."));
public FloatRange parse(@NotNull String input) throws ArgumentSyntaxException {
try {
if (input.contains("..")) {
final int index = input.indexOf('.');
final String[] split = input.split(Pattern.quote(".."));
final float min;
final float max;
if (index == 0) {
// Format ..NUMBER
min = Float.MIN_VALUE;
max = Float.parseFloat(split[0]);
} else {
if (split.length == 2) {
// Format NUMBER..NUMBER
min = Float.parseFloat(split[0]);
max = Float.parseFloat(split[1]);
final float min;
final float max;
if (index == 0) {
// Format ..NUMBER
min = Float.MIN_VALUE;
max = Float.parseFloat(split[0]);
} else {
// Format NUMBER..
min = Float.parseFloat(split[0]);
max = Float.MAX_VALUE;
if (split.length == 2) {
// Format NUMBER..NUMBER
min = Float.parseFloat(split[0]);
max = Float.parseFloat(split[1]);
} else {
// Format NUMBER..
min = Float.parseFloat(split[0]);
max = Float.MAX_VALUE;
}
}
}
return new FloatRange(min, max);
} else {
final float number = Float.parseFloat(value);
return new FloatRange(number);
return new FloatRange(min, max);
} else {
final float number = Float.parseFloat(input);
return new FloatRange(number);
}
} catch (NumberFormatException e2) {
throw new ArgumentSyntaxException("Invalid number", input, FORMAT_ERROR);
}
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.math.IntRange;
import org.jetbrains.annotations.NotNull;
@ -16,63 +17,39 @@ public class ArgumentIntRange extends ArgumentRange<IntRange> {
super(id);
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
Integer.valueOf(value);
return SUCCESS; // Is a single number
} catch (NumberFormatException e) {
String[] split = value.split(Pattern.quote(".."));
if (split.length == 1) {
try {
Integer.valueOf(split[0]);
return SUCCESS;
} catch (NumberFormatException e2) {
return FORMAT_ERROR;
}
} else if (split.length == 2) {
try {
Integer.valueOf(split[0]); // min
Integer.valueOf(split[1]); // max
return SUCCESS;
} catch (NumberFormatException e2) {
return FORMAT_ERROR;
}
} else {
return FORMAT_ERROR;
}
}
}
@NotNull
@Override
public IntRange parse(@NotNull String value) {
if (value.contains("..")) {
final int index = value.indexOf('.');
final String[] split = value.split(Pattern.quote(".."));
public IntRange parse(@NotNull String input) throws ArgumentSyntaxException {
try {
if (input.contains("..")) {
final int index = input.indexOf('.');
final String[] split = input.split(Pattern.quote(".."));
final int min;
final int max;
if (index == 0) {
// Format ..NUMBER
min = Integer.MIN_VALUE;
max = Integer.parseInt(split[0]);
} else {
if (split.length == 2) {
// Format NUMBER..NUMBER
min = Integer.parseInt(split[0]);
max = Integer.parseInt(split[1]);
final int min;
final int max;
if (index == 0) {
// Format ..NUMBER
min = Integer.MIN_VALUE;
max = Integer.parseInt(split[0]);
} else {
// Format NUMBER..
min = Integer.parseInt(split[0]);
max = Integer.MAX_VALUE;
if (split.length == 2) {
// Format NUMBER..NUMBER
min = Integer.parseInt(split[0]);
max = Integer.parseInt(split[1]);
} else {
// Format NUMBER..
min = Integer.parseInt(split[0]);
max = Integer.MAX_VALUE;
}
}
}
return new IntRange(min, max);
} else {
final int number = Integer.parseInt(value);
return new IntRange(number);
return new IntRange(min, max);
} else {
final int number = Integer.parseInt(input);
return new IntRange(number);
}
} catch (NumberFormatException e2) {
throw new ArgumentSyntaxException("Invalid number", input, FORMAT_ERROR);
}
}
}

View File

@ -1,12 +1,12 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.NBTUtils;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.jglrxavpok.hephaistos.nbt.NBTException;
import org.jglrxavpok.hephaistos.nbt.SNBTParser;
@ -29,63 +29,36 @@ public class ArgumentItemStack extends Argument<ItemStack> {
super(id, true);
}
@Override
public int getCorrectionResult(@NotNull String value) {
if (value.startsWith("{")) {
return NO_MATERIAL;
}
final int nbtIndex = value.indexOf("{");
if (nbtIndex == -1 && !value.contains(" ")) {
// Only item name
return SUCCESS;
} else {
// has nbt
final String sNBT = value.substring(nbtIndex);
try {
NBT nbt = new SNBTParser(new StringReader(sNBT)).parse();
return nbt instanceof NBTCompound ? SUCCESS : INVALID_NBT;
} catch (NBTException e) {
return INVALID_NBT;
}
}
}
@NotNull
@Override
public ItemStack parse(@NotNull String value) {
final int nbtIndex = value.indexOf("{");
public ItemStack parse(@NotNull String input) throws ArgumentSyntaxException {
final int nbtIndex = input.indexOf("{");
if (nbtIndex == 0)
throw new ArgumentSyntaxException("The item needs a material", input, NO_MATERIAL);
if (nbtIndex == -1) {
// Only item name
final Material material = Registries.getMaterial(value);
final Material material = Registries.getMaterial(input);
return new ItemStack(material, (byte) 1);
} else {
final String materialName = value.substring(0, nbtIndex);
final String materialName = input.substring(0, nbtIndex);
final Material material = Registries.getMaterial(materialName);
ItemStack itemStack = new ItemStack(material, (byte) 1);
final String sNBT = value.substring(nbtIndex).replace("\\\"", "\"");
final String sNBT = input.substring(nbtIndex).replace("\\\"", "\"");
NBTCompound compound = null;
NBTCompound compound;
try {
compound = (NBTCompound) new SNBTParser(new StringReader(sNBT)).parse();
} catch (NBTException e) {
e.printStackTrace();
throw new ArgumentSyntaxException("Item NBT is invalid", input, INVALID_NBT);
}
assert compound != null;
NBTUtils.loadDataIntoItem(itemStack, compound);
return itemStack;
}
}
@Override
public int getConditionResult(@NotNull ItemStack value) {
return SUCCESS;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
@ -22,29 +23,18 @@ public class ArgumentNbtCompoundTag extends Argument<NBTCompound> {
super(id, true);
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
NBT nbt = new SNBTParser(new StringReader(value)).parse();
return nbt instanceof NBTCompound ? SUCCESS : INVALID_NBT;
} catch (NBTException e) {
return INVALID_NBT;
}
}
@NotNull
@Override
public NBTCompound parse(@NotNull String value) {
public NBTCompound parse(@NotNull String input) throws ArgumentSyntaxException {
try {
NBT nbt = new SNBTParser(new StringReader(value)).parse();
NBT nbt = new SNBTParser(new StringReader(input)).parse();
if (!(nbt instanceof NBTCompound))
throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT);
return (NBTCompound) nbt;
} catch (NBTException e) {
return null;
throw new ArgumentSyntaxException("NBTCompound is invalid", input, INVALID_NBT);
}
}
@Override
public int getConditionResult(@NotNull NBTCompound value) {
return SUCCESS;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTException;
@ -23,28 +24,13 @@ public class ArgumentNbtTag extends Argument<NBT> {
super(id, true);
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
NBT nbt = new SNBTParser(new StringReader(value)).parse();
return nbt != null ? SUCCESS : INVALID_NBT;
} catch (NBTException e) {
return INVALID_NBT;
}
}
@NotNull
@Override
public NBT parse(@NotNull String value) {
public NBT parse(@NotNull String input) throws ArgumentSyntaxException {
try {
return new SNBTParser(new StringReader(value)).parse();
return new SNBTParser(new StringReader(input)).parse();
} catch (NBTException e) {
return null;
throw new ArgumentSyntaxException("Invalid NBT", input, INVALID_NBT);
}
}
@Override
public int getConditionResult(@NotNull NBT value) {
return SUCCESS;
}
}

View File

@ -1,7 +1,6 @@
package net.minestom.server.command.builder.arguments.minecraft;
import net.minestom.server.command.builder.arguments.Argument;
import org.jetbrains.annotations.NotNull;
/**
* Abstract class used by {@link ArgumentIntRange} and {@link ArgumentFloatRange}.
@ -15,9 +14,4 @@ public abstract class ArgumentRange<T> extends Argument<T> {
public ArgumentRange(String id) {
super(id);
}
@Override
public int getConditionResult(@NotNull T value) {
return SUCCESS;
}
}

View File

@ -3,6 +3,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.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import org.jetbrains.annotations.NotNull;
@ -23,43 +24,31 @@ public class ArgumentTime extends Argument<UpdateOption> {
super(id);
}
@Override
public int getCorrectionResult(@NotNull String value) {
final char lastChar = value.charAt(value.length() - 1);
if (!SUFFIXES.contains(lastChar))
return INVALID_TIME_FORMAT;
value = value.substring(0, value.length() - 1);
try {
// Check if value is a number
Integer.parseInt(value);
return SUCCESS;
} catch (NumberFormatException e) {
return NO_NUMBER;
}
}
@NotNull
@Override
public UpdateOption parse(@NotNull String value) {
final char lastChar = value.charAt(value.length() - 1);
TimeUnit timeUnit = null;
if (lastChar == 'd') {
timeUnit = TimeUnit.DAY;
} else if (lastChar == 's') {
timeUnit = TimeUnit.SECOND;
} else if (lastChar == 't') {
timeUnit = TimeUnit.TICK;
public UpdateOption parse(@NotNull String input) throws ArgumentSyntaxException {
final char lastChar = input.charAt(input.length() - 1);
if (!SUFFIXES.contains(lastChar))
throw new ArgumentSyntaxException("Time format is invalid", input, INVALID_TIME_FORMAT);
// Remove last char
input = input.substring(0, input.length() - 1);
try {
// Check if value is a number
final int time = Integer.parseInt(input);
TimeUnit timeUnit = null;
if (lastChar == 'd') {
timeUnit = TimeUnit.DAY;
} else if (lastChar == 's') {
timeUnit = TimeUnit.SECOND;
} else if (lastChar == 't') {
timeUnit = TimeUnit.TICK;
}
return new UpdateOption(time, timeUnit);
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("Time needs to be a number", input, NO_NUMBER);
}
value = value.substring(0, value.length() - 1);
final int time = Integer.parseInt(value);
return new UpdateOption(time, timeUnit);
}
@Override
public int getConditionResult(@NotNull UpdateOption value) {
return SUCCESS;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.command.builder.arguments.minecraft.registry;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
public abstract class ArgumentRegistry<T> extends Argument<T> {
@ -13,19 +14,13 @@ public abstract class ArgumentRegistry<T> extends Argument<T> {
public abstract T getRegistry(@NotNull String value);
@Override
public int getCorrectionResult(@NotNull String value) {
return getRegistry(value) == null ? INVALID_NAME : SUCCESS;
}
@NotNull
@Override
public T parse(@NotNull String value) {
return getRegistry(value);
}
public T parse(@NotNull String input) throws ArgumentSyntaxException {
final T registryValue = getRegistry(input);
if (registryValue == null)
throw new ArgumentSyntaxException("Registry value is invalid", input, INVALID_NAME);
@Override
public int getConditionResult(@NotNull T value) {
return SUCCESS;
return registryValue;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.number;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
public class ArgumentDouble extends ArgumentNumber<Double> {
@ -10,44 +11,33 @@ public class ArgumentDouble extends ArgumentNumber<Double> {
this.max = Double.MAX_VALUE;
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
String parsed = parseValue(value);
int radix = getRadix(value);
if (radix != 10) {
Long.parseLong(parsed, radix);
} else {
Double.parseDouble(parsed);
}
return SUCCESS;
} catch (NumberFormatException | NullPointerException e) {
return NOT_NUMBER_ERROR;
}
}
@NotNull
@Override
public Double parse(@NotNull String value) {
String parsed = parseValue(value);
int radix = getRadix(value);
if (radix != 10) {
return (double) Long.parseLong(parsed, radix);
}
return Double.parseDouble(parsed);
}
public Double parse(@NotNull String input) throws ArgumentSyntaxException {
try {
final double value;
{
String parsed = parseValue(input);
int radix = getRadix(input);
if (radix != 10) {
value = (double) Long.parseLong(parsed, radix);
} else {
value = Double.parseDouble(parsed);
}
}
@Override
public int getConditionResult(@NotNull Double value) {
// Check range
if (hasMin && value < min) {
return RANGE_ERROR;
}
if (hasMax && value > max) {
return RANGE_ERROR;
}
// Check range
if (hasMin && value < min) {
throw new ArgumentSyntaxException("Input is lower than the minimum required value", input, RANGE_ERROR);
}
if (hasMax && value > max) {
throw new ArgumentSyntaxException("Input is higher than the minimum required value", input, RANGE_ERROR);
}
return SUCCESS;
return value;
} catch (NumberFormatException | NullPointerException e) {
throw new ArgumentSyntaxException("Input is not a number/long", input, NOT_NUMBER_ERROR);
}
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.number;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
public class ArgumentFloat extends ArgumentNumber<Float> {
@ -10,44 +11,33 @@ public class ArgumentFloat extends ArgumentNumber<Float> {
this.max = Float.MAX_VALUE;
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
String parsed = parseValue(value);
int radix = getRadix(value);
if (radix != 10) {
Integer.parseInt(parsed, radix);
} else {
Float.parseFloat(parsed);
}
return SUCCESS;
} catch (NumberFormatException | NullPointerException e) {
return NOT_NUMBER_ERROR;
}
}
@NotNull
@Override
public Float parse(@NotNull String value) {
String parsed = parseValue(value);
int radix = getRadix(value);
if (radix != 10) {
return (float) Integer.parseInt(parsed, radix);
}
return Float.parseFloat(parsed);
}
public Float parse(@NotNull String input) throws ArgumentSyntaxException {
try {
final float value;
{
String parsed = parseValue(input);
int radix = getRadix(input);
if (radix != 10) {
value = (float) Integer.parseInt(parsed, radix);
} else {
value = Float.parseFloat(parsed);
}
}
@Override
public int getConditionResult(@NotNull Float value) {
// Check range
if (hasMin && value < min) {
return RANGE_ERROR;
}
if (hasMax && value > max) {
return RANGE_ERROR;
}
// Check range
if (hasMin && value < min) {
throw new ArgumentSyntaxException("Input is lower than the minimum required value", input, RANGE_ERROR);
}
if (hasMax && value > max) {
throw new ArgumentSyntaxException("Input is higher than the minimum required value", input, RANGE_ERROR);
}
return SUCCESS;
return value;
} catch (NumberFormatException | NullPointerException e) {
throw new ArgumentSyntaxException("Input is not a number/long", input, NOT_NUMBER_ERROR);
}
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.number;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
public class ArgumentInteger extends ArgumentNumber<Integer> {
@ -10,33 +11,24 @@ public class ArgumentInteger extends ArgumentNumber<Integer> {
this.max = Integer.MAX_VALUE;
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
Integer.parseInt(parseValue(value), getRadix(value));
return SUCCESS;
} catch (NumberFormatException | NullPointerException e) {
return NOT_NUMBER_ERROR;
}
}
@NotNull
@Override
public Integer parse(@NotNull String value) {
return Integer.parseInt(parseValue(value), getRadix(value));
}
public Integer parse(@NotNull String input) throws ArgumentSyntaxException {
try {
final int value = Integer.parseInt(parseValue(input), getRadix(input));
@Override
public int getConditionResult(@NotNull Integer value) {
// Check range
if (hasMin && value < min) {
return RANGE_ERROR;
}
if (hasMax && value > max) {
return RANGE_ERROR;
}
// Check range
if (hasMin && value < min) {
throw new ArgumentSyntaxException("Input is lower than the minimum required value", input, RANGE_ERROR);
}
if (hasMax && value > max) {
throw new ArgumentSyntaxException("Input is higher than the minimum required value", input, RANGE_ERROR);
}
return SUCCESS;
return value;
} catch (NumberFormatException | NullPointerException e) {
throw new ArgumentSyntaxException("Input is not a number/long", input, NOT_NUMBER_ERROR);
}
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.command.builder.arguments.number;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import org.jetbrains.annotations.NotNull;
public class ArgumentLong extends ArgumentNumber<Long> {
@ -10,33 +11,24 @@ public class ArgumentLong extends ArgumentNumber<Long> {
this.max = Long.MAX_VALUE;
}
@Override
public int getCorrectionResult(@NotNull String value) {
try {
Long.parseLong(parseValue(value), getRadix(value));
return SUCCESS;
} catch (NumberFormatException | NullPointerException e) {
return NOT_NUMBER_ERROR;
}
}
@NotNull
@Override
public Long parse(@NotNull String value) {
return Long.parseLong(parseValue(value), getRadix(value));
}
public Long parse(@NotNull String input) throws ArgumentSyntaxException {
try {
final long value = Long.parseLong(parseValue(input), getRadix(input));
@Override
public int getConditionResult(@NotNull Long value) {
// Check range
if (hasMin && value < min) {
return RANGE_ERROR;
}
if (hasMax && value > max) {
return RANGE_ERROR;
}
// Check range
if (hasMin && value < min) {
throw new ArgumentSyntaxException("Input is lower than the minimum required value", input, RANGE_ERROR);
}
if (hasMax && value > max) {
throw new ArgumentSyntaxException("Input is higher than the minimum required value", input, RANGE_ERROR);
}
return SUCCESS;
return value;
} catch (NumberFormatException | NullPointerException e) {
throw new ArgumentSyntaxException("Input is not a number/long", input, NOT_NUMBER_ERROR);
}
}
}

View File

@ -81,6 +81,7 @@ public abstract class ArgumentNumber<T extends Number> extends Argument<T> {
return max;
}
@NotNull
protected String parseValue(@NotNull String value) {
if (value.startsWith("0b")) {
value = value.replaceFirst(Pattern.quote("0b"), "");

View File

@ -1,7 +1,9 @@
package net.minestom.server.command.builder.arguments.relative;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.location.RelativeBlockPosition;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
/**
@ -15,45 +17,16 @@ public class ArgumentRelativeBlockPosition extends ArgumentRelative<RelativeBloc
super(id, 3);
}
@NotNull
@Override
public int getCorrectionResult(@NotNull String value) {
final String[] split = value.split(" ");
public RelativeBlockPosition parse(@NotNull String input) throws ArgumentSyntaxException {
final String[] split = input.split(StringUtils.SPACE);
// Check if the value has enough element to be correct
if (split.length != getNumberCount()) {
return INVALID_NUMBER_COUNT_ERROR;
throw new ArgumentSyntaxException("Invalid number of values", input, INVALID_NUMBER_COUNT_ERROR);
}
// Check if each element is correct
for (String element : split) {
if (!element.startsWith(RELATIVE_CHAR)) {
try {
// Will throw the exception if not an integer
Integer.parseInt(element);
} catch (NumberFormatException e) {
return INVALID_NUMBER_ERROR;
}
} else {
if (element.length() > RELATIVE_CHAR.length()) {
try {
final String potentialNumber = element.substring(1);
// Will throw the exception if not an integer
Integer.parseInt(potentialNumber);
} catch (NumberFormatException | IndexOutOfBoundsException e) {
return INVALID_NUMBER_ERROR;
}
}
}
}
return SUCCESS;
}
@NotNull
@Override
public RelativeBlockPosition parse(@NotNull String value) {
final String[] split = value.split(" ");
BlockPosition blockPosition = new BlockPosition(0, 0, 0);
boolean relativeX = false;
boolean relativeY = false;
@ -72,8 +45,24 @@ public class ArgumentRelativeBlockPosition extends ArgumentRelative<RelativeBloc
}
if (element.length() != RELATIVE_CHAR.length()) {
final String potentialNumber = element.substring(1);
final int number = Integer.parseInt(potentialNumber);
try {
final String potentialNumber = element.substring(1);
final int number = Integer.parseInt(potentialNumber);
if (i == 0) {
blockPosition.setX(number);
} else if (i == 1) {
blockPosition.setY(number);
} else if (i == 2) {
blockPosition.setZ(number);
}
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("Invalid number", input, INVALID_NUMBER_ERROR);
}
}
} else {
try {
final int number = Integer.parseInt(element);
if (i == 0) {
blockPosition.setX(number);
} else if (i == 1) {
@ -81,25 +70,12 @@ public class ArgumentRelativeBlockPosition extends ArgumentRelative<RelativeBloc
} else if (i == 2) {
blockPosition.setZ(number);
}
}
} else {
final int number = Integer.parseInt(element);
if (i == 0) {
blockPosition.setX(number);
} else if (i == 1) {
blockPosition.setY(number);
} else if (i == 2) {
blockPosition.setZ(number);
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("Invalid number", input, INVALID_NUMBER_ERROR);
}
}
}
return new RelativeBlockPosition(blockPosition, relativeX, relativeY, relativeZ);
}
@Override
public int getConditionResult(@NotNull RelativeBlockPosition value) {
return SUCCESS;
}
}

View File

@ -1,54 +0,0 @@
package net.minestom.server.command.builder.arguments.relative;
import net.minestom.server.utils.location.RelativeVec;
import org.jetbrains.annotations.NotNull;
/**
* Common super class for {@link ArgumentRelativeVec2} and {@link ArgumentRelativeVec3}.
*/
public abstract class ArgumentRelativeVec extends ArgumentRelative<RelativeVec> {
public ArgumentRelativeVec(@NotNull String id, int numberCount) {
super(id, numberCount);
}
@Override
public int getCorrectionResult(@NotNull String value) {
final String[] split = value.split(" ");
// Check if the value has enough element to be correct
if (split.length != getNumberCount()) {
return INVALID_NUMBER_COUNT_ERROR;
}
// Check if each element is correct
for (String element : split) {
if (!element.startsWith(RELATIVE_CHAR)) {
try {
// Will throw the exception if not a float
Float.parseFloat(element);
} catch (NumberFormatException e) {
return INVALID_NUMBER_ERROR;
}
} else {
if (element.length() > RELATIVE_CHAR.length()) {
try {
final String potentialNumber = element.substring(1);
// Will throw the exception if not a float
Float.parseFloat(potentialNumber);
} catch (NumberFormatException | IndexOutOfBoundsException e) {
return INVALID_NUMBER_ERROR;
}
}
}
}
return SUCCESS;
}
@Override
public int getConditionResult(@NotNull RelativeVec value) {
return SUCCESS;
}
}

View File

@ -1,7 +1,9 @@
package net.minestom.server.command.builder.arguments.relative;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.location.RelativeVec;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
/**
@ -9,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
* <p>
* Example: -1.2 ~
*/
public class ArgumentRelativeVec2 extends ArgumentRelativeVec {
public class ArgumentRelativeVec2 extends ArgumentRelative<RelativeVec> {
public ArgumentRelativeVec2(@NotNull String id) {
super(id, 2);
@ -17,8 +19,13 @@ public class ArgumentRelativeVec2 extends ArgumentRelativeVec {
@NotNull
@Override
public RelativeVec parse(@NotNull String value) {
final String[] split = value.split(" ");
public RelativeVec parse(@NotNull String input) throws ArgumentSyntaxException {
final String[] split = input.split(StringUtils.SPACE);
// Check if the value has enough element to be correct
if (split.length != getNumberCount()) {
throw new ArgumentSyntaxException("Invalid number of values", input, INVALID_NUMBER_COUNT_ERROR);
}
Vector vector = new Vector();
boolean relativeX = false;
@ -26,30 +33,34 @@ public class ArgumentRelativeVec2 extends ArgumentRelativeVec {
for (int i = 0; i < split.length; i++) {
final String element = split[i];
if (element.startsWith(RELATIVE_CHAR)) {
if (i == 0) {
relativeX = true;
} else if (i == 1) {
relativeZ = true;
}
try {
if (element.startsWith(RELATIVE_CHAR)) {
if (i == 0) {
relativeX = true;
} else if (i == 1) {
relativeZ = true;
}
if (element.length() != RELATIVE_CHAR.length()) {
final String potentialNumber = element.substring(1);
final float number = Float.parseFloat(potentialNumber);
if (element.length() != RELATIVE_CHAR.length()) {
final String potentialNumber = element.substring(1);
final float number = Float.parseFloat(potentialNumber);
if (i == 0) {
vector.setX(number);
} else if (i == 1) {
vector.setZ(number);
}
}
} else {
final float number = Float.parseFloat(element);
if (i == 0) {
vector.setX(number);
} else if (i == 1) {
vector.setZ(number);
}
}
} else {
final float number = Float.parseFloat(element);
if (i == 0) {
vector.setX(number);
} else if (i == 1) {
vector.setZ(number);
}
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("Invalid number", input, INVALID_NUMBER_ERROR);
}
}

View File

@ -1,7 +1,9 @@
package net.minestom.server.command.builder.arguments.relative;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.location.RelativeVec;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
/**
@ -9,7 +11,7 @@ import org.jetbrains.annotations.NotNull;
* <p>
* Example: -1.2 ~ 5
*/
public class ArgumentRelativeVec3 extends ArgumentRelativeVec {
public class ArgumentRelativeVec3 extends ArgumentRelative<RelativeVec> {
public ArgumentRelativeVec3(@NotNull String id) {
super(id, 3);
@ -17,8 +19,13 @@ public class ArgumentRelativeVec3 extends ArgumentRelativeVec {
@NotNull
@Override
public RelativeVec parse(@NotNull String value) {
final String[] split = value.split(" ");
public RelativeVec parse(@NotNull String input) throws ArgumentSyntaxException {
final String[] split = input.split(StringUtils.SPACE);
// Check if the value has enough element to be correct
if (split.length != getNumberCount()) {
throw new ArgumentSyntaxException("Invalid number of values", input, INVALID_NUMBER_COUNT_ERROR);
}
Vector vector = new Vector();
boolean relativeX = false;
@ -27,19 +34,30 @@ public class ArgumentRelativeVec3 extends ArgumentRelativeVec {
for (int i = 0; i < split.length; i++) {
final String element = split[i];
if (element.startsWith(RELATIVE_CHAR)) {
try {
if (element.startsWith(RELATIVE_CHAR)) {
if (i == 0) {
relativeX = true;
} else if (i == 1) {
relativeY = true;
} else if (i == 2) {
relativeZ = true;
}
if (i == 0) {
relativeX = true;
} else if (i == 1) {
relativeY = true;
} else if (i == 2) {
relativeZ = true;
}
if (element.length() != RELATIVE_CHAR.length()) {
final String potentialNumber = element.substring(1);
final float number = Float.parseFloat(potentialNumber);
if (i == 0) {
vector.setX(number);
} else if (i == 1) {
vector.setY(number);
} else if (i == 2) {
vector.setZ(number);
}
}
if (element.length() != RELATIVE_CHAR.length()) {
final String potentialNumber = element.substring(1);
final float number = Float.parseFloat(potentialNumber);
} else {
final float number = Float.parseFloat(element);
if (i == 0) {
vector.setX(number);
} else if (i == 1) {
@ -48,16 +66,8 @@ public class ArgumentRelativeVec3 extends ArgumentRelativeVec {
vector.setZ(number);
}
}
} else {
final float number = Float.parseFloat(element);
if (i == 0) {
vector.setX(number);
} else if (i == 1) {
vector.setY(number);
} else if (i == 2) {
vector.setZ(number);
}
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("Invalid number", input, INVALID_NUMBER_ERROR);
}
}

View File

@ -0,0 +1,45 @@
package net.minestom.server.command.builder.exception;
import net.minestom.server.command.builder.ArgumentCallback;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import org.jetbrains.annotations.NotNull;
/**
* Exception triggered when an {@link Argument} is wrongly parsed.
* <p>
* Retrieved in {@link ArgumentCallback} defined in {@link Command#setArgumentCallback(ArgumentCallback, Argument)}.
*/
public class ArgumentSyntaxException extends Exception {
private final String input;
private final int errorCode;
public ArgumentSyntaxException(@NotNull String message, @NotNull String input, int errorCode) {
super(message);
this.input = input;
this.errorCode = errorCode;
}
/**
* Gets the problematic command input.
*
* @return the command input which triggered the exception
*/
@NotNull
public String getInput() {
return input;
}
/**
* Gets the error code of the exception.
* <p>
* The code is decided arbitrary by the argument,
* check the argument class to know the meaning of each one.
*
* @return the argument error code
*/
public int getErrorCode() {
return errorCode;
}
}

View File

@ -9,6 +9,7 @@ import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.play.ClientChatMessagePacket;
import net.minestom.server.network.packet.server.play.ChatMessagePacket;
import net.minestom.server.utils.PacketUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.Collection;
import java.util.function.Function;
@ -72,8 +73,8 @@ public class ChatMessageListener {
return RichMessage.of(usernameText)
.setHoverEvent(ChatHoverEvent.showText("Click to send a message to " + username))
.setClickEvent(ChatClickEvent.suggestCommand("/msg " + username + " "))
.append(ColoredText.of(" " + chatEvent.getMessage()));
.setClickEvent(ChatClickEvent.suggestCommand("/msg " + username + StringUtils.SPACE))
.append(ColoredText.of(StringUtils.SPACE + chatEvent.getMessage()));
}
}

View File

@ -7,6 +7,7 @@ import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
import net.minestom.server.network.packet.server.play.TabCompletePacket;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Pattern;
@ -17,7 +18,7 @@ public class TabCompleteListener {
public static void listener(ClientTabCompletePacket packet, Player player) {
final String text = packet.text;
final String[] split = packet.text.split(Pattern.quote(" "));
final String[] split = packet.text.split(Pattern.quote(StringUtils.SPACE));
final String commandName = split[0].replaceFirst(CommandManager.COMMAND_PREFIX, "");
@ -45,7 +46,7 @@ public class TabCompleteListener {
}
private static int findStart(String text, String[] split) {
final boolean endSpace = text.endsWith(" ");
final boolean endSpace = text.endsWith(StringUtils.SPACE);
int start;
if (endSpace) {
start = text.length();

View File

@ -5,6 +5,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -95,7 +96,7 @@ public class ResourceGatherer {
ProcessBuilder dataGenerator = new ProcessBuilder("java", "-cp", serverJar.getName(), "net.minecraft.data.Main", "--all", "--server", "--dev");
dataGenerator.directory(TMP_FOLDER);
LOGGER.info("Now running data generator with options '--dev', '--server', '--all'");
LOGGER.info("Executing: {}", String.join(" ", dataGenerator.command()));
LOGGER.info("Executing: {}", String.join(StringUtils.SPACE, dataGenerator.command()));
LOGGER.info("Minestom will now wait for it to finish, here's its output:");
LOGGER.info("");
Process dataGeneratorProcess = dataGenerator.start();

View File

@ -5,6 +5,7 @@ import net.minestom.server.command.builder.Arguments;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
@ -66,8 +67,8 @@ public class GamemodeCommand extends Command {
}
}
private void gameModeCallback(CommandSender sender, String gamemode, int error) {
sender.sendMessage("'" + gamemode + "' is not a valid gamemode!");
private void gameModeCallback(CommandSender sender, ArgumentSyntaxException exception) {
sender.sendMessage("'" + exception.getInput() + "' is not a valid gamemode!");
}
private boolean isAllowed(CommandSender sender, String commandString) {

View File

@ -6,6 +6,7 @@ import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.arguments.number.ArgumentNumber;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.entity.Player;
public class HealthCommand extends Command {
@ -40,17 +41,19 @@ public class HealthCommand extends Command {
sender.sendMessage("Correct usage: health [set/add] [number]");
}
private void onModeError(CommandSender sender, String value, int error) {
sender.sendMessage("SYNTAX ERROR: '" + value + "' should be replaced by 'set' or 'add'");
private void onModeError(CommandSender sender, ArgumentSyntaxException exception) {
sender.sendMessage("SYNTAX ERROR: '" + exception.getInput() + "' should be replaced by 'set' or 'add'");
}
private void onValueError(CommandSender sender, String value, int error) {
private void onValueError(CommandSender sender, ArgumentSyntaxException exception) {
final int error = exception.getErrorCode();
final String input = exception.getInput();
switch (error) {
case ArgumentNumber.NOT_NUMBER_ERROR:
sender.sendMessage("SYNTAX ERROR: '" + value + "' isn't a number!");
sender.sendMessage("SYNTAX ERROR: '" + input + "' isn't a number!");
break;
case ArgumentNumber.RANGE_ERROR:
sender.sendMessage("SYNTAX ERROR: " + value + " is not between 0 and 100");
sender.sendMessage("SYNTAX ERROR: " + input + " is not between 0 and 100");
break;
}
}

View File

@ -6,6 +6,7 @@ import net.minestom.server.command.builder.Arguments;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.extensions.ExtensionManager;
import java.io.IOException;
@ -19,7 +20,7 @@ public class LoadExtensionCommand extends Command {
Argument extension = ArgumentType.DynamicStringArray("extensionName");
setArgumentCallback(this::gameModeCallback, extension);
setArgumentCallback(this::extensionCallback, extension);
addSyntax(this::execute, extension);
}
@ -59,8 +60,8 @@ public class LoadExtensionCommand extends Command {
}
}
private void gameModeCallback(CommandSender sender, String extension, int error) {
sender.sendMessage("'" + extension + "' is not a valid extension name!");
private void extensionCallback(CommandSender sender, ArgumentSyntaxException exception) {
sender.sendMessage("'" + exception.getInput() + "' is not a valid extension name!");
}
private String join(String[] extensionNameParts) {

View File

@ -6,6 +6,7 @@ import net.minestom.server.command.builder.Arguments;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.extensions.Extension;
import net.minestom.server.extensions.ExtensionManager;
import org.jetbrains.annotations.NotNull;
@ -74,8 +75,8 @@ public class ReloadExtensionCommand extends Command {
}
}
private void gameModeCallback(CommandSender sender, String extension, int error) {
sender.sendMessage("'" + extension + "' is not a valid extension name!");
private void gameModeCallback(CommandSender sender, ArgumentSyntaxException argumentSyntaxException) {
sender.sendMessage("'" + argumentSyntaxException.getInput() + "' is not a valid extension name!");
}
@Nullable

View File

@ -25,11 +25,13 @@ public class TeleportCommand extends Command {
}
private void onPlayerTeleport(CommandSender sender, Arguments args) {
Player pl = MinecraftServer.getConnectionManager().getPlayer(args.getWord("player"));
final String playerName = args.getWord("player");
Player pl = MinecraftServer.getConnectionManager().getPlayer(playerName);
if (pl != null && sender.isPlayer()) {
Player player = (Player) sender;
player.teleport(pl.getPosition());
}
sender.sendMessage("Teleported to player "+playerName);
}
private void onPositionTeleport(CommandSender sender, Arguments args) {

View File

@ -6,8 +6,10 @@ import net.minestom.server.command.builder.Arguments;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.extensions.Extension;
import net.minestom.server.extensions.ExtensionManager;
import org.apache.commons.lang3.StringUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -22,7 +24,7 @@ public class UnloadExtensionCommand extends Command {
Argument extension = ArgumentType.DynamicStringArray("extensionName");
setArgumentCallback(this::gameModeCallback, extension);
setArgumentCallback(this::extensionCallback, extension);
addSyntax(this::execute, extension);
}
@ -33,11 +35,11 @@ public class UnloadExtensionCommand extends Command {
private void execute(CommandSender sender, Arguments arguments) {
String name = join(arguments.getStringArray("extensionName"));
sender.sendMessage("extensionName = "+name+"....");
sender.sendMessage("extensionName = " + name + "....");
ExtensionManager extensionManager = MinecraftServer.getExtensionManager();
Extension ext = extensionManager.getExtension(name);
if(ext != null) {
if (ext != null) {
try {
extensionManager.unloadExtension(name);
} catch (Throwable t) {
@ -47,27 +49,27 @@ public class UnloadExtensionCommand extends Command {
t.printStackTrace(new PrintStream(baos));
baos.flush();
baos.close();
String contents = new String(baos.toByteArray(), StandardCharsets.UTF_8);
String contents = baos.toString(StandardCharsets.UTF_8);
contents.lines().forEach(sender::sendMessage);
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
sender.sendMessage("Extension '"+name+"' does not exist.");
sender.sendMessage("Extension '" + name + "' does not exist.");
}
}
private void gameModeCallback(CommandSender sender, String extension, int error) {
sender.sendMessage("'" + extension + "' is not a valid extension name!");
private void extensionCallback(CommandSender sender, ArgumentSyntaxException exception) {
sender.sendMessage("'" + exception.getInput() + "' is not a valid extension name!");
}
private String join(String[] extensionNameParts) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < extensionNameParts.length; i++) {
String s = extensionNameParts[i];
if(i != 0) {
b.append(" ");
if (i != 0) {
b.append(StringUtils.SPACE);
}
b.append(s);
}