From 95a8e92b517dc8c13dda1707459c0864a22d3d4a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 17 Mar 2020 00:33:35 +0100 Subject: [PATCH] List commands on /chroma, fixed arg names And broke the game (can't connect atm) #84 #82 --- .../buttondevteam/core/ChromaCommand.java | 10 ++++ .../java/buttondevteam/lib/chat/Command2.java | 49 +++++++++++-------- .../buttondevteam/lib/chat/Command2MC.java | 20 ++++++-- .../commandargs/BetterStringArgumentType.java | 42 ++++++++++++++++ 4 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 Chroma-Core/src/main/java/buttondevteam/lib/chat/commandargs/BetterStringArgumentType.java diff --git a/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java b/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java index 3d6465e..6328ebc 100644 --- a/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java +++ b/Chroma-Core/src/main/java/buttondevteam/core/ChromaCommand.java @@ -20,4 +20,14 @@ public class ChromaCommand extends ICommand2MC { else sender.sendMessage("§cFailed to reload config. Check console."); } + + @Command2.Subcommand + public void def(CommandSender sender) { + sender.sendMessage(ButtonPlugin.getCommand2MC().getCommandsText()); + } + + @Command2.Subcommand + public void test(CommandSender sender, char test) { + sender.sendMessage(test + ""); + } } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java index ec76a23..d2d1a6b 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2.java @@ -11,7 +11,6 @@ import lombok.RequiredArgsConstructor; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; import java.io.InputStreamReader; @@ -23,14 +22,17 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.NumberFormat; import java.text.ParseException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.function.Function; /** * The method name is the subcommand, use underlines (_) to add further subcommands. * The args may be null if the conversion failed and it's optional. */ -public abstract class Command2 { +public abstract class Command2, TP extends Command2Sender> { protected Command2() { commandHelp.add("§6---- Commands ----"); } @@ -60,10 +62,10 @@ public abstract class Command2 String[] helpText() default {}; /** - * The main permission which allows using this command (individual access can be still granted with "chroma.command.X"). + * The main permission which allows using this command (individual access can be still revoked with "chroma.command.X"). * Used to be "tbmc.admin". The {@link #MOD_GROUP} is provided to use with this. */ - String permGroup() default ""; //TODO + String permGroup() default ""; } @Target(ElementType.PARAMETER) @@ -72,13 +74,14 @@ public abstract class Command2 } @AllArgsConstructor - protected static class SubcommandData { + protected static class SubcommandData> { public final Method method; public final T command; + public final String[] parameters; public String[] helpText; } - protected static class SubcommandHelpData extends SubcommandData { + /*protected static class SubcommandHelpData extends SubcommandData { private final TreeSet ht = new TreeSet<>(); private BukkitTask task; @@ -101,7 +104,7 @@ public abstract class Command2 task = null; //Run again, if needed }); } - } + }*/ @RequiredArgsConstructor protected static class ParamConverter { @@ -131,7 +134,7 @@ public abstract class Command2 public boolean handleCommand(TP sender, String commandline) { for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { String subcommand = commandline.substring(0, i).toLowerCase(); - SubcommandData sd = subcommands.get(subcommand); //O(1) + SubcommandData sd = subcommands.get(subcommand); if (sd == null) continue; boolean sync = Bukkit.isPrimaryThread(); Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> { @@ -177,12 +180,12 @@ public abstract class Command2 if (sendertype.isAssignableFrom(sender.getClass())) params.add(sender); //The command either expects a CommandSender or it is a Player, or some other expected type else if (sender instanceof Command2MCSender - && sendertype.isAssignableFrom(((Command2MCSender) sender).getSender().getClass())) + && sendertype.isAssignableFrom(((Command2MCSender) sender).getSender().getClass())) params.add(((Command2MCSender) sender).getSender()); else if (ChromaGamerBase.class.isAssignableFrom(sendertype) - && sender instanceof Command2MCSender - && (cg = ChromaGamerBase.getFromSender(((Command2MCSender) sender).getSender())) != null - && cg.getClass() == sendertype) //The command expects a user of our system + && sender instanceof Command2MCSender + && (cg = ChromaGamerBase.getFromSender(((Command2MCSender) sender).getSender())) != null + && cg.getClass() == sendertype) //The command expects a user of our system params.add(cg); else { sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command."); @@ -198,7 +201,7 @@ public abstract class Command2 if (cl.isPrimitive()) params.add(Defaults.defaultValue(cl)); else if (Number.class.isAssignableFrom(cl) - || Number.class.isAssignableFrom(cl)) + || Number.class.isAssignableFrom(cl)) params.add(Defaults.defaultValue(Primitives.unwrap(cl))); else params.add(null); @@ -306,9 +309,10 @@ public abstract class Command2 var ht = command.getHelpText(method, ann); if (ht != null) { //The method is a subcommand val subcommand = commandChar + path + //Add command path (class name by default) - getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def' - ht = getParameterHelp(method, ht, subcommand); - var sd = new SubcommandData<>(method, command, ht); + getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def' + var params = new String[method.getParameterCount() - 1]; + ht = getParameterHelp(method, ht, subcommand, params); + var sd = new SubcommandData<>(method, command, params, ht); subcommands.put(subcommand, sd); //Result of the above (def) is that it will show the help text addedSubcommands.add(sd); scmdHelpList.add(subcommand); @@ -318,24 +322,24 @@ public abstract class Command2 if (nosubs && scmdHelpList.size() > 0) scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header if (mainMethod != null && !subcommands.containsKey(commandChar + path)) { //Command specified by the class - var sd = new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0])); + var sd = new SubcommandData<>(mainMethod, command, null, scmdHelpList.toArray(new String[0])); subcommands.put(commandChar + path, sd); addedSubcommands.add(sd); } if (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above if (isSubcommand) { //The class itself is a subcommand - val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[]{"§6---- Subcommands ----"})); + val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[0], new String[]{"§6---- Subcommands ----"})); val scmdHelp = Arrays.copyOf(scmd.helpText, scmd.helpText.length + scmdHelpList.size()); for (int i = 0; i < scmdHelpList.size(); i++) scmdHelp[scmd.helpText.length + i] = scmdHelpList.get(i); scmd.helpText = scmdHelp; } else if (!subcommands.containsKey(mainPath)) - subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0]))); + subcommands.put(mainPath, new SubcommandData<>(null, null, new String[0], scmdHelpList.toArray(new String[0]))); } return addedSubcommands; } - private String[] getParameterHelp(Method method, String[] ht, String subcommand) { + private String[] getParameterHelp(Method method, String[] ht, String subcommand, String[] parameters) { val str = method.getDeclaringClass().getResourceAsStream("/commands.yml"); if (str == null) TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!")); @@ -355,6 +359,9 @@ public abstract class Command2 String[] both = Arrays.copyOf(ht, ht.length + 1); both[ht.length] = "§6Usage:§r " + subcommand + " " + params; ht = both; + var paramArray = params.split(" "); + for (int j = 0; j < paramArray.length && j < parameters.length; j++) + parameters[j] = paramArray[j]; } else TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params)); } else diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java index 4390f14..89d42ce 100644 --- a/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -4,6 +4,7 @@ import buttondevteam.core.MainPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.chat.commandargs.BetterStringArgumentType; import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; @@ -231,7 +232,7 @@ public class Command2MC extends Command2 implemen if (parameter.isAnnotationPresent(TextArg.class)) type = StringArgumentType.greedyString(); else - type = StringArgumentType.word(); + type = BetterStringArgumentType.word(); else if (ptype == int.class || ptype == Integer.class || ptype == byte.class || ptype == Byte.class || ptype == short.class || ptype == Short.class) @@ -243,17 +244,26 @@ public class Command2MC extends Command2 implemen else if (ptype == double.class || ptype == Double.class) type = DoubleArgumentType.doubleArg(); else if (ptype == char.class || ptype == Character.class) - type = StringArgumentType.word(); + type = BetterStringArgumentType.word(1); else if (ptype == boolean.class || ptype == Boolean.class) type = BoolArgumentType.bool(); else //TODO: Custom parameter types - type = StringArgumentType.word(); - var arg = RequiredArgumentBuilder.argument(parameter.getName(), type).build(); + type = BetterStringArgumentType.word(); + var arg = RequiredArgumentBuilder.argument(subcmd.parameters[i - 1], type).build(); scmd.addChild(arg); scmd = arg; } } - commodore.register(maincmd); + /*try { + Class.forName("net.minecraft.server.v1_15_R1.ArgumentRegistry").getMethod("a", String.class, Class.class, + Class.forName("net.minecraft.server.v1_15_R1.ArgumentSerializer")) + .invoke(null, "chroma:string", BetterStringArgumentType.class, + Class.forName("net.minecraft.server.v1_15_R1.ArgumentSerializerVoid").getConstructors()[0] + .newInstance((Supplier) BetterStringArgumentType::word)); + } catch (Exception e) { - Client log: Could not deserialize chroma:string + e.printStackTrace(); + }*/ + commodore.register(bukkitCommand, maincmd); } } } diff --git a/Chroma-Core/src/main/java/buttondevteam/lib/chat/commandargs/BetterStringArgumentType.java b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commandargs/BetterStringArgumentType.java new file mode 100644 index 0000000..b77a3da --- /dev/null +++ b/Chroma-Core/src/main/java/buttondevteam/lib/chat/commandargs/BetterStringArgumentType.java @@ -0,0 +1,42 @@ +package buttondevteam.lib.chat.commandargs; + +import com.mojang.brigadier.LiteralMessage; +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import lombok.RequiredArgsConstructor; + +import java.util.Collection; + +@RequiredArgsConstructor +public class BetterStringArgumentType implements ArgumentType { + private final int len; + + public static BetterStringArgumentType word() { + return new BetterStringArgumentType(-1); + } + + public static BetterStringArgumentType word(int maxlen) { + return new BetterStringArgumentType(maxlen); + } + + @Override + public String parse(StringReader reader) throws CommandSyntaxException { + if (len < 1) + return reader.readStringUntil(' '); + + final int start = reader.getCursor(); + if (reader.canRead(len + 1) && reader.peek(len) != ' ') + throw new SimpleCommandExceptionType(new LiteralMessage("String too long")).createWithContext(reader); + for (int i = 0; i < len; i++) + reader.skip(); + return reader.getString().substring(start, reader.getCursor()); + } + + @Override + public Collection getExamples() { + return StringArgumentType.StringType.SINGLE_WORD.getExamples(); + } +}