From 5b75c2fa0291d04e8146572e4e47f6e165fa28b6 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 27 Jan 2019 01:10:10 +0100 Subject: [PATCH 1/6] Started working on command system Added a bunch of TODOs ThorpeCore --- .../buttondevteam/core/ComponentCommand.java | 8 +- .../lib/architecture/IHaveConfig.java | 4 +- .../java/buttondevteam/lib/chat/Command2.java | 102 +++++++++++++++++- ButtonCore/src/main/resources/plugin.yml | 2 +- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index a90337a..e8f2f91 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -48,10 +48,10 @@ public class ComponentCommand extends TBMCCommandBase { private Optional getComponentOrError(String arg, CommandSender sender) { val oc = Component.getComponents().values().stream().filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny(); - if (!oc.isPresent()) - sender.sendMessage("§cComponent not found!"); - return oc; - } + if (!oc.isPresent()) //TODO: There may be multiple components with the same name + sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system + return oc; //TODO: Offer overload options with clickable link (with all the plugins it found) + } //TODO: Tabcompletion for the new command system @Override public String[] GetHelpText(String alias) { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java index e2ddee2..2271d56 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java @@ -7,7 +7,7 @@ import java.util.HashMap; import java.util.function.Function; /** - * Members of this interface should be protected (access level) + * A config system */ public final class IHaveConfig { private final HashMap> datamap = new HashMap<>(); @@ -15,7 +15,7 @@ public final class IHaveConfig { private ConfigurationSection config; /** - * May be used in testing + * May be used in testing. * * @param section May be null for testing */ diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index af9052c..756dd25 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -1,12 +1,22 @@ package buttondevteam.lib.chat; +import lombok.RequiredArgsConstructor; +import lombok.val; import org.bukkit.command.CommandSender; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; 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 { /** * 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 command The (sub)command ran by the user * @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) { return false; @@ -28,4 +38,92 @@ public abstract class Command2 { @Retention(RetentionPolicy.RUNTIME) 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 subcommands = new HashMap<>(); + private static HashMap, Function> 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 The type of the result + */ + public static void addParamConverter(Class cl, Function 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(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.
+ * For example:
+ * "u admin updateplugin" or "u" for the top level one
+ * The path must be lowercase!
+ * Abstract classes with no {@link CommandClass} annotations will be ignored. + * + * @return The command path, which is the command class name by default (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, 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 diff --git a/ButtonCore/src/main/resources/plugin.yml b/ButtonCore/src/main/resources/plugin.yml index fb36458..f29bf69 100755 --- a/ButtonCore/src/main/resources/plugin.yml +++ b/ButtonCore/src/main/resources/plugin.yml @@ -1,4 +1,4 @@ -name: ButtonCore +name: ThorpeCore main: buttondevteam.core.MainPlugin version: 1.0 author: TBMCPlugins From a6effaaf43aa89788628c10348f858db364ec66f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 27 Jan 2019 22:30:23 +0100 Subject: [PATCH 2/6] Command system, /component impr. Added even more TODOs Created command preprocess event The new command system works The /component command now uses the new command system --- .../buttondevteam/core/ComponentCommand.java | 71 +++++++++-------- .../java/buttondevteam/core/MainPlugin.java | 3 +- .../buttondevteam/core/PlayerListener.java | 37 +++++++++ .../lib/TBMCCommandPreprocessEvent.java | 39 +++++++++ .../lib/architecture/Component.java | 11 +++ .../java/buttondevteam/lib/chat/Command2.java | 79 +++++++++++++++---- .../buttondevteam/lib/chat/TBMCChatAPI.java | 2 +- ButtonCore/src/main/resources/plugin.yml | 1 + 8 files changed, 194 insertions(+), 49 deletions(-) create mode 100755 ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index e8f2f91..4b090fc 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -2,59 +2,66 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.TBMCCommandBase; import lombok.val; +import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; import java.util.Optional; @CommandClass(modOnly = true) -public class ComponentCommand extends TBMCCommandBase { - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - if (args.length < 1) - return false; - boolean enable = true; +public class ComponentCommand extends Command2 { + public ComponentCommand() { + addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); + + } + + @Subcommand + public boolean enable(CommandSender sender, Plugin plugin, String component) { + if (plugin == null) return respond(sender, "§cPlugin not found!"); + plugin.reloadConfig(); //Reload config so the new config values are read - All changes are saved to disk on disable + return enable_disable(sender, plugin, component, true); + } + + @Subcommand + public boolean disable(CommandSender sender, Plugin plugin, String component) { + if (plugin == null) return respond(sender, "§cPlugin not found!"); + return enable_disable(sender, plugin, component, false); + } + + @Subcommand + public boolean list(CommandSender sender, String plugin) { + sender.sendMessage("§6List of components:"); + Component.getComponents().values().stream().filter(c -> plugin == null || c.getPlugin().getName().equalsIgnoreCase(plugin)) //If plugin is null, don't check + .map(c -> c.getPlugin().getName() + " - " + c.getClass().getSimpleName() + " - " + (c.isEnabled() ? "en" : "dis") + "abled").forEach(sender::sendMessage); + return true; + } + + private boolean enable_disable(CommandSender sender, Plugin plugin, String component, boolean enable) { try { - switch (args[0]) { - case "enable": - enable = true; - break; - case "disable": - enable = false; - break; - case "list": - sender.sendMessage("§6List of components:"); - Component.getComponents().values().stream().map(c -> c.getPlugin().getName() + " - " + c.getClass().getSimpleName() + " - " + (c.isEnabled() ? "en" : "dis") + "abled").forEach(sender::sendMessage); - return true; - default: - return false; - } - if (args.length < 2) - return false; - val oc = getComponentOrError(args[1], sender); + val oc = getComponentOrError(plugin, component, sender); if (!oc.isPresent()) return true; - if (enable) //Reload config so the new config values are read - getPlugin().reloadConfig(); //All changes are saved to disk on disable Component.setComponentEnabled(oc.get(), enable); sender.sendMessage(oc.get().getClass().getSimpleName() + " " + (enable ? "en" : "dis") + "abled."); } catch (Exception e) { - TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + args[0] + "!", e); + TBMCCoreAPI.SendException("Couldn't " + (enable ? "en" : "dis") + "able component " + component + "!", e); } return true; } - private Optional getComponentOrError(String arg, CommandSender sender) { - val oc = Component.getComponents().values().stream().filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny(); - if (!oc.isPresent()) //TODO: There may be multiple components with the same name + private Optional getComponentOrError(Plugin plugin, String arg, CommandSender sender) { + val oc = Component.getComponents().values().stream() + .filter(c -> plugin.getName().equals(c.getPlugin().getName())) + .filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny(); + if (!oc.isPresent()) sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system return oc; //TODO: Offer overload options with clickable link (with all the plugins it found) } //TODO: Tabcompletion for the new command system - @Override - public String[] GetHelpText(String alias) { + public String[] GetHelpText(String alias) { //TODO return new String[]{ "§6---- Component command ----", "Enable or disable or list components" diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index f18cedd..c92a3c9 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -14,6 +14,7 @@ import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.Color; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; @@ -68,7 +69,7 @@ public class MainPlugin extends ButtonPlugin { Component.registerComponent(this, new MemberComponent()); Component.registerComponent(this, new TownyComponent()); ComponentManager.enableComponents(); - TBMCChatAPI.AddCommand(this, ComponentCommand.class); + Command2.registerCommand(new ComponentCommand()); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender ? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks diff --git a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java index 3c3907f..91448ba 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java +++ b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java @@ -1,13 +1,21 @@ package buttondevteam.core; +import buttondevteam.lib.TBMCCommandPreprocessEvent; +import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.player.TBMCPlayerBase; +import lombok.val; import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.server.ServerCommandEvent; import java.util.Arrays; @@ -32,4 +40,33 @@ public class PlayerListener implements Listener { Bukkit.getOnlinePlayers().stream().filter(event::shouldSendTo) .forEach(p -> p.sendMessage(event.getChannel().DisplayName().get().substring(0, 2) + event.getMessage())); } + + @EventHandler + public void onPlayerChatPreprocess(PlayerCommandPreprocessEvent event) { + handlePreprocess(event.getPlayer(), event.getMessage(), event); + } + + @EventHandler + public void onSystemChatPreprocess(ServerCommandEvent event) { + handlePreprocess(event.getSender(), "/" + event.getCommand(), event); + if (event.isCancelled()) event.setCommand("dontrunthiscmd"); //Bugfix + } + + private void handlePreprocess(CommandSender sender, String message, Cancellable event) { + if (event.isCancelled()) return; + val ev = new TBMCCommandPreprocessEvent(sender, message); + Bukkit.getPluginManager().callEvent(ev); + if (ev.isCancelled()) + event.setCancelled(true); //Cancel the original event + } + + @EventHandler + public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) { + if (event.isCancelled()) return; + try { + event.setCancelled(Command2.handleCommand(event.getSender(), event.getMessage())); + } catch (Exception e) { + TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e); + } + } } \ No newline at end of file diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java new file mode 100755 index 0000000..a72c0b7 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java @@ -0,0 +1,39 @@ +package buttondevteam.lib; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.command.CommandSender; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +/** + * Can be used to change or handle commands before they're sent. + * Called on using player, console and Discord commands. + * + * @author NorbiPeti + */ +@Getter +public class TBMCCommandPreprocessEvent extends Event implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + + private final CommandSender sender; + @Setter + private String message; + @Setter + private boolean cancelled; + + public TBMCCommandPreprocessEvent(CommandSender sender, String message) { + this.sender = sender; + this.message = message; //TODO: Actually call from Discord as well + } + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 02b58e7..634f23a 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -3,6 +3,7 @@ package buttondevteam.lib.architecture; import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; @@ -183,6 +184,16 @@ public abstract class Component { */ protected abstract void disable(); + /** + * Registers a TBMCCommand to the component. Make sure to use {@link buttondevteam.lib.chat.CommandClass} and {@link buttondevteam.lib.chat.Command2.Subcommand}. + * You don't need to register the command in plugin.yml. + * + * @param commandBase Custom coded command class + */ + protected final void registerCommand(Command2 commandBase) { + Command2.registerCommand(commandBase); + } + /** * Registers a TBMCCommand to the component. Make sure to add it to plugin.yml and use {@link buttondevteam.lib.chat.CommandClass}. * diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 756dd25..014b512 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -1,5 +1,6 @@ package buttondevteam.lib.chat; +import buttondevteam.lib.player.ChromaGamerBase; import lombok.RequiredArgsConstructor; import lombok.val; import org.bukkit.command.CommandSender; @@ -22,14 +23,26 @@ 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 command The (sub)command ran by the user * @param args All of the arguments passed as is * @return The success of the command */ - public boolean def(CommandSender sender, String command, @TextArg String args) { + @Subcommand + 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=...) * Parameters annotated with this receive all of the remaining arguments @@ -57,9 +70,6 @@ public abstract class Command2 { private static HashMap, Function> 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(); } @@ -76,16 +86,41 @@ public abstract class Command2 { } 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); + for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { + String subcommand = commandline.substring(0, i).toLowerCase(); + //System.out.println("Subcommand: "+subcommand); + //System.out.println("Subcmds: "+subcommands.toString()); SubcommandData sd = subcommands.get(subcommand); //O(1) if (sd == null) continue; //TODO: This will run each time someone runs any command + //System.out.println("sd.method: "+sd.method); //TODO: Rename in Maven val params = new ArrayList(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); + int j = subcommand.length(), pj; + Class[] parameterTypes = sd.method.getParameterTypes(); + if (parameterTypes.length == 0) + throw new Exception("No sender parameter for method '" + sd.method + "'"); + val sendertype = parameterTypes[0]; + final ChromaGamerBase cg; + if (sendertype.isAssignableFrom(sender.getClass())) + params.add(sender); //The command either expects a CommandSender or it is a Player, or some other expected type + else if (ChromaGamerBase.class.isAssignableFrom(sendertype) + && (cg = ChromaGamerBase.getFromSender(sender)) != null + && cg.getClass() == sendertype) //The command expects a user of our system + params.add(cg); + else { + sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command."); + return true; + } + for (int i1 = 1; i1 < parameterTypes.length; i1++) { + Class cl = parameterTypes[i1]; + pj = j + 1; //Start index + if (pj == commandline.length() + 1) { //No param given + params.add(null); + continue; //Fill the remaining params with nulls + } + j = commandline.indexOf(' ', j + 1); //End index + if (j == -1) //Last parameter + j = commandline.length(); + String param = commandline.substring(pj, j); if (cl == String.class) { params.add(param); continue; @@ -95,11 +130,25 @@ public abstract class Command2 { 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); + //System.out.println("Our params: "+params); + val ret = sd.method.invoke(sd.command, params.toArray()); //I FORGOT TO TURN IT INTO AN ARRAY (for a long time) + if (ret instanceof Boolean) { + if (!(boolean) ret) + sender.sendMessage("Wrong usage."); //TODO: Show help text + } else if (ret != null) + throw new Exception("Wrong return type! Must return a boolean or void. Return value: "+ret); return true; //We found a method } return false; //Didn't handle - } //TODO: Use preprocess event and add to the help + } //TODO: Add to the help + + public static void registerCommand(Command2 command) { + for (val method : command.getClass().getMethods()) + if (method.isAnnotationPresent(Subcommand.class)) + subcommands.put("/" + command.path + //Add command path (class name by default) + (method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()), //Add method name, unless it's 'def' + new SubcommandData(method, command)); //Result of the above (def) is that it will show the help text + } private final String path; @@ -126,4 +175,4 @@ public abstract class Command2 { path = path.length() == 0 ? getFromClass.apply(getClass()) : path; return path; } -} //TODO: Support Player instead of CommandSender +} //TODO: Test support of Player instead of CommandSender diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java index a2da67e..66eac93 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java @@ -160,7 +160,7 @@ public class TBMCChatAPI { } catch (Exception e) { TBMCCoreAPI.SendException("An error occured while registering command " + thecmdclass.getSimpleName(), e); } - } //TODO: onCommand(CommandSender sender, String alias, int arg1, String arg2) (planned for a while) + } /** *

diff --git a/ButtonCore/src/main/resources/plugin.yml b/ButtonCore/src/main/resources/plugin.yml index f29bf69..43c609f 100755 --- a/ButtonCore/src/main/resources/plugin.yml +++ b/ButtonCore/src/main/resources/plugin.yml @@ -15,3 +15,4 @@ commands: description: Add or remove a member component: description: Enable or disable or list components + dontrunthiscmd: \ No newline at end of file From 41d40fa415fc949debaa1d54d36e4ecec7d16324 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 28 Jan 2019 23:09:07 +0100 Subject: [PATCH 3/6] Compman and config API extension Fancy way of saying: I added 3 methods --- .../buttondevteam/core/ComponentManager.java | 12 ++++++ .../lib/architecture/IHaveConfig.java | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java index 0c3c51b..842badb 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java @@ -54,4 +54,16 @@ public final class ComponentManager { val c = Component.getComponents().get(cl); return c != null && c.isEnabled(); } + + /** + * Will also return false if the component is not registered. + * + * @param cl The component class + * @return The component if it's registered and enabled + */ + @SuppressWarnings("unchecked") + public static T getIfEnabled(Class cl) { + val c = Component.getComponents().get(cl); + return c != null && c.isEnabled() ? (T) c : null; + } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java index 2271d56..98fa241 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java @@ -1,10 +1,12 @@ package buttondevteam.lib.architecture; import lombok.Getter; +import lombok.val; import org.bukkit.configuration.ConfigurationSection; import java.util.HashMap; import java.util.function.Function; +import java.util.function.Supplier; /** * A config system @@ -73,4 +75,42 @@ public final class IHaveConfig { datamap.put(path, data = new ConfigData<>(config, path, getter.apply(primitiveDef), primitiveDef, getter, setter)); return (ConfigData) data; } + + /** + * This method overload should only be used with primitves or String. + * + * @param path The path in config to use + * @param def The value to use by default + * @param The type of this variable (only use primitives or String) + * @return The data object that can be used to get or set the value + */ + @SuppressWarnings("unchecked") + public ConfigData getData(String path, Supplier def) { + ConfigData data = datamap.get(path); + if (data == null) { + val defval = def.get(); + datamap.put(path, data = new ConfigData<>(config, path, defval, defval)); + } + return (ConfigData) data; + } + + /** + * This method overload may be used with any class. + * + * @param path The path in config to use + * @param def The value to use by default + * @param getter A function that converts a primitive representation to the correct value + * @param setter A function that converts a value to a primitive representation + * @param The type of this variable (can be any class) + * @return The data object that can be used to get or set the value + */ + @SuppressWarnings("unchecked") + public ConfigData getData(String path, Supplier def, Function getter, Function setter) { + ConfigData data = datamap.get(path); + if (data == null) { + val defval = def.get(); + datamap.put(path, data = new ConfigData<>(config, path, defval, setter.apply(defval), getter, setter)); + } + return (ConfigData) data; + } } From 7331568886883d5227b64d2397587070a1d91488 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 29 Jan 2019 21:39:14 +0100 Subject: [PATCH 4/6] Command, restart, command improvements Fixed default command handler not being overridable in some cases Schrestart now takes seconds as param, not ticks Allowing to change the current timer value in the restart event HelpText support added Automatically generating usage text (ButtonProcessor) --- ...s_ButtonCore_Towny_master_248b0d8d0a_1.xml | 13 - ..._milkbowl_VaultAPI_master_431c5273c2_1.xml | 13 - BuildConfigUpdater/BuildConfigUpdater.iml | 1 + BuildConfigUpdater/src/main/java/BCUMain.java | 2 +- .../buttondevteam/core/ComponentCommand.java | 14 +- .../java/buttondevteam/core/MainPlugin.java | 18 +- .../java/buttondevteam/core/TestPrepare.java | 4 +- .../{ => core}/component/channel/Channel.java | 2 +- .../component/channel/ChannelComponent.java | 2 +- .../channel/ChatChannelRegisterEvent.java | 2 +- .../component/channel/ChatRoom.java | 2 +- .../component/members/MemberCommand.java | 2 +- .../component/members/MemberComponent.java | 2 +- .../component/randomtp/RandomTP.java | 2 +- .../component/randomtp/RandomTPComponent.java | 2 +- .../restart/PrimeRestartCommand.java | 2 +- .../component/restart/RestartComponent.java | 2 +- .../restart/ScheduledRestartCommand.java | 42 +- .../component/towny/TownyComponent.java | 2 +- .../component/updater/PluginUpdater.java | 2 +- .../updater/PluginUpdaterComponent.java | 2 +- .../updater/UpdatePluginCommand.java | 2 +- .../lib/ScheduledServerRestartEvent.java | 16 +- .../java/buttondevteam/lib/TBMCChatEvent.java | 2 +- .../buttondevteam/lib/TBMCChatEventBase.java | 2 +- .../lib/TBMCChatPreprocessEvent.java | 2 +- .../java/buttondevteam/lib/TBMCCoreAPI.java | 374 +++++++++--------- .../lib/TBMCSystemChatEvent.java | 2 +- .../java/buttondevteam/lib/ThorpeUtils.java | 38 ++ .../java/buttondevteam/lib/chat/Command2.java | 70 +++- .../buttondevteam/lib/chat/CommandClass.java | 2 +- .../buttondevteam/lib/chat/TBMCChatAPI.java | 4 +- .../lib/player/ChannelPlayerData.java | 2 +- .../lib/player/ChromaGamerBase.java | 2 +- .../lib/player/TBMCPlayerBase.java | 2 +- ButtonProcessor/ButtonProcessor.iml | 7 + ButtonProcessor/pom.xml | 94 +++-- .../buttonproc/ButtonProcessor.java | 74 +++- 38 files changed, 487 insertions(+), 341 deletions(-) delete mode 100644 .idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml delete mode 100644 .idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/channel/Channel.java (99%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/channel/ChannelComponent.java (89%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/channel/ChatChannelRegisterEvent.java (91%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/channel/ChatRoom.java (95%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/members/MemberCommand.java (97%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/members/MemberComponent.java (96%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/randomtp/RandomTP.java (99%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/randomtp/RandomTPComponent.java (84%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/restart/PrimeRestartCommand.java (96%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/restart/RestartComponent.java (96%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/restart/ScheduledRestartCommand.java (66%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/towny/TownyComponent.java (97%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/updater/PluginUpdater.java (99%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/updater/PluginUpdaterComponent.java (87%) rename ButtonCore/src/main/java/buttondevteam/{ => core}/component/updater/UpdatePluginCommand.java (96%) create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java diff --git a/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml b/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml deleted file mode 100644 index 0d3e00e..0000000 --- a/.idea/libraries/Maven__com_github_TBMCPlugins_ButtonCore_Towny_master_248b0d8d0a_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml b/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml deleted file mode 100644 index 19b24a3..0000000 --- a/.idea/libraries/Maven__com_github_milkbowl_VaultAPI_master_431c5273c2_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index 73696cd..4902d56 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,6 +12,7 @@ + diff --git a/BuildConfigUpdater/src/main/java/BCUMain.java b/BuildConfigUpdater/src/main/java/BCUMain.java index 07666d3..a5e2007 100644 --- a/BuildConfigUpdater/src/main/java/BCUMain.java +++ b/BuildConfigUpdater/src/main/java/BCUMain.java @@ -1,4 +1,4 @@ -import buttondevteam.component.updater.PluginUpdater; +import buttondevteam.core.component.updater.PluginUpdater; import java.util.List; import java.util.stream.Collectors; diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index 4b090fc..655192c 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -11,7 +11,10 @@ import org.bukkit.plugin.Plugin; import java.util.Optional; -@CommandClass(modOnly = true) +@CommandClass(modOnly = true, helpText = { + "§6---- Component command ----", + "Can be used to enable/disable/list components" +}) public class ComponentCommand extends Command2 { public ComponentCommand() { addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); @@ -58,13 +61,6 @@ public class ComponentCommand extends Command2 { .filter(c -> c.getClass().getSimpleName().equalsIgnoreCase(arg)).findAny(); if (!oc.isPresent()) sender.sendMessage("§cComponent not found!"); //^ Much simpler to solve in the new command system - return oc; //TODO: Offer overload options with clickable link (with all the plugins it found) + return oc; } //TODO: Tabcompletion for the new command system - - public String[] GetHelpText(String alias) { //TODO - return new String[]{ - "§6---- Component command ----", - "Enable or disable or list components" - }; - } } diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index c92a3c9..65966d8 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -1,14 +1,14 @@ package buttondevteam.core; -import buttondevteam.component.channel.Channel; -import buttondevteam.component.channel.ChannelComponent; -import buttondevteam.component.channel.ChatRoom; -import buttondevteam.component.members.MemberComponent; -import buttondevteam.component.randomtp.RandomTPComponent; -import buttondevteam.component.restart.RestartComponent; -import buttondevteam.component.towny.TownyComponent; -import buttondevteam.component.updater.PluginUpdater; -import buttondevteam.component.updater.PluginUpdaterComponent; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.core.component.channel.ChannelComponent; +import buttondevteam.core.component.channel.ChatRoom; +import buttondevteam.core.component.members.MemberComponent; +import buttondevteam.core.component.randomtp.RandomTPComponent; +import buttondevteam.core.component.restart.RestartComponent; +import buttondevteam.core.component.towny.TownyComponent; +import buttondevteam.core.component.updater.PluginUpdater; +import buttondevteam.core.component.updater.PluginUpdaterComponent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; diff --git a/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java b/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java index 179e9cf..b0b9610 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java +++ b/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java @@ -1,7 +1,7 @@ package buttondevteam.core; -import buttondevteam.component.channel.Channel; -import buttondevteam.component.channel.ChannelComponent; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.core.component.channel.ChannelComponent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; diff --git a/ButtonCore/src/main/java/buttondevteam/component/channel/Channel.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/Channel.java similarity index 99% rename from ButtonCore/src/main/java/buttondevteam/component/channel/Channel.java rename to ButtonCore/src/main/java/buttondevteam/core/component/channel/Channel.java index 38b53c0..c643880 100755 --- a/ButtonCore/src/main/java/buttondevteam/component/channel/Channel.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/Channel.java @@ -1,4 +1,4 @@ -package buttondevteam.component.channel; +package buttondevteam.core.component.channel; import buttondevteam.core.ComponentManager; import buttondevteam.core.MainPlugin; diff --git a/ButtonCore/src/main/java/buttondevteam/component/channel/ChannelComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java similarity index 89% rename from ButtonCore/src/main/java/buttondevteam/component/channel/ChannelComponent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java index a49ea1e..083633d 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/channel/ChannelComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.channel; +package buttondevteam.core.component.channel; import buttondevteam.lib.architecture.Component; import org.bukkit.plugin.java.JavaPlugin; diff --git a/ButtonCore/src/main/java/buttondevteam/component/channel/ChatChannelRegisterEvent.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatChannelRegisterEvent.java similarity index 91% rename from ButtonCore/src/main/java/buttondevteam/component/channel/ChatChannelRegisterEvent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatChannelRegisterEvent.java index 896a64d..4797b3e 100755 --- a/ButtonCore/src/main/java/buttondevteam/component/channel/ChatChannelRegisterEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatChannelRegisterEvent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.channel; +package buttondevteam.core.component.channel; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; diff --git a/ButtonCore/src/main/java/buttondevteam/component/channel/ChatRoom.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java similarity index 95% rename from ButtonCore/src/main/java/buttondevteam/component/channel/ChatRoom.java rename to ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java index ea01ed6..a086a42 100755 --- a/ButtonCore/src/main/java/buttondevteam/component/channel/ChatRoom.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java @@ -1,4 +1,4 @@ -package buttondevteam.component.channel; +package buttondevteam.core.component.channel; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; diff --git a/ButtonCore/src/main/java/buttondevteam/component/members/MemberCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberCommand.java similarity index 97% rename from ButtonCore/src/main/java/buttondevteam/component/members/MemberCommand.java rename to ButtonCore/src/main/java/buttondevteam/core/component/members/MemberCommand.java index d5334a1..d395d99 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/members/MemberCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberCommand.java @@ -1,4 +1,4 @@ -package buttondevteam.component.members; +package buttondevteam.core.component.members; import buttondevteam.core.MainPlugin; import buttondevteam.lib.chat.CommandClass; diff --git a/ButtonCore/src/main/java/buttondevteam/component/members/MemberComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java similarity index 96% rename from ButtonCore/src/main/java/buttondevteam/component/members/MemberComponent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java index 453f535..0caeca7 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/members/MemberComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.members; +package buttondevteam.core.component.members; import buttondevteam.core.MainPlugin; import buttondevteam.lib.architecture.Component; diff --git a/ButtonCore/src/main/java/buttondevteam/component/randomtp/RandomTP.java b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTP.java similarity index 99% rename from ButtonCore/src/main/java/buttondevteam/component/randomtp/RandomTP.java rename to ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTP.java index 1f0f396..a0612db 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/randomtp/RandomTP.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTP.java @@ -1,4 +1,4 @@ -package buttondevteam.component.randomtp; +package buttondevteam.core.component.randomtp; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.CommandClass; diff --git a/ButtonCore/src/main/java/buttondevteam/component/randomtp/RandomTPComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java similarity index 84% rename from ButtonCore/src/main/java/buttondevteam/component/randomtp/RandomTPComponent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java index 0261c59..e324b3a 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/randomtp/RandomTPComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.randomtp; +package buttondevteam.core.component.randomtp; import buttondevteam.lib.architecture.Component; diff --git a/ButtonCore/src/main/java/buttondevteam/component/restart/PrimeRestartCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java similarity index 96% rename from ButtonCore/src/main/java/buttondevteam/component/restart/PrimeRestartCommand.java rename to ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java index 51ee9b2..32773ab 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/restart/PrimeRestartCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java @@ -1,4 +1,4 @@ -package buttondevteam.component.restart; +package buttondevteam.core.component.restart; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.TBMCCommandBase; diff --git a/ButtonCore/src/main/java/buttondevteam/component/restart/RestartComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java similarity index 96% rename from ButtonCore/src/main/java/buttondevteam/component/restart/RestartComponent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java index e2f98b2..e49e3b2 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/restart/RestartComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.restart; +package buttondevteam.core.component.restart; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.IFakePlayer; diff --git a/ButtonCore/src/main/java/buttondevteam/component/restart/ScheduledRestartCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java similarity index 66% rename from ButtonCore/src/main/java/buttondevteam/component/restart/ScheduledRestartCommand.java rename to ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java index ecc44ad..fea469e 100755 --- a/ButtonCore/src/main/java/buttondevteam/component/restart/ScheduledRestartCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java @@ -1,9 +1,11 @@ -package buttondevteam.component.restart; +package buttondevteam.core.component.restart; import buttondevteam.core.MainPlugin; import buttondevteam.lib.ScheduledServerRestartEvent; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.TBMCCommandBase; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarFlag; @@ -14,43 +16,45 @@ import org.bukkit.scheduler.BukkitTask; @CommandClass(modOnly = true, path = "schrestart") public class ScheduledRestartCommand extends TBMCCommandBase { - private static volatile int restartcounter; - private static volatile BukkitTask restarttask; - private static volatile BossBar restartbar; + @Getter + @Setter + private int restartCounter; + private BukkitTask restarttask; + private volatile BossBar restartbar; @Override public boolean OnCommand(CommandSender sender, String alias, String[] args) { - int ticks = 20 * 60; + int secs = 60; try { if (args.length > 0) - ticks = Integer.parseInt(args[0]); + secs = Integer.parseInt(args[0]); } catch (NumberFormatException e) { - sender.sendMessage("§cError: Ticks must be a number."); + sender.sendMessage("§cError: Seconds must be a number."); return false; } - if (ticks < 20) { - sender.sendMessage("§cError: Ticks must be more than 20."); + if (secs < 10) { + sender.sendMessage("§cError: Seconds must be at least 10."); return false; } - final int restarttime = restartcounter = ticks; - restartbar = Bukkit.createBossBar("Server restart in " + ticks / 20f + "s", BarColor.RED, BarStyle.SOLID, + final int restarttime = restartCounter = secs * 20; + restartbar = Bukkit.createBossBar("Server restart in " + secs + "s", BarColor.RED, BarStyle.SOLID, BarFlag.DARKEN_SKY); restartbar.setProgress(1); Bukkit.getOnlinePlayers().forEach(p -> restartbar.addPlayer(p)); - sender.sendMessage("Scheduled restart in " + ticks / 20f); - ScheduledServerRestartEvent e = new ScheduledServerRestartEvent(ticks); + sender.sendMessage("Scheduled restart in " + secs); + ScheduledServerRestartEvent e = new ScheduledServerRestartEvent(restarttime, this); Bukkit.getPluginManager().callEvent(e); restarttask = Bukkit.getScheduler().runTaskTimer(MainPlugin.Instance, () -> { - if (restartcounter < 0) { + if (restartCounter < 0) { restarttask.cancel(); restartbar.getPlayers().forEach(p -> restartbar.removePlayer(p)); Bukkit.spigot().restart(); } - if (restartcounter % 200 == 0) - Bukkit.broadcastMessage("§c-- The server is restarting in " + restartcounter / 20 + " seconds!"); - restartbar.setProgress(restartcounter / (double) restarttime); - restartbar.setTitle(String.format("Server restart in %.2f", restartcounter / 20f)); - restartcounter--; + if (restartCounter % 200 == 0) + Bukkit.broadcastMessage("§c-- The server is restarting in " + restartCounter / 20 + " seconds! (/press)"); + restartbar.setProgress(restartCounter / (double) restarttime); + restartbar.setTitle(String.format("Server restart in %.2f", restartCounter / 20f)); + restartCounter--; }, 1, 1); return true; } diff --git a/ButtonCore/src/main/java/buttondevteam/component/towny/TownyComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java similarity index 97% rename from ButtonCore/src/main/java/buttondevteam/component/towny/TownyComponent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java index 61a9c5a..1b2bf9d 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/towny/TownyComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.towny; +package buttondevteam.core.component.towny; import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCCoreAPI; diff --git a/ButtonCore/src/main/java/buttondevteam/component/updater/PluginUpdater.java b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdater.java similarity index 99% rename from ButtonCore/src/main/java/buttondevteam/component/updater/PluginUpdater.java rename to ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdater.java index ce2e993..64401fd 100755 --- a/ButtonCore/src/main/java/buttondevteam/component/updater/PluginUpdater.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdater.java @@ -1,4 +1,4 @@ -package buttondevteam.component.updater; +package buttondevteam.core.component.updater; import buttondevteam.lib.TBMCCoreAPI; import com.google.gson.JsonArray; diff --git a/ButtonCore/src/main/java/buttondevteam/component/updater/PluginUpdaterComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java similarity index 87% rename from ButtonCore/src/main/java/buttondevteam/component/updater/PluginUpdaterComponent.java rename to ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java index bd64c05..2ead741 100644 --- a/ButtonCore/src/main/java/buttondevteam/component/updater/PluginUpdaterComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java @@ -1,4 +1,4 @@ -package buttondevteam.component.updater; +package buttondevteam.core.component.updater; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.TBMCChatAPI; diff --git a/ButtonCore/src/main/java/buttondevteam/component/updater/UpdatePluginCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/updater/UpdatePluginCommand.java similarity index 96% rename from ButtonCore/src/main/java/buttondevteam/component/updater/UpdatePluginCommand.java rename to ButtonCore/src/main/java/buttondevteam/core/component/updater/UpdatePluginCommand.java index ee006c4..0569e89 100755 --- a/ButtonCore/src/main/java/buttondevteam/component/updater/UpdatePluginCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/updater/UpdatePluginCommand.java @@ -1,4 +1,4 @@ -package buttondevteam.component.updater; +package buttondevteam.core.component.updater; import buttondevteam.core.MainPlugin; import buttondevteam.lib.TBMCCoreAPI; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/ScheduledServerRestartEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/ScheduledServerRestartEvent.java index 749578f..4531ad9 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/ScheduledServerRestartEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/ScheduledServerRestartEvent.java @@ -1,20 +1,18 @@ package buttondevteam.lib; +import buttondevteam.core.component.restart.ScheduledRestartCommand; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; +@Getter +@RequiredArgsConstructor public class ScheduledServerRestartEvent extends Event { private static final HandlerList handlers = new HandlerList(); - private final int restartticks; - - public ScheduledServerRestartEvent(int restartticks) { - this.restartticks = restartticks; - } - - public int getRestartTicks() { - return restartticks; - } + private final int restartTicks; + private final ScheduledRestartCommand command; @Override public HandlerList getHandlers() { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEvent.java index cae2c39..ee37c30 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEvent.java @@ -1,6 +1,6 @@ package buttondevteam.lib; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.chat.ChatMessage; import lombok.Getter; import lombok.experimental.Delegate; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEventBase.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEventBase.java index bed34a6..d30e12e 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEventBase.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatEventBase.java @@ -1,6 +1,6 @@ package buttondevteam.lib; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatPreprocessEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatPreprocessEvent.java index 28bd27e..6ff3bda 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatPreprocessEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCChatPreprocessEvent.java @@ -1,6 +1,6 @@ package buttondevteam.lib; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import lombok.Getter; import lombok.Setter; import org.bukkit.command.CommandSender; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCCoreAPI.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCCoreAPI.java index e114196..d4d06cf 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCCoreAPI.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCCoreAPI.java @@ -1,188 +1,188 @@ -package buttondevteam.lib; - -import buttondevteam.component.updater.PluginUpdater; -import buttondevteam.core.MainPlugin; -import buttondevteam.lib.player.ChromaGamerBase; -import buttondevteam.lib.potato.DebugPotato; -import org.apache.commons.io.IOUtils; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.Listener; -import org.bukkit.plugin.Plugin; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; - -public class TBMCCoreAPI { - static final List coders = new ArrayList() { - private static final long serialVersionUID = -4462159250738367334L; - { - add("Alisolarflare"); - add("NorbiPeti"); - add("iie"); - add("thewindmillman"); - add("mayskam1995"); - } - }; - - /** - * Updates or installs the specified plugin. The plugin must use Maven. - * - * @param name - * The plugin's repository name. - * @param sender - * The command sender (if not console, messages will be printed to console as well). - */ - public static void UpdatePlugin(String name, CommandSender sender) { - UpdatePlugin(name, sender, "master"); - } - - /** - * Updates or installs the specified plugin from the specified branch. The plugin must use Maven. - * - * @param name - * The plugin's repository name. - * @param sender - * The command sender (if not console, messages will be printed to console as well). - * @param branch - * The branch to download the plugin from. - * @return Success or not - */ - public static boolean UpdatePlugin(String name, CommandSender sender, String branch) { - return PluginUpdater.UpdatePlugin(name, sender, branch); - } - - public static String DownloadString(String urlstr) throws IOException { - URL url = new URL(urlstr); - URLConnection con = url.openConnection(); - con.setRequestProperty("User-Agent", "TBMCPlugins"); - InputStream in = con.getInputStream(); - String encoding = con.getContentEncoding(); - encoding = encoding == null ? "UTF-8" : encoding; - String body = IOUtils.toString(in, encoding); - in.close(); - return body; - } - - private static final HashMap exceptionsToSend = new HashMap<>(); - private static final List debugMessagesToSend = new ArrayList<>(); - - /** - * Send exception to the {@link TBMCExceptionEvent}. - * - * @param sourcemsg - * A message that is shown at the top of the exception (before the exception's message) - * @param e - * The exception to send - */ - public static void SendException(String sourcemsg, Throwable e) { - SendException(sourcemsg, e, false); - } - - public static void SendException(String sourcemsg, Throwable e, boolean debugPotato) { - SendUnsentExceptions(); - TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e); - Bukkit.getPluginManager().callEvent(event); - synchronized (exceptionsToSend) { - if (!event.isHandled()) - exceptionsToSend.put(sourcemsg, e); - } - Bukkit.getLogger().warning(sourcemsg); - e.printStackTrace(); - if (debugPotato) { - List devsOnline = new ArrayList(); - for (Player player : Bukkit.getOnlinePlayers()) { - if (coders.contains(player.getName())) { - devsOnline.add(player); - } - } - if (!devsOnline.isEmpty()) { - DebugPotato potato = new DebugPotato() - .setMessage(new String[] { // - "§b§o" + e.getClass().getSimpleName(), // - "§c§o" + sourcemsg, // - "§a§oFind a dev to fix this issue" }) - .setType(e instanceof IOException ? "Throwable Potato" - : e instanceof ClassCastException ? "Squished Potato" - : e instanceof NullPointerException ? "Plain Potato" - : e instanceof StackOverflowError ? "Chips" : "Error Potato"); - for (Player dev : devsOnline) { - potato.Send(dev); - } - } - } - } - - public static void sendDebugMessage(String debugMessage) { - SendUnsentDebugMessages(); - TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(debugMessage); - Bukkit.getPluginManager().callEvent(event); - synchronized (debugMessagesToSend) { - if (!event.isSent()) - debugMessagesToSend.add(debugMessage); - } - } - - /** - * Registers Bukkit events, handling the exceptions occurring in those events - * - * @param listener - * The class that handles the events - * @param plugin - * The plugin which the listener belongs to - */ - public static void RegisterEventsForExceptions(Listener listener, Plugin plugin) { - EventExceptionHandler.registerEvents(listener, plugin, new EventExceptionCoreHandler()); - } - - public static void RegisterUserClass(Class userclass) { - ChromaGamerBase.RegisterPluginUserClass(userclass); - } - - /** - * Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event - */ - public static void SendUnsentExceptions() { - synchronized (exceptionsToSend) { - if (exceptionsToSend.size() > 20) { - exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded - Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!"); - } - for (Iterator> iterator = exceptionsToSend.entrySet().iterator(); iterator.hasNext(); ) { - Entry entry = iterator.next(); - TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue()); - Bukkit.getPluginManager().callEvent(event); - if (event.isHandled()) - iterator.remove(); - } - } - } - - public static void SendUnsentDebugMessages() { - synchronized (debugMessagesToSend) { - if (debugMessagesToSend.size() > 20) { - debugMessagesToSend.clear(); // Don't call more and more DebugMessages if all the handler plugins are unloaded - Bukkit.getLogger().warning("Unhandled Debug Message list is over 20! Clearing!"); - } - for (Iterator iterator = debugMessagesToSend.iterator(); iterator.hasNext(); ) { - String message = iterator.next(); - TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(message); - Bukkit.getPluginManager().callEvent(event); - if (event.isSent()) - iterator.remove(); - } - } - } - - public static boolean IsTestServer() { - return MainPlugin.Test; - } +package buttondevteam.lib; + +import buttondevteam.core.MainPlugin; +import buttondevteam.core.component.updater.PluginUpdater; +import buttondevteam.lib.player.ChromaGamerBase; +import buttondevteam.lib.potato.DebugPotato; +import org.apache.commons.io.IOUtils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +public class TBMCCoreAPI { + static final List coders = new ArrayList() { + private static final long serialVersionUID = -4462159250738367334L; + { + add("Alisolarflare"); + add("NorbiPeti"); + add("iie"); + add("thewindmillman"); + add("mayskam1995"); + } + }; + + /** + * Updates or installs the specified plugin. The plugin must use Maven. + * + * @param name + * The plugin's repository name. + * @param sender + * The command sender (if not console, messages will be printed to console as well). + */ + public static void UpdatePlugin(String name, CommandSender sender) { + UpdatePlugin(name, sender, "master"); + } + + /** + * Updates or installs the specified plugin from the specified branch. The plugin must use Maven. + * + * @param name + * The plugin's repository name. + * @param sender + * The command sender (if not console, messages will be printed to console as well). + * @param branch + * The branch to download the plugin from. + * @return Success or not + */ + public static boolean UpdatePlugin(String name, CommandSender sender, String branch) { + return PluginUpdater.UpdatePlugin(name, sender, branch); + } + + public static String DownloadString(String urlstr) throws IOException { + URL url = new URL(urlstr); + URLConnection con = url.openConnection(); + con.setRequestProperty("User-Agent", "TBMCPlugins"); + InputStream in = con.getInputStream(); + String encoding = con.getContentEncoding(); + encoding = encoding == null ? "UTF-8" : encoding; + String body = IOUtils.toString(in, encoding); + in.close(); + return body; + } + + private static final HashMap exceptionsToSend = new HashMap<>(); + private static final List debugMessagesToSend = new ArrayList<>(); + + /** + * Send exception to the {@link TBMCExceptionEvent}. + * + * @param sourcemsg + * A message that is shown at the top of the exception (before the exception's message) + * @param e + * The exception to send + */ + public static void SendException(String sourcemsg, Throwable e) { + SendException(sourcemsg, e, false); + } + + public static void SendException(String sourcemsg, Throwable e, boolean debugPotato) { + SendUnsentExceptions(); + TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e); + Bukkit.getPluginManager().callEvent(event); + synchronized (exceptionsToSend) { + if (!event.isHandled()) + exceptionsToSend.put(sourcemsg, e); + } + Bukkit.getLogger().warning(sourcemsg); + e.printStackTrace(); + if (debugPotato) { + List devsOnline = new ArrayList(); + for (Player player : Bukkit.getOnlinePlayers()) { + if (coders.contains(player.getName())) { + devsOnline.add(player); + } + } + if (!devsOnline.isEmpty()) { + DebugPotato potato = new DebugPotato() + .setMessage(new String[] { // + "§b§o" + e.getClass().getSimpleName(), // + "§c§o" + sourcemsg, // + "§a§oFind a dev to fix this issue" }) + .setType(e instanceof IOException ? "Throwable Potato" + : e instanceof ClassCastException ? "Squished Potato" + : e instanceof NullPointerException ? "Plain Potato" + : e instanceof StackOverflowError ? "Chips" : "Error Potato"); + for (Player dev : devsOnline) { + potato.Send(dev); + } + } + } + } + + public static void sendDebugMessage(String debugMessage) { + SendUnsentDebugMessages(); + TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(debugMessage); + Bukkit.getPluginManager().callEvent(event); + synchronized (debugMessagesToSend) { + if (!event.isSent()) + debugMessagesToSend.add(debugMessage); + } + } + + /** + * Registers Bukkit events, handling the exceptions occurring in those events + * + * @param listener + * The class that handles the events + * @param plugin + * The plugin which the listener belongs to + */ + public static void RegisterEventsForExceptions(Listener listener, Plugin plugin) { + EventExceptionHandler.registerEvents(listener, plugin, new EventExceptionCoreHandler()); + } + + public static void RegisterUserClass(Class userclass) { + ChromaGamerBase.RegisterPluginUserClass(userclass); + } + + /** + * Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event + */ + public static void SendUnsentExceptions() { + synchronized (exceptionsToSend) { + if (exceptionsToSend.size() > 20) { + exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded + Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!"); + } + for (Iterator> iterator = exceptionsToSend.entrySet().iterator(); iterator.hasNext(); ) { + Entry entry = iterator.next(); + TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue()); + Bukkit.getPluginManager().callEvent(event); + if (event.isHandled()) + iterator.remove(); + } + } + } + + public static void SendUnsentDebugMessages() { + synchronized (debugMessagesToSend) { + if (debugMessagesToSend.size() > 20) { + debugMessagesToSend.clear(); // Don't call more and more DebugMessages if all the handler plugins are unloaded + Bukkit.getLogger().warning("Unhandled Debug Message list is over 20! Clearing!"); + } + for (Iterator iterator = debugMessagesToSend.iterator(); iterator.hasNext(); ) { + String message = iterator.next(); + TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(message); + Bukkit.getPluginManager().callEvent(event); + if (event.isSent()) + iterator.remove(); + } + } + } + + public static boolean IsTestServer() { + return MainPlugin.Test; + } } \ No newline at end of file diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java index f4ded2a..80cd634 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java @@ -1,6 +1,6 @@ package buttondevteam.lib; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import lombok.Getter; import org.bukkit.command.CommandSender; import org.bukkit.event.HandlerList; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java b/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java new file mode 100644 index 0000000..4f8560c --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java @@ -0,0 +1,38 @@ +package buttondevteam.lib; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public final class ThorpeUtils { + private ThorpeUtils() {} + + public static String getDisplayName(CommandSender sender) { + if (sender instanceof IHaveFancyName) + return ((IHaveFancyName) sender).getFancyName(); + if (sender instanceof Player) + return ((Player) sender).getDisplayName(); + return sender.getName(); + } + + public static String getFullDisplayName(CommandSender sender) { + if (sender instanceof IHaveFancyName) + return ((IHaveFancyName) sender).getFancyFullName(); + return getDisplayName(sender); + } + + public interface IHaveFancyName { + /** + * May not be null. + * + * @return The name to be displayed in most places. + */ + String getFancyName(); + + /** + * May return null. + * + * @return The full name that can be used to uniquely indentify the user. + */ + String getFancyFullName(); + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 014b512..87a1a18 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -1,18 +1,24 @@ package buttondevteam.lib.chat; +import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.player.ChromaGamerBase; import lombok.RequiredArgsConstructor; +import lombok.experimental.var; import lombok.val; import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import java.io.InputStreamReader; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.function.Function; +import java.util.stream.Collectors; /** * The method name is the subcommand, use underlines (_) to add further subcommands. @@ -26,7 +32,6 @@ public abstract class Command2 { * @param args All of the arguments passed as is * @return The success of the command */ - @Subcommand public boolean def(CommandSender sender, @TextArg String args) { return false; } @@ -58,12 +63,17 @@ public abstract class Command2 { @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Subcommand { + /** + * Help text to show players. A usage message will be also shown below it. + */ + String[] helpText() default {}; } @RequiredArgsConstructor private static class SubcommandData { public final Method method; public final Command2 command; + public final String[] helpText; } private static HashMap subcommands = new HashMap<>(); @@ -133,8 +143,8 @@ public abstract class Command2 { //System.out.println("Our params: "+params); val ret = sd.method.invoke(sd.command, params.toArray()); //I FORGOT TO TURN IT INTO AN ARRAY (for a long time) if (ret instanceof Boolean) { - if (!(boolean) ret) - sender.sendMessage("Wrong usage."); //TODO: Show help text + if (!(boolean) ret) //Show usage + sender.sendMessage(sd.helpText); } else if (ret != null) throw new Exception("Wrong return type! Must return a boolean or void. Return value: "+ret); return true; //We found a method @@ -143,11 +153,55 @@ public abstract class Command2 { } //TODO: Add to the help public static void registerCommand(Command2 command) { - for (val method : command.getClass().getMethods()) - if (method.isAnnotationPresent(Subcommand.class)) - subcommands.put("/" + command.path + //Add command path (class name by default) - (method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()), //Add method name, unless it's 'def' - new SubcommandData(method, command)); //Result of the above (def) is that it will show the help text + try { //Register the default handler first so it can be reliably overwritten + val method = command.getClass().getMethod("def", CommandSender.class, String.class); + val cc = command.getClass().getAnnotation(CommandClass.class); + var ht = cc == null ? new String[0] : cc.helpText(); + String[] both = Arrays.copyOf(ht, ht.length + 1); + both[ht.length] = "Usage: /" + command.path; //TODO: Print subcommands + ht = both; + subcommands.put("/" + command.path, new SubcommandData(method, command, ht)); //TODO: Disable components when the plugin is disabled + } catch (Exception e) { + TBMCCoreAPI.SendException("Could not register default handler for command /" + command.path, e); + } //Continue on + for (val method : command.getClass().getMethods()) { + val ann = method.getAnnotation(Subcommand.class); + if (ann != null) { + val cc = command.getClass().getAnnotation(CommandClass.class); + var ht = ann.helpText().length != 0 || cc == null ? ann.helpText() : cc.helpText(); //If cc is null then it's empty array + val subcommand = "/" + command.path + //Add command path (class name by default) + (method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()); //Add method name, unless it's 'def' + ht = getHelpText(method, ht, subcommand); + subcommands.put(subcommand, new SubcommandData(method, command, ht)); //Result of the above (def) is that it will show the help text + } + } + } + + private static String[] getHelpText(Method method, String[] ht, String subcommand) { //TODO: helpText[0]="§6---- "+helpText[0]+" ----"; + val str = Command2.class.getResourceAsStream("/commands.yml"); + if (str == null) + TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!")); + else { + YamlConfiguration yc = YamlConfiguration.loadConfiguration(new InputStreamReader(str)); //Generated by ButtonProcessor + val ccs = yc.getConfigurationSection(method.getDeclaringClass().getName()); + if (ccs != null) { + val cs = ccs.getConfigurationSection(method.getName()); + if (cs != null) { + val mname = cs.getString("method"); + val params = cs.getString("params"); + val goodname = method.getName() + "(" + Arrays.stream(method.getParameterTypes()).map(cl -> cl.getCanonicalName()).collect(Collectors.joining(",")) + ")"; + if (goodname.equals(mname) && params != null) { + String[] both = Arrays.copyOf(ht, ht.length + 1); + both[ht.length] = "Usage: " + subcommand + " " + params; + ht = both; + } else + TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params)); + } else + TBMCCoreAPI.SendException("Error while getting command data!", new Exception("cs is " + cs)); + } else + TBMCCoreAPI.SendException("Error while getting command data!", new Exception("ccs is " + ccs)); + } + return ht; } private final String path; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java index 55fcfec..ddfff22 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java @@ -38,7 +38,7 @@ public @interface CommandClass { boolean excludeFromPath() default false; /** - * The help text to show for the players. + * The help text to show for the players. A usage message will be also shown below it. * * @return The help text */ diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java index 66eac93..d143d8b 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java @@ -1,9 +1,9 @@ package buttondevteam.lib.chat; -import buttondevteam.component.channel.Channel; -import buttondevteam.component.channel.Channel.RecipientTestResult; import buttondevteam.core.CommandCaller; import buttondevteam.core.MainPlugin; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.core.component.channel.Channel.RecipientTestResult; import buttondevteam.lib.TBMCChatEvent; import buttondevteam.lib.TBMCChatPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/player/ChannelPlayerData.java b/ButtonCore/src/main/java/buttondevteam/lib/player/ChannelPlayerData.java index 6cebce8..5f12ca9 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/player/ChannelPlayerData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/player/ChannelPlayerData.java @@ -1,6 +1,6 @@ package buttondevteam.lib.player; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import org.bukkit.configuration.file.YamlConfiguration; public class ChannelPlayerData { //I just want this to work diff --git a/ButtonCore/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java b/ButtonCore/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java index 902a00a..6c6ea0b 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/player/ChromaGamerBase.java @@ -1,6 +1,6 @@ package buttondevteam.lib.player; -import buttondevteam.component.channel.Channel; +import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.TBMCCoreAPI; import com.google.common.collect.HashBiMap; import lombok.val; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java b/ButtonCore/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java index ba15bb4..0093c4e 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/player/TBMCPlayerBase.java @@ -1,6 +1,6 @@ package buttondevteam.lib.player; -import buttondevteam.component.towny.TownyComponent; +import buttondevteam.core.component.towny.TownyComponent; import buttondevteam.lib.TBMCCoreAPI; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index cc79963..35bfd14 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -12,6 +12,13 @@ + + + + + + + \ No newline at end of file diff --git a/ButtonProcessor/pom.xml b/ButtonProcessor/pom.xml index 54981ad..ccc6888 100755 --- a/ButtonProcessor/pom.xml +++ b/ButtonProcessor/pom.xml @@ -1,40 +1,54 @@ - - 4.0.0 - - com.github.TBMCPlugins - ButtonCore - master-SNAPSHOT - - com.github.TBMCPlugins.ButtonCore - ButtonProcessor - jar - - ButtonProcessor - http://maven.apache.org - - - - - maven-compiler-plugin - - 1.8 - 1.8 - -proc:none - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - - - - UTF-8 - - + + 4.0.0 + + + org.yaml + snakeyaml + 1.21 + compile + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + compile + + + + com.github.TBMCPlugins + ButtonCore + master-SNAPSHOT + + com.github.TBMCPlugins.ButtonCore + ButtonProcessor + jar + + ButtonProcessor + http://maven.apache.org + + + + + maven-compiler-plugin + + 1.8 + 1.8 + -proc:none + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + + + + UTF-8 + + diff --git a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java index e9e36ba..f7bb7fe 100755 --- a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java +++ b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java @@ -1,17 +1,25 @@ package buttondevteam.buttonproc; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; +import javax.lang.model.element.*; +import javax.tools.Diagnostic; import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import java.io.File; +import java.io.IOException; +import java.io.Writer; import java.util.List; import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; @SupportedAnnotationTypes("buttondevteam.*") public class ButtonProcessor extends AbstractProcessor { @@ -23,7 +31,7 @@ public class ButtonProcessor extends AbstractProcessor { System.out.println("Processing " + targetcl); List annotationMirrors = processingEnv.getElementUtils() .getAllAnnotationMirrors(targetcl); - System.out.println("Annotations: " + annotationMirrors); + //System.out.println("Annotations: " + annotationMirrors); Function hasAnnotation = ann -> annotationMirrors.stream() .anyMatch(am -> am.getAnnotationType().toString().contains(ann)); if (hasAnnotation.apply("ChromaGamerEnforcer") && !hasAnnotation.apply("UserClass") @@ -36,15 +44,67 @@ public class ButtonProcessor extends AbstractProcessor { "No PlayerClass annotation found for " + targetcl.getSimpleName(), targetcl); for (AnnotationMirror annotation : annotationMirrors) { String type = annotation.getAnnotationType().toString(); - System.out.println("Type: " + type); + //System.out.println("Type: " + type); } + processSubcommands(targetcl, annotationMirrors); } } + try { + if (found) { + FileObject fo = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "commands.yml"); + yc.save(new File(fo.toUri())); + found = false; + } + } catch (IOException e) { + e.printStackTrace(); + } return true; // claim the annotations } - @Override + private YamlConfiguration yc = new YamlConfiguration(); + private boolean found = false; + + private void processSubcommands(Element targetcl, List annotationMirrors) { + if (!(targetcl instanceof ExecutableElement)) + return; + //System.out.println("Annotations: "+annotationMirrors); + if (annotationMirrors.stream().noneMatch(an -> an.getAnnotationType().toString().endsWith("Subcommand"))) + return; + //System.out.print("Processing method: " + targetcl.getEnclosingElement()+" "+targetcl); + ConfigurationSection cs = yc.createSection(targetcl.getEnclosingElement().toString() + + "." + targetcl.getSimpleName().toString()); //Need to do the 2 config sections at once so it doesn't overwrite the class section + System.out.println(targetcl); + cs.set("method", targetcl.toString()); + cs.set("params", ((ExecutableElement) targetcl).getParameters().stream().skip(1).map(p -> { + //String tn=p.asType().toString(); + //return tn.substring(tn.lastIndexOf('.')+1)+" "+p.getSimpleName(); + boolean optional = p.getAnnotationMirrors().stream().anyMatch(am -> am.getAnnotationType().toString().endsWith("Optional")); + if (optional) + return "[" + p.getSimpleName() + "]"; + return "<" + p.getSimpleName() + ">"; + }).collect(Collectors.joining(" "))); + //System.out.println(); + found = true; + } + + @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latestSupported(); } + + private String fetchSourcePath() { + try { + JavaFileObject generationForPath = processingEnv.getFiler().createSourceFile("PathFor" + getClass().getSimpleName()); + Writer writer = generationForPath.openWriter(); + String sourcePath = generationForPath.toUri().getPath(); + writer.close(); + generationForPath.delete(); + + return sourcePath; + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Unable to determine source file path!"); + } + + return ""; + } } From a4e96b0ed7d7c614325e92005243405dde247562 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Jan 2019 21:14:00 +0100 Subject: [PATCH 5/6] Component unregistering, command impr. Automatically unregistering components in order (#57) Made the command system applicable for Discord as well --- .../buttondevteam/core/ComponentCommand.java | 4 +-- .../buttondevteam/core/ComponentManager.java | 16 ++++----- .../java/buttondevteam/core/MainPlugin.java | 5 ++- .../buttondevteam/core/PlayerListener.java | 4 +-- .../java/buttondevteam/core/TestPrepare.java | 3 +- .../lib/architecture/ButtonPlugin.java | 9 +++++ .../lib/architecture/Component.java | 27 +++++++++------ .../java/buttondevteam/lib/chat/Command2.java | 33 ++++++++----------- .../buttondevteam/lib/chat/Command2MC.java | 24 ++++++++++++++ 9 files changed, 78 insertions(+), 47 deletions(-) create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index 655192c..4aaceac 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -2,7 +2,7 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.CommandClass; import lombok.val; import org.bukkit.Bukkit; @@ -15,7 +15,7 @@ import java.util.Optional; "§6---- Component command ----", "Can be used to enable/disable/list components" }) -public class ComponentCommand extends Command2 { +public class ComponentCommand extends Command2MC { public ComponentCommand() { addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java index 842badb..9a84ddd 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java @@ -1,6 +1,7 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import lombok.val; @@ -31,16 +32,11 @@ public final class ComponentManager { } /** - * Disables all components that are enabled + * Unregister all components of a plugin that are enabled - called on {@link ButtonPlugin} disable */ - public static void disableComponents() { - Component.getComponents().values().stream().filter(Component::isEnabled).forEach(c -> { - try { - Component.setComponentEnabled(c, false); - } catch (Exception e) { - TBMCCoreAPI.SendException("Failed to disable one of the components: " + c.getClass().getSimpleName(), e); - } - }); + public static void unregComponents(ButtonPlugin plugin) { + while (!plugin.getComponentStack().empty()) //Unregister in reverse order + Component.unregisterComponent(plugin, plugin.getComponentStack().pop()); //Components are pushed on register componentsEnabled = false; } @@ -56,7 +52,7 @@ public final class ComponentManager { } /** - * Will also return false if the component is not registered. + * Will also return null if the component is not registered. * * @param cl The component class * @return The component if it's registered and enabled diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index 65966d8..d15d2a9 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -14,7 +14,7 @@ import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; @@ -69,7 +69,7 @@ public class MainPlugin extends ButtonPlugin { Component.registerComponent(this, new MemberComponent()); Component.registerComponent(this, new TownyComponent()); ComponentManager.enableComponents(); - Command2.registerCommand(new ComponentCommand()); + Command2MC.registerCommand(new ComponentCommand()); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender ? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks @@ -101,7 +101,6 @@ public class MainPlugin extends ButtonPlugin { @Override public void pluginDisable() { - ComponentManager.disableComponents(); logger.info("Saving player data..."); TBMCPlayerBase.savePlayers(); logger.info("Player data saved."); diff --git a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java index 91448ba..c5146cd 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java +++ b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java @@ -3,7 +3,7 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; -import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.player.TBMCPlayerBase; import lombok.val; import org.bukkit.Bukkit; @@ -64,7 +64,7 @@ public class PlayerListener implements Listener { public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) { if (event.isCancelled()) return; try { - event.setCancelled(Command2.handleCommand(event.getSender(), event.getMessage())); + event.setCancelled(Command2MC.handleCommand(event.getSender(), event.getMessage())); } catch (Exception e) { TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e); } diff --git a/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java b/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java index b0b9610..67b0a33 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java +++ b/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java @@ -8,6 +8,7 @@ import buttondevteam.lib.chat.TBMCChatAPI; import org.bukkit.Bukkit; import org.bukkit.Server; import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; @@ -40,7 +41,7 @@ public class TestPrepare { return cl.isAssignableFrom(invocation.getMethod().getReturnType()); } })); - Component.registerComponent(Mockito.mock(MainPlugin.class), new ChannelComponent()); + Component.registerComponent(Mockito.mock(JavaPlugin.class), new ChannelComponent()); TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 2eee783..bc0e46d 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -1,5 +1,6 @@ package buttondevteam.lib.architecture; +import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.chat.TBMCChatAPI; import lombok.AccessLevel; @@ -7,9 +8,16 @@ import lombok.Getter; import lombok.experimental.var; import org.bukkit.plugin.java.JavaPlugin; +import java.util.Stack; + public abstract class ButtonPlugin extends JavaPlugin { @Getter(AccessLevel.PROTECTED) private IHaveConfig iConfig; + /** + * Used to unregister components in the right order + */ + @Getter + private Stack componentStack = new Stack<>(); protected abstract void pluginEnable(); @@ -30,6 +38,7 @@ public abstract class ButtonPlugin extends JavaPlugin { @Override public final void onDisable() { try { + ComponentManager.unregComponents(this); pluginDisable(); saveConfig(); iConfig = null; //Clearing the hashmap is not enough, we need to update the section as well diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 634f23a..e052555 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -3,7 +3,7 @@ package buttondevteam.lib.architecture; import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.exceptions.UnregisteredComponentException; -import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; @@ -39,7 +39,8 @@ public abstract class Component { /** * Registers a component checking it's dependencies and calling {@link #register(JavaPlugin)}.
* Make sure to register the dependencies first.
- * The component will be enabled automatically, regardless of when it was registered. + * The component will be enabled automatically, regardless of when it was registered.
+ * If not using {@link ButtonPlugin}, call {@link ComponentManager#unregComponents(ButtonPlugin)} on plugin disable. * * @param component The component to register * @return Whether the component is registered successfully (it may have failed to enable) @@ -50,15 +51,13 @@ public abstract class Component { /** * Unregisters a component by calling {@link #unregister(JavaPlugin)}.
- * Make sure to unregister the dependencies last. + * Make sure to unregister the dependencies last.
+ * Components will be unregistered in opposite order of registering by default by {@link ButtonPlugin} or {@link ComponentManager#unregComponents(ButtonPlugin)}. * - * @param componentClass The component class to unregister + * @param component The component to unregister * @return Whether the component is unregistered successfully (it also got disabled) */ - public static boolean unregisterComponent(JavaPlugin plugin, Class componentClass) { - val component = components.get(componentClass); - if (component == null) - return false; //Failed to load + public static boolean unregisterComponent(JavaPlugin plugin, Component component) { return registerUnregisterComponent(plugin, component, false); } @@ -75,10 +74,16 @@ public abstract class Component { } } if (register) { + if (components.containsKey(component.getClass())) { + TBMCCoreAPI.SendException("Failed to register component " + component.getClassName(), new IllegalArgumentException("The component is already registered!")); + return false; + } component.plugin = plugin; updateConfig(plugin, component); component.register(plugin); components.put(component.getClass(), component); + if (plugin instanceof ButtonPlugin) + ((ButtonPlugin) plugin).getComponentStack().push(component); if (ComponentManager.areComponentsEnabled() && component.shouldBeEnabled().get()) { try { //Enable components registered after the previous ones getting enabled setComponentEnabled(component, true); @@ -90,6 +95,8 @@ public abstract class Component { } return true; //Component shouldn't be enabled } else { + if (!components.containsKey(component.getClass())) + return true; //Already unregistered if (component.enabled) { try { setComponentEnabled(component, false); @@ -190,8 +197,8 @@ public abstract class Component { * * @param commandBase Custom coded command class */ - protected final void registerCommand(Command2 commandBase) { - Command2.registerCommand(commandBase); + protected final void registerCommand(Command2MC commandBase) { + Command2MC.registerCommand(commandBase); } /** diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 87a1a18..cb77556 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -70,15 +70,12 @@ public abstract class Command2 { } @RequiredArgsConstructor - private static class SubcommandData { + protected static class SubcommandData { public final Method method; - public final Command2 command; + public final T command; public final String[] helpText; } - private static HashMap subcommands = new HashMap<>(); - private static HashMap, Function> paramConverters = new HashMap<>(); - public Command2() { path = getcmdpath(); } @@ -91,18 +88,16 @@ public abstract class Command2 { * @param converter The converter to use * @param The type of the result */ - public static void addParamConverter(Class cl, Function converter) { - paramConverters.put(cl, converter); + protected static void addParamConverter(Class cl, Function converter, HashMap, Function> map) { + map.put(cl, converter); } - public static boolean handleCommand(CommandSender sender, String commandline) throws Exception { + protected static boolean handleCommand(CommandSender sender, String commandline, + HashMap> subcommands, HashMap, Function> paramConverters) throws Exception { for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { String subcommand = commandline.substring(0, i).toLowerCase(); - //System.out.println("Subcommand: "+subcommand); - //System.out.println("Subcmds: "+subcommands.toString()); SubcommandData sd = subcommands.get(subcommand); //O(1) if (sd == null) continue; //TODO: This will run each time someone runs any command - //System.out.println("sd.method: "+sd.method); //TODO: Rename in Maven val params = new ArrayList(sd.method.getParameterCount()); int j = subcommand.length(), pj; Class[] parameterTypes = sd.method.getParameterTypes(); @@ -152,27 +147,28 @@ public abstract class Command2 { return false; //Didn't handle } //TODO: Add to the help - public static void registerCommand(Command2 command) { + protected static void registerCommand(T command, HashMap> subcommands, char commandChar) { + val path = command.getCommandPath(); try { //Register the default handler first so it can be reliably overwritten val method = command.getClass().getMethod("def", CommandSender.class, String.class); val cc = command.getClass().getAnnotation(CommandClass.class); var ht = cc == null ? new String[0] : cc.helpText(); String[] both = Arrays.copyOf(ht, ht.length + 1); - both[ht.length] = "Usage: /" + command.path; //TODO: Print subcommands + both[ht.length] = "Usage: " + commandChar + path; //TODO: Print subcommands ht = both; - subcommands.put("/" + command.path, new SubcommandData(method, command, ht)); //TODO: Disable components when the plugin is disabled + subcommands.put(commandChar + path, new SubcommandData<>(method, command, ht)); //TODO: Disable components when the plugin is disabled } catch (Exception e) { - TBMCCoreAPI.SendException("Could not register default handler for command /" + command.path, e); + TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); } //Continue on for (val method : command.getClass().getMethods()) { val ann = method.getAnnotation(Subcommand.class); if (ann != null) { val cc = command.getClass().getAnnotation(CommandClass.class); var ht = ann.helpText().length != 0 || cc == null ? ann.helpText() : cc.helpText(); //If cc is null then it's empty array - val subcommand = "/" + command.path + //Add command path (class name by default) + val subcommand = commandChar + path + //Add command path (class name by default) (method.getName().equals("def") ? "" : " " + method.getName().replace('_', ' ').toLowerCase()); //Add method name, unless it's 'def' ht = getHelpText(method, ht, subcommand); - subcommands.put(subcommand, new SubcommandData(method, command, ht)); //Result of the above (def) is that it will show the help text + subcommands.put(subcommand, new SubcommandData<>(method, command, ht)); //Result of the above (def) is that it will show the help text } } } @@ -211,11 +207,10 @@ public abstract class Command2 { * For example:
* "u admin updateplugin" or "u" for the top level one
* The path must be lowercase!
- * Abstract classes with no {@link CommandClass} annotations will be ignored. * * @return The command path, which is the command class name by default (removing any "command" from it) - Change via the {@link CommandClass} annotation */ - public final String GetCommandPath() { + public final String getCommandPath() { return path; } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java new file mode 100644 index 0000000..715d078 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -0,0 +1,24 @@ +package buttondevteam.lib.chat; + +import org.bukkit.command.CommandSender; + +import java.util.HashMap; +import java.util.function.Function; + +public class Command2MC extends Command2 { + + private static HashMap> subcommands = new HashMap<>(); + private static HashMap, Function> paramConverters = new HashMap<>(); + + public static boolean handleCommand(CommandSender sender, String commandLine) throws Exception { + return handleCommand(sender, commandLine, subcommands, paramConverters); + } + + public static void registerCommand(Command2MC command) { + registerCommand(command, subcommands, '/'); + } + + public static void addParamConverter(Class cl, Function converter) { + addParamConverter(cl, converter, paramConverters); + } +} From ab603276d3fdc8e4dd9f6f11c60c2b697c1b53ec Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 30 Jan 2019 23:31:20 +0100 Subject: [PATCH 6/6] Fixes, another plugin disable event Fixed/implemented number handling in config Fixed help text error Fixed annotation processing in other plugins Fixed error message on console chat Fixed CI building (hopefully) - Spigot repo --- BuildConfigUpdater/BuildConfigUpdater.iml | 1 + ButtonCore/pom.xml | 398 +++++++++--------- .../java/buttondevteam/core/MainPlugin.java | 1 + .../lib/architecture/ButtonPlugin.java | 10 + .../lib/architecture/ConfigData.java | 12 + .../java/buttondevteam/lib/chat/Command2.java | 10 +- ButtonProcessor/pom.xml | 6 + 7 files changed, 234 insertions(+), 204 deletions(-) diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index 4902d56..f14440c 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -20,6 +20,7 @@ + diff --git a/ButtonCore/pom.xml b/ButtonCore/pom.xml index 2bbce2d..e044b9a 100755 --- a/ButtonCore/pom.xml +++ b/ButtonCore/pom.xml @@ -1,200 +1,200 @@ - - 4.0.0 - - com.github.TBMCPlugins - ButtonCore - master-SNAPSHOT - - com.github.TBMCPlugins.ButtonCore - ButtonCore - ButtonCore - ButtonCore - - src/main/java - - - src/main/resources - - *.properties - *.yml - *.csv - *.txt - - true - - - ButtonCore - - - maven-compiler-plugin - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.2 - - - package - - shade - - - - - - - - - - org.apache.maven.plugins - maven-resources-plugin - 3.0.1 - - - copy - compile - - copy-resources - - - target - - - src/main/resources - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - - jitpack.io - https://jitpack.io/ - - - vault-repo - http://nexus.hc.to/content/repositories/pub_releases - - - ess-repo - http://repo.ess3.net/content/repositories/essrel/ - - - - - org.reflections - reflections - 0.9.10 - compile - - - org.spigotmc - spigot-api - 1.12.2-R0.1-SNAPSHOT - provided - - - - commons-io - commons-io - 1.3.2 - provided - - - - com.github.TBMCPlugins.ButtonCore - Towny - master-SNAPSHOT - provided - - - com.github.milkbowl - VaultAPI - master-SNAPSHOT - provided - - - - org.javassist - javassist - 3.20.0-GA - - - org.mockito - mockito-core - 2.7.20 - - - - org.projectlombok - lombok - 1.16.16 - provided - - - com.github.TBMCPlugins.ButtonCore - ButtonProcessor - master-SNAPSHOT - provided - - - net.ess3 - Essentials - 2.13.1 - provided - - - - TBMCPlugins - https://github.com/TBMCPlugins - - - - internal.repo - Temporary Staging Repository - file://${project.build.directory}/mvn-repo/${project.name} - - - - - github - UTF-8 - - - https://github.com/TBMCPlugins/mvn-repo - scm:git:https://github.com/TBMCPlugins/mvn-repo.git - scm:git:https://github.com/TBMCPlugins/mvn-repo.git - + + 4.0.0 + + com.github.TBMCPlugins + ButtonCore + master-SNAPSHOT + + com.github.TBMCPlugins.ButtonCore + ButtonCore + ButtonCore + ButtonCore + + src/main/java + + + src/main/resources + + *.properties + *.yml + *.csv + *.txt + + true + + + ButtonCore + + + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.2 + + + package + + shade + + + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + + + copy + compile + + copy-resources + + + target + + + src/main/resources + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + false + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + jitpack.io + https://jitpack.io/ + + + vault-repo + http://nexus.hc.to/content/repositories/pub_releases + + + ess-repo + http://repo.ess3.net/content/repositories/essrel/ + + + + + org.reflections + reflections + 0.9.10 + compile + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + provided + + + + commons-io + commons-io + 1.3.2 + provided + + + + com.github.TBMCPlugins.ButtonCore + Towny + master-SNAPSHOT + provided + + + com.github.milkbowl + VaultAPI + master-SNAPSHOT + provided + + + + org.javassist + javassist + 3.20.0-GA + + + org.mockito + mockito-core + 2.7.20 + + + + org.projectlombok + lombok + 1.16.16 + provided + + + com.github.TBMCPlugins.ButtonCore + ButtonProcessor + master-SNAPSHOT + compile + + + net.ess3 + Essentials + 2.13.1 + provided + + + + TBMCPlugins + https://github.com/TBMCPlugins + + + + internal.repo + Temporary Staging Repository + file://${project.build.directory}/mvn-repo/${project.name} + + + + + github + UTF-8 + + + https://github.com/TBMCPlugins/mvn-repo + scm:git:https://github.com/TBMCPlugins/mvn-repo.git + scm:git:https://github.com/TBMCPlugins/mvn-repo.git + \ No newline at end of file diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index d15d2a9..b2200a4 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -132,6 +132,7 @@ public class MainPlugin extends ButtonPlugin { @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (command.getName().equals("dontrunthiscmd")) return true; //Used in chat preprocess for console sender.sendMessage("§cThis command isn't available."); //In theory, unregistered commands use this method return true; } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index bc0e46d..5b26d9d 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -21,8 +21,17 @@ public abstract class ButtonPlugin extends JavaPlugin { protected abstract void pluginEnable(); + /** + * Called after the components are unregistered + */ protected abstract void pluginDisable(); + /** + * Called before the components are unregistered + */ + protected void pluginPreDisable() { + } + @Override public final void onEnable() { var section = super.getConfig().getConfigurationSection("global"); @@ -38,6 +47,7 @@ public abstract class ButtonPlugin extends JavaPlugin { @Override public final void onDisable() { try { + pluginPreDisable(); ComponentManager.unregComponents(this); pluginDisable(); saveConfig(); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java index 6ca2bbe..1a3a11f 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -62,6 +62,18 @@ public class ConfigData { //TODO: Save after a while 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(); + } return (T) val; } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index cb77556..c16d318 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -174,12 +174,12 @@ public abstract class Command2 { } private static String[] getHelpText(Method method, String[] ht, String subcommand) { //TODO: helpText[0]="§6---- "+helpText[0]+" ----"; - val str = Command2.class.getResourceAsStream("/commands.yml"); + val str = method.getDeclaringClass().getResourceAsStream("/commands.yml"); if (str == null) TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!")); else { YamlConfiguration yc = YamlConfiguration.loadConfiguration(new InputStreamReader(str)); //Generated by ButtonProcessor - val ccs = yc.getConfigurationSection(method.getDeclaringClass().getName()); + val ccs = yc.getConfigurationSection(method.getDeclaringClass().getCanonicalName()); if (ccs != null) { val cs = ccs.getConfigurationSection(method.getName()); if (cs != null) { @@ -191,11 +191,11 @@ public abstract class Command2 { both[ht.length] = "Usage: " + subcommand + " " + params; ht = both; } else - TBMCCoreAPI.SendException("Error while getting command data!", 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 - TBMCCoreAPI.SendException("Error while getting command data!", new Exception("cs is " + cs)); + TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("cs is " + cs)); } else - TBMCCoreAPI.SendException("Error while getting command data!", new Exception("ccs is " + ccs)); + TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("ccs is " + ccs + " - class: " + method.getDeclaringClass().getCanonicalName())); } return ht; } diff --git a/ButtonProcessor/pom.xml b/ButtonProcessor/pom.xml index ccc6888..975ead3 100755 --- a/ButtonProcessor/pom.xml +++ b/ButtonProcessor/pom.xml @@ -1,6 +1,12 @@ 4.0.0 + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + org.yaml