12
0

Add SWCommand.Register.Registeres #104

Manuell gemergt
Lixfel hat 19 Commits von Registeres nach master 2021-05-12 20:35:45 +02:00 zusammengeführt
4 geänderte Dateien mit 83 neuen und 138 gelöschten Zeilen

Datei anzeigen

@ -23,20 +23,4 @@ public class CommandParseException extends Exception {
public CommandParseException() { public CommandParseException() {
} }
public CommandParseException(String message) {
super(message);
}
public CommandParseException(String message, Throwable cause) {
super(message, cause);
}
public CommandParseException(Throwable cause) {
super(cause);
}
public CommandParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
YoyoNow markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Diese Konstruktoren werden auch in keinem aufs CommandSystem-umgewandelten Systeme verwendet?

Diese Konstruktoren werden auch in keinem aufs CommandSystem-umgewandelten Systeme verwendet?
Veraltet
Review

Nicht das ich wüsste, nicht das ich es verwendet habe. Da dies nur eine Code Flow Exception ist, sollte man dies auch nicht machen. Da die anderen Werte gar nicht ausgewertet werden.

Nicht das ich wüsste, nicht das ich es verwendet habe. Da dies nur eine Code Flow Exception ist, sollte man dies auch nicht machen. Da die anderen Werte gar nicht ausgewertet werden.
super(message, cause, enableSuppression, writableStackTrace);
}
} }

Datei anzeigen

@ -30,12 +30,13 @@ import java.util.*;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.IntPredicate; import java.util.function.IntPredicate;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
public abstract class SWCommand { public abstract class SWCommand {
private final Command command; private final Command command;
private final List<SubCommand> commandSet = new ArrayList<>(); private final List<SubCommand> commandList = new ArrayList<>();
private final List<SubCommand> commandHelpSet = new ArrayList<>(); private final List<SubCommand> commandHelpList = new ArrayList<>();
private final Map<String, TypeMapper<?>> localTypeMapper = new HashMap<>(); private final Map<String, TypeMapper<?>> localTypeMapper = new HashMap<>();
protected SWCommand(String command) { protected SWCommand(String command) {
@ -46,58 +47,36 @@ public abstract class SWCommand {
this.command = new Command(command, "", "/" + command, Arrays.asList(aliases)) { this.command = new Command(command, "", "/" + command, Arrays.asList(aliases)) {
@Override @Override
public boolean execute(CommandSender sender, String alias, String[] args) { public boolean execute(CommandSender sender, String alias, String[] args) {
for (SubCommand subCommand : commandSet) { if (commandList.stream().anyMatch(s -> s.invoke(sender, args))) return false;
if (subCommand.invoke(sender, args)) { commandHelpList.stream().anyMatch(s -> s.invoke(sender, args));
return false;
}
}
for (SubCommand subCommand : commandHelpSet) {
if (subCommand.invoke(sender, args)) {
return false;
}
}
return false; return false;
} }
@Override @Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
List<String> strings = new ArrayList<>(); String string = args[args.length - 1].toLowerCase();
for (SubCommand subCommand : commandSet) { return commandList.stream()
List<String> tabCompletes = subCommand.tabComplete(sender, args); .map(s -> s.tabComplete(sender, args))
if (tabCompletes != null) { .filter(Objects::nonNull)
strings.addAll(tabCompletes); .flatMap(Collection::stream)
} .filter(s -> !s.isEmpty())
} .filter(s -> s.toLowerCase().startsWith(string))
strings = new ArrayList<>(strings); .collect(Collectors.toList());
for (int i = strings.size() - 1; i >= 0; i--) {
if (!strings.get(i).toLowerCase().startsWith(args[args.length - 1].toLowerCase())) {
strings.remove(i);
}
}
return strings;
} }
}; };
unregister();
register(); register();
for (Method method : getClass().getDeclaredMethods()) { Method[] methods = getClass().getDeclaredMethods();
for (Method method : methods) {
addMapper(Mapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> { addMapper(Mapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
if (anno.local()) { (anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value(), typeMapper);
localTypeMapper.put(anno.value(), typeMapper);
} else {
SWCommandUtils.addMapper(anno.value(), typeMapper);
}
}); });
addMapper(ClassMapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> { addMapper(ClassMapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
if (anno.local()) { (anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value().getTypeName(), typeMapper);
localTypeMapper.put(anno.value().getTypeName(), typeMapper);
} else {
SWCommandUtils.addMapper(anno.value().getTypeName(), typeMapper);
}
}); });
add(Register.class, method, i -> i > 0, true, null, (anno, parameters) -> { add(Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
if (!anno.help()) { if (!anno.help()) return;
return;
}
if (parameters.length != 2) { if (parameters.length != 2) {
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking parameters or has too many"); Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking parameters or has too many");
} }
@ -108,14 +87,12 @@ public abstract class SWCommand {
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument"); Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
return; return;
} }
commandHelpSet.add(new SubCommand(this, method, anno.value())); commandHelpList.add(new SubCommand(this, method, anno.value(), new HashMap<>()));
}); });
} }
for (Method method : getClass().getDeclaredMethods()) { for (Method method : methods) {
add(Register.class, method, i -> i > 0, true, null, (anno, parameters) -> { add(Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
if (anno.help()) { if (anno.help()) return;
return;
}
for (int i = 1; i < parameters.length; i++) { for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i]; Parameter parameter = parameters[i];
Class<?> clazz = parameter.getType(); Class<?> clazz = parameter.getType();
@ -126,37 +103,31 @@ public abstract class SWCommand {
if (clazz.isEnum() && mapper == null && !SWCommandUtils.MAPPER_FUNCTIONS.containsKey(clazz.getTypeName())) { if (clazz.isEnum() && mapper == null && !SWCommandUtils.MAPPER_FUNCTIONS.containsKey(clazz.getTypeName())) {
continue; continue;
} }
String name = clazz.getTypeName(); String name = mapper != null ? mapper.value() : clazz.getTypeName();
if (mapper != null) {
name = mapper.value();
}
if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name) && !localTypeMapper.containsKey(name)) { if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name) && !localTypeMapper.containsKey(name)) {
Bukkit.getLogger().log(Level.WARNING, "The parameter '" + parameter.toString() + "' is using an unsupported Mapper of type '" + name + "'"); Bukkit.getLogger().log(Level.WARNING, "The parameter '" + parameter.toString() + "' is using an unsupported Mapper of type '" + name + "'");
return; return;
} }
} }
commandSet.add(new SubCommand(this, method, anno.value(), localTypeMapper)); commandList.add(new SubCommand(this, method, anno.value(), localTypeMapper));
}); });
this.commandSet.sort((o1, o2) -> { this.commandList.sort((o1, o2) -> {
int compare = Integer.compare(-o1.subCommand.length, -o2.subCommand.length); int compare = Integer.compare(-o1.subCommand.length, -o2.subCommand.length);
if (compare != 0) { if (compare != 0) {
return compare; return compare;
} else { } else {
int i1 = o1.varArgType != null ? Integer.MAX_VALUE : o1.arguments.length; return Integer.compare(o1.varArgType != null ? Integer.MAX_VALUE : o1.arguments.length,
int i2 = o2.varArgType != null ? Integer.MAX_VALUE : o2.arguments.length; o2.varArgType != null ? Integer.MAX_VALUE : o2.arguments.length);
return Integer.compare(i1, i2);
} }
}); });
commandHelpSet.sort(Comparator.comparingInt(o -> -o.subCommand.length)); commandHelpList.sort(Comparator.comparingInt(o -> -o.subCommand.length));
} }
} }
private <T extends Annotation> void add(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, Parameter[]> consumer) { private <T extends Annotation> void add(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, Parameter[]> consumer) {
T anno = SWCommandUtils.getAnnotation(method, annotation); T[] anno = SWCommandUtils.getAnnotation(method, annotation);
if (anno == null) { if (anno == null || anno.length == 0) return;
return;
}
Parameter[] parameters = method.getParameters(); Parameter[] parameters = method.getParameters();
if (!parameterTester.test(parameters.length)) { if (!parameterTester.test(parameters.length)) {
@ -171,15 +142,14 @@ public abstract class SWCommand {
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the desired return type '" + returnType.getTypeName() + "'"); Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the desired return type '" + returnType.getTypeName() + "'");
return; return;
} }
consumer.accept(anno, parameters); Arrays.stream(anno).forEach(t -> consumer.accept(t, parameters));
} }
private <T extends Annotation> void addMapper(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, TypeMapper<?>> consumer) { private <T extends Annotation> void addMapper(Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, TypeMapper<?>> consumer) {
add(annotation, method, parameterTester, firstParameter, returnType, (anno, parameters) -> { add(annotation, method, parameterTester, firstParameter, returnType, (anno, parameters) -> {
try { try {
method.setAccessible(true); method.setAccessible(true);
Object object = method.invoke(this); consumer.accept(anno, (TypeMapper<?>) method.invoke(this));
consumer.accept(anno, (TypeMapper<?>) object);
} catch (Exception e) { } catch (Exception e) {
throw new SecurityException(e.getMessage(), e); throw new SecurityException(e.getMessage(), e);
} }
@ -188,9 +158,7 @@ public abstract class SWCommand {
public void unregister() { public void unregister() {
SWCommandUtils.knownCommandMap.remove(command.getName()); SWCommandUtils.knownCommandMap.remove(command.getName());
for (String alias : command.getAliases()) { command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
SWCommandUtils.knownCommandMap.remove(alias);
}
command.unregister(SWCommandUtils.commandMap); command.unregister(SWCommandUtils.commandMap);
} }
@ -200,10 +168,17 @@ public abstract class SWCommand {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD}) @Target({ElementType.METHOD})
@Repeatable(Register.Registeres.class)
YoyoNow markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Das wirkt mir nach einem sehr dreckigen workaround, geht das nicht schöner?

Das wirkt mir nach einem sehr dreckigen workaround, geht das nicht schöner?
Veraltet
Review

Dies ist eigentlich kein so dreckiger workdaround, dies ist dafür da, dass man die Befehle erst nachdem alle Plugins initialisiert sind geladen werden. Dies ist besonders interessant bei so sachen, wenn man WE Command oder so überschreibt, wenn diese später als das hier erstellt werden. Ansonsten hat Zeanon die Änderungen getestet und keine Fehler gefunden. Ich glaube sogar das es etwas besser läuft, was ich aber noch nicht nachgewiesen habe.

Dies ist eigentlich kein so dreckiger workdaround, dies ist dafür da, dass man die Befehle erst nachdem alle Plugins initialisiert sind geladen werden. Dies ist besonders interessant bei so sachen, wenn man WE Command oder so überschreibt, wenn diese später als das hier erstellt werden. Ansonsten hat Zeanon die Änderungen getestet und keine Fehler gefunden. Ich glaube sogar das es etwas besser läuft, was ich aber noch nicht nachgewiesen habe.
Veraltet
Review

Das ist nicht nötig, dann soll man das zumindest als soft-dependend markieren, dann können die Befehle auch sofort überschrieben werden.

Das ist nicht nötig, dann soll man das zumindest als soft-dependend markieren, dann können die Befehle auch sofort überschrieben werden.
Veraltet
Review

Wenn du meinst. Dann schmeiße ich es dir noch raus.

Wenn du meinst. Dann schmeiße ich es dir noch raus.
protected @interface Register { protected @interface Register {
String[] value() default {}; String[] value() default {};
boolean help() default false; boolean help() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@interface Registeres {
Register[] value();
}
} }
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

Datei anzeigen

@ -50,10 +50,7 @@ public class SWCommandUtils {
static final BiFunction<Class<Enum<?>>, String, Enum<?>> ENUM_MAPPER = (enumClass, s) -> { static final BiFunction<Class<Enum<?>>, String, Enum<?>> ENUM_MAPPER = (enumClass, s) -> {
Enum<?>[] enums = enumClass.getEnumConstants(); Enum<?>[] enums = enumClass.getEnumConstants();
for (Enum<?> e : enums) { return Arrays.stream(enums).filter(e -> e.name().equalsIgnoreCase(s)).findFirst().orElse(null);
if (e.name().equalsIgnoreCase(s)) return e;
}
return null;
}; };
static { static {
@ -61,6 +58,7 @@ public class SWCommandUtils {
addMapper(float.class, Float.class, createMapper(numberMapper(Float::parseFloat), numberCompleter(Float::parseFloat))); addMapper(float.class, Float.class, createMapper(numberMapper(Float::parseFloat), numberCompleter(Float::parseFloat)));
addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble))); addMapper(double.class, Double.class, createMapper(numberMapper(Double::parseDouble), numberCompleter(Double::parseDouble)));
addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt))); addMapper(int.class, Integer.class, createMapper(numberMapper(Integer::parseInt), numberCompleter(Integer::parseInt)));
addMapper(long.class, Long.class, createMapper(numberMapper(Long::parseLong), numberCompleter(Long::parseLong)));
MAPPER_FUNCTIONS.put(String.class.getTypeName(), createMapper(s -> s, Collections::singletonList)); MAPPER_FUNCTIONS.put(String.class.getTypeName(), createMapper(s -> s, Collections::singletonList));
MAPPER_FUNCTIONS.put(Player.class.getTypeName(), createMapper(Bukkit::getPlayer, s -> Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList()))); MAPPER_FUNCTIONS.put(Player.class.getTypeName(), createMapper(Bukkit::getPlayer, s -> Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList())));
MAPPER_FUNCTIONS.put(GameMode.class.getTypeName(), createMapper(s -> { MAPPER_FUNCTIONS.put(GameMode.class.getTypeName(), createMapper(s -> {
@ -104,37 +102,31 @@ public class SWCommandUtils {
Object[] arguments = new Object[parameters.length + 1]; Object[] arguments = new Object[parameters.length + 1];
int index = 0; int index = 0;
while (index < subCommand.length) { while (index < subCommand.length) {
if (!args[index].equalsIgnoreCase(subCommand[index])) { if (!args[index].equalsIgnoreCase(subCommand[index])) throw new CommandParseException();
throw new CommandParseException();
}
index++; index++;
} }
if (varArgType != null && index > args.length - 1) { int length = 0;
Object varArgument = Array.newInstance(varArgType, 0); if (varArgType != null) {
arguments[arguments.length - 1] = varArgument; length = args.length - parameters.length - subCommand.length + 1;
} else { arguments[arguments.length - 1] = Array.newInstance(varArgType, length);
for (int i = 0; i < parameters.length - (varArgType != null ? 1 : 0); i++) { if (index > args.length - 1) return arguments;
arguments[i + 1] = parameters[i].map(commandSender, Arrays.copyOf(args, index), args[index]); }
for (int i = 0; i < parameters.length - (varArgType != null ? 1 : 0); i++) {
arguments[i + 1] = parameters[i].map(commandSender, Arrays.copyOf(args, index), args[index]);
index++;
if (arguments[i + 1] == null) throw new CommandParseException();
}
if (varArgType != null) {
Object varArgument = arguments[arguments.length - 1];
for (int i = 0; i < length; i++) {
Object value = parameters[parameters.length - 1].map(commandSender, Arrays.copyOf(args, index), args[index]);
if (value == null) throw new CommandParseException();
Array.set(varArgument, i, value);
index++; index++;
if (arguments[i + 1] == null) {
throw new CommandParseException();
}
}
if (varArgType != null) {
int length = args.length - parameters.length - subCommand.length + 1;
Object varArgument = Array.newInstance(varArgType, length);
arguments[arguments.length - 1] = varArgument;
for (int i = 0; i < length; i++) {
Object value = parameters[parameters.length - 1].map(commandSender, Arrays.copyOf(args, index), args[index]);
if (value == null) {
throw new CommandParseException();
}
Array.set(varArgument, i, value);
index++;
}
} }
} }
return arguments; return arguments;
@ -145,8 +137,7 @@ public class SWCommandUtils {
} }
public static void addMapper(String name, TypeMapper<?> mapper) { public static void addMapper(String name, TypeMapper<?> mapper) {
if (MAPPER_FUNCTIONS.containsKey(name)) return; MAPPER_FUNCTIONS.putIfAbsent(name, mapper);
MAPPER_FUNCTIONS.put(name, mapper);
} }
public static <T> TypeMapper<T> createMapper(Function<String, T> mapper, Function<String, List<String>> tabCompleter) { public static <T> TypeMapper<T> createMapper(Function<String, T> mapper, Function<String, List<String>> tabCompleter) {
@ -178,18 +169,13 @@ public class SWCommandUtils {
} }
private static Function<String, List<String>> numberCompleter(Function<String, ?> mapper) { private static Function<String, List<String>> numberCompleter(Function<String, ?> mapper) {
return s -> { return s -> numberMapper(mapper).apply(s) != null
try { ? Collections.singletonList(s)
mapper.apply(s); : Collections.emptyList();
return Collections.singletonList(s);
} catch (Exception e) {
return Collections.emptyList();
}
};
} }
static <T extends Annotation> T getAnnotation(Method method, Class<T> annotation) { static <T extends Annotation> T[] getAnnotation(Method method, Class<T> annotation) {
if (method.getAnnotations().length != 1) return null; if (method.getAnnotations().length != 1) return null;
return method.getAnnotation(annotation); return method.getDeclaredAnnotationsByType(annotation);
} }
} }

Datei anzeigen

@ -28,6 +28,8 @@ import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import static de.steamwar.command.SWCommandUtils.*;
class SubCommand { class SubCommand {
private SWCommand swCommand; private SWCommand swCommand;
@ -38,11 +40,7 @@ class SubCommand {
private Function<CommandSender, ?> commandSenderFunction; private Function<CommandSender, ?> commandSenderFunction;
Class<?> varArgType = null; Class<?> varArgType = null;
public SubCommand(SWCommand swCommand, Method method, String[] subCommand) { SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map<String, TypeMapper<?>> localTypeMapper) {
this(swCommand, method, subCommand, new HashMap<>());
}
public SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map<String, TypeMapper<?>> localTypeMapper) {
this.swCommand = swCommand; this.swCommand = swCommand;
this.method = method; this.method = method;
@ -61,13 +59,13 @@ class SubCommand {
} }
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class); SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
if (clazz.isEnum() && mapper == null && !SWCommandUtils.MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) { if (clazz.isEnum() && mapper == null && !MAPPER_FUNCTIONS.containsKey(clazz.getTypeName()) && !localTypeMapper.containsKey(clazz.getTypeName())) {
Class<Enum<?>> enumClass = (Class<Enum<?>>) clazz; Class<Enum<?>> enumClass = (Class<Enum<?>>) clazz;
List<String> tabCompletes = new ArrayList<>(); List<String> tabCompletes = new ArrayList<>();
for (Enum<?> enumConstant : enumClass.getEnumConstants()) { for (Enum<?> enumConstant : enumClass.getEnumConstants()) {
tabCompletes.add(enumConstant.name().toLowerCase()); tabCompletes.add(enumConstant.name().toLowerCase());
} }
arguments[i - 1] = SWCommandUtils.createMapper(s -> SWCommandUtils.ENUM_MAPPER.apply(enumClass, s), s -> tabCompletes); arguments[i - 1] = SWCommandUtils.createMapper(s -> ENUM_MAPPER.apply(enumClass, s), s -> tabCompletes);
continue; continue;
} }
@ -75,11 +73,9 @@ class SubCommand {
if (mapper != null) { if (mapper != null) {
name = mapper.value(); name = mapper.value();
} }
if (localTypeMapper.containsKey(name)) { arguments[i - 1] = localTypeMapper.containsKey(name)
arguments[i - 1] = localTypeMapper.getOrDefault(name, SWCommandUtils.ERROR_FUNCTION); ? localTypeMapper.get(name)
} else { : MAPPER_FUNCTIONS.getOrDefault(name, ERROR_FUNCTION);
arguments[i - 1] = SWCommandUtils.MAPPER_FUNCTIONS.getOrDefault(name, SWCommandUtils.ERROR_FUNCTION);
}
} }
} }
@ -120,7 +116,9 @@ class SubCommand {
} }
for (TypeMapper<?> argument : arguments) { for (TypeMapper<?> argument : arguments) {
String s = argsList.remove(0); String s = argsList.remove(0);
if (argsList.isEmpty()) return argument.tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s); if (argsList.isEmpty()) {
return argument.tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s);
}
try { try {
if (argument.map(commandSender, Arrays.copyOf(args, index), s) == null) { if (argument.map(commandSender, Arrays.copyOf(args, index), s) == null) {
return null; return null;
@ -133,7 +131,9 @@ class SubCommand {
if (varArgType != null && !argsList.isEmpty()) { if (varArgType != null && !argsList.isEmpty()) {
while (!argsList.isEmpty()) { while (!argsList.isEmpty()) {
String s = argsList.remove(0); String s = argsList.remove(0);
if (argsList.isEmpty()) return arguments[arguments.length - 1].tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s); if (argsList.isEmpty()) {
return arguments[arguments.length - 1].tabCompletes(commandSender, Arrays.copyOf(args, args.length - 1), s);
}
try { try {
if (arguments[arguments.length - 1].map(commandSender, Arrays.copyOf(args, index), s) == null) { if (arguments[arguments.length - 1].map(commandSender, Arrays.copyOf(args, index), s) == null) {
return null; return null;