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
3 geänderte Dateien mit 106 neuen und 15 gelöschten Zeilen
Nur Änderungen aus Commit 97a8862b62 werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -1,9 +1,33 @@
/*
* 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.acommand;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TestCommand extends SWCommand {
Veraltet
Review

Ich fände es besser, wenn es ein Implements sein würde, dann kann die Klasse auch noch anderes als ein Befehl sein.

Ich fände es besser, wenn es ein Implements sein würde, dann kann die Klasse auch noch anderes als ein Befehl sein.
Veraltet
Review

Im Moment geht dies nicht, wegen dem Constructor, und den Sachen, welche dort drin passieren. Dementsprechend ist dies so im Moment nicht möglich. Wie würdest du das umsetzten?

Im Moment geht dies nicht, wegen dem Constructor, und den Sachen, welche dort drin passieren. Dementsprechend ist dies so im Moment nicht möglich. Wie würdest du das umsetzten?
Veraltet
Review

Ich würde ungern mit defaults und so arbeiten, deswegen habe ich es im Moment so gelöst.

Ich würde ungern mit defaults und so arbeiten, deswegen habe ich es im Moment so gelöst.
public TestCommand() {
@ -18,10 +42,33 @@ public class TestCommand extends SWCommand {
}
// Another Command, subCommands can be implemented with the Register Annotation,
// you can Implement custom Mappers Annotation by @Mapper on a Parameter
// you can use custom Mappers by putting a Mapper Annotation on a Parameter
@Register({"two"})
public void testTwo(Player player, int i, @Mapper("Hello World") Material material) {
}
// Add Custom Mapper when this command is registered, all Mapper of you class will be
// created first and than the Commands. Do not use this mapper outside your class, as
// it can only create failures. Use on your own risk. Definition order should be considered.
Veraltet
Review

Liest sich arg hacky, ich fände es gut, wenn Mapperobjekte nur einmal erstellt werden und ggf. von mehreren Befehlen genutzt werden könnten. Evtl. eine Annotation @Mapper mit einem TypeMapper als Argument statt einem String? Dann haben wir auch nicht mehr die dreckige string-lösung.

Liest sich arg hacky, ich fände es gut, wenn Mapperobjekte nur einmal erstellt werden und ggf. von mehreren Befehlen genutzt werden könnten. Evtl. eine Annotation @Mapper mit einem TypeMapper als Argument statt einem String? Dann haben wir auch nicht mehr die dreckige string-lösung.
Veraltet
Review

Ich wollte die Mapper explizit von dem Parameter weghaben, damit diese explizit auch global erzeugt werden können. Das was du da liest ist eine abkürzung, womit du Mapper, welche du nur hier in diesem Befehl brauchst hier definierst und verwendest. Ab dem Moment wird es für alle Befehle, welche danach erzeugt werden auch existieren. Der String ist explizit, damit man ein Argument 'Material' haben kann, welches jedoch einen anderen Mapper haben kann. Der name ist dann auch so gut zu wählen wie nötig oder möglich.
Die Mapper an sich werden auch nur einmal erzeugt und dann in eine Map intern gepackt. Außerdem kann man in Annotationen keine Interfaces als fields verwenden:
image
Deswegen geht deine Idee leider nicht, hatte ich auch schon als Idee.

Ich wollte die Mapper explizit von dem Parameter weghaben, damit diese explizit auch global erzeugt werden können. Das was du da liest ist eine abkürzung, womit du Mapper, welche du nur hier in diesem Befehl brauchst hier definierst und verwendest. Ab dem Moment wird es für alle Befehle, welche danach erzeugt werden auch existieren. Der String ist explizit, damit man ein Argument 'Material' haben kann, welches jedoch einen anderen Mapper haben kann. Der name ist dann auch so gut zu wählen wie nötig oder möglich. Die Mapper an sich werden auch nur einmal erzeugt und dann in eine Map intern gepackt. Außerdem kann man in Annotationen keine Interfaces als fields verwenden: ![image](/devlabs/attachments/7bc5f00b-475e-4314-bdd1-7fc6a4dbe5f0) Deswegen geht deine Idee leider nicht, hatte ich auch schon als Idee.
@Mapper("Hello World")
public TypeMapper<Material> materialTypeMapper() {
Review

Das das ganze mit Strings funktioniert, gefällt mir immer noch nicht (und dir wsl. auch nicht). Da anscheinend keine Interfaces, sondern nur konkrete Instanzen einer Klasse verwendet werden können: Mach doch eine Klasse TypeMapper, die als Parameter eine Funktion String -> Objekt nimmt. Dann ist das eine klare Klasse. Ggf. ist das dann erstmal ein Object (wenn Templating nicht geht) ansonsten spricht aber meines Wissens nach nix dagegen, oder?

Das das ganze mit Strings funktioniert, gefällt mir immer noch nicht (und dir wsl. auch nicht). Da anscheinend keine Interfaces, sondern nur konkrete Instanzen einer Klasse verwendet werden können: Mach doch eine Klasse TypeMapper, die als Parameter eine Funktion String -> Objekt nimmt. Dann ist das eine klare Klasse. Ggf. ist das dann erstmal ein Object (wenn Templating nicht geht) ansonsten spricht aber meines Wissens nach nix dagegen, oder?
Review

Ich verstehe dein Vorschlag nicht ganz. Du willst, dass ich in der Annotation eine Object angebe, welches dann eine Function<String, Object> beinhaltet. Wie soll das das Mapper zeug lösen. Kannst du versuchen das nochmal etwas genauer zu beschreiben?

Ich verstehe dein Vorschlag nicht ganz. Du willst, dass ich in der Annotation eine Object angebe, welches dann eine Function\<String, Object> beinhaltet. Wie soll das das Mapper zeug lösen. Kannst du versuchen das nochmal etwas genauer zu beschreiben?
Review

image

Das hier spricht dagegen (Allowed Types in Annotation):

  • primitive
  • String
  • an Enum
  • another Annotation
  • Class
  • an Array of the above

Multidimensional arrays are forbidden. Arrays of type Class are forbidden.

Hier warum letzteres verboten ist:
image

'Constant Expressions' ist das Stichwort

![image](/devlabs/attachments/3c90a023-f8d5-4ba7-827e-473af354ade4) Das hier spricht dagegen (Allowed Types in Annotation): - primitive - String - an Enum - another Annotation - Class - an Array of the above Multidimensional arrays are forbidden. Arrays of type Class are forbidden. Hier warum letzteres verboten ist: ![image](/devlabs/attachments/2081e223-2da1-4f23-96ca-2cd5b0101bd7) 'Constant Expressions' ist das Stichwort
List<String> tabCompletes = Arrays.stream(Material.values())
.filter(Material::isSolid)
.map(Material::name)
.map(String::toLowerCase)
.collect(Collectors.toList());
return new TypeMapper<>() {
@Override
public Material map(String s) {
return Material.valueOf(s.toUpperCase());
}
@Override
public List<String> tabCompletes(String s) {
return tabCompletes;
}
};
}
}

Datei anzeigen

@ -74,24 +74,26 @@ public abstract class SWCommand {
});
for (Method method : getClass().getDeclaredMethods()) {
Register register = method.getDeclaredAnnotation(Register.class);
if (register == null) {
continue;
}
if (!validMethod(method)) {
continue;
}
commandSet.add(new SubCommand(this, method));
addMapper(method);
}
for (Method method : getClass().getDeclaredMethods()) {
addCommand(method);
}
}
private boolean validMethod(Method method) {
private void addCommand(Method method) {
Register register = method.getDeclaredAnnotation(Register.class);
Mapper methodMapper = method.getDeclaredAnnotation(Mapper.class);
if (register == null || methodMapper != null) {
return;
}
Parameter[] parameters = method.getParameters();
if (parameters.length == 0) {
return false;
return;
}
if (!CommandSender.class.isAssignableFrom(parameters[0].getType())) {
return false;
return;
}
for (int i = 1; i < parameters.length; i++) {
Parameter parameter = parameters[i];
@ -107,9 +109,32 @@ public abstract class SWCommand {
if (mapper != null) {
name = mapper.value();
}
if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name)) return false;
if (!SWCommandUtils.MAPPER_FUNCTIONS.containsKey(name)) return;
}
commandSet.add(new SubCommand(this, method));
}
private void addMapper(Method method) {
Register register = method.getDeclaredAnnotation(Register.class);
Mapper methodMapper = method.getDeclaredAnnotation(Mapper.class);
if (register != null || methodMapper == null) {
return;
}
Parameter[] parameters = method.getParameters();
if (parameters.length != 0) {
return;
}
if (method.getReturnType() != TypeMapper.class) {
return;
}
try {
method.setAccessible(true);
Object object = method.invoke(this);
SWCommandUtils.addMapper(methodMapper.value(), (TypeMapper<?>) object);
} catch (Exception e) {
throw new SecurityException(e.getMessage(), e);
}
return true;
}
protected final void setHelpMessage(Consumer<CommandSender> helpMessage) {
@ -128,7 +153,7 @@ public abstract class SWCommand {
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Target({ElementType.PARAMETER, ElementType.METHOD})
protected @interface Mapper {
String value();
}

Datei anzeigen

@ -1,3 +1,22 @@
/*
* 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;