SteamWar/SpigotCore
Archiviert
13
0

CommandFramework #107

Geschlossen
YoyoNow möchte 27 Commits von CommandFramework nach master mergen
2 geänderte Dateien mit 109 neuen und 21 gelöschten Zeilen

Datei anzeigen

@ -19,9 +19,11 @@
package de.steamwar.command;
import org.bukkit.Bukkit;
import de.steamwar.message.Message;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.lang.annotation.*;
import java.lang.reflect.Method;
@ -29,21 +31,33 @@ import java.lang.reflect.Parameter;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.IntPredicate;
import java.util.logging.Level;
import java.util.stream.Collectors;
public abstract class SWCommand {
private List<String> help = null;
private final Command command;
private final List<SubCommand> commandList = new ArrayList<>();
private final List<SubCommand> commandHelpList = new ArrayList<>();
private final Map<String, TypeMapper<?>> localTypeMapper = new HashMap<>();
private final Message message;
protected SWCommand(String command) {
this(command, new String[0]);
}
protected SWCommand(String command, Message message) {
this(command, message, new String[0]);
}
protected SWCommand(String command, String... aliases) {
this(command, null, aliases);
}
protected SWCommand(String command, Message message, String... aliases) {
this.message = message;
this.command = new Command(command, "", "/" + command, Arrays.asList(aliases)) {
@Override
public boolean execute(CommandSender sender, String alias, String[] args) {
@ -67,7 +81,7 @@ public abstract class SWCommand {
unregister();
register();
Method[] methods = getClass().getDeclaredMethods();
List<Method> methods = methods();
for (Method method : methods) {
addMapper(Mapper.class, method, i -> i == 0, false, TypeMapper.class, (anno, typeMapper) -> {
(anno.local() ? localTypeMapper : SWCommandUtils.MAPPER_FUNCTIONS).putIfAbsent(anno.value(), typeMapper);
@ -78,16 +92,15 @@ public abstract class SWCommand {
add(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");
throw new SecurityException("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");
throw new SecurityException("The method '" + method.toString() + "' is lacking the varArgs parameters as last Argument");
}
if (parameters[parameters.length - 1].getType().getComponentType() != String.class) {
YoyoNow markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Warum nicht direkt die WARNINGS printen bzw. sind das nicht Programmierfehler, also müssten nicht Exceptions fliegen?

Warum nicht direkt die WARNINGS printen bzw. sind das nicht Programmierfehler, also müssten nicht Exceptions fliegen?
Veraltet
Review

Kann ich gerne als Exception fliegen lassen, aber ich will es gesamt halt sagen.

Kann ich gerne als Exception fliegen lassen, aber ich will es gesamt halt sagen.
Veraltet
Review

Programmierfehler sollst du nicht mehr oder weniger silent verstecken, sondern korrekt werfen, was wiederum zum einen Logeinträge hinterlässt, Stacktraces und ggf. den Nutzer über die fehlgeschlagene Operation informiert. Exceptions sind sprichwörtlich dafür gemacht.

Programmierfehler sollst du nicht mehr oder weniger silent verstecken, sondern korrekt werfen, was wiederum zum einen Logeinträge hinterlässt, Stacktraces und ggf. den Nutzer über die fehlgeschlagene Operation informiert. Exceptions sind sprichwörtlich dafür gemacht.
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
return;
throw new SecurityException("The method '" + method.toString() + "' is lacking the varArgs parameters of type '" + String.class.getTypeName() + "' as last Argument");
}
commandHelpList.add(new SubCommand(this, method, anno.value(), new HashMap<>()));
commandHelpList.add(new SubCommand(this, method, anno.description(), anno.value(), new HashMap<>()));
});
}
for (Method method : methods) {
@ -105,11 +118,10 @@ public abstract class SWCommand {
}
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.toString() + "' is using an unsupported Mapper of type '" + name + "'");
return;
throw new SecurityException("The parameter '" + parameter.toString() + "' is using an unsupported Mapper of type '" + name + "'");
}
}
commandList.add(new SubCommand(this, method, anno.value(), localTypeMapper));
commandList.add(new SubCommand(this, method, anno.description(), anno.value(), localTypeMapper));
});
this.commandList.sort((o1, o2) -> {
@ -121,7 +133,15 @@ public abstract class SWCommand {
o2.varArgType != null ? Integer.MAX_VALUE : o2.arguments.length);
}
});
commandHelpList.sort(Comparator.comparingInt(o -> -o.subCommand.length));
commandHelpList.sort((o1, o2) -> {
int compare = Integer.compare(-o1.subCommand.length, -o2.subCommand.length);
if (compare != 0) {
return compare;
} else {
return Integer.compare(o1.method.getDeclaringClass() == SWCommand.class ? 1 : 0,
o2.method.getDeclaringClass() == SWCommand.class ? 1 : 0);
}
});
}
}
@ -131,16 +151,13 @@ public abstract class SWCommand {
YoyoNow markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Nope nope nope. Lass dir beim Erstellen des Commands ein Message-Objekt übergeben.

Nope nope nope. Lass dir beim Erstellen des Commands ein Message-Objekt übergeben.
Veraltet
Review

Doch, Doch, Doch, weil ich will kein Sache übergeben bekommen! Ich will es auch optional halten usw usw!

Doch, Doch, Doch, weil ich will kein Sache übergeben bekommen! Ich will es auch optional halten usw usw!
Veraltet
Review

Dann nutze einen Setter.

Dann nutze einen Setter.
Veraltet
Review

Ist nicht einfach so da, ich will das ich nichts dafür aufrufen oder sonst machen muss! So wie das Register und Mapper und so.

Ist nicht einfach so da, ich will das ich nichts dafür aufrufen oder sonst machen muss! So wie das Register und Mapper und so.
Veraltet
Review

Der Einsatz von Reflections zu diesem Grund ist einfach nur unangemessen. Ein Objekt MESSAGE zur Verfügung zu stellen, ist genauso. Warum nicht einfach message als protected Parameter im SWCommand haben, dann kann das auch einfach problemlos gesetzt werden....

Der Einsatz von Reflections zu diesem Grund ist einfach nur unangemessen. Ein Objekt MESSAGE zur Verfügung zu stellen, ist genauso. Warum nicht einfach message als protected Parameter im SWCommand haben, dann kann das auch einfach problemlos gesetzt werden....
Veraltet
Review

Lixfel dieses System kann man so noch einfach aus dem SpigotCore kopieren und woanders verwenden, wenn ich das verdrahte nicht mehr!

Lixfel dieses System kann man so noch einfach aus dem SpigotCore kopieren und woanders verwenden, wenn ich das verdrahte nicht mehr!
Veraltet
Review

Wohin hast du denn vor, dieses System eins zu eins zu kopieren?

Wohin hast du denn vor, dieses System eins zu eins zu kopieren?
Veraltet
Review

Zeanon verwendet es in einem seiner Projekte.

Zeanon verwendet es in einem seiner Projekte.
Veraltet
Review

Njoa, Also das Message-System ist exakt eine Klasse mehr. Ich glaube, es ist komplexer, Support für mit und ohne Message-System vorzuhalten, als einfach das Message-System mit dranzuhängen.

Njoa, Also das Message-System ist exakt eine Klasse mehr. Ich glaube, es ist komplexer, Support für mit und ohne Message-System vorzuhalten, als einfach das Message-System mit dranzuhängen.
Parameter[] parameters = method.getParameters();
if (!parameterTester.test(parameters.length)) {
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking parameters or has too many");
return;
throw new SecurityException("The method '" + method.toString() + "' is lacking parameters or has too many");
}
if (firstParameter && !CommandSender.class.isAssignableFrom(parameters[0].getType())) {
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the first parameter of type '" + CommandSender.class.getTypeName() + "'");
return;
throw new SecurityException("The method '" + method.toString() + "' is lacking the first parameter of type '" + CommandSender.class.getTypeName() + "'");
}
if (returnType != null && method.getReturnType() != returnType) {
Bukkit.getLogger().log(Level.WARNING, "The method '" + method.toString() + "' is lacking the desired return type '" + returnType.getTypeName() + "'");
return;
throw new SecurityException("The method '" + method.toString() + "' is lacking the desired return type '" + returnType.getTypeName() + "'");
}
Arrays.stream(anno).forEach(t -> consumer.accept(t, parameters));
}
@ -156,6 +173,12 @@ public abstract class SWCommand {
});
}
private List<Method> methods() {
List<Method> methods = new ArrayList<>(Arrays.asList(getClass().getDeclaredMethods()));
methods.addAll(Arrays.asList(SWCommand.class.getDeclaredMethods()));
return methods;
}
public void unregister() {
SWCommandUtils.knownCommandMap.remove(command.getName());
command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
@ -166,12 +189,68 @@ public abstract class SWCommand {
SWCommandUtils.commandMap.register("steamwar", this.command);
}
public void inject(Plugin plugin) {
new BukkitRunnable() {
@Override
public void run() {
SWCommand.this.unregister();
SWCommand.this.register();
}
}.runTask(plugin);
}
@Register(help = true)
private void internalHelp(CommandSender sender, String... args) {
if (help == null) {
help = new ArrayList<>();
commandList.forEach(subCommand -> {
StringBuilder st = new StringBuilder();
st.append("§8/§7").append(command.getName()).append(" ");
st.append("§7").append(String.join(" ", subCommand.subCommand));
String cmd = Arrays.stream(subCommand.parameters)
.skip(1)
.map(parameter -> {
Name name = parameter.getAnnotation(Name.class);
if (name != null) {
return name.name();
} else {
return parameter.getName();
}
})
.map(param -> " §8[§e" + param + "§8]")
.collect(Collectors.joining(""));
YoyoNow markierte diese Unterhaltung als gelöst Veraltet
Veraltet
Review

Warum muss das jetzt wieder plötzlich injected werden?

Warum muss das jetzt wieder plötzlich injected werden?
Veraltet
Review

Weil wichtig und so und API, welche uns bei zeiten helfen kann.

Weil wichtig und so und API, welche uns bei zeiten helfen kann.
st.append(cmd);
if (subCommand.varArgType != null) {
st.append("§7...");
}
if (!subCommand.description.isEmpty()) {
st.append("§8 - §7").append(message != null ? message.parse(subCommand.description, sender) : subCommand.description);
}
help.add(st.toString());
});
}
String string = "/" + command.getName() + " " + String.join(" ", args);
sender.sendMessage("§7----==== §e" + command.getName() + " §7====----");
sender.sendMessage("§7" + (message != null ? message.parse("COMMAND_ALIASES", sender) : "Aliases") + "§8:§e " + String.join("§8,§e ", command.getAliases()));
help.forEach(s -> {
if (s.replaceAll("§[0-9A-Z]", "").startsWith(string)) {
sender.sendMessage(s);
Veraltet
Review

Sämtliche Color-Codes sind auch Teil des Message-Systems. Farben haben in anderen Sprach- und Kulturkreisen andere Bedeutungen.

Sämtliche Color-Codes sind auch Teil des Message-Systems. Farben haben in anderen Sprach- und Kulturkreisen andere Bedeutungen.
Veraltet
Review

Haben nicht die SteamwarFarben aus einem Grund?

Haben nicht die SteamwarFarben aus einem Grund?
Veraltet
Review

? Deutsch? Wir haben die Farben aus dem Grund, dass wir Stil haben und nicht wie nahezu jeder andere Server einfach einen kunterbunten flashy Colorstyle haben.

? Deutsch? Wir haben die Farben aus dem Grund, dass wir Stil haben und nicht wie nahezu jeder andere Server einfach einen kunterbunten flashy Colorstyle haben.
Veraltet
Review

*wir

\*wir
Veraltet
Review

Können wir nicht dann trotzdem unser Style in jede Message setzten?

Können wir nicht dann trotzdem unser Style in jede Message setzten?
Veraltet
Review

Ja genau, in die Message, und nicht in den Code.

Ja genau, in die Message, und nicht in den Code.
Veraltet
Review

Ok und wie soll ich dies deiner Meinung dann machen?
Also wie soll ich die keys nennen, wo soll ich dies dokumentieren und was soll ich machen, wenn diese nicht existieren?

Ok und wie soll ich dies deiner Meinung dann machen? Also wie soll ich die keys nennen, wo soll ich dies dokumentieren und was soll ich machen, wenn diese nicht existieren?
}
});
}
private String translate(String description, CommandSender sender) {
return message != null ? message.parse(description, sender) : description;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Register.Registeres.class)
protected @interface Register {
String[] value() default {};
String description() default "";
boolean help() default false;
@Retention(RetentionPolicy.RUNTIME)
@ -196,4 +275,10 @@ public abstract class SWCommand {
boolean local() default false;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface Name {
String name();
}
}

Datei anzeigen

@ -33,18 +33,21 @@ import static de.steamwar.command.SWCommandUtils.*;
class SubCommand {
private SWCommand swCommand;
private Method method;
Method method;
String description;
Parameter[] parameters;
String[] subCommand;
TypeMapper<?>[] arguments;
private Predicate<CommandSender> commandSenderPredicate;
private Function<CommandSender, ?> commandSenderFunction;
Class<?> varArgType = null;
SubCommand(SWCommand swCommand, Method method, String[] subCommand, Map<String, TypeMapper<?>> localTypeMapper) {
SubCommand(SWCommand swCommand, Method method, String description, String[] subCommand, Map<String, TypeMapper<?>> localTypeMapper) {
this.swCommand = swCommand;
this.method = method;
this.description = description;
Parameter[] parameters = method.getParameters();
parameters = method.getParameters();
commandSenderPredicate = sender -> parameters[0].getType().isAssignableFrom(sender.getClass());
commandSenderFunction = sender -> parameters[0].getType().cast(sender);
this.subCommand = subCommand;