SteamWar/SpigotCore
Archiviert
13
0

CommandFramework3 #94

Manuell gemergt
Zeanon hat 71 Commits von CommandFramework3 nach master 2021-03-30 21:15:40 +02:00 zusammengeführt
5 geänderte Dateien mit 117 neuen und 191 gelöschten Zeilen
Nur Änderungen aus Commit ea4d6f2a0a werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -1,89 +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;
import org.bukkit.command.CommandSender;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collections;
import java.util.List;
class InternalCommand {
private SWCommand swCommand;
private Method method;
private int increment = 0;
private Parameter[] parameters;
InternalCommand(SWCommand swCommand, Method method) {
this.swCommand = swCommand;
this.method = method;
parameters = method.getParameters();
increment = method.getAnnotation(SWCommand.Register.class).subCommand().length;
}
boolean invoke(CommandSender commandSender, String[] args) {
if (args.length < parameters.length - 1) {
return false;
}
try {
Object[] objects = SWCommandUtils.generateArgumentArray(commandSender, method, parameters, args);
method.setAccessible(true);
method.invoke(swCommand, objects);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new SecurityException(e.getMessage(), e);
} catch (InvocationTargetException e) {
return false;
}
return true;
}
List<String> tabComplete(String[] args) {
if (args.length > parameters.length - increment) {
if (parameters[parameters.length - 1].isVarArgs()) {
String name = parameters[parameters.length - 1].getType().getComponentType().getTypeName();
SWCommand.Mapper mapper = parameters[parameters.length - 1].getAnnotation(SWCommand.Mapper.class);
if (mapper != null) {
name = mapper.mapper();
}
try {
return SWCommandUtils.MAPPER_FUNCTIONS.getOrDefault(name, SWCommandUtils.ERROR_FUNCTION).tabCompletes(args[args.length - 1]);
} catch (Exception e) {
// Ignored
}
}
return Collections.emptyList();
}
String name = parameters[args.length - increment + 1].getType().getTypeName();
SWCommand.Mapper mapper = parameters[args.length - increment + 1].getAnnotation(SWCommand.Mapper.class);
if (mapper != null) {
name = mapper.mapper();
}
try {
return SWCommandUtils.MAPPER_FUNCTIONS.getOrDefault(name, SWCommandUtils.ERROR_FUNCTION).tabCompletes(args[args.length - 1]);
} catch (Exception e) {
return Collections.emptyList();
}
}
}

Datei anzeigen

@ -1,55 +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;
import org.bukkit.command.CommandSender;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
class InternalTabComplete {
private SWCommand swCommand;
private Method method;
private Parameter[] parameters;
InternalTabComplete(SWCommand swCommand, Method method) {
this.swCommand = swCommand;
this.method = method;
parameters = method.getParameters();
}
SWCommandUtils.TabComplete invoke(CommandSender commandSender, String[] args) {
if (args.length < parameters.length - 1) {
return null;
}
try {
Object[] objects = SWCommandUtils.generateArgumentArray(commandSender, method, parameters, args);
method.setAccessible(true);
return (SWCommandUtils.TabComplete) method.invoke(swCommand, objects);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new SecurityException(e.getMessage(), e);
} catch (InvocationTargetException e) {
return null;
}
}
}

Datei anzeigen

@ -33,9 +33,7 @@ import java.util.function.Consumer;
public abstract class SWCommand {
Veraltet
Review

Das ist nicht so das, was ich fürs FightSystem gemeint habe. Ich möchte eigentlich nicht, dass sich der Command merkt, ob er jetzt enabled oder disabled ist, sondern den Command einfach Registrieren und aber auch wieder Entregistrieren können. Dann kann ich nämlich auch bestimmen, wass der Command macht, wenn er "disabled" ist, oder gar komplexere State-Machines umsetzen.

Das ist nicht so das, was ich fürs FightSystem gemeint habe. Ich möchte eigentlich nicht, dass sich der Command merkt, ob er jetzt enabled oder disabled ist, sondern den Command einfach Registrieren und aber auch wieder Entregistrieren können. Dann kann ich nämlich auch bestimmen, wass der Command macht, wenn er "disabled" ist, oder gar komplexere State-Machines umsetzen.
Veraltet
Review

Ok ich gucke, dass ich das eingebaut bekomme, an sich muss ich ja nur unregister können. Weril registerieren tust du ja mit einer Instanz erzeugen,

Ok ich gucke, dass ich das eingebaut bekomme, an sich muss ich ja nur unregister können. Weril registerieren tust du ja mit einer Instanz erzeugen,
Veraltet
Review

Dies sollte nun möglich sein.

Dies sollte nun möglich sein.
Veraltet
Review

Da du glaube sowieso keinen Befehl doppelt einfügst und dann häufig drüberiterierst, wäre glaube ich eine ArrayList angebrachter.

Da du glaube sowieso keinen Befehl doppelt einfügst und dann häufig drüberiterierst, wäre glaube ich eine ArrayList angebrachter.
Veraltet
Review

Ich glaube eher eine LinkedList, weil ich nur drüber iteriere oder?

Ich glaube eher eine LinkedList, weil ich nur drüber iteriere oder?
Veraltet
Review

Nein, der Vorteil einer Linkedlist ist eher nur bei häufigem Entfernen aus der Mitte gegeben. Die ArrayList ist auch beim Iterieren schneller, weil da ja einfach nur der index um eins erhöht werden muss (bessere Speicherpositionierung)

Nein, der Vorteil einer Linkedlist ist eher nur bei häufigem Entfernen aus der Mitte gegeben. Die ArrayList ist auch beim Iterieren schneller, weil da ja einfach nur der index um eins erhöht werden muss (bessere Speicherpositionierung)
private final Set<InternalCommand> commandSet = new HashSet<>();
private final Set<InternalTabComplete> tabCompleteSet = new HashSet<>();
private final Map<Integer, Set<String>> subCommandTabCompletes = new HashMap<>();
private final Set<SubCommand> commandSet = new HashSet<>();
private Consumer<CommandSender> helpMessage = sender -> {
};
@ -47,8 +45,8 @@ public abstract class SWCommand {
SWCommandUtils.commandMap.register("steamwar", new Command(command, "", "/" + command, Arrays.asList(aliases)) {
@Override
public boolean execute(CommandSender sender, String alias, String[] args) {
for (InternalCommand internalCommand : commandSet) {
if (internalCommand.invoke(sender, args)) {
for (SubCommand subCommand : commandSet) {
if (subCommand.invoke(sender, args)) {
return false;
}
}
@ -58,17 +56,11 @@ public abstract class SWCommand {
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
List<String> strings = new ArrayList<>(subCommandTabCompletes.getOrDefault(args.length, new HashSet<>()));
for (InternalTabComplete internalTabComplete : tabCompleteSet) {
SWCommandUtils.TabComplete tabComplete = internalTabComplete.invoke(sender, args);
if (tabComplete != null) {
strings.addAll(tabComplete.tabCompletes);
}
}
for (InternalCommand internalCommand : commandSet) {
List<String> stringList = internalCommand.tabComplete(args);
if (stringList != null) {
strings.addAll(stringList);
List<String> strings = new ArrayList<>();
for (SubCommand subCommand : commandSet) {
List<String> tabCompletes = subCommand.tabComplete(sender, args);
if (tabCompletes != null) {
strings.addAll(tabCompletes);
}
}
strings = new ArrayList<>(strings);
@ -86,19 +78,10 @@ public abstract class SWCommand {
if (register == null) {
continue;
}
for (int i = 0; i < register.subCommand().length; i++) {
subCommandTabCompletes.computeIfAbsent(i, integer -> new HashSet<>()).add(register.subCommand()[i]);
}
if (!validMethod(method)) {
continue;
}
if (method.getReturnType() == Void.TYPE) {
commandSet.add(new InternalCommand(this, method));
}
if (method.getReturnType() == SWCommandUtils.TabComplete.class) {
tabCompleteSet.add(new InternalTabComplete(this, method));
}
commandSet.add(new SubCommand(this, method));
}
}

Datei anzeigen

@ -40,7 +40,7 @@ class SWCommandUtils {
static final Map<String, TypeMapper<?>> MAPPER_FUNCTIONS = new HashMap<>();
static final TypeMapper<?> ERROR_FUNCTION = new TypeMapper<>() {
static final TypeMapper<?> ERROR_FUNCTION = new TypeMapper<Object>() {
@Override
public Object map(String s) {
throw new SecurityException();
@ -173,36 +173,31 @@ class SWCommandUtils {
}
}
public static Object[] generateArgumentArray(CommandSender commandSender, Method method, Parameter[] parameters, String[] args) {
Object[] arguments = new Object[args.length + 1];
boolean varArgs = false;
if (parameters[parameters.length - 1].isVarArgs()) {
varArgs = true;
arguments = new Object[parameters.length];
}
arguments[0] = parameters[0].getType().cast(commandSender);
SWCommand.Register register = method.getAnnotation(SWCommand.Register.class);
int subCommandIndex = 1;
for (String s : register.subCommand()) {
if (!args[subCommandIndex++].equals(s)) throw new SecurityException();
public static Object[] generateArgumentArray(TypeMapper<?>[] parameters, String[] args, boolean varArgs, String[] subCommand) {
Object[] arguments = new Object[parameters.length + 1];
int index = 0;
while (index < subCommand.length) {
if (!args[index].equals(subCommand[index])) {
throw new SecurityException();
}
index++;
}
for (int i = subCommandIndex; i < parameters.length - (varArgs ? 1 : 0); i++) {
arguments[i] = mapper(parameters[i]).apply(args[i - 1]);
for (int i = 0; i < parameters.length - (varArgs ? 1 : 0); i++) {
arguments[i + 1] = parameters[i].map(args[index++]);
if (arguments[i + 1] == null) {
throw new SecurityException();
}
}
if (varArgs) {
Object[] varArgument = new Object[args.length - parameters.length + 2];
arguments[arguments.length - 1] = varArgument;
Function<String, Object> mapper = mapper(parameters[parameters.length - 1]);
int index = 0;
for (int i = parameters.length - 2; i < args.length; i++) {
varArgument[index++] = mapper.apply(args[i]);
for (int i = 0; i < varArgument.length; i++) {
varArgument[i] = parameters[parameters.length - 1].map(args[index++]);
}
}
return arguments;
}

Datei anzeigen

@ -0,0 +1,92 @@
package de.steamwar.command;
import org.bukkit.command.CommandSender;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
class SubCommand {
private SWCommand swCommand;
private Method method;
private String[] subCommand;
private TypeMapper<?>[] arguments;
private boolean varArgs = false;
private Function<CommandSender, ?> commandSenderFunction;
public SubCommand(SWCommand swCommand, Method method) {
this.swCommand = swCommand;
this.method = method;
Parameter[] parameters = method.getParameters();
commandSenderFunction = sender -> parameters[0].getType().cast(sender);
SWCommand.Register register = method.getAnnotation(SWCommand.Register.class);
subCommand = register.subCommand();
arguments = new TypeMapper[parameters.length - 1];
for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i];
Class<?> clazz = parameter.getType();
if (parameter.isVarArgs()) {
varArgs = true;
clazz = clazz.getComponentType();
}
if (clazz.isEnum()) {
Class<Enum<?>> enumClass = (Class<Enum<?>>) clazz;
List<String> tabCompletes = new ArrayList<>();
for (Enum<?> enumConstant : enumClass.getEnumConstants()) {
tabCompletes.add(enumConstant.name().toLowerCase());
}
arguments[i] = new TypeMapper<Object>() {
@Override
public Object map(String s) {
return SWCommandUtils.ENUM_MAPPER.apply(enumClass, s);
}
@Override
public List<String> tabCompletes(String s) {
return tabCompletes;
}
};
continue;
}
String name = clazz.getTypeName();
SWCommand.Mapper mapper = parameter.getAnnotation(SWCommand.Mapper.class);
if (mapper != null) {
name = mapper.mapper();
}
arguments[i] = SWCommandUtils.MAPPER_FUNCTIONS.getOrDefault(name, SWCommandUtils.ERROR_FUNCTION);
}
}
boolean invoke(CommandSender commandSender, String[] args) {
if (args.length < arguments.length - 1) {
return false;
}
try {
Object[] objects = SWCommandUtils.generateArgumentArray(arguments, args, varArgs, subCommand);
objects[0] = commandSenderFunction.apply(commandSender);
method.setAccessible(true);
method.invoke(swCommand, objects);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new SecurityException(e.getMessage(), e);
} catch (InvocationTargetException e) {
return false;
}
return true;
}
List<String> tabComplete(CommandSender commandSender, String[] args) {
// TODO: implement tabCompleting for SubCommand
return null;
}
}