List commands on /chroma, fixed arg names

And broke the game (can't connect atm)
#84
#82
This commit is contained in:
Norbi Peti 2020-03-17 00:33:35 +01:00
parent 792a127bdd
commit 95a8e92b51
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
4 changed files with 95 additions and 26 deletions

View file

@ -20,4 +20,14 @@ public class ChromaCommand extends ICommand2MC {
else else
sender.sendMessage("§cFailed to reload config. Check console."); 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 + "");
}
} }

View file

@ -11,7 +11,6 @@ import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -23,14 +22,17 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.text.ParseException; 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; import java.util.function.Function;
/** /**
* The method name is the subcommand, use underlines (_) to add further subcommands. * 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. * The args may be null if the conversion failed and it's optional.
*/ */
public abstract class Command2<TC extends ICommand2, TP extends Command2Sender> { public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Sender> {
protected Command2() { protected Command2() {
commandHelp.add("§6---- Commands ----"); commandHelp.add("§6---- Commands ----");
} }
@ -60,10 +62,10 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
String[] helpText() default {}; 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. * 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) @Target(ElementType.PARAMETER)
@ -72,13 +74,14 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
} }
@AllArgsConstructor @AllArgsConstructor
protected static class SubcommandData<T extends ICommand2> { protected static class SubcommandData<T extends ICommand2<?>> {
public final Method method; public final Method method;
public final T command; public final T command;
public final String[] parameters;
public String[] helpText; public String[] helpText;
} }
protected static class SubcommandHelpData<T extends ICommand2> extends SubcommandData<T> { /*protected static class SubcommandHelpData<T extends ICommand2> extends SubcommandData<T> {
private final TreeSet<String> ht = new TreeSet<>(); private final TreeSet<String> ht = new TreeSet<>();
private BukkitTask task; private BukkitTask task;
@ -101,7 +104,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
task = null; //Run again, if needed task = null; //Run again, if needed
}); });
} }
} }*/
@RequiredArgsConstructor @RequiredArgsConstructor
protected static class ParamConverter<T> { protected static class ParamConverter<T> {
@ -131,7 +134,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
public boolean handleCommand(TP sender, String commandline) { public boolean handleCommand(TP sender, String commandline) {
for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) {
String subcommand = commandline.substring(0, i).toLowerCase(); String subcommand = commandline.substring(0, i).toLowerCase();
SubcommandData<TC> sd = subcommands.get(subcommand); //O(1) SubcommandData<TC> sd = subcommands.get(subcommand);
if (sd == null) continue; if (sd == null) continue;
boolean sync = Bukkit.isPrimaryThread(); boolean sync = Bukkit.isPrimaryThread();
Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> { Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> {
@ -307,8 +310,9 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
if (ht != null) { //The method is a subcommand if (ht != null) { //The method is a subcommand
val subcommand = commandChar + path + //Add command path (class name by default) val subcommand = commandChar + path + //Add command path (class name by default)
getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def' getCommandPath(method.getName(), ' '); //Add method name, unless it's 'def'
ht = getParameterHelp(method, ht, subcommand); var params = new String[method.getParameterCount() - 1];
var sd = new SubcommandData<>(method, command, ht); 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 subcommands.put(subcommand, sd); //Result of the above (def) is that it will show the help text
addedSubcommands.add(sd); addedSubcommands.add(sd);
scmdHelpList.add(subcommand); scmdHelpList.add(subcommand);
@ -318,24 +322,24 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
if (nosubs && scmdHelpList.size() > 0) if (nosubs && scmdHelpList.size() > 0)
scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header
if (mainMethod != null && !subcommands.containsKey(commandChar + path)) { //Command specified by the class 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); subcommands.put(commandChar + path, sd);
addedSubcommands.add(sd); addedSubcommands.add(sd);
} }
if (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above if (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above
if (isSubcommand) { //The class itself is a subcommand 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()); val scmdHelp = Arrays.copyOf(scmd.helpText, scmd.helpText.length + scmdHelpList.size());
for (int i = 0; i < scmdHelpList.size(); i++) for (int i = 0; i < scmdHelpList.size(); i++)
scmdHelp[scmd.helpText.length + i] = scmdHelpList.get(i); scmdHelp[scmd.helpText.length + i] = scmdHelpList.get(i);
scmd.helpText = scmdHelp; scmd.helpText = scmdHelp;
} else if (!subcommands.containsKey(mainPath)) } 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; 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"); val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
if (str == null) if (str == null)
TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!")); TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!"));
@ -355,6 +359,9 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
String[] both = Arrays.copyOf(ht, ht.length + 1); String[] both = Arrays.copyOf(ht, ht.length + 1);
both[ht.length] = "§6Usage:§r " + subcommand + " " + params; both[ht.length] = "§6Usage:§r " + subcommand + " " + params;
ht = both; ht = both;
var paramArray = params.split(" ");
for (int j = 0; j < paramArray.length && j < parameters.length; j++)
parameters[j] = paramArray[j];
} else } else
TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params)); TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params));
} else } else

View file

@ -4,6 +4,7 @@ import buttondevteam.core.MainPlugin;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.ButtonPlugin;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.commandargs.BetterStringArgumentType;
import com.mojang.brigadier.arguments.*; import com.mojang.brigadier.arguments.*;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
@ -231,7 +232,7 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
if (parameter.isAnnotationPresent(TextArg.class)) if (parameter.isAnnotationPresent(TextArg.class))
type = StringArgumentType.greedyString(); type = StringArgumentType.greedyString();
else else
type = StringArgumentType.word(); type = BetterStringArgumentType.word();
else if (ptype == int.class || ptype == Integer.class else if (ptype == int.class || ptype == Integer.class
|| ptype == byte.class || ptype == Byte.class || ptype == byte.class || ptype == Byte.class
|| ptype == short.class || ptype == Short.class) || ptype == short.class || ptype == Short.class)
@ -243,17 +244,26 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implemen
else if (ptype == double.class || ptype == Double.class) else if (ptype == double.class || ptype == Double.class)
type = DoubleArgumentType.doubleArg(); type = DoubleArgumentType.doubleArg();
else if (ptype == char.class || ptype == Character.class) else if (ptype == char.class || ptype == Character.class)
type = StringArgumentType.word(); type = BetterStringArgumentType.word(1);
else if (ptype == boolean.class || ptype == Boolean.class) else if (ptype == boolean.class || ptype == Boolean.class)
type = BoolArgumentType.bool(); type = BoolArgumentType.bool();
else //TODO: Custom parameter types else //TODO: Custom parameter types
type = StringArgumentType.word(); type = BetterStringArgumentType.word();
var arg = RequiredArgumentBuilder.argument(parameter.getName(), type).build(); var arg = RequiredArgumentBuilder.argument(subcmd.parameters[i - 1], type).build();
scmd.addChild(arg); scmd.addChild(arg);
scmd = 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>) BetterStringArgumentType::word));
} catch (Exception e) { - Client log: Could not deserialize chroma:string
e.printStackTrace();
}*/
commodore.register(bukkitCommand, maincmd);
} }
} }
} }

View file

@ -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<String> {
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<String> getExamples() {
return StringArgumentType.StringType.SINGLE_WORD.getExamples();
}
}