From e617b0f87a031ba26f723a7f64a6951a8666863e Mon Sep 17 00:00:00 2001 From: Paldiu Date: Fri, 16 Apr 2021 00:51:18 -0500 Subject: [PATCH] Update Command System --- .../simplexcore/SimplexCorePlugin.java | 2 +- .../simplexcore/command/CommandLoader.java | 95 ++++++++++--------- .../command/CommandLoaderException.java | 19 ++++ .../simplexcore/command/SimplexCommand.java | 19 +++- .../command/defaults/Command_info.java | 9 +- .../command/defaults/DefaultCommand.java | 5 + 6 files changed, 100 insertions(+), 49 deletions(-) create mode 100644 src/main/java/io/github/simplexdev/simplexcore/command/CommandLoaderException.java diff --git a/src/main/java/io/github/simplexdev/simplexcore/SimplexCorePlugin.java b/src/main/java/io/github/simplexdev/simplexcore/SimplexCorePlugin.java index 86178bf..a408707 100644 --- a/src/main/java/io/github/simplexdev/simplexcore/SimplexCorePlugin.java +++ b/src/main/java/io/github/simplexdev/simplexcore/SimplexCorePlugin.java @@ -42,7 +42,7 @@ public final class SimplexCorePlugin extends SimplexModule { public void start() { try { getRegistry().register(this); - getCommandLoader().classpath(Command_info.class).load(this); + getCommandLoader().classpath(this, Command_info.class).load(); getYamlConfig().reload(); getInternals().reload(); // diff --git a/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoader.java b/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoader.java index fa9eef3..cb83f5b 100644 --- a/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoader.java +++ b/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoader.java @@ -1,12 +1,13 @@ package io.github.simplexdev.simplexcore.command; import io.github.simplexdev.api.annotations.CommandInfo; -import io.github.simplexdev.simplexcore.command.defaults.DefaultCommand; +import io.github.simplexdev.simplexcore.SimplexCorePlugin; import io.github.simplexdev.simplexcore.module.SimplexModule; import io.github.simplexdev.simplexcore.utils.ReflectionTools; -import io.github.simplexdev.simplexcore.SimplexCorePlugin; -import org.bukkit.Bukkit; -import org.bukkit.command.*; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandMap; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.TabCompleter; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.SimplePluginManager; import org.jetbrains.annotations.NotNull; @@ -20,7 +21,10 @@ import java.util.MissingResourceException; public final class CommandLoader { private Reflections reflections; + private ClassLoader classLoader; + private SimplexModule plugin; private static final CommandLoader instance = new CommandLoader(); + private final Registry registry = new Registry(); /** * @return A Singleton Pattern instance of this class. @@ -38,15 +42,15 @@ public final class CommandLoader { * If the class provided does not have the {@link CommandInfo} annotation, the loader will throw a new * {@link MissingResourceException} and will not load your plugin's commands. * If the class provided does not extend {@link SimplexCommand}, the loader will throw a new - * {@link RuntimeException} and your commands will not be loaded. + * {@link CommandLoaderException} and your commands will not be loaded. *

* * @param clazz The command class to load from * @return An instance of this where the classpath has been prepared for loading the commands. */ - public CommandLoader classpath(Class clazz) { + public CommandLoader classpath(SimplexModule plugin, Class clazz) { if (clazz == null) { - throw new IllegalStateException("The class provided cannot be found!"); + throw new IllegalArgumentException("The class provided cannot be found!"); } if (!clazz.isAnnotationPresent(CommandInfo.class)) { @@ -54,22 +58,26 @@ public final class CommandLoader { } if (!SimplexCommand.class.isAssignableFrom(clazz)) { - throw new RuntimeException("Your command must extend SimplexCommand.class for it to be used as the reference point for loading commands."); + throw new CommandLoaderException("Your command must extend SimplexCommand.class for it to be used as the reference point for loading commands."); } - reflections = ReflectionTools.reflect(clazz); + this.reflections = ReflectionTools.reflect(clazz); + this.plugin = plugin; + this.classLoader = plugin.getClass().getClassLoader(); return this; } /** * Loads all the commands from the specified classpath. - * This should be used immediately after {@link CommandLoader#classpath(Class)} has been called. + * This should be used immediately after {@link CommandLoader#classpath(SimplexModule, Class)} has been called. * If used before, an exception will be thrown, and your commands will not be loaded. - * - * @param plugin An instance of your plugin to assign as the parent plugin for each command. */ - public void load(SimplexModule plugin) { + public void load() { + if (reflections == null || plugin == null || classLoader == null) { + throw new CommandLoaderException("Please run CommandLoader#classpath(SimplexModule, Class) first!"); + } + reflections.getTypesAnnotatedWith(CommandInfo.class).forEach(annotated -> { CommandInfo info = annotated.getDeclaredAnnotation(CommandInfo.class); @@ -89,7 +97,7 @@ public final class CommandLoader { return; } - PluginCommand command = Registry.create(plugin, info.name().toLowerCase()); + PluginCommand command = registry.create(plugin, info.name().toLowerCase()); command.setAliases(Arrays.asList(info.aliases().split(","))); command.setDescription(info.description()); command.setExecutor(getExecutorFromName(info.name())); @@ -98,7 +106,7 @@ public final class CommandLoader { command.setPermissionMessage(info.permissionMessage()); command.setTabCompleter(getTabFromName(info.name())); command.setUsage(info.usage()); - Registry.registerCommand(command); + registry.registerCommand(command); }); } @@ -110,28 +118,27 @@ public final class CommandLoader { * @param name The name of the command. * @return An instance of the command class as a CommandExecutor. */ - public CommandExecutor getExecutorFromName(String name) { - for (Class obj : reflections.getSubTypesOf(CommandExecutor.class)) { + private CommandExecutor getExecutorFromName(String name) { + for (Class obj : reflections.getSubTypesOf(SimplexCommand.class)) { if (!obj.isAnnotationPresent(CommandInfo.class)) { - SimplexCorePlugin.getInstance() - .getLogger().warning(obj.getSimpleName() + plugin.getLogger().warning(obj.getSimpleName() + " is missing a required annotation: " + CommandInfo.class.getSimpleName()); + continue; } CommandInfo info = obj.getDeclaredAnnotation(CommandInfo.class); if (name.equalsIgnoreCase(info.name())) { - try { - Constructor constr = obj.getDeclaredConstructor(); - constr.setAccessible(true); - return constr.newInstance(); - } catch (ReflectiveOperationException ignored) { - return new DefaultCommand(); + Constructor constr = + ReflectionTools.getDeclaredConstructor(obj, SimplexModule.class); + if (constr == null) { + throw new CommandLoaderException("Constructor does not exist! Are you extending SimplexCommand properly?"); } + return ReflectionTools.initConstructor(constr, plugin); } } - throw new RuntimeException("Unable to assign a CommandExecutor from the provided classes!"); + throw new CommandLoaderException("Unable to assign a CommandExecutor from the provided classes!"); } /** @@ -143,52 +150,50 @@ public final class CommandLoader { * @return The command as an instance of TabCompleter */ @Nullable - public TabCompleter getTabFromName(String name) { - for (Class obj : reflections.getSubTypesOf(TabCompleter.class)) { + private TabCompleter getTabFromName(String name) { + for (Class obj : reflections.getSubTypesOf(SimplexCommand.class)) { if (!obj.isAnnotationPresent(CommandInfo.class)) { - SimplexCorePlugin.getInstance() - .getLogger().warning(obj.getSimpleName() + plugin.getLogger().warning(obj.getSimpleName() + " is missing required annotation: " + CommandInfo.class.getSimpleName()); continue; } CommandInfo info = obj.getDeclaredAnnotation(CommandInfo.class); + if (name.equalsIgnoreCase(info.name())) { - try { - Constructor constr = obj.getDeclaredConstructor(); - constr.setAccessible(true); - return constr.newInstance(); - } catch (ReflectiveOperationException ignored) { - return new DefaultCommand(); + Constructor constr = ReflectionTools.getDeclaredConstructor(obj, SimplexModule.class); + if (constr == null) { + throw new CommandLoaderException("Constructor does not exist! Are you extending SimplexCommand properly?"); } + return ReflectionTools.initConstructor(constr, plugin); } } - return null; + throw new CommandLoaderException("Unable to assign a TabCompleter from the provided classes!"); } /** * Registry class, which forces all necessary fields to accessible. */ - private static class Registry { - private static final Constructor constructor; - private static final Field cmdMapField; + private final class Registry { + private final Constructor constructor; + private final Field cmdMapField; - static { + public Registry() { constructor = ReflectionTools.getDeclaredConstructor(PluginCommand.class, String.class, Plugin.class); cmdMapField = ReflectionTools.getDeclaredField(SimplePluginManager.class, "commandMap"); } - public static PluginCommand create(@NotNull Plugin plugin, @NotNull String name) { + public PluginCommand create(@NotNull SimplexModule plugin, @NotNull String name) { return ReflectionTools.initConstructor(constructor, name, plugin); } - public static void registerCommand(PluginCommand command) { + public void registerCommand(PluginCommand command) { try { - CommandMap map = (CommandMap) cmdMapField.get(Bukkit.getPluginManager()); + CommandMap map = (CommandMap) cmdMapField.get(plugin.getManager()); map.register(command.getName().toLowerCase(), command); } catch (IllegalAccessException e) { - throw new RuntimeException(e); + throw new CommandLoaderException(e); } } } diff --git a/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoaderException.java b/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoaderException.java new file mode 100644 index 0000000..1965484 --- /dev/null +++ b/src/main/java/io/github/simplexdev/simplexcore/command/CommandLoaderException.java @@ -0,0 +1,19 @@ +package io.github.simplexdev.simplexcore.command; + +import org.apache.commons.lang.exception.ExceptionUtils; + +public class CommandLoaderException extends RuntimeException { + public CommandLoaderException() { + super("The Command Loader has encountered an exception and has failed to execute properly. " + + "Some commands may not be loaded."); + ExceptionUtils.getMessage(super.getCause()); + } + + public CommandLoaderException(String msg) { + super(msg); + } + + public CommandLoaderException(Throwable th) { + super(th); + } +} diff --git a/src/main/java/io/github/simplexdev/simplexcore/command/SimplexCommand.java b/src/main/java/io/github/simplexdev/simplexcore/command/SimplexCommand.java index 07f1c27..140d8d0 100644 --- a/src/main/java/io/github/simplexdev/simplexcore/command/SimplexCommand.java +++ b/src/main/java/io/github/simplexdev/simplexcore/command/SimplexCommand.java @@ -1,6 +1,7 @@ package io.github.simplexdev.simplexcore.command; import io.github.simplexdev.simplexcore.SimplexCorePlugin; +import io.github.simplexdev.simplexcore.module.SimplexModule; import io.github.simplexdev.simplexcore.utils.Utilities; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -15,6 +16,15 @@ import java.util.List; import java.util.UUID; public abstract class SimplexCommand implements CommandExecutor, TabCompleter { + private final SimplexModule plugin; + + public SimplexCommand(SimplexModule plugin) { + this.plugin = plugin; + } + + public final SimplexModule getPlugin() { + return plugin; + } public boolean isPlayer(CommandSender sender) { return sender instanceof Player; @@ -22,6 +32,7 @@ public abstract class SimplexCommand implements CommandExecutor, TabCompleter { /** * Gets an online player from their username + * * @param name The player's username * @return An instance of {@link Player} which represents the online player in question. */ @@ -32,6 +43,7 @@ public abstract class SimplexCommand implements CommandExecutor, TabCompleter { /** * Gets an online player from their {@link UUID}. + * * @param uuid The player's UUID * @return An instance of {@link Player} which represents the online player in question. */ @@ -43,6 +55,7 @@ public abstract class SimplexCommand implements CommandExecutor, TabCompleter { /** * Gets an instance of {@link Player} based off an instance of {@link CommandSender}. * This will be null if the condition {CommandSender instanceof Player} is false. + * * @param sender The CommandSender to cast * @return An instance of Player relating to CommandSender. */ @@ -54,7 +67,8 @@ public abstract class SimplexCommand implements CommandExecutor, TabCompleter { /** * Send a message or a group of messages to a {@link Player}. * If you want the messages to send on new lines, put \n at the end of each message to send. - * @param player The Player to send a message to + * + * @param player The Player to send a message to * @param messages The messages to send. */ public void playerMsg(Player player, String... messages) { @@ -66,7 +80,8 @@ public abstract class SimplexCommand implements CommandExecutor, TabCompleter { /** * Send a message or a group of messages to a {@link CommandSender} * If you want the messages to send on new lines, put \n at the end of each message to send. - * @param sender The CommandSender to send a message to. + * + * @param sender The CommandSender to send a message to. * @param messages The messages to send. */ public void msg(CommandSender sender, String... messages) { diff --git a/src/main/java/io/github/simplexdev/simplexcore/command/defaults/Command_info.java b/src/main/java/io/github/simplexdev/simplexcore/command/defaults/Command_info.java index 7ddd0e9..b9de62e 100644 --- a/src/main/java/io/github/simplexdev/simplexcore/command/defaults/Command_info.java +++ b/src/main/java/io/github/simplexdev/simplexcore/command/defaults/Command_info.java @@ -1,16 +1,23 @@ package io.github.simplexdev.simplexcore.command.defaults; import io.github.simplexdev.api.annotations.CommandInfo; +import io.github.simplexdev.simplexcore.chat.Messages; import io.github.simplexdev.simplexcore.command.SimplexCommand; +import io.github.simplexdev.simplexcore.module.SimplexModule; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @CommandInfo(name = "Info", description = "Gets info on this API / Library.", usage = "/", permission = "simplex.core.info") public class Command_info extends SimplexCommand { + + public Command_info(SimplexModule plugin) { + super(plugin); + } + @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - sender.sendMessage("This is an API!"); + sender.sendMessage(Messages.DISCORD.getMessage()); return true; } } diff --git a/src/main/java/io/github/simplexdev/simplexcore/command/defaults/DefaultCommand.java b/src/main/java/io/github/simplexdev/simplexcore/command/defaults/DefaultCommand.java index 6d09d8a..7443e01 100644 --- a/src/main/java/io/github/simplexdev/simplexcore/command/defaults/DefaultCommand.java +++ b/src/main/java/io/github/simplexdev/simplexcore/command/defaults/DefaultCommand.java @@ -2,12 +2,17 @@ package io.github.simplexdev.simplexcore.command.defaults; import io.github.simplexdev.api.annotations.CommandInfo; import io.github.simplexdev.simplexcore.command.SimplexCommand; +import io.github.simplexdev.simplexcore.module.SimplexModule; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @CommandInfo(name = "default", usage = "/", description = "Default plugin command.") public final class DefaultCommand extends SimplexCommand { + public DefaultCommand(SimplexModule plugin) { + super(plugin); + } + @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { sender.sendMessage("If you are seeing this when running your command, your command didn't register properly.");