CMDoS because Brigadier
Dieser Commit ist enthalten in:
Ursprung
df6974ad04
Commit
7e02212680
@ -55,14 +55,6 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<source>9</source>
|
|
||||||
<target>9</target>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
<finalName>spigotcore</finalName>
|
<finalName>spigotcore</finalName>
|
||||||
</build>
|
</build>
|
||||||
|
@ -60,6 +60,11 @@ public abstract class SWCommand {
|
|||||||
swCommandInterface.register();
|
swCommandInterface.register();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SWCommandInterface {
|
||||||
|
void unregister();
|
||||||
|
void register();
|
||||||
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
@Repeatable(Register.Registeres.class)
|
@Repeatable(Register.Registeres.class)
|
||||||
|
@ -24,90 +24,36 @@ import com.mojang.brigadier.builder.ArgumentBuilder;
|
|||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Parameter;
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.IntPredicate;
|
import java.util.function.IntPredicate;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static de.steamwar.command.SWCommandUtils.*;
|
class SWCommandBrigadier implements SWCommand.SWCommandInterface {
|
||||||
|
|
||||||
class SWCommandBrigadier implements SWCommandInterface {
|
|
||||||
|
|
||||||
private SWCommandNormal swCommandNormal = null;
|
|
||||||
private final SWCommand swCommand;
|
private final SWCommand swCommand;
|
||||||
|
private Command command;
|
||||||
private final List<SubCommand> commandList = new ArrayList<>();
|
private final List<SubCommand> commandList = new ArrayList<>();
|
||||||
private final List<SubCommand> commandHelpList = 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 SWCommandBrigadier(SWCommand swCommand, String command, String... aliases) {
|
protected SWCommandBrigadier(SWCommand swCommand, String command, String... aliases) {
|
||||||
this.swCommand = swCommand;
|
this.swCommand = swCommand;
|
||||||
|
SWCommandUtils.createList(swCommand, commandList, commandHelpList, localTypeMapper, this::createSubCommand);
|
||||||
Method[] methods = swCommand.getClass().getDeclaredMethods();
|
Stream.of(commandList, commandHelpList).flatMap(List::stream).forEach(subCommand -> {
|
||||||
for (Method method : methods) {
|
|
||||||
addMapper(SWCommand.Mapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
|
|
||||||
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value(), typeMapper);
|
|
||||||
});
|
|
||||||
addMapper(SWCommand.ClassMapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
|
|
||||||
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value().getTypeName(), typeMapper);
|
|
||||||
});
|
|
||||||
add(SWCommand.Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
|
||||||
if (!anno.help()) return;
|
|
||||||
if (parameters.length != 2) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking parameters or has too many");
|
|
||||||
}
|
|
||||||
if (!parameters[parameters.length - 1].isVarArgs()) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters as last Argument");
|
|
||||||
}
|
|
||||||
if (parameters[parameters.length - 1].getType().getComponentType() != String.class) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
commandList.add(createSubCommand(method, anno.value()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (Method method : methods) {
|
|
||||||
add(SWCommand.Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
|
||||||
if (anno.help()) return;
|
|
||||||
for (int i = 1; i < parameters.length; i++) {
|
|
||||||
Parameter parameter = parameters[i];
|
|
||||||
Class<?> clazz = parameter.getType();
|
|
||||||
if (parameter.isVarArgs() && i == parameters.length - 1) {
|
|
||||||
clazz = parameter.getType().getComponentType();
|
|
||||||
}
|
|
||||||
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
|
|
||||||
if (clazz.isEnum() && mapper == null && !SWCommandUtils.MAPPER_FUNCTIONS.containsKey(clazz.getTypeName())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = mapper != null ? mapper.value() : clazz.getTypeName();
|
|
||||||
if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name) && !localTypeMapper.containsKey(name)) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The parameter '" + parameter + "' is using an unsupported Mapper of type '" + name + "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
commandList.add(createSubCommand(method, anno.value()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (SubCommand subCommand : commandList) {
|
|
||||||
register(command, subCommand, command, aliases);
|
register(command, subCommand, command, aliases);
|
||||||
for (String s : aliases) {
|
for (String s : aliases) {
|
||||||
register(s, subCommand, command, aliases);
|
register(s, subCommand, command, aliases);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
for (SubCommand subCommand : commandHelpList) {
|
|
||||||
register(command, subCommand, command, aliases);
|
|
||||||
for (String s : aliases) {
|
|
||||||
register(s, subCommand, command, aliases);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubCommand createSubCommand(Method method, String[] strings) {
|
private SubCommand createSubCommand(Method method, String[] strings) {
|
||||||
@ -171,8 +117,27 @@ class SWCommandBrigadier implements SWCommandInterface {
|
|||||||
if (subCommand.argumentNode == null) {
|
if (subCommand.argumentNode == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (subCommand.normalTabCompleteNeeded) {
|
if (subCommand.normalTabCompleteNeeded && command == null) {
|
||||||
swCommandNormal = new SWCommandNormal(swCommand, command, aliases);
|
this.command = new Command(command, "", "/" + command, Arrays.asList(aliases)) {
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, String alias, String[] args) {
|
||||||
|
if (commandList.stream().anyMatch(s -> s.invoke(sender, args))) return false;
|
||||||
|
commandHelpList.stream().anyMatch(s -> s.invoke(sender, args));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
|
||||||
|
String string = args[args.length - 1].toLowerCase();
|
||||||
|
return commandList.stream()
|
||||||
|
.map(s -> s.tabComplete(sender, args))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.filter(s -> !s.isEmpty())
|
||||||
|
.filter(s -> s.toLowerCase().startsWith(string))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
literalArgumentBuilder.then(subCommand.argumentNode);
|
literalArgumentBuilder.then(subCommand.argumentNode);
|
||||||
SWCommand.dispatcher.register(literalArgumentBuilder);
|
SWCommand.dispatcher.register(literalArgumentBuilder);
|
||||||
@ -211,14 +176,16 @@ class SWCommandBrigadier implements SWCommandInterface {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unregister() {
|
public void unregister() {
|
||||||
if (swCommandNormal == null) return;
|
if (command == null) return;
|
||||||
swCommandNormal.unregister();
|
SWCommandUtils.knownCommandMap.remove(command.getName());
|
||||||
|
command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
|
||||||
|
command.unregister(SWCommandUtils.commandMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void register() {
|
public void register() {
|
||||||
if (swCommandNormal == null) return;
|
if (command == null) return;
|
||||||
swCommandNormal.register();
|
SWCommandUtils.commandMap.register("steamwar", this.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArgumentType<?> getArgumentType(Parameter parameter, Class<?> parameterType, SubCommand subCommand) {
|
private ArgumentType<?> getArgumentType(Parameter parameter, Class<?> parameterType, SubCommand subCommand) {
|
||||||
@ -227,32 +194,20 @@ class SWCommandBrigadier implements SWCommandInterface {
|
|||||||
argumentType = BoolArgumentType.bool();
|
argumentType = BoolArgumentType.bool();
|
||||||
} else if (parameterType == int.class || parameterType == Integer.class) {
|
} else if (parameterType == int.class || parameterType == Integer.class) {
|
||||||
SWCommand.IntRange intRange = parameter.getAnnotation(SWCommand.IntRange.class);
|
SWCommand.IntRange intRange = parameter.getAnnotation(SWCommand.IntRange.class);
|
||||||
if (intRange != null) {
|
if (intRange != null) argumentType = IntegerArgumentType.integer(intRange.min(), intRange.max());
|
||||||
argumentType = IntegerArgumentType.integer(intRange.min(), intRange.max());
|
else argumentType = IntegerArgumentType.integer();
|
||||||
} else {
|
|
||||||
argumentType = IntegerArgumentType.integer();
|
|
||||||
}
|
|
||||||
} else if (parameterType == float.class || parameterType == Float.class) {
|
} else if (parameterType == float.class || parameterType == Float.class) {
|
||||||
SWCommand.FloatRange floatRange = parameter.getAnnotation(SWCommand.FloatRange.class);
|
SWCommand.FloatRange floatRange = parameter.getAnnotation(SWCommand.FloatRange.class);
|
||||||
if (floatRange != null) {
|
if (floatRange != null) argumentType = FloatArgumentType.floatArg(floatRange.min(), floatRange.max());
|
||||||
argumentType = FloatArgumentType.floatArg(floatRange.min(), floatRange.max());
|
else argumentType = FloatArgumentType.floatArg();
|
||||||
} else {
|
|
||||||
argumentType = FloatArgumentType.floatArg();
|
|
||||||
}
|
|
||||||
} else if (parameterType == long.class || parameterType == Long.class) {
|
} else if (parameterType == long.class || parameterType == Long.class) {
|
||||||
SWCommand.LongRange longRange = parameter.getAnnotation(SWCommand.LongRange.class);
|
SWCommand.LongRange longRange = parameter.getAnnotation(SWCommand.LongRange.class);
|
||||||
if (longRange != null) {
|
if (longRange != null) argumentType = LongArgumentType.longArg(longRange.min(), longRange.max());
|
||||||
argumentType = LongArgumentType.longArg(longRange.min(), longRange.max());
|
else argumentType = LongArgumentType.longArg();
|
||||||
} else {
|
|
||||||
argumentType = LongArgumentType.longArg();
|
|
||||||
}
|
|
||||||
} else if (parameterType == double.class || parameterType == Double.class) {
|
} else if (parameterType == double.class || parameterType == Double.class) {
|
||||||
SWCommand.DoubleRange doubleRange = parameter.getAnnotation(SWCommand.DoubleRange.class);
|
SWCommand.DoubleRange doubleRange = parameter.getAnnotation(SWCommand.DoubleRange.class);
|
||||||
if (doubleRange != null) {
|
if (doubleRange != null) argumentType = DoubleArgumentType.doubleArg(doubleRange.min(), doubleRange.max());
|
||||||
argumentType = DoubleArgumentType.doubleArg(doubleRange.min(), doubleRange.max());
|
else argumentType = DoubleArgumentType.doubleArg();
|
||||||
} else {
|
|
||||||
argumentType = DoubleArgumentType.doubleArg();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
argumentType = StringArgumentType.string();
|
argumentType = StringArgumentType.string();
|
||||||
subCommand.normalTabCompleteNeeded = true;
|
subCommand.normalTabCompleteNeeded = true;
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.command;
|
|
||||||
|
|
||||||
public interface SWCommandInterface {
|
|
||||||
void unregister();
|
|
||||||
void register();
|
|
||||||
}
|
|
@ -32,7 +32,7 @@ import java.util.function.IntPredicate;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
class SWCommandNormal implements SWCommandInterface {
|
class SWCommandNormal implements SWCommand.SWCommandInterface {
|
||||||
|
|
||||||
private final SWCommand swCommand;
|
private final SWCommand swCommand;
|
||||||
private final Command command;
|
private final Command command;
|
||||||
@ -65,100 +65,13 @@ class SWCommandNormal implements SWCommandInterface {
|
|||||||
};
|
};
|
||||||
unregister();
|
unregister();
|
||||||
register();
|
register();
|
||||||
|
SWCommandUtils.createList(swCommand, commandList, commandHelpList, localTypeMapper, this::createSubCommand);
|
||||||
Method[] methods = swCommand.getClass().getDeclaredMethods();
|
|
||||||
for (Method method : methods) {
|
|
||||||
addMapper(SWCommand.Mapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
|
|
||||||
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value(), typeMapper);
|
|
||||||
});
|
|
||||||
addMapper(SWCommand.ClassMapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
|
|
||||||
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value().getTypeName(), typeMapper);
|
|
||||||
});
|
|
||||||
add(SWCommand.Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
|
||||||
if (!anno.help()) return;
|
|
||||||
if (parameters.length != 2) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking parameters or has too many");
|
|
||||||
}
|
|
||||||
if (!parameters[parameters.length - 1].isVarArgs()) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters as last Argument");
|
|
||||||
}
|
|
||||||
if (parameters[parameters.length - 1].getType().getComponentType() != String.class) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
commandHelpList.add(createSubCommand(method, anno.value()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (Method method : methods) {
|
|
||||||
add(SWCommand.Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
|
||||||
if (anno.help()) return;
|
|
||||||
for (int i = 1; i < parameters.length; i++) {
|
|
||||||
Parameter parameter = parameters[i];
|
|
||||||
Class<?> clazz = parameter.getType();
|
|
||||||
if (parameter.isVarArgs() && i == parameters.length - 1) {
|
|
||||||
clazz = parameter.getType().getComponentType();
|
|
||||||
}
|
|
||||||
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
|
|
||||||
if (clazz.isEnum() && mapper == null && !SWCommandUtils.MAPPER_FUNCTIONS.containsKey(clazz.getTypeName())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String name = mapper != null ? mapper.value() : clazz.getTypeName();
|
|
||||||
if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name) && !localTypeMapper.containsKey(name)) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The parameter '" + parameter + "' is using an unsupported Mapper of type '" + name + "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
commandList.add(createSubCommand(method, anno.value()));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.commandList.sort((o1, o2) -> {
|
|
||||||
int compare = Integer.compare(-o1.subCommand.length, -o2.subCommand.length);
|
|
||||||
if (compare != 0) {
|
|
||||||
return compare;
|
|
||||||
} else {
|
|
||||||
return Integer.compare(o1.varArgType != null ? Integer.MAX_VALUE : o1.arguments.length,
|
|
||||||
o2.varArgType != null ? Integer.MAX_VALUE : o2.arguments.length);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
commandHelpList.sort(Comparator.comparingInt(o -> -o.subCommand.length));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private de.steamwar.command.SubCommand createSubCommand(Method method, String[] strings) {
|
private SubCommand createSubCommand(Method method, String[] strings) {
|
||||||
return new de.steamwar.command.SubCommand(swCommand, method, strings, localTypeMapper, current -> {});
|
return new de.steamwar.command.SubCommand(swCommand, method, strings, localTypeMapper, current -> {});
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
if (anno == null || anno.length == 0) return;
|
|
||||||
|
|
||||||
Parameter[] parameters = method.getParameters();
|
|
||||||
if (!parameterTester.test(parameters.length)) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method + "' is lacking parameters or has too many");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (firstParameter && !CommandSender.class.isAssignableFrom(parameters[0].getType())) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method + "' is lacking the first parameter of type '" + CommandSender.class.getTypeName() + "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (returnType != null && method.getReturnType() != returnType) {
|
|
||||||
Bukkit.getLogger().log(Level.WARNING, "The method '" + method + "' is lacking the desired return type '" + returnType.getTypeName() + "'");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
add(annotation, method, parameterTester, firstParameter, returnType, (anno, parameters) -> {
|
|
||||||
try {
|
|
||||||
method.setAccessible(true);
|
|
||||||
consumer.accept(anno, (TypeMapper<?>) method.invoke(swCommand));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SecurityException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregister() {
|
public void unregister() {
|
||||||
SWCommandUtils.knownCommandMap.remove(command.getName());
|
SWCommandUtils.knownCommandMap.remove(command.getName());
|
||||||
command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
|
command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
|
||||||
|
@ -31,9 +31,13 @@ import java.lang.annotation.Annotation;
|
|||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Parameter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.IntPredicate;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class SWCommandUtils {
|
public class SWCommandUtils {
|
||||||
@ -178,4 +182,83 @@ public class SWCommandUtils {
|
|||||||
if (method.getAnnotations().length != 1) return null;
|
if (method.getAnnotations().length != 1) return null;
|
||||||
return method.getDeclaredAnnotationsByType(annotation);
|
return method.getDeclaredAnnotationsByType(annotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void createList(SWCommand swCommand, List<SubCommand> commandList, List<SubCommand> commandHelpList, Map<String, TypeMapper<?>> localTypeMapper, BiFunction<Method, String[], SubCommand> creator) {
|
||||||
|
Method[] methods = swCommand.getClass().getDeclaredMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
addMapper(swCommand, SWCommand.Mapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
|
||||||
|
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value(), typeMapper);
|
||||||
|
});
|
||||||
|
addMapper(swCommand, SWCommand.ClassMapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
|
||||||
|
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value().getTypeName(), typeMapper);
|
||||||
|
});
|
||||||
|
add(SWCommand.Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
||||||
|
if (!anno.help()) return;
|
||||||
|
if (parameters.length != 2) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking parameters or has too many");
|
||||||
|
}
|
||||||
|
if (!parameters[parameters.length - 1].isVarArgs()) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters as last Argument");
|
||||||
|
}
|
||||||
|
if (parameters[parameters.length - 1].getType().getComponentType() != String.class) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
commandHelpList.add(creator.apply(method, anno.value()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (Method method : methods) {
|
||||||
|
add(SWCommand.Register.class, method, i -> i > 0, true, null, (anno, parameters) -> {
|
||||||
|
if (anno.help()) return;
|
||||||
|
for (int i = 1; i < parameters.length; i++) {
|
||||||
|
Parameter parameter = parameters[i];
|
||||||
|
Class<?> clazz = parameter.getType();
|
||||||
|
if (parameter.isVarArgs() && i == parameters.length - 1) {
|
||||||
|
clazz = parameter.getType().getComponentType();
|
||||||
|
}
|
||||||
|
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
|
||||||
|
if (clazz.isEnum() && mapper == null && !SWCommandUtils.MAPPER_FUNCTIONS.containsKey(clazz.getTypeName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = mapper != null ? mapper.value() : clazz.getTypeName();
|
||||||
|
if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name) && !localTypeMapper.containsKey(name)) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The parameter '" + parameter + "' is using an unsupported Mapper of type '" + name + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commandList.add(creator.apply(method, anno.value()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <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);
|
||||||
|
if (anno == null || anno.length == 0) return;
|
||||||
|
|
||||||
|
Parameter[] parameters = method.getParameters();
|
||||||
|
if (!parameterTester.test(parameters.length)) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The method '" + method + "' is lacking parameters or has too many");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (firstParameter && !CommandSender.class.isAssignableFrom(parameters[0].getType())) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The method '" + method + "' is lacking the first parameter of type '" + CommandSender.class.getTypeName() + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (returnType != null && method.getReturnType() != returnType) {
|
||||||
|
Bukkit.getLogger().log(Level.WARNING, "The method '" + method + "' is lacking the desired return type '" + returnType.getTypeName() + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Arrays.stream(anno).forEach(t -> consumer.accept(t, parameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends Annotation> void addMapper(SWCommand swCommand, Class<T> annotation, Method method, IntPredicate parameterTester, boolean firstParameter, Class<?> returnType, BiConsumer<T, TypeMapper<?>> consumer) {
|
||||||
|
add(annotation, method, parameterTester, firstParameter, returnType, (anno, parameters) -> {
|
||||||
|
try {
|
||||||
|
method.setAccessible(true);
|
||||||
|
consumer.accept(anno, (TypeMapper<?>) method.invoke(swCommand));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new SecurityException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren