Command improvements, number converter
Setting to modOnly if any of the superclasses are modOnly Re-added support for command path inheritance getHelpText() for a particular command Subcommands are properly printed across classes now Using a general number converter for both the config and commands
This commit is contained in:
parent
70cabfaa81
commit
0d5ca5a9af
5 changed files with 86 additions and 21 deletions
|
@ -35,4 +35,18 @@ public final class ThorpeUtils {
|
|||
*/
|
||||
String getFancyFullName();
|
||||
}
|
||||
|
||||
public static Number convertNumber(Number number, Class<? extends Number> targetcl) {
|
||||
if (targetcl == long.class || Long.class.isAssignableFrom(targetcl))
|
||||
return number.longValue();
|
||||
else if (targetcl == short.class || Short.class.isAssignableFrom(targetcl))
|
||||
return number.shortValue();
|
||||
else if (targetcl == byte.class || Byte.class.isAssignableFrom(targetcl))
|
||||
return number.byteValue();
|
||||
else if (targetcl == float.class || Float.class.isAssignableFrom(targetcl))
|
||||
return number.floatValue();
|
||||
else if (targetcl == double.class || Double.class.isAssignableFrom(targetcl))
|
||||
return number.doubleValue();
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package buttondevteam.lib.architecture;
|
||||
|
||||
import buttondevteam.core.MainPlugin;
|
||||
import buttondevteam.lib.ThorpeUtils;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -80,18 +81,9 @@ public class ConfigData<T> {
|
|||
if (hmm == null) hmm = def; //Set if the getter returned null
|
||||
return hmm;
|
||||
}
|
||||
if (val instanceof Number) {
|
||||
if (def instanceof Long)
|
||||
val = ((Number) val).longValue();
|
||||
else if (def instanceof Short)
|
||||
val = ((Number) val).shortValue();
|
||||
else if (def instanceof Byte)
|
||||
val = ((Number) val).byteValue();
|
||||
else if (def instanceof Float)
|
||||
val = ((Number) val).floatValue();
|
||||
else if (def instanceof Double)
|
||||
val = ((Number) val).doubleValue();
|
||||
}
|
||||
if (val instanceof Number && def != null)
|
||||
val = ThorpeUtils.convertNumber((Number) val,
|
||||
(Class<? extends Number>) def.getClass());
|
||||
if (val instanceof List && def != null && def.getClass().isArray())
|
||||
val = ((List<T>) val).toArray((T[]) Array.newInstance(def.getClass().getComponentType(), 0));
|
||||
return value = (T) val; //Always cache, if not cached yet
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package buttondevteam.lib.chat;
|
||||
|
||||
import buttondevteam.lib.TBMCCoreAPI;
|
||||
import buttondevteam.lib.ThorpeUtils;
|
||||
import buttondevteam.lib.player.ChromaGamerBase;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.var;
|
||||
import lombok.val;
|
||||
|
@ -13,6 +15,8 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
@ -52,11 +56,11 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
|
|||
public @interface OptionalArg {
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@AllArgsConstructor
|
||||
protected static class SubcommandData<T extends ICommand2> {
|
||||
public final Method method;
|
||||
public final T command;
|
||||
public final String[] helpText;
|
||||
public String[] helpText;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
|
@ -136,6 +140,15 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
|
|||
if (cl == String.class) {
|
||||
params.add(param);
|
||||
continue;
|
||||
} else if (Number.class.isAssignableFrom(cl) || cl.isPrimitive()) {
|
||||
try {
|
||||
//noinspection unchecked
|
||||
params.add(ThorpeUtils.convertNumber(NumberFormat.getInstance().parse(param), (Class<? extends Number>) cl));
|
||||
} catch (ParseException e) {
|
||||
sender.sendMessage("§c'" + param + "' is not a number.");
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
val conv = paramConverters.get(cl);
|
||||
if (conv == null)
|
||||
|
@ -169,13 +182,15 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
|
|||
val scmdHelpList = new ArrayList<String>();
|
||||
Method mainMethod = null;
|
||||
boolean nosubs = true;
|
||||
boolean isSubcommand = x != -1;
|
||||
try { //Register the default handler first so it can be reliably overwritten
|
||||
mainMethod = command.getClass().getMethod("def", Command2Sender.class, String.class);
|
||||
val cc = command.getClass().getAnnotation(CommandClass.class);
|
||||
var ht = cc == null ? new String[0] : cc.helpText();
|
||||
var ht = cc == null || isSubcommand ? new String[0] : cc.helpText(); //If it's not the main command, don't add it
|
||||
if (ht.length > 0)
|
||||
ht[0] = "§6---- " + ht[0] + " ----";
|
||||
scmdHelpList.addAll(Arrays.asList(ht));
|
||||
if (!isSubcommand)
|
||||
scmdHelpList.add("§6Subcommands:");
|
||||
if (!commandHelp.contains(mainPath))
|
||||
commandHelp.add(mainPath);
|
||||
|
@ -199,9 +214,17 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
|
|||
scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header
|
||||
if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class
|
||||
subcommands.put(commandChar + path, new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0])));
|
||||
if (mainMethod != null && !subcommands.containsKey(mainPath)) //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
|
||||
val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, 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])));
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getHelpText(Method method, String[] ht, String subcommand) {
|
||||
val str = method.getDeclaringClass().getResourceAsStream("/commands.yml");
|
||||
|
@ -238,4 +261,10 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
|
|||
public String[] getCommandsText() {
|
||||
return commandHelp.toArray(new String[0]);
|
||||
}
|
||||
|
||||
public String[] getHelpText(String path) {
|
||||
val scmd = subcommands.get(path);
|
||||
if (scmd == null) return null;
|
||||
return scmd.helpText;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package buttondevteam.lib.chat;
|
||||
|
||||
import buttondevteam.core.MainPlugin;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
|
@ -12,11 +13,25 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> {
|
|||
|
||||
@Override
|
||||
public boolean hasPermission(Command2MCSender sender, ICommand2MC command) {
|
||||
return command.getClass().getAnnotation(CommandClass.class).modOnly()
|
||||
return modOnly(command)
|
||||
? MainPlugin.permission.has(sender.getSender(), "tbmc.admin") //TODO: Change when groups are implemented
|
||||
: MainPlugin.permission.has(sender.getSender(), "thorpe.command." + command.getCommandPath().replace(' ', '.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class or <u>any</u> of the superclasses are mod only.
|
||||
*
|
||||
* @param command The command to check
|
||||
* @return Whether the command is mod only
|
||||
*/
|
||||
private boolean modOnly(ICommand2MC command) {
|
||||
for (Class<?> cl = command.getClass(); cl != null; cl = cl.getSuperclass()) {
|
||||
val cc = command.getClass().getAnnotation(CommandClass.class);
|
||||
if (cc != null && cc.modOnly()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically colors the message red.
|
||||
* {@see super#addParamConverter}
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Getter;
|
|||
import lombok.val;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class ICommand2<TP extends Command2Sender> {
|
||||
|
@ -69,8 +70,22 @@ public abstract class ICommand2<TP extends Command2Sender> {
|
|||
"No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
|
||||
Function<Class<?>, String> getFromClass = cl -> cl.getSimpleName().toLowerCase().replace("commandbase", "") // <-- ...
|
||||
.replace("command", "");
|
||||
String path = getClass().getAnnotation(CommandClass.class).path();
|
||||
path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
|
||||
String path = getClass().getAnnotation(CommandClass.class).path(),
|
||||
prevpath = path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
|
||||
for (Class<?> cl = getClass().getSuperclass(); cl != null
|
||||
&& !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
|
||||
.getSuperclass()) { //
|
||||
String newpath;
|
||||
if (!cl.isAnnotationPresent(CommandClass.class)
|
||||
|| (newpath = cl.getAnnotation(CommandClass.class).path()).length() == 0
|
||||
|| newpath.equals(prevpath)) {
|
||||
if ((Modifier.isAbstract(cl.getModifiers()) && !cl.isAnnotationPresent(CommandClass.class))
|
||||
|| cl.getAnnotation(CommandClass.class).excludeFromPath()) // <--
|
||||
continue;
|
||||
newpath = getFromClass.apply(cl);
|
||||
}
|
||||
path = (prevpath = newpath) + " " + path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue