Separated commands and handlers

WIP
This commit is contained in:
Norbi Peti 2019-02-02 02:45:32 +01:00
parent ab603276d3
commit ab24480f89
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
8 changed files with 98 additions and 69 deletions

View file

@ -12,7 +12,6 @@
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" /> <orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="library" name="Maven: org.reflections:reflections:0.9.10" level="project" /> <orderEntry type="library" name="Maven: org.reflections:reflections:0.9.10" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:annotations:2.0.1" level="project" /> <orderEntry type="library" name="Maven: com.google.code.findbugs:annotations:2.0.1" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.20.0-GA" level="project" /> <orderEntry type="library" name="Maven: org.javassist:javassist:3.20.0-GA" level="project" />

View file

@ -2,8 +2,9 @@ package buttondevteam.core;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.Component;
import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.Command2.Subcommand;
import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.CommandClass;
import buttondevteam.lib.chat.ICommand2MC;
import lombok.val; import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -15,10 +16,9 @@ import java.util.Optional;
"§6---- Component command ----", "§6---- Component command ----",
"Can be used to enable/disable/list components" "Can be used to enable/disable/list components"
}) })
public class ComponentCommand extends Command2MC { public class ComponentCommand extends ICommand2MC {
public ComponentCommand() { public ComponentCommand() {
addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg));
} }
@Subcommand @Subcommand

View file

@ -2,6 +2,7 @@ package buttondevteam.lib.architecture;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.chat.Command2MC;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
@ -11,6 +12,8 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.util.Stack; import java.util.Stack;
public abstract class ButtonPlugin extends JavaPlugin { public abstract class ButtonPlugin extends JavaPlugin {
@Getter
private static Command2MC command2MC = new Command2MC();
@Getter(AccessLevel.PROTECTED) @Getter(AccessLevel.PROTECTED)
private IHaveConfig iConfig; private IHaveConfig iConfig;
/** /**

View file

@ -3,7 +3,7 @@ package buttondevteam.lib.architecture;
import buttondevteam.core.ComponentManager; import buttondevteam.core.ComponentManager;
import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCCoreAPI;
import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException; import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException;
import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.ICommand2;
import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCChatAPI;
import buttondevteam.lib.chat.TBMCCommandBase; import buttondevteam.lib.chat.TBMCCommandBase;
import lombok.Getter; import lombok.Getter;
@ -197,8 +197,8 @@ public abstract class Component {
* *
* @param commandBase Custom coded command class * @param commandBase Custom coded command class
*/ */
protected final void registerCommand(Command2MC commandBase) { protected final void registerCommand(ICommand2 commandBase) {
Command2MC.registerCommand(commandBase); ButtonPlugin.getCommand2MC().registerCommand(commandBase);
} }
/** /**

View file

@ -25,29 +25,6 @@ import java.util.stream.Collectors;
* The args may be null if the conversion failed. * The args may be null if the conversion failed.
*/ */
public abstract class Command2 { public abstract class Command2 {
/**
* Default handler for commands, can be used to copy the args too.
*
* @param sender The sender which ran the command
* @param args All of the arguments passed as is
* @return The success of the command
*/
public boolean def(CommandSender sender, @TextArg String args) {
return false;
}
/**
* Convenience method. Return with this.
*
* @param sender The sender of the command
* @param message The message to send to the sender
* @return Always true so that the usage isn't shown
*/
protected boolean respond(CommandSender sender, String message) {
sender.sendMessage(message);
return true;
}
/** /**
* TODO: @CommandClass(helpText=...) * TODO: @CommandClass(helpText=...)
* Parameters annotated with this receive all of the remaining arguments * Parameters annotated with this receive all of the remaining arguments
@ -70,16 +47,11 @@ public abstract class Command2 {
} }
@RequiredArgsConstructor @RequiredArgsConstructor
protected static class SubcommandData<T extends Command2> { 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[] helpText; public final String[] helpText;
} }
public Command2() {
path = getcmdpath();
}
/** /**
* Adds a param converter that obtains a specific object from a string parameter. * Adds a param converter that obtains a specific object from a string parameter.
* The converter may return null. * The converter may return null.
@ -88,11 +60,15 @@ public abstract class Command2 {
* @param converter The converter to use * @param converter The converter to use
* @param <T> The type of the result * @param <T> The type of the result
*/ */
protected static <T> void addParamConverter(Class<T> cl, Function<String, T> converter, HashMap<Class<?>, Function<String, ?>> map) { public abstract <T> void addParamConverter(Class<T> cl, Function<String, T> converter);
protected <T> void addParamConverter(Class<T> cl, Function<String, T> converter, HashMap<Class<?>, Function<String, ?>> map) {
map.put(cl, converter); map.put(cl, converter);
} }
protected static <T extends Command2> boolean handleCommand(CommandSender sender, String commandline, public abstract boolean handleCommand(CommandSender sender, String commandLine) throws Exception;
protected <T extends ICommand2> boolean handleCommand(CommandSender sender, String commandline,
HashMap<String, SubcommandData<T>> subcommands, HashMap<Class<?>, Function<String, ?>> paramConverters) throws Exception { HashMap<String, SubcommandData<T>> subcommands, HashMap<Class<?>, Function<String, ?>> paramConverters) throws Exception {
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();
@ -147,7 +123,9 @@ public abstract class Command2 {
return false; //Didn't handle return false; //Didn't handle
} //TODO: Add to the help } //TODO: Add to the help
protected static <T extends Command2> void registerCommand(T command, HashMap<String, SubcommandData<T>> subcommands, char commandChar) { public abstract void registerCommand(ICommand2 command);
protected <T extends ICommand2> void registerCommand(T command, HashMap<String, SubcommandData<T>> subcommands, char commandChar) {
val path = command.getCommandPath(); val path = command.getCommandPath();
try { //Register the default handler first so it can be reliably overwritten try { //Register the default handler first so it can be reliably overwritten
val method = command.getClass().getMethod("def", CommandSender.class, String.class); val method = command.getClass().getMethod("def", CommandSender.class, String.class);
@ -200,28 +178,5 @@ public abstract class Command2 {
return ht; return ht;
} }
private final String path; public abstract boolean hasPermission(CommandSender sender, ICommand2 command);
/**
* The command's path, or name if top-level command.<br>
* For example:<br>
* "u admin updateplugin" or "u" for the top level one<br>
* <u>The path must be lowercase!</u><br>
*
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) - Change via the {@link CommandClass} annotation
*/
public final String getCommandPath() {
return path;
}
private String getcmdpath() {
if (!getClass().isAnnotationPresent(CommandClass.class))
throw new RuntimeException(
"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;
return path;
}
} //TODO: Test support of Player instead of CommandSender } //TODO: Test support of Player instead of CommandSender

View file

@ -7,18 +7,18 @@ import java.util.function.Function;
public class Command2MC extends Command2 { public class Command2MC extends Command2 {
private static HashMap<String, SubcommandData<Command2MC>> subcommands = new HashMap<>(); private HashMap<String, SubcommandData<ICommand2>> subcommands = new HashMap<>();
private static HashMap<Class<?>, Function<String, ?>> paramConverters = new HashMap<>(); private HashMap<Class<?>, Function<String, ?>> paramConverters = new HashMap<>();
public static boolean handleCommand(CommandSender sender, String commandLine) throws Exception { public boolean handleCommand(CommandSender sender, String commandLine) throws Exception {
return handleCommand(sender, commandLine, subcommands, paramConverters); return handleCommand(sender, commandLine, subcommands, paramConverters);
} }
public static void registerCommand(Command2MC command) { public void registerCommand(ICommand2 command) {
registerCommand(command, subcommands, '/'); registerCommand(command, subcommands, '/');
} }
public static <T> void addParamConverter(Class<T> cl, Function<String, T> converter) { public <T> void addParamConverter(Class<T> cl, Function<String, T> converter) {
addParamConverter(cl, converter, paramConverters); addParamConverter(cl, converter, paramConverters);
} }
} }

View file

@ -0,0 +1,63 @@
package buttondevteam.lib.chat;
import lombok.Getter;
import org.bukkit.command.CommandSender;
import java.util.function.Function;
public abstract class ICommand2 {
/**
* Default handler for commands, can be used to copy the args too.
*
* @param sender The sender which ran the command
* @param args All of the arguments passed as is
* @return The success of the command
*/
public boolean def(CommandSender sender, @Command2.TextArg String args) {
return false;
}
/**
* Convenience method. Return with this.
*
* @param sender The sender of the command
* @param message The message to send to the sender
* @return Always true so that the usage isn't shown
*/
protected boolean respond(CommandSender sender, String message) {
sender.sendMessage(message);
return true;
}
private final String path;
@Getter
private final Command2 manager;
public ICommand2(Command2 manager) {
path = getcmdpath();
this.manager = manager;
}
/**
* The command's path, or name if top-level command.<br>
* For example:<br>
* "u admin updateplugin" or "u" for the top level one<br>
* <u>The path must be lowercase!</u><br>
*
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) - Change via the {@link CommandClass} annotation
*/
public final String getCommandPath() {
return path;
}
private String getcmdpath() {
if (!getClass().isAnnotationPresent(CommandClass.class))
throw new RuntimeException(
"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;
return path;
}
}

View file

@ -0,0 +1,9 @@
package buttondevteam.lib.chat;
import buttondevteam.lib.architecture.ButtonPlugin;
public class ICommand2MC extends ICommand2 {
public ICommand2MC() {
super(ButtonPlugin.getCommand2MC());
}
}