CommandFramework3 #94
@ -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 {
|
||||
|
||||
|
||||
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.
|
||||
Lixfel
hat
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.
YoyoNow
hat
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. 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() {
|
||||
Lixfel
hat
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?
YoyoNow
hat
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?
YoyoNow
hat
Das hier spricht dagegen (Allowed Types in Annotation):
Multidimensional arrays are forbidden. Arrays of type Class are forbidden. Hier warum letzteres verboten ist: '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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
Ich fände es besser, wenn es ein Implements sein würde, dann kann die Klasse auch noch anderes als ein Befehl sein.
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?
Ich würde ungern mit defaults und so arbeiten, deswegen habe ich es im Moment so gelöst.