Started working on command system
Added a bunch of TODOs ThorpeCore
This commit is contained in:
parent
2beb6662ea
commit
5b75c2fa02
4 changed files with 107 additions and 9 deletions
|
@ -48,10 +48,10 @@ public class ComponentCommand extends TBMCCommandBase {
|
||||||
|
|
||||||
private Optional<Component> getComponentOrError(String arg, CommandSender sender) {
|
private Optional<Component> getComponentOrError(String arg, CommandSender sender) {
|
||||||
val oc = Component.getComponents().values().stream().filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
|
val oc = Component.getComponents().values().stream().filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny();
|
||||||
if (!oc.isPresent())
|
if (!oc.isPresent()) //TODO: There may be multiple components with the same name
|
||||||
sender.sendMessage("§cComponent not found!");
|
sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system
|
||||||
return oc;
|
return oc; //TODO: Offer overload options with clickable link (with all the plugins it found)
|
||||||
}
|
} //TODO: Tabcompletion for the new command system
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] GetHelpText(String alias) {
|
public String[] GetHelpText(String alias) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.util.HashMap;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Members of this interface should be protected (access level)
|
* A config system
|
||||||
*/
|
*/
|
||||||
public final class IHaveConfig {
|
public final class IHaveConfig {
|
||||||
private final HashMap<String, ConfigData<?>> datamap = new HashMap<>();
|
private final HashMap<String, ConfigData<?>> datamap = new HashMap<>();
|
||||||
|
@ -15,7 +15,7 @@ public final class IHaveConfig {
|
||||||
private ConfigurationSection config;
|
private ConfigurationSection config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* May be used in testing
|
* May be used in testing.
|
||||||
*
|
*
|
||||||
* @param section May be null for testing
|
* @param section May be null for testing
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,12 +1,22 @@
|
||||||
package buttondevteam.lib.chat;
|
package buttondevteam.lib.chat;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.val;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
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.
|
||||||
|
*/
|
||||||
public abstract class Command2 {
|
public abstract class Command2 {
|
||||||
/**
|
/**
|
||||||
* Default handler for commands, can be used to copy the args too.
|
* Default handler for commands, can be used to copy the args too.
|
||||||
|
@ -14,7 +24,7 @@ public abstract class Command2 {
|
||||||
* @param sender The sender which ran the command
|
* @param sender The sender which ran the command
|
||||||
* @param command The (sub)command ran by the user
|
* @param command The (sub)command ran by the user
|
||||||
* @param args All of the arguments passed as is
|
* @param args All of the arguments passed as is
|
||||||
* @return
|
* @return The success of the command
|
||||||
*/
|
*/
|
||||||
public boolean def(CommandSender sender, String command, @TextArg String args) {
|
public boolean def(CommandSender sender, String command, @TextArg String args) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -28,4 +38,92 @@ public abstract class Command2 {
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface TextArg {
|
public @interface TextArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods annotated with this will be recognised as subcommands
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Subcommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
private static class SubcommandData {
|
||||||
|
public final Method method;
|
||||||
|
public final Command2 command;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashMap<String, SubcommandData> subcommands = new HashMap<>();
|
||||||
|
private static HashMap<Class<?>, Function<String, ?>> paramConverters = new HashMap<>();
|
||||||
|
|
||||||
|
public Command2() {
|
||||||
|
for (val method : getClass().getMethods())
|
||||||
|
if (method.isAnnotationPresent(Subcommand.class))
|
||||||
|
subcommands.put(method.getName().replace('_', ' '), new SubcommandData(method, this));
|
||||||
|
path = getcmdpath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a param converter that obtains a specific object from a string parameter.
|
||||||
|
* The converter may return null.
|
||||||
|
*
|
||||||
|
* @param cl The class of the result object
|
||||||
|
* @param converter The converter to use
|
||||||
|
* @param <T> The type of the result
|
||||||
|
*/
|
||||||
|
public static <T> void addParamConverter(Class<T> cl, Function<String, T> converter) {
|
||||||
|
paramConverters.put(cl, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean handleCommand(CommandSender sender, String commandline) throws Exception {
|
||||||
|
for (int i = commandline.lastIndexOf(' '); i != -1; i = commandline.lastIndexOf(' ', i - 1)) {
|
||||||
|
String subcommand = commandline.substring(0, i);
|
||||||
|
SubcommandData sd = subcommands.get(subcommand); //O(1)
|
||||||
|
if (sd == null) continue; //TODO: This will run each time someone runs any command
|
||||||
|
val params = new ArrayList<Object>(sd.method.getParameterCount());
|
||||||
|
int j = 0, pj;
|
||||||
|
for (val cl : sd.method.getParameterTypes()) {
|
||||||
|
pj = j + 1;
|
||||||
|
j = commandline.indexOf(' ', j + 1);
|
||||||
|
String param = subcommand.substring(pj, j);
|
||||||
|
if (cl == String.class) {
|
||||||
|
params.add(param);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
val conv = paramConverters.get(cl);
|
||||||
|
if (conv == null)
|
||||||
|
throw new Exception("No suitable converter found for parameter type '" + cl.getCanonicalName() + "' for command '" + sd.method.toString() + "'");
|
||||||
|
params.add(conv.apply(param));
|
||||||
|
}
|
||||||
|
sd.method.invoke(sd.command, params);
|
||||||
|
return true; //We found a method
|
||||||
|
}
|
||||||
|
return false; //Didn't handle
|
||||||
|
} //TODO: Use preprocess event and add to the help
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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>
|
||||||
|
* <b>Abstract classes with no {@link CommandClass} annotations will be ignored.</b>
|
||||||
|
*
|
||||||
|
* @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: Support Player instead of CommandSender
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name: ButtonCore
|
name: ThorpeCore
|
||||||
main: buttondevteam.core.MainPlugin
|
main: buttondevteam.core.MainPlugin
|
||||||
version: 1.0
|
version: 1.0
|
||||||
author: TBMCPlugins
|
author: TBMCPlugins
|
||||||
|
|
Loading…
Reference in a new issue