From ab24480f898130d31946a68ee5658f2351056145 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 2 Feb 2019 02:45:32 +0100 Subject: [PATCH 01/23] Separated commands and handlers WIP --- BuildConfigUpdater/BuildConfigUpdater.iml | 1 - .../buttondevteam/core/ComponentCommand.java | 8 +-- .../lib/architecture/ButtonPlugin.java | 3 + .../lib/architecture/Component.java | 6 +- .../java/buttondevteam/lib/chat/Command2.java | 67 +++---------------- .../buttondevteam/lib/chat/Command2MC.java | 10 +-- .../buttondevteam/lib/chat/ICommand2.java | 63 +++++++++++++++++ .../buttondevteam/lib/chat/ICommand2MC.java | 9 +++ 8 files changed, 98 insertions(+), 69 deletions(-) create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index f14440c..274b3de 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,7 +12,6 @@ - diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index 4aaceac..78aa6ea 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -2,8 +2,9 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; -import buttondevteam.lib.chat.Command2MC; +import buttondevteam.lib.chat.Command2.Subcommand; import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.ICommand2MC; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -15,10 +16,9 @@ import java.util.Optional; "§6---- Component command ----", "Can be used to enable/disable/list components" }) -public class ComponentCommand extends Command2MC { +public class ComponentCommand extends ICommand2MC { public ComponentCommand() { - addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); - + getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); } @Subcommand diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 5b26d9d..8ca1109 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -2,6 +2,7 @@ package buttondevteam.lib.architecture; import buttondevteam.core.ComponentManager; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.TBMCChatAPI; import lombok.AccessLevel; import lombok.Getter; @@ -11,6 +12,8 @@ import org.bukkit.plugin.java.JavaPlugin; import java.util.Stack; public abstract class ButtonPlugin extends JavaPlugin { + @Getter + private static Command2MC command2MC = new Command2MC(); @Getter(AccessLevel.PROTECTED) private IHaveConfig iConfig; /** diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index e052555..7d8a2d4 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.Command2MC; +import buttondevteam.lib.chat.ICommand2; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; @@ -197,8 +197,8 @@ public abstract class Component { * * @param commandBase Custom coded command class */ - protected final void registerCommand(Command2MC commandBase) { - Command2MC.registerCommand(commandBase); + protected final void registerCommand(ICommand2 commandBase) { + ButtonPlugin.getCommand2MC().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 c16d318..5e3cf01 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -25,29 +25,6 @@ import java.util.stream.Collectors; * 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. - * - * @param sender The sender which ran the command - * @param args All of the arguments passed as is - * @return The success of the command - */ - public boolean def(CommandSender sender, @TextArg String args) { - return false; - } - - /** - * Convenience method. Return with this. - * - * @param sender The sender of the command - * @param message The message to send to the sender - * @return Always true so that the usage isn't shown - */ - protected boolean respond(CommandSender sender, String message) { - sender.sendMessage(message); - return true; - } - /** * TODO: @CommandClass(helpText=...) * Parameters annotated with this receive all of the remaining arguments @@ -70,16 +47,11 @@ public abstract class Command2 { } @RequiredArgsConstructor - protected static class SubcommandData { + protected static class SubcommandData { public final Method method; public final T command; public final String[] helpText; } - - public Command2() { - path = getcmdpath(); - } - /** * Adds a param converter that obtains a specific object from a string parameter. * The converter may return null. @@ -88,11 +60,15 @@ public abstract class Command2 { * @param converter The converter to use * @param The type of the result */ - protected static void addParamConverter(Class cl, Function converter, HashMap, Function> map) { + public abstract void addParamConverter(Class cl, Function converter); + + protected void addParamConverter(Class cl, Function converter, HashMap, Function> map) { map.put(cl, converter); } - protected static boolean handleCommand(CommandSender sender, String commandline, + public abstract boolean handleCommand(CommandSender sender, String commandLine) throws Exception; + + protected 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(); @@ -147,7 +123,9 @@ public abstract class Command2 { return false; //Didn't handle } //TODO: Add to the help - protected static void registerCommand(T command, HashMap> subcommands, char commandChar) { + public abstract void registerCommand(ICommand2 command); + + protected 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); @@ -200,28 +178,5 @@ public abstract class Command2 { return ht; } - 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!
- * - * @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; - } + public abstract boolean hasPermission(CommandSender sender, ICommand2 command); } //TODO: Test support of Player instead of CommandSender diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index 715d078..e49ca0d 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -7,18 +7,18 @@ import java.util.function.Function; public class Command2MC extends Command2 { - private static HashMap> subcommands = new HashMap<>(); - private static HashMap, Function> paramConverters = new HashMap<>(); + private HashMap> subcommands = new HashMap<>(); + private HashMap, Function> paramConverters = new HashMap<>(); - public static boolean handleCommand(CommandSender sender, String commandLine) throws Exception { + public boolean handleCommand(CommandSender sender, String commandLine) throws Exception { return handleCommand(sender, commandLine, subcommands, paramConverters); } - public static void registerCommand(Command2MC command) { + public void registerCommand(ICommand2 command) { registerCommand(command, subcommands, '/'); } - public static void addParamConverter(Class cl, Function converter) { + public void addParamConverter(Class cl, Function converter) { addParamConverter(cl, converter, paramConverters); } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java new file mode 100644 index 0000000..3aa0a96 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -0,0 +1,63 @@ +package buttondevteam.lib.chat; + +import lombok.Getter; +import org.bukkit.command.CommandSender; + +import java.util.function.Function; + +public abstract class ICommand2 { + /** + * Default handler for commands, can be used to copy the args too. + * + * @param sender The sender which ran the command + * @param args All of the arguments passed as is + * @return The success of the command + */ + public boolean def(CommandSender sender, @Command2.TextArg String args) { + return false; + } + + /** + * Convenience method. Return with this. + * + * @param sender The sender of the command + * @param message The message to send to the sender + * @return Always true so that the usage isn't shown + */ + protected boolean respond(CommandSender sender, String message) { + sender.sendMessage(message); + return true; + } + + private final String path; + @Getter + private final Command2 manager; + + public ICommand2(Command2 manager) { + path = getcmdpath(); + this.manager = manager; + } + + /** + * The command's path, or name if top-level command.
+ * For example:
+ * "u admin updateplugin" or "u" for the top level one
+ * The path must be lowercase!
+ * + * @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; + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java new file mode 100644 index 0000000..d051597 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java @@ -0,0 +1,9 @@ +package buttondevteam.lib.chat; + +import buttondevteam.lib.architecture.ButtonPlugin; + +public class ICommand2MC extends ICommand2 { + public ICommand2MC() { + super(ButtonPlugin.getCommand2MC()); + } +} From e32805c1fc38ab994cdd7ebad1ee5b8e45048d0a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 3 Feb 2019 00:33:38 +0100 Subject: [PATCH 02/23] Listing subcommands, other fixes Member command converted Now requiring the permissions plugin Added support for optional arguments Automatically sending an error if parameter conversion fails Automatically sending the help text if there aren't enough args Automatically converting the first line of the help text to a header --- .../buttondevteam/core/ComponentCommand.java | 9 +- .../java/buttondevteam/core/MainPlugin.java | 8 +- .../buttondevteam/core/PlayerListener.java | 4 +- .../core/component/members/MemberCommand.java | 71 ++++++-------- .../component/members/MemberComponent.java | 4 +- .../lib/architecture/Component.java | 4 +- .../java/buttondevteam/lib/chat/Command2.java | 94 ++++++++++++++----- .../buttondevteam/lib/chat/Command2MC.java | 26 +++-- .../buttondevteam/lib/chat/CommandClass.java | 3 +- .../buttondevteam/lib/chat/ICommand2.java | 4 +- 10 files changed, 137 insertions(+), 90 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index 78aa6ea..a0e18f7 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -2,6 +2,7 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2.Subcommand; import buttondevteam.lib.chat.CommandClass; import buttondevteam.lib.chat.ICommand2MC; @@ -13,29 +14,27 @@ import org.bukkit.plugin.Plugin; import java.util.Optional; @CommandClass(modOnly = true, helpText = { - "§6---- Component command ----", + "Component command", "Can be used to enable/disable/list components" }) public class ComponentCommand extends ICommand2MC { public ComponentCommand() { - getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg)); + getManager().addParamConverter(Plugin.class, arg -> Bukkit.getPluginManager().getPlugin(arg), "Plugin not found!"); } @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) { + public boolean list(CommandSender sender, @Command2.OptionalArg 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); diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index b2200a4..6286e32 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -14,7 +14,6 @@ import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.architecture.ConfigData; import buttondevteam.lib.chat.Color; -import buttondevteam.lib.chat.Command2MC; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; @@ -30,7 +29,6 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.RegisteredServiceProvider; -import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -42,7 +40,6 @@ import java.util.logging.Logger; public class MainPlugin extends ButtonPlugin { public static MainPlugin Instance; - @Nullable public static Permission permission; public static boolean Test; public static Essentials ess; @@ -59,7 +56,8 @@ public class MainPlugin extends ButtonPlugin { Instance = this; PluginDescriptionFile pdf = getDescription(); logger = getLogger(); - setupPermissions(); + if (!setupPermissions()) + throw new NullPointerException("No permission plugin found!"); Test = getConfig().getBoolean("test", true); saveConfig(); Component.registerComponent(this, new PluginUpdaterComponent()); @@ -69,7 +67,7 @@ public class MainPlugin extends ButtonPlugin { Component.registerComponent(this, new MemberComponent()); Component.registerComponent(this, new TownyComponent()); ComponentManager.enableComponents(); - Command2MC.registerCommand(new ComponentCommand()); + getCommand2MC().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 c5146cd..073cb87 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.Command2MC; +import buttondevteam.lib.architecture.ButtonPlugin; 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(Command2MC.handleCommand(event.getSender(), event.getMessage())); + event.setCancelled(ButtonPlugin.getCommand2MC().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/component/members/MemberCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberCommand.java index d395d99..1059b26 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberCommand.java @@ -1,56 +1,47 @@ package buttondevteam.core.component.members; import buttondevteam.core.MainPlugin; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; -import buttondevteam.lib.chat.TBMCCommandBase; -import lombok.val; +import buttondevteam.lib.chat.ICommand2MC; import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; -@CommandClass(modOnly = true, path = "member") -public class MemberCommand extends TBMCCommandBase { - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { - if (args.length < 2) - return false; - final boolean add; - if (args[0].equalsIgnoreCase("add")) - add = true; - else if (args[0].equalsIgnoreCase("remove")) - add = false; - else - return false; +@CommandClass(modOnly = true, path = "member", helpText = { // + "Member command", // + "Add or remove server members.", // +}) +public class MemberCommand extends ICommand2MC { + private final MemberComponent component; + + public MemberCommand(MemberComponent component) { + getManager().addParamConverter(OfflinePlayer.class, Bukkit::getOfflinePlayer, "Player not found!"); + this.component = component; + } + + @Command2.Subcommand + public boolean add(CommandSender sender, OfflinePlayer player) { + return addRemove(sender, player, true); + } + + @Command2.Subcommand + public boolean remove(CommandSender sender, OfflinePlayer player) { + return addRemove(sender, player, false); + } + + public boolean addRemove(CommandSender sender, OfflinePlayer op, boolean add) { Bukkit.getScheduler().runTaskAsynchronously(MainPlugin.Instance, () -> { - if (MainPlugin.permission == null) { - sender.sendMessage("§cError: No permission plugin found!"); - return; - } - val op = Bukkit.getOfflinePlayer(args[1]); if (!op.hasPlayedBefore()) { sender.sendMessage("§cCannot find player or haven't played before."); return; } - if (add) { - if (MainPlugin.permission.playerAddGroup(null, op, "member")) - sender.sendMessage("§b" + op.getName() + " added as a member!"); - else - sender.sendMessage("§cFailed to add " + op.getName() + " as a member!"); - } else { - if (MainPlugin.permission.playerRemoveGroup(null, op, "member")) - sender.sendMessage("§b" + op.getName() + " removed as a member!"); - else - sender.sendMessage("§bFailed to remove " + op.getName() + " as a member!"); - } + if (add ? MainPlugin.permission.playerAddGroup(null, op, component.memberGroup().get()) + : MainPlugin.permission.playerRemoveGroup(null, op, component.memberGroup().get())) + sender.sendMessage("§b" + op.getName() + " " + (add ? "added" : "removed") + " as a member!"); + else + sender.sendMessage("§cFailed to " + (add ? "add" : "remove") + " " + op.getName() + " as a member!"); }); return true; } - - @Override - public String[] GetHelpText(String alias) { - return new String[]{ // - "06---- Member ----", // - "Add or remove server members.", // - "Usage: /member " // - }; - } } diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java index 0caeca7..1fff614 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java @@ -15,14 +15,14 @@ import java.util.Date; import static buttondevteam.core.MainPlugin.permission; public class MemberComponent extends Component implements Listener { - private ConfigData memberGroup() { + ConfigData memberGroup() { return getConfig().getData("memberGroup", "member"); } @Override protected void enable() { registerListener(this); - registerCommand(new MemberCommand()); + registerCommand(new MemberCommand(this)); } @Override diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 7d8a2d4..6e0a9c3 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.ICommand2; +import buttondevteam.lib.chat.ICommand2MC; import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; @@ -197,7 +197,7 @@ public abstract class Component { * * @param commandBase Custom coded command class */ - protected final void registerCommand(ICommand2 commandBase) { + protected final void registerCommand(ICommand2MC commandBase) { ButtonPlugin.getCommand2MC().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 5e3cf01..899fdbb 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -22,11 +22,13 @@ import java.util.stream.Collectors; /** * The method name is the subcommand, use underlines (_) to add further subcommands. - * The args may be null if the conversion failed. + * The args may be null if the conversion failed and it's optional. */ -public abstract class Command2 { +public abstract class Command2 { + protected Command2() { + } + /** - * TODO: @CommandClass(helpText=...) * Parameters annotated with this receive all of the remaining arguments */ @Target(ElementType.PARAMETER) @@ -46,12 +48,24 @@ public abstract class Command2 { String[] helpText() default {}; } + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.RUNTIME) + public @interface OptionalArg { + } + @RequiredArgsConstructor protected static class SubcommandData { public final Method method; public final T command; public final String[] helpText; } + + @RequiredArgsConstructor + protected static class ParamConverter { + public final Function converter; + public final String errormsg; + } + /** * Adds a param converter that obtains a specific object from a string parameter. * The converter may return null. @@ -60,20 +74,29 @@ public abstract class Command2 { * @param converter The converter to use * @param The type of the result */ - public abstract void addParamConverter(Class cl, Function converter); + public abstract void addParamConverter(Class cl, Function converter, String errormsg); - protected void addParamConverter(Class cl, Function converter, HashMap, Function> map) { - map.put(cl, converter); + protected void addParamConverter(Class cl, Function converter, String errormsg, HashMap, ParamConverter> map) { + map.put(cl, new ParamConverter<>(converter, errormsg)); } public abstract boolean handleCommand(CommandSender sender, String commandLine) throws Exception; - protected boolean handleCommand(CommandSender sender, String commandline, - HashMap> subcommands, HashMap, Function> paramConverters) throws Exception { + protected boolean handleCommand(CommandSender sender, String commandline, + HashMap> subcommands, + HashMap, ParamConverter> paramConverters) throws Exception { for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { String subcommand = commandline.substring(0, i).toLowerCase(); - SubcommandData sd = subcommands.get(subcommand); //O(1) - if (sd == null) continue; //TODO: This will run each time someone runs any command + SubcommandData sd = subcommands.get(subcommand); //O(1) + if (sd == null) continue; + if (sd.method == null || sd.command == null) { //Main command not registered, but we have subcommands + sender.sendMessage(sd.helpText); + return true; + } + if (!hasPermission(sender, sd.command)) { + sender.sendMessage("§cYou don't have permission to use this command"); + return true; + } val params = new ArrayList(sd.method.getParameterCount()); int j = subcommand.length(), pj; Class[] parameterTypes = sd.method.getParameterTypes(); @@ -91,12 +114,18 @@ public abstract class Command2 { sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command."); return true; } + val paramArr = sd.method.getParameters(); 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 + if (paramArr[i1].isAnnotationPresent(OptionalArg.class)) { + params.add(null); + continue; //Fill the remaining params with nulls + } else { + sender.sendMessage(sd.helpText); //Required param missing + return true; + } } j = commandline.indexOf(' ', j + 1); //End index if (j == -1) //Last parameter @@ -109,7 +138,12 @@ public abstract class Command2 { 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)); + val cparam = conv.converter.apply(param); + if (cparam == null) { + sender.sendMessage(conv.errormsg); //Param conversion failed - ex. plugin not found + return true; + } + params.add(cparam); } //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) @@ -123,21 +157,26 @@ public abstract class Command2 { return false; //Didn't handle } //TODO: Add to the help - public abstract void registerCommand(ICommand2 command); + public abstract void registerCommand(TC command); - protected void registerCommand(T command, HashMap> subcommands, char commandChar) { + protected void registerCommand(TC command, HashMap> subcommands, char commandChar) { val path = command.getCommandPath(); + int x = path.indexOf(' '); + val mainPath = commandChar + path.substring(0, x == -1 ? path.length() : x); + //var scmdmap = subcommandStrings.computeIfAbsent(mainPath, k -> new HashSet<>()); //Used to display subcommands + val scmdHelpList = new ArrayList(); + Method mainMethod = null; try { //Register the default handler first so it can be reliably overwritten - val method = command.getClass().getMethod("def", CommandSender.class, String.class); + mainMethod = 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: " + commandChar + path; //TODO: Print subcommands - ht = both; - subcommands.put(commandChar + path, new SubcommandData<>(method, command, ht)); //TODO: Disable components when the plugin is disabled + if (ht.length > 0) + ht[0] = "§6---- " + ht[0] + " ----"; + scmdHelpList.addAll(Arrays.asList(ht)); + scmdHelpList.add("§6Subcommands:"); } catch (Exception 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) { @@ -147,15 +186,22 @@ public abstract class Command2 { (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 + scmdHelpList.add(subcommand); } } + if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class + subcommands.put(commandChar + path, new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0]))); + if (mainMethod != null && !subcommands.containsKey(mainPath)) //Main command, typically the same as the above + subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0]))); } - private static String[] getHelpText(Method method, String[] ht, String subcommand) { //TODO: helpText[0]="§6---- "+helpText[0]+" ----"; + private String[] getHelpText(Method method, String[] ht, String subcommand) { val str = method.getDeclaringClass().getResourceAsStream("/commands.yml"); if (str == null) TBMCCoreAPI.SendException("Error while getting command data!", new Exception("Resource not found!")); else { + if (ht.length > 0) + ht[0] = "§6---- " + ht[0] + " ----"; YamlConfiguration yc = YamlConfiguration.loadConfiguration(new InputStreamReader(str)); //Generated by ButtonProcessor val ccs = yc.getConfigurationSection(method.getDeclaringClass().getCanonicalName()); if (ccs != null) { @@ -166,7 +212,7 @@ public abstract class Command2 { 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; + both[ht.length] = "§6Usage:§r " + subcommand + " " + params; ht = both; } else TBMCCoreAPI.SendException("Error while getting command data for " + method + "!", new Exception("Method '" + method.toString() + "' != " + mname + " or params is " + params)); @@ -178,5 +224,5 @@ public abstract class Command2 { return ht; } - public abstract boolean hasPermission(CommandSender sender, ICommand2 command); + public abstract boolean hasPermission(CommandSender sender, TC command); } //TODO: Test support of Player instead of CommandSender diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index e49ca0d..10d3035 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -1,24 +1,36 @@ package buttondevteam.lib.chat; +import buttondevteam.core.MainPlugin; import org.bukkit.command.CommandSender; import java.util.HashMap; import java.util.function.Function; -public class Command2MC extends Command2 { - - private HashMap> subcommands = new HashMap<>(); - private HashMap, Function> paramConverters = new HashMap<>(); +public class Command2MC extends Command2 { + private HashMap> subcommands = new HashMap<>(); + private HashMap, ParamConverter> paramConverters = new HashMap<>(); + @Override public boolean handleCommand(CommandSender sender, String commandLine) throws Exception { return handleCommand(sender, commandLine, subcommands, paramConverters); } - public void registerCommand(ICommand2 command) { + @Override + public void registerCommand(ICommand2MC command) { registerCommand(command, subcommands, '/'); } - public void addParamConverter(Class cl, Function converter) { - addParamConverter(cl, converter, paramConverters); + @Override + public boolean hasPermission(CommandSender sender, ICommand2MC command) { + return MainPlugin.permission.has(sender, "thorpe.command." + command.getCommandPath().replace(' ', '.')); + } + + /** + * Automatically colors the message red. + * {@see super#addParamConverter} + */ + @Override + public void addParamConverter(Class cl, Function converter, String errormsg) { + addParamConverter(cl, converter, "§c" + errormsg, paramConverters); } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java index ddfff22..aa497fd 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/CommandClass.java @@ -38,7 +38,8 @@ public @interface CommandClass { boolean excludeFromPath() default false; /** - * The help text to show for the players. A usage message will be also shown below it. + * The help text to show for the players. A usage message will be also shown below it.
+ * The fist line will be converted to a header. * * @return The help text */ diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index 3aa0a96..b0da534 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -31,9 +31,9 @@ public abstract class ICommand2 { private final String path; @Getter - private final Command2 manager; + private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) - public ICommand2(Command2 manager) { + public ICommand2(Command2 manager) { path = getcmdpath(); this.manager = manager; } From e3df62af7e08a6a41137f06ba7c12ce0f19bb044 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 9 Feb 2019 00:23:20 +0100 Subject: [PATCH 03/23] Supporting any sender for the commands --- .../buttondevteam/core/PlayerListener.java | 3 ++- .../java/buttondevteam/lib/chat/Command2.java | 11 +++++----- .../buttondevteam/lib/chat/Command2MC.java | 9 ++++----- .../lib/chat/Command2MCSender.java | 20 +++++++++++++++++++ .../lib/chat/Command2Sender.java | 7 +++++++ .../buttondevteam/lib/chat/ICommand2.java | 4 ++-- 6 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MCSender.java create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/chat/Command2Sender.java diff --git a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java index 073cb87..d151e51 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java +++ b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java @@ -4,6 +4,7 @@ import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.ButtonPlugin; +import buttondevteam.lib.chat.Command2MCSender; import buttondevteam.lib.player.TBMCPlayerBase; import lombok.val; import org.bukkit.Bukkit; @@ -64,7 +65,7 @@ public class PlayerListener implements Listener { public void onTBMCPreprocess(TBMCCommandPreprocessEvent event) { if (event.isCancelled()) return; try { - event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(event.getSender(), event.getMessage())); + event.setCancelled(ButtonPlugin.getCommand2MC().handleCommand(new Command2MCSender(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/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 899fdbb..ba6d8c5 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -24,7 +24,7 @@ import java.util.stream.Collectors; * The method name is the subcommand, use underlines (_) to add further subcommands. * The args may be null if the conversion failed and it's optional. */ -public abstract class Command2 { +public abstract class Command2 { protected Command2() { } @@ -80,9 +80,9 @@ public abstract class Command2 { map.put(cl, new ParamConverter<>(converter, errormsg)); } - public abstract boolean handleCommand(CommandSender sender, String commandLine) throws Exception; + public abstract boolean handleCommand(TP sender, String commandLine) throws Exception; - protected boolean handleCommand(CommandSender sender, String commandline, + protected boolean handleCommand(TP sender, String commandline, HashMap> subcommands, HashMap, ParamConverter> paramConverters) throws Exception { for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { @@ -107,7 +107,8 @@ public abstract class Command2 { 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 + && sender instanceof Command2MCSender + && (cg = ChromaGamerBase.getFromSender(((Command2MCSender) sender).getSender())) != null && cg.getClass() == sendertype) //The command expects a user of our system params.add(cg); else { @@ -224,5 +225,5 @@ public abstract class Command2 { return ht; } - public abstract boolean hasPermission(CommandSender sender, TC command); + public abstract boolean hasPermission(TP sender, TC command); } //TODO: Test support of Player instead of CommandSender diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index 10d3035..9e7e004 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -1,17 +1,16 @@ package buttondevteam.lib.chat; import buttondevteam.core.MainPlugin; -import org.bukkit.command.CommandSender; import java.util.HashMap; import java.util.function.Function; -public class Command2MC extends Command2 { +public class Command2MC extends Command2 { private HashMap> subcommands = new HashMap<>(); private HashMap, ParamConverter> paramConverters = new HashMap<>(); @Override - public boolean handleCommand(CommandSender sender, String commandLine) throws Exception { + public boolean handleCommand(Command2MCSender sender, String commandLine) throws Exception { return handleCommand(sender, commandLine, subcommands, paramConverters); } @@ -21,8 +20,8 @@ public class Command2MC extends Command2 { } @Override - public boolean hasPermission(CommandSender sender, ICommand2MC command) { - return MainPlugin.permission.has(sender, "thorpe.command." + command.getCommandPath().replace(' ', '.')); + public boolean hasPermission(Command2MCSender sender, ICommand2MC command) { + return MainPlugin.permission.has(sender.getSender(), "thorpe.command." + command.getCommandPath().replace(' ', '.')); } /** diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MCSender.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MCSender.java new file mode 100644 index 0000000..059d953 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MCSender.java @@ -0,0 +1,20 @@ +package buttondevteam.lib.chat; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.bukkit.command.CommandSender; + +@RequiredArgsConstructor +public class Command2MCSender implements Command2Sender { + private @Getter final CommandSender sender; + + @Override + public void sendMessage(String message) { + sender.sendMessage(message); + } + + @Override + public void sendMessage(String[] message) { + sender.sendMessage(message); + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2Sender.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2Sender.java new file mode 100644 index 0000000..ebb2b66 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2Sender.java @@ -0,0 +1,7 @@ +package buttondevteam.lib.chat; + +public interface Command2Sender { //We don't need the 'extras' of CommandSender on Discord + void sendMessage(String message); + + void sendMessage(String[] message); +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index b0da534..6ee2264 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -31,9 +31,9 @@ public abstract class ICommand2 { private final String path; @Getter - private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) + private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) - public ICommand2(Command2 manager) { + public ICommand2(Command2 manager) { path = getcmdpath(); this.manager = manager; } From 6b99bc22d73bcdf789bb06469cba12f7dfc9b185 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 12 Feb 2019 22:25:50 +0100 Subject: [PATCH 04/23] Added broadcast toggles TBMCPlugins/DiscordPlugin#89 --- .../component/channel/ChannelComponent.java | 6 ++- .../core/component/channel/ChatRoom.java | 4 +- .../lib/TBMCSystemChatEvent.java | 38 ++++++++++++++++++- .../buttondevteam/lib/chat/TBMCChatAPI.java | 4 +- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java index 083633d..14aff26 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java @@ -1,22 +1,26 @@ package buttondevteam.core.component.channel; +import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import org.bukkit.plugin.java.JavaPlugin; public class ChannelComponent extends Component { + static TBMCSystemChatEvent.BroadcastTarget roomJoinLeave; @Override protected void register(JavaPlugin plugin) { super.register(plugin); + roomJoinLeave = TBMCSystemChatEvent.BroadcastTarget.add("roomJoinLeave"); //Even if it's disabled, global channels continue to work } @Override protected void unregister(JavaPlugin plugin) { super.unregister(plugin); + TBMCSystemChatEvent.BroadcastTarget.remove(roomJoinLeave); + roomJoinLeave = null; } @Override protected void enable() { - } @Override diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java index a086a42..4172d5f 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java @@ -17,11 +17,11 @@ public class ChatRoom extends Channel { public void joinRoom(CommandSender sender) { usersInRoom.add(sender); - TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " joined the room"); + TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " joined the room", ChannelComponent.roomJoinLeave); } public void leaveRoom(CommandSender sender) { usersInRoom.remove(sender); - TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " left the room"); + TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " left the room", ChannelComponent.roomJoinLeave); } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java index 80cd634..df04be4 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java @@ -1,10 +1,18 @@ package buttondevteam.lib; import buttondevteam.core.component.channel.Channel; +import lombok.AccessLevel; import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.val; import org.bukkit.command.CommandSender; import org.bukkit.event.HandlerList; +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Objects; +import java.util.stream.Stream; + /** * Make sure to only send the message to users who {@link #shouldSendTo(CommandSender)} returns true. * @@ -14,15 +22,17 @@ import org.bukkit.event.HandlerList; @Getter public class TBMCSystemChatEvent extends TBMCChatEventBase { private final String[] exceptions; + private final BroadcastTarget target; private boolean handled; public void setHandled() { handled = true; } - public TBMCSystemChatEvent(Channel channel, String message, int score, String groupid, String[] exceptions) { // TODO: Rich message + public TBMCSystemChatEvent(Channel channel, String message, int score, String groupid, String[] exceptions, BroadcastTarget target) { // TODO: Rich message super(channel, message, score, groupid); this.exceptions = exceptions; + this.target = target; } private static final HandlerList handlers = new HandlerList(); @@ -35,4 +45,30 @@ public class TBMCSystemChatEvent extends TBMCChatEventBase { public static HandlerList getHandlerList() { return handlers; } + + @RequiredArgsConstructor(access = AccessLevel.PRIVATE) + public static class BroadcastTarget { + private final @Getter String name; + private static final HashSet targets = new HashSet<>(); + public static final BroadcastTarget ALL = new BroadcastTarget("ALL"); + + public static BroadcastTarget add(String name) { + val bt = new BroadcastTarget(Objects.requireNonNull(name)); + targets.add(bt); + return bt; + } + + public static void remove(BroadcastTarget target) { + targets.remove(target); + } + + @Nullable + public static BroadcastTarget get(String name) { + return targets.stream().filter(bt -> bt.name.equals(name)).findAny().orElse(null); + } + + public static Stream stream() { + return targets.stream(); + } + } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java index d143d8b..21f772e 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/TBMCChatAPI.java @@ -311,12 +311,12 @@ public class TBMCChatAPI { * @param exceptions Platforms where this message shouldn't be sent (same as {@link ChatMessage#getOrigin()} * @return The event cancelled state */ - public static boolean SendSystemMessage(Channel channel, RecipientTestResult rtr, String message, String... exceptions) { + public static boolean SendSystemMessage(Channel channel, RecipientTestResult rtr, String message, TBMCSystemChatEvent.BroadcastTarget target, String... exceptions) { if (!Channel.getChannelList().contains(channel)) throw new RuntimeException("Channel " + channel.DisplayName().get() + " not registered!"); if (!channel.Enabled().get()) return true; //Cancel sending - TBMCSystemChatEvent event = new TBMCSystemChatEvent(channel, message, rtr.score, rtr.groupID, exceptions); + TBMCSystemChatEvent event = new TBMCSystemChatEvent(channel, message, rtr.score, rtr.groupID, exceptions, target); Bukkit.getPluginManager().callEvent(event); return event.isCancelled(); } From d245d21a8443cb075056191250b6f7c6711fe88a Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 15 Feb 2019 23:48:15 +0100 Subject: [PATCH 05/23] Command system fixes Removed Vault repo as it seems to be offline and wasn't even used Fixed CommandSender type, no subcommands handling Made the default handler use the correct sender type (actually, the generic type might be completely unnecessary but oh well) No longer checking param types to match methods (needed for generic types) --- BuildConfigUpdater/BuildConfigUpdater.iml | 1 + ButtonCore/pom.xml | 8 ++++---- .../main/java/buttondevteam/lib/chat/Command2.java | 14 ++++++++++---- .../java/buttondevteam/lib/chat/ICommand2.java | 11 +++++------ .../java/buttondevteam/lib/chat/ICommand2MC.java | 2 +- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index 274b3de..f14440c 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,6 +12,7 @@ + diff --git a/ButtonCore/pom.xml b/ButtonCore/pom.xml index e044b9a..013fe73 100755 --- a/ButtonCore/pom.xml +++ b/ButtonCore/pom.xml @@ -103,10 +103,10 @@ jitpack.io https://jitpack.io/ - - vault-repo - http://nexus.hc.to/content/repositories/pub_releases - + ess-repo http://repo.ess3.net/content/repositories/essrel/ diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index ba6d8c5..3cd2a35 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -18,7 +18,6 @@ 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. @@ -106,6 +105,8 @@ public abstract class Command2 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 (CommandSender.class.isAssignableFrom(sendertype) && sender instanceof Command2MCSender) + params.add(((Command2MCSender) sender).getSender()); else if (ChromaGamerBase.class.isAssignableFrom(sendertype) && sender instanceof Command2MCSender && (cg = ChromaGamerBase.getFromSender(((Command2MCSender) sender).getSender())) != null @@ -167,8 +168,9 @@ public abstract class Command2 //var scmdmap = subcommandStrings.computeIfAbsent(mainPath, k -> new HashSet<>()); //Used to display subcommands val scmdHelpList = new ArrayList(); Method mainMethod = null; + boolean nosubs = true; try { //Register the default handler first so it can be reliably overwritten - mainMethod = command.getClass().getMethod("def", CommandSender.class, String.class); + mainMethod = command.getClass().getMethod("def", Command2Sender.class, String.class); val cc = command.getClass().getAnnotation(CommandClass.class); var ht = cc == null ? new String[0] : cc.helpText(); if (ht.length > 0) @@ -188,8 +190,11 @@ public abstract class Command2 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 scmdHelpList.add(subcommand); + nosubs = false; } } + if (nosubs && scmdHelpList.size() > 0) + scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class subcommands.put(commandChar + path, new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0]))); if (mainMethod != null && !subcommands.containsKey(mainPath)) //Main command, typically the same as the above @@ -210,8 +215,9 @@ public abstract class Command2 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) { + //val goodname = method.getName() + "(" + Arrays.stream(method.getGenericParameterTypes()).map(cl -> cl.getTypeName()).collect(Collectors.joining(",")) + ")"; + int i = mname.indexOf('('); //Check only the name - the whole method is still stored for backwards compatibility and in case it may be useful + if (i != -1 && method.getName().equals(mname.substring(0, i)) && params != null) { String[] both = Arrays.copyOf(ht, ht.length + 1); both[ht.length] = "§6Usage:§r " + subcommand + " " + params; ht = both; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index 6ee2264..588c744 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -1,11 +1,10 @@ package buttondevteam.lib.chat; import lombok.Getter; -import org.bukkit.command.CommandSender; import java.util.function.Function; -public abstract class ICommand2 { +public abstract class ICommand2 { /** * Default handler for commands, can be used to copy the args too. * @@ -13,7 +12,7 @@ public abstract class ICommand2 { * @param args All of the arguments passed as is * @return The success of the command */ - public boolean def(CommandSender sender, @Command2.TextArg String args) { + public boolean def(TP sender, @Command2.TextArg String args) { return false; } @@ -24,16 +23,16 @@ public abstract class ICommand2 { * @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) { + protected boolean respond(TP sender, String message) { sender.sendMessage(message); return true; } private final String path; @Getter - private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) + private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) - public ICommand2(Command2 manager) { + public ICommand2(Command2 manager) { path = getcmdpath(); this.manager = manager; } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java index d051597..4ad997b 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2MC.java @@ -2,7 +2,7 @@ package buttondevteam.lib.chat; import buttondevteam.lib.architecture.ButtonPlugin; -public class ICommand2MC extends ICommand2 { +public class ICommand2MC extends ICommand2 { public ICommand2MC() { super(ButtonPlugin.getCommand2MC()); } From a91786cf0d8649f4252e37a58ab07006934d7735 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Feb 2019 14:04:41 +0100 Subject: [PATCH 06/23] Added support for dynamic help text --- .../java/buttondevteam/lib/chat/Command2.java | 6 ++---- .../java/buttondevteam/lib/chat/ICommand2.java | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 3cd2a35..c5c2f5a 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -181,10 +181,8 @@ public abstract class Command2 TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); } 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 + var ht = command.getHelpText(method); + if (ht != null) { 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); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index 588c744..7d46821 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -1,7 +1,9 @@ package buttondevteam.lib.chat; import lombok.Getter; +import lombok.val; +import java.lang.reflect.Method; import java.util.function.Function; public abstract class ICommand2 { @@ -28,6 +30,21 @@ public abstract class ICommand2 { return true; } + /** + * Return null to not add any help text, return an empty array to only print subcommands.
+ * By default, returns null if the Subcommand annotation is not present and returns an empty array if no help text can be found. + * + * @param method The method of the subcommand + * @return The help text, empty array or null + */ + public String[] getHelpText(Method method) { + val ann = method.getAnnotation(Command2.Subcommand.class); + if (ann == null) + return null; + val cc = getClass().getAnnotation(CommandClass.class); + return ann.helpText().length != 0 || cc == null ? ann.helpText() : cc.helpText(); //If cc is null then it's empty array + } + private final String path; @Getter private final Command2 manager; //TIL that if I use a raw type on a variable then none of the type args will work (including what's defined on a method, not on the type) From 95796a1b3ef694ab2f54231774ca3017d1c98ce4 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sun, 17 Feb 2019 02:22:06 +0100 Subject: [PATCH 07/23] Command fix, using the brtoggles DiscordPlugin#89 Started #60 Should have committed this earlier --- .../core/component/channel/ChatRoom.java | 3 ++- .../component/restart/PrimeRestartCommand.java | 9 +++++++-- .../core/component/restart/RestartComponent.java | 14 +++++++++----- .../component/restart/ScheduledRestartCommand.java | 7 ++++++- .../buttondevteam/lib/TBMCSystemChatEvent.java | 2 +- .../lib/architecture/ButtonPlugin.java | 2 ++ .../buttondevteam/lib/architecture/Component.java | 1 + .../main/java/buttondevteam/lib/chat/Command2.java | 4 +++- .../java/buttondevteam/lib/chat/ICommand2.java | 5 +---- 9 files changed, 32 insertions(+), 15 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java index 4172d5f..428007a 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChatRoom.java @@ -1,5 +1,6 @@ package buttondevteam.core.component.channel; +import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.chat.Color; import buttondevteam.lib.chat.TBMCChatAPI; import org.bukkit.command.CommandSender; @@ -17,7 +18,7 @@ public class ChatRoom extends Channel { public void joinRoom(CommandSender sender) { usersInRoom.add(sender); - TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " joined the room", ChannelComponent.roomJoinLeave); + TBMCChatAPI.SendSystemMessage(this, RecipientTestResult.ALL, sender.getName() + " joined the room", TBMCSystemChatEvent.BroadcastTarget.ALL); //Always show message in the same kind of channel } public void leaveRoom(CommandSender sender) { diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java index 32773ab..f387b1d 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java @@ -1,26 +1,31 @@ package buttondevteam.core.component.restart; +import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @CommandClass(path = "primerestart", modOnly = true) +@RequiredArgsConstructor public class PrimeRestartCommand extends TBMCCommandBase { + private final RestartComponent component; @Override public boolean OnCommand(CommandSender sender, String alias, String[] args) { loud = args.length > 0; if (Bukkit.getOnlinePlayers().size() > 0) { sender.sendMessage("§bPlayers online, restart delayed."); if (loud) - Bukkit.broadcastMessage(ChatColor.DARK_RED + "The server will restart as soon as nobody is online."); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, ChatColor.DARK_RED + "The server will restart as soon as nobody is online.", component.restartBroadcast); plsrestart = true; } else { sender.sendMessage("§bNobody is online. Restarting now."); if (loud) - Bukkit.broadcastMessage("§cNobody is online. Restarting server."); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§cNobody is online. Restarting server.", component.restartBroadcast); Bukkit.spigot().restart(); } return true; diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java index e49e3b2..332f9dc 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java @@ -1,5 +1,7 @@ package buttondevteam.core.component.restart; +import buttondevteam.core.component.channel.Channel; +import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.IFakePlayer; import buttondevteam.lib.chat.TBMCChatAPI; @@ -13,17 +15,19 @@ public class RestartComponent extends Component implements Listener { @Override public void enable() { //TODO: Permissions for the commands - TBMCChatAPI.AddCommand(this, new ScheduledRestartCommand()); - TBMCChatAPI.AddCommand(this, new PrimeRestartCommand()); + TBMCChatAPI.AddCommand(this, new ScheduledRestartCommand(this)); + TBMCChatAPI.AddCommand(this, new PrimeRestartCommand(this)); registerListener(this); + restartBroadcast = TBMCSystemChatEvent.BroadcastTarget.add("restartCountdown"); } @Override public void disable() { - + TBMCSystemChatEvent.BroadcastTarget.remove(restartBroadcast); } private long lasttime = 0; + TBMCSystemChatEvent.BroadcastTarget restartBroadcast; @EventHandler public void onPlayerLeave(PlayerQuitEvent event) { @@ -32,12 +36,12 @@ public class RestartComponent extends Component implements Listener { && !event.getQuitMessage().equalsIgnoreCase("Server is restarting")) { if (Bukkit.getOnlinePlayers().size() <= 1) { if (PrimeRestartCommand.isLoud()) - Bukkit.broadcastMessage("§cNobody is online anymore. Restarting."); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§cNobody is online anymore. Restarting.", restartBroadcast); Bukkit.spigot().restart(); } else if (!(event.getPlayer() instanceof IFakePlayer) && System.nanoTime() - 10 * 1000000000L - lasttime > 0) { //Ten seconds passed since last reminder lasttime = System.nanoTime(); if (PrimeRestartCommand.isLoud()) - Bukkit.broadcastMessage(ChatColor.DARK_RED + "The server will restart as soon as nobody is online."); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, ChatColor.DARK_RED + "The server will restart as soon as nobody is online.", restartBroadcast); } } } diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java index fea469e..3f83e48 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java @@ -1,10 +1,13 @@ package buttondevteam.core.component.restart; import buttondevteam.core.MainPlugin; +import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.ScheduledServerRestartEvent; import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.TBMCChatAPI; import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.boss.BarColor; @@ -15,12 +18,14 @@ import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitTask; @CommandClass(modOnly = true, path = "schrestart") +@RequiredArgsConstructor public class ScheduledRestartCommand extends TBMCCommandBase { @Getter @Setter private int restartCounter; private BukkitTask restarttask; private volatile BossBar restartbar; + private final RestartComponent component; @Override public boolean OnCommand(CommandSender sender, String alias, String[] args) { @@ -51,7 +56,7 @@ public class ScheduledRestartCommand extends TBMCCommandBase { Bukkit.spigot().restart(); } if (restartCounter % 200 == 0) - Bukkit.broadcastMessage("§c-- The server is restarting in " + restartCounter / 20 + " seconds! (/press)"); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§c-- The server is restarting in " + restartCounter / 20 + " seconds! (/press)", component.restartBroadcast); restartbar.setProgress(restartCounter / (double) restarttime); restartbar.setTitle(String.format("Server restart in %.2f", restartCounter / 20f)); restartCounter--; diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java index df04be4..f5d5a0f 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCSystemChatEvent.java @@ -64,7 +64,7 @@ public class TBMCSystemChatEvent extends TBMCChatEventBase { @Nullable public static BroadcastTarget get(String name) { - return targets.stream().filter(bt -> bt.name.equals(name)).findAny().orElse(null); + return targets.stream().filter(bt -> bt.name.equalsIgnoreCase(name)).findAny().orElse(null); } public static Stream stream() { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 8ca1109..a4b5bdf 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -16,6 +16,8 @@ public abstract class ButtonPlugin extends JavaPlugin { private static Command2MC command2MC = new Command2MC(); @Getter(AccessLevel.PROTECTED) private IHaveConfig iConfig; + @Getter(AccessLevel.PROTECTED) + private IHaveConfig data; //TODO /** * Used to unregister components in the right order */ diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 6e0a9c3..5494c78 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -31,6 +31,7 @@ public abstract class Component { @NonNull private @Getter IHaveConfig config; + private @Getter IHaveConfig data; //TODO public final ConfigData shouldBeEnabled() { return config.getData("enabled", true); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index c5c2f5a..9b8ad31 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -181,7 +181,9 @@ public abstract class Command2 TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); } for (val method : command.getClass().getMethods()) { - var ht = command.getHelpText(method); + val ann = method.getAnnotation(Subcommand.class); + if (ann == null) continue; //Don't call the method on non-subcommands because they're not in the yaml + var ht = command.getHelpText(method, ann); if (ht != null) { 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' diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index 7d46821..781efe4 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -37,10 +37,7 @@ public abstract class ICommand2 { * @param method The method of the subcommand * @return The help text, empty array or null */ - public String[] getHelpText(Method method) { - val ann = method.getAnnotation(Command2.Subcommand.class); - if (ann == null) - return null; + public String[] getHelpText(Method method, Command2.Subcommand ann) { val cc = getClass().getAnnotation(CommandClass.class); return ann.helpText().length != 0 || cc == null ? ann.helpText() : cc.helpText(); //If cc is null then it's empty array } From 9022d87dc423284f7c429f4c45e7b4cc8a5312d7 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 20 Feb 2019 13:39:43 +0100 Subject: [PATCH 08/23] Adding project files --- BuildConfigUpdater/BuildConfigUpdater.iml | 1 - ButtonCore/.gitignore | 2 +- ...1) (com.github.TBMCPlugins.ButtonCore).iml | 37 +++++++++++++++++++ ButtonProcessor/ButtonProcessor.iml | 1 + 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index f14440c..274b3de 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,7 +12,6 @@ - diff --git a/ButtonCore/.gitignore b/ButtonCore/.gitignore index 86472d4..8983379 100755 --- a/ButtonCore/.gitignore +++ b/ButtonCore/.gitignore @@ -218,7 +218,7 @@ pip-log.txt .mr.developer.cfg .metadata/* TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar -*.iml +#*.iml *.name .idea/compiler.xml *.xml diff --git a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml new file mode 100644 index 0000000..249c28a --- /dev/null +++ b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index 35bfd14..3c6a51e 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -13,6 +13,7 @@ + From d19936309fbda81d3f22aad2545a15c754b56707 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 20 Feb 2019 15:20:32 +0100 Subject: [PATCH 09/23] Added Maven plugin versions --- .../ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml | 2 +- ButtonCore/pom.xml | 2 ++ ButtonProcessor/ButtonProcessor.iml | 1 - ButtonProcessor/pom.xml | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml index 249c28a..692ea56 100644 --- a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml +++ b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml @@ -1,5 +1,5 @@ - + diff --git a/ButtonCore/pom.xml b/ButtonCore/pom.xml index 013fe73..0bd3d00 100755 --- a/ButtonCore/pom.xml +++ b/ButtonCore/pom.xml @@ -75,6 +75,7 @@ org.apache.maven.plugins maven-surefire-plugin + 3.0.0-M3 false @@ -83,6 +84,7 @@ org.apache.maven.plugins maven-source-plugin + 3.0.1 attach-sources diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index 3c6a51e..35bfd14 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -13,7 +13,6 @@ - diff --git a/ButtonProcessor/pom.xml b/ButtonProcessor/pom.xml index 975ead3..401e62c 100755 --- a/ButtonProcessor/pom.xml +++ b/ButtonProcessor/pom.xml @@ -46,6 +46,7 @@ org.apache.maven.plugins maven-surefire-plugin + 3.0.0-M3 false From e4f5850ad6922b6a0c848a8e562b2ffdb915bb8d Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 22 Feb 2019 00:40:11 +0100 Subject: [PATCH 10/23] Component stuff, command stuff Made the components return correctly-typed plugins Added support for showing commands Moved the subcommands and paramconverters to the base class --- BuildConfigUpdater/BuildConfigUpdater.iml | 2 ++ .../buttondevteam/core/ComponentCommand.java | 2 +- .../lib/TBMCCommandPreprocessEvent.java | 2 +- .../lib/architecture/Component.java | 14 +++++----- .../java/buttondevteam/lib/chat/Command2.java | 26 ++++++++++++------- .../buttondevteam/lib/chat/Command2MC.java | 13 ++-------- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index 274b3de..72a504c 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,6 +12,8 @@ + + diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index a0e18f7..4e4a998 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -54,7 +54,7 @@ public class ComponentCommand extends ICommand2MC { return true; } - private Optional getComponentOrError(Plugin plugin, String arg, CommandSender sender) { + 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(); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java b/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java index a72c0b7..d7cd103 100755 --- a/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/TBMCCommandPreprocessEvent.java @@ -25,7 +25,7 @@ public class TBMCCommandPreprocessEvent extends Event implements Cancellable { public TBMCCommandPreprocessEvent(CommandSender sender, String message) { this.sender = sender; - this.message = message; //TODO: Actually call from Discord as well + this.message = message; } @Override diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 5494c78..4338179 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -20,14 +20,14 @@ import java.util.Map; /** * Configuration is based on class name */ -public abstract class Component { - private static HashMap, Component> components = new HashMap<>(); +public abstract class Component { + private static HashMap, Component> components = new HashMap<>(); @Getter private boolean enabled = false; @Getter @NonNull - private JavaPlugin plugin; + private TP plugin; @NonNull private @Getter IHaveConfig config; @@ -46,7 +46,7 @@ public abstract class Component { * @param component The component to register * @return Whether the component is registered successfully (it may have failed to enable) */ - public static boolean registerComponent(JavaPlugin plugin, Component component) { + public static boolean registerComponent(T plugin, Component component) { return registerUnregisterComponent(plugin, component, true); } @@ -58,11 +58,11 @@ public abstract class Component { * @param component The component to unregister * @return Whether the component is unregistered successfully (it also got disabled) */ - public static boolean unregisterComponent(JavaPlugin plugin, Component component) { + public static boolean unregisterComponent(T plugin, Component component) { return registerUnregisterComponent(plugin, component, false); } - public static boolean registerUnregisterComponent(JavaPlugin plugin, Component component, boolean register) { + public static boolean registerUnregisterComponent(T plugin, Component component, boolean register) { try { val metaAnn = component.getClass().getAnnotation(ComponentMetadata.class); if (metaAnn != null) { @@ -153,7 +153,7 @@ public abstract class Component { * * @return The currently registered components */ - public static Map, Component> getComponents() { + public static Map, Component> getComponents() { return Collections.unmodifiableMap(components); } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 9b8ad31..c6c0de0 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -25,6 +25,7 @@ import java.util.function.Function; */ public abstract class Command2 { protected Command2() { + commandHelp.add("§6---- Commands ----"); } /** @@ -65,6 +66,11 @@ public abstract class Command2 public final String errormsg; } + private HashMap> subcommands = new HashMap<>(); + private HashMap, ParamConverter> paramConverters = new HashMap<>(); + + private ArrayList commandHelp = new ArrayList<>(); //Mainly needed by Discord + /** * Adds a param converter that obtains a specific object from a string parameter. * The converter may return null. @@ -73,17 +79,11 @@ public abstract class Command2 * @param converter The converter to use * @param The type of the result */ - public abstract void addParamConverter(Class cl, Function converter, String errormsg); - - protected void addParamConverter(Class cl, Function converter, String errormsg, HashMap, ParamConverter> map) { - map.put(cl, new ParamConverter<>(converter, errormsg)); + public void addParamConverter(Class cl, Function converter, String errormsg) { + paramConverters.put(cl, new ParamConverter<>(converter, errormsg)); } - public abstract boolean handleCommand(TP sender, String commandLine) throws Exception; - - protected boolean handleCommand(TP sender, String commandline, - HashMap> subcommands, - HashMap, ParamConverter> paramConverters) throws Exception { + public boolean handleCommand(TP sender, String commandline) throws Exception { for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) { String subcommand = commandline.substring(0, i).toLowerCase(); SubcommandData sd = subcommands.get(subcommand); //O(1) @@ -161,7 +161,7 @@ public abstract class Command2 public abstract void registerCommand(TC command); - protected void registerCommand(TC command, HashMap> subcommands, char commandChar) { + protected void registerCommand(TC command, char commandChar) { val path = command.getCommandPath(); int x = path.indexOf(' '); val mainPath = commandChar + path.substring(0, x == -1 ? path.length() : x); @@ -177,6 +177,8 @@ public abstract class Command2 ht[0] = "§6---- " + ht[0] + " ----"; scmdHelpList.addAll(Arrays.asList(ht)); scmdHelpList.add("§6Subcommands:"); + if (!commandHelp.contains(mainPath)) + commandHelp.add(mainPath); } catch (Exception e) { TBMCCoreAPI.SendException("Could not register default handler for command /" + path, e); } @@ -232,4 +234,8 @@ public abstract class Command2 } public abstract boolean hasPermission(TP sender, TC command); + + public String[] getCommandsText() { + return commandHelp.toArray(new String[0]); + } } //TODO: Test support of Player instead of CommandSender diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index 9e7e004..4a26622 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -2,21 +2,12 @@ package buttondevteam.lib.chat; import buttondevteam.core.MainPlugin; -import java.util.HashMap; import java.util.function.Function; public class Command2MC extends Command2 { - private HashMap> subcommands = new HashMap<>(); - private HashMap, ParamConverter> paramConverters = new HashMap<>(); - - @Override - public boolean handleCommand(Command2MCSender sender, String commandLine) throws Exception { - return handleCommand(sender, commandLine, subcommands, paramConverters); - } - @Override public void registerCommand(ICommand2MC command) { - registerCommand(command, subcommands, '/'); + super.registerCommand(command, '/'); } @Override @@ -30,6 +21,6 @@ public class Command2MC extends Command2 { */ @Override public void addParamConverter(Class cl, Function converter, String errormsg) { - addParamConverter(cl, converter, "§c" + errormsg, paramConverters); + super.addParamConverter(cl, converter, "§c" + errormsg); } } From 0cdfcb9ff4ea2a12b0ba41aa229ad9fc37beb01f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 27 Feb 2019 16:39:45 +0100 Subject: [PATCH 11/23] Restart impr. --- .idea/compiler.xml | 2 +- .../restart/PrimeRestartCommand.java | 4 +-- .../component/restart/RestartComponent.java | 6 +++-- .../restart/ScheduledRestartCommand.java | 27 +++++++++---------- ButtonProcessor/ButtonProcessor.iml | 1 + 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index ba952b2..b761e6a 100755 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -12,7 +12,7 @@ - + diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java index f387b1d..389da82 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/PrimeRestartCommand.java @@ -20,12 +20,12 @@ public class PrimeRestartCommand extends TBMCCommandBase { if (Bukkit.getOnlinePlayers().size() > 0) { sender.sendMessage("§bPlayers online, restart delayed."); if (loud) - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, ChatColor.DARK_RED + "The server will restart as soon as nobody is online.", component.restartBroadcast); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, ChatColor.DARK_RED + "The server will restart as soon as nobody is online.", component.getRestartBroadcast()); plsrestart = true; } else { sender.sendMessage("§bNobody is online. Restarting now."); if (loud) - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§cNobody is online. Restarting server.", component.restartBroadcast); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§cNobody is online. Restarting server.", component.getRestartBroadcast()); Bukkit.spigot().restart(); } return true; diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java index 332f9dc..f8eeb11 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java @@ -5,6 +5,7 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.IFakePlayer; import buttondevteam.lib.chat.TBMCChatAPI; +import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.event.EventHandler; @@ -15,7 +16,7 @@ public class RestartComponent extends Component implements Listener { @Override public void enable() { //TODO: Permissions for the commands - TBMCChatAPI.AddCommand(this, new ScheduledRestartCommand(this)); + registerCommand(new ScheduledRestartCommand(this)); TBMCChatAPI.AddCommand(this, new PrimeRestartCommand(this)); registerListener(this); restartBroadcast = TBMCSystemChatEvent.BroadcastTarget.add("restartCountdown"); @@ -27,7 +28,8 @@ public class RestartComponent extends Component implements Listener { } private long lasttime = 0; - TBMCSystemChatEvent.BroadcastTarget restartBroadcast; + @Getter + private TBMCSystemChatEvent.BroadcastTarget restartBroadcast; @EventHandler public void onPlayerLeave(PlayerQuitEvent event) { diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java index 3f83e48..dabd48a 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/ScheduledRestartCommand.java @@ -3,9 +3,10 @@ package buttondevteam.core.component.restart; import buttondevteam.core.MainPlugin; import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.ScheduledServerRestartEvent; +import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.ICommand2MC; import buttondevteam.lib.chat.TBMCChatAPI; -import buttondevteam.lib.chat.TBMCCommandBase; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -17,18 +18,23 @@ import org.bukkit.boss.BossBar; import org.bukkit.command.CommandSender; import org.bukkit.scheduler.BukkitTask; -@CommandClass(modOnly = true, path = "schrestart") +@CommandClass(modOnly = true, path = "schrestart", helpText = { + "Scheduled restart", // + "This command restarts the server 1 minute after it's executed, warning players every 10 seconds.", // + "You can optionally set the amount of seconds to wait before the restart." // +}) @RequiredArgsConstructor -public class ScheduledRestartCommand extends TBMCCommandBase { +public class ScheduledRestartCommand extends ICommand2MC { @Getter @Setter private int restartCounter; private BukkitTask restarttask; private volatile BossBar restartbar; + @Getter private final RestartComponent component; - @Override - public boolean OnCommand(CommandSender sender, String alias, String[] args) { + @Command2.Subcommand + public boolean def(CommandSender sender, String alias, String[] args) { int secs = 60; try { if (args.length > 0) @@ -56,20 +62,11 @@ public class ScheduledRestartCommand extends TBMCCommandBase { Bukkit.spigot().restart(); } if (restartCounter % 200 == 0) - TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§c-- The server is restarting in " + restartCounter / 20 + " seconds! (/press)", component.restartBroadcast); + TBMCChatAPI.SendSystemMessage(Channel.GlobalChat, Channel.RecipientTestResult.ALL, "§c-- The server is restarting in " + restartCounter / 20 + " seconds! (/press)", component.getRestartBroadcast()); restartbar.setProgress(restartCounter / (double) restarttime); restartbar.setTitle(String.format("Server restart in %.2f", restartCounter / 20f)); restartCounter--; }, 1, 1); return true; } - - @Override - public String[] GetHelpText(String alias) { - return new String[] { // - "§6---- Scheduled restart ----", // - "This command restarts the server 1 minute after it's executed, warning players every 10 seconds.", // - "You can optionally set the amount of ticks to wait before the restart." // - }; - } } diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index 35bfd14..3c6a51e 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -13,6 +13,7 @@ + From fab2b5819d0ff61ccf403d2e7ab2cffe52f39608 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 1 Mar 2019 17:52:45 +0100 Subject: [PATCH 12/23] Moved Votifier reward here, fixes Checking if Towny or Votifier is present --- .idea/compiler.xml | 2 +- BuildConfigUpdater/BuildConfigUpdater.iml | 1 - ...1) (com.github.TBMCPlugins.ButtonCore).iml | 1 + ButtonCore/pom.xml | 10 ++++ .../java/buttondevteam/core/MainPlugin.java | 34 +++++++++++--- .../java/buttondevteam/core/TestPrepare.java | 1 + .../component/members/MemberComponent.java | 2 +- .../component/randomtp/RandomTPComponent.java | 3 +- .../component/restart/RestartComponent.java | 3 +- .../core/component/towny/TownyComponent.java | 3 +- .../updater/PluginUpdaterComponent.java | 3 +- .../component/votifier/VotifierComponent.java | 46 +++++++++++++++++++ ButtonCore/src/main/resources/plugin.yml | 7 ++- ButtonProcessor/ButtonProcessor.iml | 1 - 14 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b761e6a..ba952b2 100755 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -12,7 +12,7 @@ - + diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index 72a504c..f14440c 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -13,7 +13,6 @@ - diff --git a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml index 692ea56..7c2fa83 100644 --- a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml +++ b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml @@ -32,6 +32,7 @@ + \ No newline at end of file diff --git a/ButtonCore/pom.xml b/ButtonCore/pom.xml index 0bd3d00..ed35499 100755 --- a/ButtonCore/pom.xml +++ b/ButtonCore/pom.xml @@ -113,6 +113,10 @@ ess-repo http://repo.ess3.net/content/repositories/essrel/
+ + Votifier + https://dl.bintray.com/nuvotifier/maven/ + @@ -177,6 +181,12 @@ 2.13.1 provided + + com.vexsoftware + nuvotifier-universal + 2.3.4 + provided + TBMCPlugins diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index 6286e32..b6c78f4 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -9,6 +9,7 @@ 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.core.component.votifier.VotifierComponent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; @@ -19,6 +20,7 @@ import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayerBase; import com.earth2me.essentials.Essentials; +import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.command.BlockCommandSender; @@ -29,6 +31,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.RegisteredServiceProvider; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -45,6 +48,8 @@ public class MainPlugin extends ButtonPlugin { public static Essentials ess; private Logger logger; + @Nullable + private Economy economy; private ConfigData writePluginList() { return getIConfig().getData("writePluginList", false); @@ -58,14 +63,20 @@ public class MainPlugin extends ButtonPlugin { logger = getLogger(); if (!setupPermissions()) throw new NullPointerException("No permission plugin found!"); + if (!setupEconomy()) //Though Essentials always provides economy so this shouldn't happen + getLogger().warning("No economy plugin found! Components using economy will not be registered."); Test = getConfig().getBoolean("test", true); saveConfig(); Component.registerComponent(this, new PluginUpdaterComponent()); Component.registerComponent(this, new RestartComponent()); + //noinspection unchecked - needed for testing Component.registerComponent(this, new ChannelComponent()); Component.registerComponent(this, new RandomTPComponent()); Component.registerComponent(this, new MemberComponent()); - Component.registerComponent(this, new TownyComponent()); + if (Bukkit.getPluginManager().isPluginEnabled("Towny")) //It fails to load the component class otherwise + Component.registerComponent(this, new TownyComponent()); + if (Bukkit.getPluginManager().isPluginEnabled("Votifier") && economy != null) + Component.registerComponent(this, new VotifierComponent(economy)); ComponentManager.enableComponents(); getCommand2MC().registerCommand(new ComponentCommand()); TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this); @@ -74,7 +85,7 @@ public class MainPlugin extends ButtonPlugin { ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player ? TBMCPlayer.getPlayer(((Player) sender).getUniqueId(), TBMCPlayer.class) : null)); //Players, has higher priority TBMCCoreAPI.RegisterUserClass(TBMCPlayerBase.class); - TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fOOC§f", Color.White, "g", null)); //The /ooc ID has moved to the config + TBMCChatAPI.RegisterChatChannel(Channel.GlobalChat = new Channel("§fg§f", Color.White, "g", null)); //The /ooc ID has moved to the config TBMCChatAPI.RegisterChatChannel( Channel.AdminChat = new Channel("§cADMIN§f", Color.Red, "a", Channel.inGroupFilter(null))); TBMCChatAPI.RegisterChatChannel( @@ -120,14 +131,23 @@ public class MainPlugin extends ButtonPlugin { } private boolean setupPermissions() { - RegisteredServiceProvider permissionProvider = getServer().getServicesManager() - .getRegistration(Permission.class); - if (permissionProvider != null) { - permission = permissionProvider.getProvider(); - } + permission = setupProvider(Permission.class); return (permission != null); } + private boolean setupEconomy() { + economy = setupProvider(Economy.class); + return (economy != null); + } + + private T setupProvider(Class cl) { + RegisteredServiceProvider provider = getServer().getServicesManager() + .getRegistration(cl); + if (provider != null) + return provider.getProvider(); + return null; + } + @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 diff --git a/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java b/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java index 67b0a33..13513b4 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java +++ b/ButtonCore/src/main/java/buttondevteam/core/TestPrepare.java @@ -41,6 +41,7 @@ public class TestPrepare { return cl.isAssignableFrom(invocation.getMethod().getReturnType()); } })); + //noinspection unchecked 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/core/component/members/MemberComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java index 1fff614..6cc9536 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java @@ -14,7 +14,7 @@ import java.util.Date; import static buttondevteam.core.MainPlugin.permission; -public class MemberComponent extends Component implements Listener { +public class MemberComponent extends Component implements Listener { ConfigData memberGroup() { return getConfig().getData("memberGroup", "member"); } diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java index e324b3a..e7df49d 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java @@ -1,8 +1,9 @@ package buttondevteam.core.component.randomtp; +import buttondevteam.core.MainPlugin; import buttondevteam.lib.architecture.Component; -public class RandomTPComponent extends Component { +public class RandomTPComponent extends Component { @Override protected void enable() { new RandomTP().onEnable(this); //It registers it's command diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java index f8eeb11..dd58a0c 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java @@ -1,5 +1,6 @@ package buttondevteam.core.component.restart; +import buttondevteam.core.MainPlugin; import buttondevteam.core.component.channel.Channel; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; @@ -12,7 +13,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; -public class RestartComponent extends Component implements Listener { +public class RestartComponent extends Component implements Listener { @Override public void enable() { //TODO: Permissions for the commands diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java index 1b2bf9d..0397c8a 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java @@ -1,6 +1,7 @@ package buttondevteam.core.component.towny; import buttondevteam.core.ComponentManager; +import buttondevteam.core.MainPlugin; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.architecture.Component; import com.palmergames.bukkit.towny.Towny; @@ -10,7 +11,7 @@ import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.TownyUniverse; import org.bukkit.Bukkit; -public class TownyComponent extends Component { +public class TownyComponent extends Component { @Override protected void enable() { } diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java index 2ead741..0adef98 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java @@ -1,9 +1,10 @@ package buttondevteam.core.component.updater; +import buttondevteam.core.MainPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.TBMCChatAPI; -public class PluginUpdaterComponent extends Component { +public class PluginUpdaterComponent extends Component { @Override public void enable() { TBMCChatAPI.AddCommand(this, new UpdatePluginCommand()); diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java new file mode 100644 index 0000000..839ea17 --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java @@ -0,0 +1,46 @@ +package buttondevteam.core.component.votifier; + +import buttondevteam.core.MainPlugin; +import buttondevteam.lib.architecture.Component; +import buttondevteam.lib.architecture.ConfigData; +import com.vexsoftware.votifier.model.Vote; +import com.vexsoftware.votifier.model.VotifierEvent; +import lombok.RequiredArgsConstructor; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; + +@RequiredArgsConstructor +public class VotifierComponent extends Component { + private final Economy economy; + + private ConfigData rewardAmount() { + return getConfig().getData("rewardAmount", 50.0); + } + + @Override + protected void enable() { + + } + + @Override + protected void disable() { + + } + + @EventHandler + @SuppressWarnings("deprecation") + public void onVotifierEvent(VotifierEvent event) { + Vote vote = event.getVote(); + getPlugin().getLogger().info("Vote: " + vote); + org.bukkit.OfflinePlayer op = Bukkit.getOfflinePlayer(vote.getUsername()); + Player p = Bukkit.getPlayer(vote.getUsername()); + if (op != null) { + economy.depositPlayer(op, rewardAmount().get()); + } + if (p != null) { + p.sendMessage("§bThanks for voting! $50 was added to your account."); + } + } +} diff --git a/ButtonCore/src/main/resources/plugin.yml b/ButtonCore/src/main/resources/plugin.yml index 43c609f..29bfbb1 100755 --- a/ButtonCore/src/main/resources/plugin.yml +++ b/ButtonCore/src/main/resources/plugin.yml @@ -15,4 +15,9 @@ commands: description: Add or remove a member component: description: Enable or disable or list components - dontrunthiscmd: \ No newline at end of file + dontrunthiscmd: +depend: + - Vault +softdepend: + - Towny + - Votifier \ No newline at end of file diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index 3c6a51e..35bfd14 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -13,7 +13,6 @@ - From f875985aa966b472fbdee93d9eab28748199978f Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 2 Mar 2019 18:56:01 +0100 Subject: [PATCH 13/23] Moved the MC chat handler here And gitignore is moved as well The chat handler doesn't interfere with displaying the chat, that's still handled by the chat plugin --- ButtonCore/.gitignore => .gitignore | 0 .../java/buttondevteam/core/PlayerListener.java | 14 ++++++++++++++ 2 files changed, 14 insertions(+) rename ButtonCore/.gitignore => .gitignore (100%) diff --git a/ButtonCore/.gitignore b/.gitignore similarity index 100% rename from ButtonCore/.gitignore rename to .gitignore diff --git a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java index d151e51..0ea7ac4 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java +++ b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java @@ -4,7 +4,10 @@ import buttondevteam.lib.TBMCCommandPreprocessEvent; import buttondevteam.lib.TBMCCoreAPI; import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.ButtonPlugin; +import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.Command2MCSender; +import buttondevteam.lib.chat.TBMCChatAPI; +import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayerBase; import lombok.val; import org.bukkit.Bukkit; @@ -13,6 +16,7 @@ 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.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -70,4 +74,14 @@ public class PlayerListener implements Listener { TBMCCoreAPI.SendException("Command processing failed for sender '" + event.getSender() + "' and message '" + event.getMessage() + "'", e); } } + + @EventHandler(priority = EventPriority.HIGH) //The one in the chat plugin is set to highest + public void onPlayerChat(AsyncPlayerChatEvent event) { + if (event.isCancelled()) + return; //The chat plugin should cancel it after this handler + val cp = TBMCPlayer.getPlayer(event.getPlayer().getUniqueId(), TBMCPlayer.class); + TBMCChatAPI.SendChatMessage(ChatMessage.builder(event.getPlayer(), cp, event.getMessage()).build()); + //Not cancelling the original event here, it's cancelled in the chat plugin + //This way other plugins can deal with the MC formatting if the chat plugin isn't present, but other platforms still get the message + } } \ No newline at end of file From 7fd422136bd088ff2cc064a147cc111af6a83ace Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 6 Mar 2019 15:19:36 +0100 Subject: [PATCH 14/23] Added getConfigMap() method --- BuildConfigUpdater/BuildConfigUpdater.iml | 1 - ...re (1) (com.github.TBMCPlugins.ButtonCore).iml | 2 +- .../buttondevteam/lib/architecture/Component.java | 15 +++++++++++++++ ButtonProcessor/ButtonProcessor.iml | 1 + 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/BuildConfigUpdater/BuildConfigUpdater.iml b/BuildConfigUpdater/BuildConfigUpdater.iml index f14440c..274b3de 100644 --- a/BuildConfigUpdater/BuildConfigUpdater.iml +++ b/BuildConfigUpdater/BuildConfigUpdater.iml @@ -12,7 +12,6 @@ - diff --git a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml index 7c2fa83..c89b771 100644 --- a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml +++ b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml @@ -1,5 +1,5 @@ - + diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 4338179..b6c880b 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -10,12 +10,14 @@ import lombok.Getter; import lombok.NonNull; import lombok.experimental.var; import lombok.val; +import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; /** * Configuration is based on class name @@ -222,6 +224,19 @@ public abstract class Component { return listener; } + /** + * Returns a map of configs that are under the given key. + * @param key The key to use + * @return A map containing configs + */ + protected Map getConfigMap(String key) { + val c=getConfig().getConfig(); + var cs=c.getConfigurationSection(key); + if(cs==null) cs=c.createSection(key); + return cs.getValues(false).entrySet().stream().filter(e->e.getValue() instanceof ConfigurationSection) + .collect(Collectors.toMap(Map.Entry::getKey, kv -> new IHaveConfig((ConfigurationSection) kv.getValue()))); + } + private String getClassName() { return getClass().getSimpleName(); } diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index 35bfd14..3c6a51e 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -13,6 +13,7 @@ + From 138259412f02be9742e5f7cd8cf0c6c4c4df6711 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Fri, 8 Mar 2019 22:17:49 +0100 Subject: [PATCH 15/23] Config and command fixes/improvements Default value for config maps added Added support for array types in configs and handling null in setting Added support for TextArg annotation Allowing to override the command path Fixed optional argument detection in the annotation processor ("Optional" --> "OptionalArg") --- .../buttondevteam/lib/architecture/Component.java | 14 ++++++++++++-- .../buttondevteam/lib/architecture/ConfigData.java | 6 +++++- .../main/java/buttondevteam/lib/chat/Command2.java | 2 +- .../java/buttondevteam/lib/chat/ICommand2.java | 2 +- .../buttondevteam/buttonproc/ButtonProcessor.java | 2 +- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index b6c880b..3090a07 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -17,6 +17,7 @@ import org.bukkit.plugin.java.JavaPlugin; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.function.Consumer; import java.util.stream.Collectors; /** @@ -227,14 +228,23 @@ public abstract class Component { /** * Returns a map of configs that are under the given key. * @param key The key to use + * @param defaultProvider A mapping between config paths and config generators * @return A map containing configs */ - protected Map getConfigMap(String key) { + protected Map getConfigMap(String key, Map> defaultProvider) { val c=getConfig().getConfig(); var cs=c.getConfigurationSection(key); if(cs==null) cs=c.createSection(key); - return cs.getValues(false).entrySet().stream().filter(e->e.getValue() instanceof ConfigurationSection) + val res = cs.getValues(false).entrySet().stream().filter(e -> e.getValue() instanceof ConfigurationSection) .collect(Collectors.toMap(Map.Entry::getKey, kv -> new IHaveConfig((ConfigurationSection) kv.getValue()))); + if (res.size() == 0) { + for (val entry : defaultProvider.entrySet()) { + val conf = new IHaveConfig(cs.createSection(entry.getKey())); + entry.getValue().accept(conf); + res.put(entry.getKey(), conf); + } + } + return res; } private String getClassName() { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java index 1a3a11f..8cff0f9 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -5,6 +5,8 @@ import lombok.RequiredArgsConstructor; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; +import java.lang.reflect.Array; +import java.util.List; import java.util.Objects; import java.util.function.Function; @@ -74,12 +76,14 @@ public class ConfigData { //TODO: Save after a while else if (def instanceof Double) val = ((Number) val).doubleValue(); } + if (val instanceof List && def.getClass().isArray()) + val = ((List) val).toArray((T[]) Array.newInstance(def.getClass().getComponentType(), 0)); return (T) val; } public void set(T value) { Object val; - if (setter != null) + if (setter != null && value != null) val = setter.apply(value); else val = value; if (config != null) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index c6c0de0..8327314 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -130,7 +130,7 @@ public abstract class Command2 } } j = commandline.indexOf(' ', j + 1); //End index - if (j == -1) //Last parameter + if (j == -1 || paramArr[i1].isAnnotationPresent(TextArg.class)) //Last parameter j = commandline.length(); String param = commandline.substring(pj, j); if (cl == String.class) { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index 781efe4..dba5664 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -59,7 +59,7 @@ public abstract class ICommand2 { * * @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 String getCommandPath() { return path; } diff --git a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java index f7bb7fe..1fda004 100755 --- a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java +++ b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java @@ -78,7 +78,7 @@ public class ButtonProcessor extends AbstractProcessor { 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")); + boolean optional = p.getAnnotationMirrors().stream().anyMatch(am -> am.getAnnotationType().toString().endsWith("OptionalArg")); if (optional) return "[" + p.getSimpleName() + "]"; return "<" + p.getSimpleName() + ">"; From 9620ae44f61e274b6f888f175f4c0332cbd3383e Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 9 Mar 2019 01:51:13 +0100 Subject: [PATCH 16/23] Config fix Saving primitive defaults even if def is null --- .../main/java/buttondevteam/lib/architecture/ConfigData.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java index 8cff0f9..a86c071 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -56,7 +56,10 @@ public class ConfigData { //TODO: Save after a while val = primitiveDef; } if (!saved && Objects.equals(val, primitiveDef)) { //String needs .equals() - set(def); //Save default value - def is always set + if (def == null && config != null) //In Discord's case def may be null + config.set(path, primitiveDef); + else + set(def); //Save default value - def is always set saved = true; } if (getter != null) { From 9c15d0ffff3e9804e57d768de09fe57e41af77b9 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 9 Mar 2019 22:57:38 +0100 Subject: [PATCH 17/23] Chat handler improvements and config doc gen Configuration documentation generation --- .../java/buttondevteam/core/MainPlugin.java | 14 ++++++ .../buttondevteam/core/PlayerListener.java | 22 ++++++++-- .../component/channel/ChannelComponent.java | 4 ++ .../component/members/MemberComponent.java | 24 ++++++++++- .../component/randomtp/RandomTPComponent.java | 4 ++ .../component/restart/RestartComponent.java | 3 ++ .../core/component/towny/TownyComponent.java | 3 ++ .../updater/PluginUpdaterComponent.java | 5 ++- .../component/votifier/VotifierComponent.java | 5 ++- .../lib/architecture/ButtonPlugin.java | 1 + .../lib/architecture/Component.java | 1 + .../lib/architecture/ComponentMetadata.java | 2 +- .../lib/architecture/HasConfig.java | 13 ++++++ .../buttonproc/ButtonProcessor.java | 24 +++-------- .../buttonproc/ConfigProcessor.java | 43 +++++++++++++++++++ 15 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 ButtonCore/src/main/java/buttondevteam/lib/architecture/HasConfig.java create mode 100644 ButtonProcessor/src/main/java/buttondevteam/buttonproc/ConfigProcessor.java diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index b6c78f4..f46a85c 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -20,6 +20,8 @@ import buttondevteam.lib.player.ChromaGamerBase; import buttondevteam.lib.player.TBMCPlayer; import buttondevteam.lib.player.TBMCPlayerBase; import com.earth2me.essentials.Essentials; +import lombok.Getter; +import lombok.Setter; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; @@ -50,11 +52,23 @@ public class MainPlugin extends ButtonPlugin { private Logger logger; @Nullable private Economy economy; + /** + * Whether the Core's chat handler should be enabled. + * Other chat plugins handling messages from other platforms should set this to false. + */ + @Getter + @Setter + private boolean chatHandlerEnabled = true; private ConfigData writePluginList() { return getIConfig().getData("writePluginList", false); } + ConfigData chatFormat() { + return getIConfig().getData("chatFormat", "[{origin}|" + + "{channel}] <{name}> {message}"); + } + @Override public void pluginEnable() { // Logs "Plugin Enabled", registers commands diff --git a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java index 0ea7ac4..097b90a 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java +++ b/ButtonCore/src/main/java/buttondevteam/core/PlayerListener.java @@ -1,8 +1,6 @@ package buttondevteam.core; -import buttondevteam.lib.TBMCCommandPreprocessEvent; -import buttondevteam.lib.TBMCCoreAPI; -import buttondevteam.lib.TBMCSystemChatEvent; +import buttondevteam.lib.*; import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.chat.ChatMessage; import buttondevteam.lib.chat.Command2MCSender; @@ -12,6 +10,7 @@ import buttondevteam.lib.player.TBMCPlayerBase; import lombok.val; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -84,4 +83,21 @@ public class PlayerListener implements Listener { //Not cancelling the original event here, it's cancelled in the chat plugin //This way other plugins can deal with the MC formatting if the chat plugin isn't present, but other platforms still get the message } + + @EventHandler(priority = EventPriority.HIGH) //The one in the chat plugin is set to highest + public void onPlayerChat(TBMCChatEvent event) { + if (event.isCancelled()) + return; + if (!MainPlugin.Instance.isChatHandlerEnabled()) return; + if (event.getOrigin().equals("Minecraft")) return; //Let other plugins handle MC messages + String msg = MainPlugin.Instance.chatFormat().get() + .replace("{channel}", event.getChannel().DisplayName().get()) + .replace("{origin}", event.getOrigin().substring(0, 1)) + .replace("{name}", ThorpeUtils.getDisplayName(event.getSender())) + .replace("{message}", event.getMessage()); + for (Player player : Bukkit.getOnlinePlayers()) + if (event.shouldSendTo(player)) + player.sendMessage(msg); + Bukkit.getConsoleSender().sendMessage(msg); + } } \ No newline at end of file diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java index 14aff26..5e19ea0 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/channel/ChannelComponent.java @@ -4,8 +4,12 @@ import buttondevteam.lib.TBMCSystemChatEvent; import buttondevteam.lib.architecture.Component; import org.bukkit.plugin.java.JavaPlugin; +/** + * Manages chat channels. If disabled, only global channels will be registered. + */ public class ChannelComponent extends Component { static TBMCSystemChatEvent.BroadcastTarget roomJoinLeave; + @Override protected void register(JavaPlugin plugin) { super.register(plugin); diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java index 6cc9536..b5bab6e 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/members/MemberComponent.java @@ -14,11 +14,31 @@ import java.util.Date; import static buttondevteam.core.MainPlugin.permission; +/** + * Allows giving a 'member' group over some time elapsed OR played. + */ public class MemberComponent extends Component implements Listener { + /** + * The permission group to give to the player + */ ConfigData memberGroup() { return getConfig().getData("memberGroup", "member"); } + /** + * The amount of hours needed to play before promotion + */ + private ConfigData playedHours() { + return getConfig().getData("playedHours", 12); + } + + /** + * The amount of days passed since first login + */ + private ConfigData registeredForDays() { + return getConfig().getData("registeredForDays", 7); + } + @Override protected void enable() { registerListener(this); @@ -32,8 +52,8 @@ public class MemberComponent extends Component implements Listener { @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { if (permission != null && !permission.playerInGroup(event.getPlayer(), memberGroup().get()) - && (new Date(event.getPlayer().getFirstPlayed()).toInstant().plus(7, ChronoUnit.DAYS).isBefore(Instant.now()) - || event.getPlayer().getStatistic(Statistic.PLAY_ONE_TICK) > 20 * 3600 * 12)) { + && (new Date(event.getPlayer().getFirstPlayed()).toInstant().plus(registeredForDays().get(), ChronoUnit.DAYS).isBefore(Instant.now()) + || event.getPlayer().getStatistic(Statistic.PLAY_ONE_TICK) > 20 * 3600 * playedHours().get())) { permission.playerAddGroup(null, event.getPlayer(), memberGroup().get()); event.getPlayer().sendMessage("§bYou are a member now. YEEHAW"); MainPlugin.Instance.getLogger().info("Added " + event.getPlayer().getName() + " as a member."); diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java index e7df49d..0f1fb5e 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/randomtp/RandomTPComponent.java @@ -3,6 +3,10 @@ package buttondevteam.core.component.randomtp; import buttondevteam.core.MainPlugin; import buttondevteam.lib.architecture.Component; +/** + * Teleport player to random location within world border. + * Every five players teleport to the same general area, and then a new general area is randomly selected for the next five players. + */ public class RandomTPComponent extends Component { @Override protected void enable() { diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java index dd58a0c..6b431bb 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/restart/RestartComponent.java @@ -13,6 +13,9 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerQuitEvent; +/** + * Provides commands such as /schrestart (restart after a countdown) and /primerestart (restart when nobody is online) + */ public class RestartComponent extends Component implements Listener { @Override public void enable() { diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java index 0397c8a..42c857d 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/towny/TownyComponent.java @@ -11,6 +11,9 @@ import com.palmergames.bukkit.towny.object.Resident; import com.palmergames.bukkit.towny.object.TownyUniverse; import org.bukkit.Bukkit; +/** + * Automatically renames Towny players if they changed their Minecraft name + */ public class TownyComponent extends Component { @Override protected void enable() { diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java index 0adef98..3ea44c8 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/updater/PluginUpdaterComponent.java @@ -4,7 +4,10 @@ import buttondevteam.core.MainPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.TBMCChatAPI; -public class PluginUpdaterComponent extends Component { +/** + * Downloads plugin updates built from their source using JitPack - older code + */ +public class PluginUpdaterComponent extends Component { //TODO: Config @Override public void enable() { TBMCChatAPI.AddCommand(this, new UpdatePluginCommand()); diff --git a/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java b/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java index 839ea17..94ffe55 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java +++ b/ButtonCore/src/main/java/buttondevteam/core/component/votifier/VotifierComponent.java @@ -11,12 +11,15 @@ import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +/** + * Do not use (EULA) + */ @RequiredArgsConstructor public class VotifierComponent extends Component { private final Economy economy; private ConfigData rewardAmount() { - return getConfig().getData("rewardAmount", 50.0); + return getConfig().getData("rewardAmount", 0.0); } @Override diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index a4b5bdf..602aefa 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -11,6 +11,7 @@ import org.bukkit.plugin.java.JavaPlugin; import java.util.Stack; +@HasConfig public abstract class ButtonPlugin extends JavaPlugin { @Getter private static Command2MC command2MC = new Command2MC(); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 3090a07..d9a15c3 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; /** * Configuration is based on class name */ +@HasConfig //Used for obtaining javadoc public abstract class Component { private static HashMap, Component> components = new HashMap<>(); diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ComponentMetadata.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ComponentMetadata.java index 6519fca..a182df8 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ComponentMetadata.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ComponentMetadata.java @@ -8,5 +8,5 @@ import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ComponentMetadata { - Class[] depends(); + Class[] depends() default {}; } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/HasConfig.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/HasConfig.java new file mode 100644 index 0000000..8e1e63a --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/HasConfig.java @@ -0,0 +1,13 @@ +package buttondevteam.lib.architecture; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Target; + +/** + * Used to generate documentation for the config + */ +@Target(ElementType.TYPE) +@Inherited +public @interface HasConfig { +} diff --git a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java index 1fda004..50e1939 100755 --- a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java +++ b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ButtonProcessor.java @@ -8,14 +8,11 @@ import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; 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; @@ -25,6 +22,8 @@ import java.util.stream.Collectors; public class ButtonProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (configProcessor == null) + configProcessor = new ConfigProcessor(processingEnv); for (TypeElement te : annotations) { Set classes = roundEnv.getElementsAnnotatedWith(te); for (Element targetcl : classes) { @@ -47,6 +46,8 @@ public class ButtonProcessor extends AbstractProcessor { //System.out.println("Type: " + type); } processSubcommands(targetcl, annotationMirrors); + if (hasAnnotation.apply("HasConfig")) + configProcessor.process(targetcl); } } try { @@ -63,6 +64,7 @@ public class ButtonProcessor extends AbstractProcessor { private YamlConfiguration yc = new YamlConfiguration(); private boolean found = false; + private ConfigProcessor configProcessor; private void processSubcommands(Element targetcl, List annotationMirrors) { if (!(targetcl instanceof ExecutableElement)) @@ -91,20 +93,4 @@ public class ButtonProcessor extends AbstractProcessor { 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 ""; - } } diff --git a/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ConfigProcessor.java b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ConfigProcessor.java new file mode 100644 index 0000000..f244553 --- /dev/null +++ b/ButtonProcessor/src/main/java/buttondevteam/buttonproc/ConfigProcessor.java @@ -0,0 +1,43 @@ +package buttondevteam.buttonproc; + +import org.bukkit.configuration.file.YamlConfiguration; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.File; +import java.io.IOException; + +public class ConfigProcessor { + private final ProcessingEnvironment procEnv; + private final YamlConfiguration yaml; + private final File file; + + public ConfigProcessor(ProcessingEnvironment procEnv) { + this.procEnv = procEnv; + FileObject file = null; + try { + file = procEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", "config.yml"); + } catch (IOException e) { + e.printStackTrace(); + } + yaml = new YamlConfiguration(); + this.file = new File(file.toUri()); + } + + public void process(Element targetcl) { + if (targetcl.getModifiers().contains(Modifier.ABSTRACT)) return; + String javadoc = procEnv.getElementUtils().getDocComment(targetcl); + if (javadoc == null) return; + System.out.println("JAVADOC"); //TODO: Config methods + System.out.println(javadoc); + yaml.set("components." + targetcl.getSimpleName() + "._doc", javadoc); + try { + yaml.save(file); + } catch (IOException e) { + e.printStackTrace(); + } + } +} From 7289385a3349b075e2f8fa820fb56ab3321760c1 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Mon, 11 Mar 2019 16:50:24 +0100 Subject: [PATCH 18/23] Automatic config saving --- ...igotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml | 6 ++--- .../lib/architecture/ButtonPlugin.java | 2 +- .../lib/architecture/Component.java | 4 +-- .../lib/architecture/ConfigData.java | 26 ++++++++++++++++--- .../lib/architecture/IHaveConfig.java | 16 +++++++----- ButtonProcessor/ButtonProcessor.iml | 1 + 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml b/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml index b6f88ae..42f0d6f 100644 --- a/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml +++ b/.idea/libraries/Maven__org_spigotmc_spigot_api_1_12_2_R0_1_SNAPSHOT.xml @@ -1,13 +1,13 @@ - + - + - + \ No newline at end of file diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 602aefa..381bfc6 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -42,7 +42,7 @@ public abstract class ButtonPlugin extends JavaPlugin { public final void onEnable() { var section = super.getConfig().getConfigurationSection("global"); if (section == null) section = super.getConfig().createSection("global"); - iConfig = new IHaveConfig(section); + iConfig = new IHaveConfig(section, this::saveConfig); try { pluginEnable(); } catch (Exception e) { diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index d9a15c3..43e77fa 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -147,9 +147,9 @@ public abstract class Component { var configSect = compconf.getConfigurationSection(component.getClassName()); if (configSect == null) configSect = compconf.createSection(component.getClassName()); - component.config = new IHaveConfig(configSect); + component.config = new IHaveConfig(configSect, plugin::saveConfig); } else //Testing - component.config = new IHaveConfig(null); + component.config = new IHaveConfig(null, plugin::saveConfig); } /** diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java index a86c071..b2961a1 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -1,11 +1,17 @@ package buttondevteam.lib.architecture; +import buttondevteam.core.MainPlugin; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.configuration.Configuration; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; import java.lang.reflect.Array; +import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.function.Function; @@ -16,7 +22,8 @@ import java.util.function.Function; */ @RequiredArgsConstructor(access = AccessLevel.PACKAGE) //@AllArgsConstructor(access = AccessLevel.PACKAGE) -public class ConfigData { //TODO: Save after a while +public class ConfigData { + private static final HashMap saveTasks= new HashMap<>(); /** * May be null for testing */ @@ -24,6 +31,7 @@ public class ConfigData { //TODO: Save after a while private final String path; private final T def; private final Object primitiveDef; + private final Runnable saveAction; /** * The parameter is of a primitive type as returned by {@link YamlConfiguration#get(String)} */ @@ -39,13 +47,14 @@ public class ConfigData { //TODO: Save after a while private T value; private boolean saved = false; - public ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function getter, Function setter) { + public ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function getter, Function setter, Runnable saveAction) { this.config = config; this.path = path; this.def = def; this.primitiveDef = primitiveDef; this.getter = getter; this.setter = setter; + this.saveAction=saveAction; } @SuppressWarnings("unchecked") @@ -89,8 +98,19 @@ public class ConfigData { //TODO: Save after a while if (setter != null && value != null) val = setter.apply(value); else val = value; - if (config != null) + if (config != null) { config.set(path, val); + if(!saveTasks.containsKey(config.getRoot())) { + synchronized (saveTasks) { + saveTasks.put(config.getRoot(), Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, () -> { + synchronized (saveTasks) { + saveTasks.remove(config.getRoot()); + saveAction.run(); + } + }, 100)); + } + } + } this.value = value; } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java index 98fa241..241e4f5 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/IHaveConfig.java @@ -3,6 +3,8 @@ package buttondevteam.lib.architecture; import lombok.Getter; import lombok.val; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; import java.util.HashMap; import java.util.function.Function; @@ -15,14 +17,16 @@ public final class IHaveConfig { private final HashMap> datamap = new HashMap<>(); @Getter private ConfigurationSection config; + private final Runnable saveAction; /** * May be used in testing. * * @param section May be null for testing */ - IHaveConfig(ConfigurationSection section) { + IHaveConfig(ConfigurationSection section, Runnable saveAction) { config = section; + this.saveAction=saveAction; } /** @@ -36,7 +40,7 @@ public final class IHaveConfig { @SuppressWarnings("unchecked") public ConfigData getData(String path, T def) { ConfigData data = datamap.get(path); - if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def, def)); + if (data == null) datamap.put(path, data = new ConfigData<>(config, path, def, def, saveAction)); return (ConfigData) data; } @@ -54,7 +58,7 @@ public final class IHaveConfig { public ConfigData getData(String path, T def, Function getter, Function setter) { ConfigData data = datamap.get(path); if (data == null) - datamap.put(path, data = new ConfigData<>(config, path, def, setter.apply(def), getter, setter)); + datamap.put(path, data = new ConfigData<>(config, path, def, setter.apply(def), getter, setter, saveAction)); return (ConfigData) data; } @@ -72,7 +76,7 @@ public final class IHaveConfig { public ConfigData getDataPrimDef(String path, Object primitiveDef, Function getter, Function setter) { ConfigData data = datamap.get(path); if (data == null) - datamap.put(path, data = new ConfigData<>(config, path, getter.apply(primitiveDef), primitiveDef, getter, setter)); + datamap.put(path, data = new ConfigData<>(config, path, getter.apply(primitiveDef), primitiveDef, getter, setter, saveAction)); return (ConfigData) data; } @@ -89,7 +93,7 @@ public final class IHaveConfig { ConfigData data = datamap.get(path); if (data == null) { val defval = def.get(); - datamap.put(path, data = new ConfigData<>(config, path, defval, defval)); + datamap.put(path, data = new ConfigData<>(config, path, defval, defval, saveAction)); } return (ConfigData) data; } @@ -109,7 +113,7 @@ public final class IHaveConfig { 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)); + datamap.put(path, data = new ConfigData<>(config, path, defval, setter.apply(defval), getter, setter, saveAction)); } return (ConfigData) data; } diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index 3c6a51e..b606543 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -14,6 +14,7 @@ + From 25b9caa903feb2e441172b2e5f89609f20c1d685 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 13 Mar 2019 13:47:49 +0100 Subject: [PATCH 19/23] Implemented config save and reload Always caching config value if it hasn't been cached --- ...1) (com.github.TBMCPlugins.ButtonCore).iml | 2 +- .../buttondevteam/core/ComponentCommand.java | 6 +++- .../buttondevteam/core/ComponentManager.java | 5 +-- .../buttondevteam/core/ThorpeCommand.java | 14 ++++++++ .../lib/architecture/ButtonPlugin.java | 29 +++++++++++++--- .../lib/architecture/Component.java | 6 ++-- .../lib/architecture/ConfigData.java | 33 +++++++++++++++---- ButtonProcessor/ButtonProcessor.iml | 2 -- 8 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java diff --git a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml index c89b771..7c2fa83 100644 --- a/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml +++ b/ButtonCore/ButtonCore (1) (com.github.TBMCPlugins.ButtonCore).iml @@ -1,5 +1,5 @@ - + diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java index 4e4a998..10b4b16 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentCommand.java @@ -1,6 +1,7 @@ package buttondevteam.core; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.architecture.ButtonPlugin; import buttondevteam.lib.architecture.Component; import buttondevteam.lib.chat.Command2; import buttondevteam.lib.chat.Command2.Subcommand; @@ -24,7 +25,10 @@ public class ComponentCommand extends ICommand2MC { @Subcommand public boolean enable(CommandSender sender, Plugin plugin, String component) { - plugin.reloadConfig(); //Reload config so the new config values are read - All changes are saved to disk on disable + if (plugin instanceof ButtonPlugin) + ((ButtonPlugin) plugin).justReload(); + else + 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); } diff --git a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java index 9a84ddd..db9c2e3 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ComponentManager.java @@ -34,9 +34,10 @@ public final class ComponentManager { /** * Unregister all components of a plugin that are enabled - called on {@link ButtonPlugin} disable */ - public static void unregComponents(ButtonPlugin plugin) { + @SuppressWarnings("unchecked") + public static void unregComponents(T plugin) { while (!plugin.getComponentStack().empty()) //Unregister in reverse order - Component.unregisterComponent(plugin, plugin.getComponentStack().pop()); //Components are pushed on register + Component.unregisterComponent(plugin, (Component) plugin.getComponentStack().pop()); //Components are pushed on register componentsEnabled = false; } diff --git a/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java new file mode 100644 index 0000000..5fb924f --- /dev/null +++ b/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java @@ -0,0 +1,14 @@ +package buttondevteam.core; + +import buttondevteam.lib.chat.Command2; +import buttondevteam.lib.chat.CommandClass; +import buttondevteam.lib.chat.ICommand2MC; +import org.bukkit.command.CommandSender; + +@CommandClass +public class ThorpeCommand extends ICommand2MC { + @Command2.Subcommand //TODO: Main permissions (groups) like 'mod' + public void reload(CommandSender sender) { + MainPlugin.Instance.reloadConfig(); + } +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 381bfc6..3c46b59 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -20,10 +20,10 @@ public abstract class ButtonPlugin extends JavaPlugin { @Getter(AccessLevel.PROTECTED) private IHaveConfig data; //TODO /** - * Used to unregister components in the right order + * Used to unregister components in the right order - and to reload configs */ @Getter - private Stack componentStack = new Stack<>(); + private Stack> componentStack = new Stack<>(); protected abstract void pluginEnable(); @@ -40,9 +40,7 @@ public abstract class ButtonPlugin extends JavaPlugin { @Override public final void onEnable() { - var section = super.getConfig().getConfigurationSection("global"); - if (section == null) section = super.getConfig().createSection("global"); - iConfig = new IHaveConfig(section, this::saveConfig); + loadConfig(); try { pluginEnable(); } catch (Exception e) { @@ -50,6 +48,12 @@ public abstract class ButtonPlugin extends JavaPlugin { } } + private void loadConfig() { + var section = super.getConfig().getConfigurationSection("global"); + if (section == null) section = super.getConfig().createSection("global"); + iConfig = new IHaveConfig(section, this::saveConfig); + } + @Override public final void onDisable() { try { @@ -63,4 +67,19 @@ public abstract class ButtonPlugin extends JavaPlugin { TBMCCoreAPI.SendException("Error while disabling plugin " + getName() + "!", e); } } + + @Override + public void reloadConfig() { + justReload(); + loadConfig(); + componentStack.forEach(c -> Component.updateConfig(this, c)); + } + + public void justReload() { + if (ConfigData.saveNow(getConfig())) { + getLogger().warning("Saved pending configuration changes to the file, didn't reload (try again)."); + return; + } + super.reloadConfig(); + } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java index 43e77fa..4d2c9cf 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/Component.java @@ -140,7 +140,7 @@ public abstract class Component { } } - private static void updateConfig(JavaPlugin plugin, Component component) { + public static void updateConfig(JavaPlugin plugin, Component component) { if (plugin.getConfig() != null) { //Production var compconf = plugin.getConfig().getConfigurationSection("components"); if (compconf == null) compconf = plugin.getConfig().createSection("components"); @@ -237,10 +237,10 @@ public abstract class Component { var cs=c.getConfigurationSection(key); if(cs==null) cs=c.createSection(key); val res = cs.getValues(false).entrySet().stream().filter(e -> e.getValue() instanceof ConfigurationSection) - .collect(Collectors.toMap(Map.Entry::getKey, kv -> new IHaveConfig((ConfigurationSection) kv.getValue()))); + .collect(Collectors.toMap(Map.Entry::getKey, kv -> new IHaveConfig((ConfigurationSection) kv.getValue(), getPlugin()::saveConfig))); if (res.size() == 0) { for (val entry : defaultProvider.entrySet()) { - val conf = new IHaveConfig(cs.createSection(entry.getKey())); + val conf = new IHaveConfig(cs.createSection(entry.getKey()), getPlugin()::saveConfig); entry.getValue().accept(conf); res.put(entry.getKey(), conf); } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java index b2961a1..f055717 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -2,12 +2,12 @@ package buttondevteam.lib.architecture; import buttondevteam.core.MainPlugin; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; import org.bukkit.configuration.Configuration; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitTask; import java.lang.reflect.Array; @@ -23,7 +23,7 @@ import java.util.function.Function; @RequiredArgsConstructor(access = AccessLevel.PACKAGE) //@AllArgsConstructor(access = AccessLevel.PACKAGE) public class ConfigData { - private static final HashMap saveTasks= new HashMap<>(); + private static final HashMap saveTasks = new HashMap<>(); /** * May be null for testing */ @@ -45,8 +45,12 @@ public class ConfigData { * The config value should not change outside this instance */ private T value; + /** + * Whether the default value is saved in the yaml + */ private boolean saved = false; + //This constructor is needed because it sets the getter and setter public ConfigData(ConfigurationSection config, String path, T def, Object primitiveDef, Function getter, Function setter, Runnable saveAction) { this.config = config; this.path = path; @@ -88,9 +92,9 @@ public class ConfigData { else if (def instanceof Double) val = ((Number) val).doubleValue(); } - if (val instanceof List && def.getClass().isArray()) + if (val instanceof List && def != null && def.getClass().isArray()) val = ((List) val).toArray((T[]) Array.newInstance(def.getClass().getComponentType(), 0)); - return (T) val; + return value = (T) val; //Always cache, if not cached yet } public void set(T value) { @@ -102,15 +106,32 @@ public class ConfigData { config.set(path, val); if(!saveTasks.containsKey(config.getRoot())) { synchronized (saveTasks) { - saveTasks.put(config.getRoot(), Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, () -> { + saveTasks.put(config.getRoot(), new SaveTask(Bukkit.getScheduler().runTaskLaterAsynchronously(MainPlugin.Instance, () -> { synchronized (saveTasks) { saveTasks.remove(config.getRoot()); saveAction.run(); } - }, 100)); + }, 100), saveAction)); } } } this.value = value; } + + @AllArgsConstructor + private static class SaveTask { + BukkitTask task; + Runnable saveAction; + } + + public static boolean saveNow(Configuration config) { + SaveTask st = saveTasks.get(config); + if (st != null) { + st.task.cancel(); + saveTasks.remove(config); + st.saveAction.run(); + return true; + } + return false; + } } diff --git a/ButtonProcessor/ButtonProcessor.iml b/ButtonProcessor/ButtonProcessor.iml index b606543..35bfd14 100755 --- a/ButtonProcessor/ButtonProcessor.iml +++ b/ButtonProcessor/ButtonProcessor.iml @@ -13,8 +13,6 @@ - - From c62424389fa71e5cd30a70318ac2f047d6435a7c Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 14 Mar 2019 00:40:40 +0100 Subject: [PATCH 20/23] A fix and another --- ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java | 1 + .../java/buttondevteam/lib/architecture/ButtonPlugin.java | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java index f46a85c..e810c67 100755 --- a/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/core/MainPlugin.java @@ -93,6 +93,7 @@ public class MainPlugin extends ButtonPlugin { Component.registerComponent(this, new VotifierComponent(economy)); ComponentManager.enableComponents(); getCommand2MC().registerCommand(new ComponentCommand()); + getCommand2MC().registerCommand(new ThorpeCommand()); 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/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index 3c46b59..e06ab95 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -19,6 +19,7 @@ public abstract class ButtonPlugin extends JavaPlugin { private IHaveConfig iConfig; @Getter(AccessLevel.PROTECTED) private IHaveConfig data; //TODO + private boolean loaded = false; /** * Used to unregister components in the right order - and to reload configs */ @@ -76,10 +77,11 @@ public abstract class ButtonPlugin extends JavaPlugin { } public void justReload() { - if (ConfigData.saveNow(getConfig())) { + if (loaded && ConfigData.saveNow(getConfig())) { getLogger().warning("Saved pending configuration changes to the file, didn't reload (try again)."); return; } super.reloadConfig(); + loaded = true; //Needed because for the first time it uses reloadConfig() to load it } } From 70cabfaa81ea2e2a0ebc9e899a74b628e5d12198 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Thu, 14 Mar 2019 16:27:22 +0100 Subject: [PATCH 21/23] Reload msg, old perm check, Player cmd fix --- .../java/buttondevteam/core/ThorpeCommand.java | 5 ++++- .../lib/architecture/ButtonPlugin.java | 16 +++++++++++----- .../java/buttondevteam/lib/chat/Command2.java | 6 +++--- .../java/buttondevteam/lib/chat/Command2MC.java | 4 +++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java b/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java index 5fb924f..91f2d5c 100644 --- a/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java +++ b/ButtonCore/src/main/java/buttondevteam/core/ThorpeCommand.java @@ -9,6 +9,9 @@ import org.bukkit.command.CommandSender; public class ThorpeCommand extends ICommand2MC { @Command2.Subcommand //TODO: Main permissions (groups) like 'mod' public void reload(CommandSender sender) { - MainPlugin.Instance.reloadConfig(); + if (MainPlugin.Instance.tryReloadConfig()) + sender.sendMessage("§bConfig reloaded."); + else + sender.sendMessage("§cFailed to reload config. Check console."); } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java index e06ab95..25df8af 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ButtonPlugin.java @@ -71,17 +71,23 @@ public abstract class ButtonPlugin extends JavaPlugin { @Override public void reloadConfig() { - justReload(); - loadConfig(); - componentStack.forEach(c -> Component.updateConfig(this, c)); + tryReloadConfig(); } - public void justReload() { + public boolean tryReloadConfig() { + if (!justReload()) return false; + loadConfig(); + componentStack.forEach(c -> Component.updateConfig(this, c)); + return true; + } + + public boolean justReload() { if (loaded && ConfigData.saveNow(getConfig())) { getLogger().warning("Saved pending configuration changes to the file, didn't reload (try again)."); - return; + return false; } super.reloadConfig(); loaded = true; //Needed because for the first time it uses reloadConfig() to load it + return true; } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 8327314..03e5dd4 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -5,7 +5,6 @@ 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; @@ -105,7 +104,8 @@ public abstract class Command2 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 (CommandSender.class.isAssignableFrom(sendertype) && sender instanceof Command2MCSender) + else if (sender instanceof Command2MCSender + && sendertype.isAssignableFrom(((Command2MCSender) sender).getSender().getClass())) params.add(((Command2MCSender) sender).getSender()); else if (ChromaGamerBase.class.isAssignableFrom(sendertype) && sender instanceof Command2MCSender @@ -238,4 +238,4 @@ public abstract class Command2 public String[] getCommandsText() { return commandHelp.toArray(new String[0]); } -} //TODO: Test support of Player instead of CommandSender +} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index 4a26622..b7a736c 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -12,7 +12,9 @@ public class Command2MC extends Command2 { @Override public boolean hasPermission(Command2MCSender sender, ICommand2MC command) { - return MainPlugin.permission.has(sender.getSender(), "thorpe.command." + command.getCommandPath().replace(' ', '.')); + return command.getClass().getAnnotation(CommandClass.class).modOnly() + ? MainPlugin.permission.has(sender.getSender(), "tbmc.admin") //TODO: Change when groups are implemented + : MainPlugin.permission.has(sender.getSender(), "thorpe.command." + command.getCommandPath().replace(' ', '.')); } /** From 0d5ca5a9af21a85401a6f5b6eb2cb6d7d281d2b6 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Mar 2019 02:57:45 +0100 Subject: [PATCH 22/23] Command improvements, number converter Setting to modOnly if any of the superclasses are modOnly Re-added support for command path inheritance getHelpText() for a particular command Subcommands are properly printed across classes now Using a general number converter for both the config and commands --- .../java/buttondevteam/lib/ThorpeUtils.java | 14 +++++++ .../lib/architecture/ConfigData.java | 16 ++------ .../java/buttondevteam/lib/chat/Command2.java | 41 ++++++++++++++++--- .../buttondevteam/lib/chat/Command2MC.java | 17 +++++++- .../buttondevteam/lib/chat/ICommand2.java | 19 ++++++++- 5 files changed, 86 insertions(+), 21 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java b/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java index 4f8560c..8c464b0 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java @@ -35,4 +35,18 @@ public final class ThorpeUtils { */ String getFancyFullName(); } + + public static Number convertNumber(Number number, Class targetcl) { + if (targetcl == long.class || Long.class.isAssignableFrom(targetcl)) + return number.longValue(); + else if (targetcl == short.class || Short.class.isAssignableFrom(targetcl)) + return number.shortValue(); + else if (targetcl == byte.class || Byte.class.isAssignableFrom(targetcl)) + return number.byteValue(); + else if (targetcl == float.class || Float.class.isAssignableFrom(targetcl)) + return number.floatValue(); + else if (targetcl == double.class || Double.class.isAssignableFrom(targetcl)) + return number.doubleValue(); + return number; + } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java index f055717..6374db0 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/architecture/ConfigData.java @@ -1,6 +1,7 @@ package buttondevteam.lib.architecture; import buttondevteam.core.MainPlugin; +import buttondevteam.lib.ThorpeUtils; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; @@ -80,18 +81,9 @@ public class ConfigData { if (hmm == null) hmm = def; //Set if the getter returned null return hmm; } - if (val instanceof Number) { - if (def instanceof Long) - val = ((Number) val).longValue(); - else if (def instanceof Short) - val = ((Number) val).shortValue(); - else if (def instanceof Byte) - val = ((Number) val).byteValue(); - else if (def instanceof Float) - val = ((Number) val).floatValue(); - else if (def instanceof Double) - val = ((Number) val).doubleValue(); - } + if (val instanceof Number && def != null) + val = ThorpeUtils.convertNumber((Number) val, + (Class) def.getClass()); if (val instanceof List && def != null && def.getClass().isArray()) val = ((List) val).toArray((T[]) Array.newInstance(def.getClass().getComponentType(), 0)); return value = (T) val; //Always cache, if not cached yet diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 03e5dd4..5e10530 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -1,7 +1,9 @@ package buttondevteam.lib.chat; import buttondevteam.lib.TBMCCoreAPI; +import buttondevteam.lib.ThorpeUtils; import buttondevteam.lib.player.ChromaGamerBase; +import lombok.AllArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.experimental.var; import lombok.val; @@ -13,6 +15,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; +import java.text.NumberFormat; +import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -52,11 +56,11 @@ public abstract class Command2 public @interface OptionalArg { } - @RequiredArgsConstructor + @AllArgsConstructor protected static class SubcommandData { public final Method method; public final T command; - public final String[] helpText; + public String[] helpText; } @RequiredArgsConstructor @@ -136,6 +140,15 @@ public abstract class Command2 if (cl == String.class) { params.add(param); continue; + } else if (Number.class.isAssignableFrom(cl) || cl.isPrimitive()) { + try { + //noinspection unchecked + params.add(ThorpeUtils.convertNumber(NumberFormat.getInstance().parse(param), (Class) cl)); + } catch (ParseException e) { + sender.sendMessage("§c'" + param + "' is not a number."); + return true; + } + continue; } val conv = paramConverters.get(cl); if (conv == null) @@ -169,14 +182,16 @@ public abstract class Command2 val scmdHelpList = new ArrayList(); Method mainMethod = null; boolean nosubs = true; + boolean isSubcommand = x != -1; try { //Register the default handler first so it can be reliably overwritten mainMethod = command.getClass().getMethod("def", Command2Sender.class, String.class); val cc = command.getClass().getAnnotation(CommandClass.class); - var ht = cc == null ? new String[0] : cc.helpText(); + var ht = cc == null || isSubcommand ? new String[0] : cc.helpText(); //If it's not the main command, don't add it if (ht.length > 0) ht[0] = "§6---- " + ht[0] + " ----"; scmdHelpList.addAll(Arrays.asList(ht)); - scmdHelpList.add("§6Subcommands:"); + if (!isSubcommand) + scmdHelpList.add("§6Subcommands:"); if (!commandHelp.contains(mainPath)) commandHelp.add(mainPath); } catch (Exception e) { @@ -199,8 +214,16 @@ public abstract class Command2 scmdHelpList.remove(scmdHelpList.size() - 1); //Remove Subcommands header if (mainMethod != null && !subcommands.containsKey(commandChar + path)) //Command specified by the class subcommands.put(commandChar + path, new SubcommandData<>(mainMethod, command, scmdHelpList.toArray(new String[0]))); - if (mainMethod != null && !subcommands.containsKey(mainPath)) //Main command, typically the same as the above - subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0]))); + if (mainMethod != null && !mainPath.equals(commandChar + path)) { //Main command, typically the same as the above + if (isSubcommand) { //The class itself is a subcommand + val scmd = subcommands.computeIfAbsent(mainPath, p -> new SubcommandData<>(null, null, new String[]{"§6---- Subcommands ----"})); + val scmdHelp = Arrays.copyOf(scmd.helpText, scmd.helpText.length + scmdHelpList.size()); + for (int i = 0; i < scmdHelpList.size(); i++) + scmdHelp[scmd.helpText.length + i] = scmdHelpList.get(i); + scmd.helpText = scmdHelp; + } else if (!subcommands.containsKey(mainPath)) + subcommands.put(mainPath, new SubcommandData<>(null, null, scmdHelpList.toArray(new String[0]))); + } } private String[] getHelpText(Method method, String[] ht, String subcommand) { @@ -238,4 +261,10 @@ public abstract class Command2 public String[] getCommandsText() { return commandHelp.toArray(new String[0]); } + + public String[] getHelpText(String path) { + val scmd = subcommands.get(path); + if (scmd == null) return null; + return scmd.helpText; + } } diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java index b7a736c..9761ea5 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2MC.java @@ -1,6 +1,7 @@ package buttondevteam.lib.chat; import buttondevteam.core.MainPlugin; +import lombok.val; import java.util.function.Function; @@ -12,11 +13,25 @@ public class Command2MC extends Command2 { @Override public boolean hasPermission(Command2MCSender sender, ICommand2MC command) { - return command.getClass().getAnnotation(CommandClass.class).modOnly() + return modOnly(command) ? MainPlugin.permission.has(sender.getSender(), "tbmc.admin") //TODO: Change when groups are implemented : MainPlugin.permission.has(sender.getSender(), "thorpe.command." + command.getCommandPath().replace(' ', '.')); } + /** + * Returns true if this class or any of the superclasses are mod only. + * + * @param command The command to check + * @return Whether the command is mod only + */ + private boolean modOnly(ICommand2MC command) { + for (Class cl = command.getClass(); cl != null; cl = cl.getSuperclass()) { + val cc = command.getClass().getAnnotation(CommandClass.class); + if (cc != null && cc.modOnly()) return true; + } + return false; + } + /** * Automatically colors the message red. * {@see super#addParamConverter} diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java index dba5664..b55a85a 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/ICommand2.java @@ -4,6 +4,7 @@ import lombok.Getter; import lombok.val; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.function.Function; public abstract class ICommand2 { @@ -69,8 +70,22 @@ public abstract class ICommand2 { "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; + String path = getClass().getAnnotation(CommandClass.class).path(), + prevpath = path = path.length() == 0 ? getFromClass.apply(getClass()) : path; + for (Class cl = getClass().getSuperclass(); cl != null + && !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl + .getSuperclass()) { // + String newpath; + if (!cl.isAnnotationPresent(CommandClass.class) + || (newpath = cl.getAnnotation(CommandClass.class).path()).length() == 0 + || newpath.equals(prevpath)) { + if ((Modifier.isAbstract(cl.getModifiers()) && !cl.isAnnotationPresent(CommandClass.class)) + || cl.getAnnotation(CommandClass.class).excludeFromPath()) // <-- + continue; + newpath = getFromClass.apply(cl); + } + path = (prevpath = newpath) + " " + path; + } return path; } } From 9ea811ba4095d539c47cbbf9b6c3e45ff77a38d6 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Sat, 16 Mar 2019 14:31:26 +0100 Subject: [PATCH 23/23] Number fix, added varargs support for cmds Added support for int conversion Varargs take... a variable amount of args Command error handling (less lines in stack traces) --- .../java/buttondevteam/lib/ThorpeUtils.java | 2 ++ .../java/buttondevteam/lib/chat/Command2.java | 28 +++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java b/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java index 8c464b0..d69983e 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/ThorpeUtils.java @@ -39,6 +39,8 @@ public final class ThorpeUtils { public static Number convertNumber(Number number, Class targetcl) { if (targetcl == long.class || Long.class.isAssignableFrom(targetcl)) return number.longValue(); + else if (targetcl == int.class || Integer.class.isAssignableFrom(targetcl)) + return number.intValue(); //Needed because the parser can get longs else if (targetcl == short.class || Short.class.isAssignableFrom(targetcl)) return number.shortValue(); else if (targetcl == byte.class || Byte.class.isAssignableFrom(targetcl)) diff --git a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java index 5e10530..bc10fc7 100644 --- a/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java +++ b/ButtonCore/src/main/java/buttondevteam/lib/chat/Command2.java @@ -14,6 +14,7 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.NumberFormat; import java.text.ParseException; @@ -133,6 +134,10 @@ public abstract class Command2 return true; } } + if (paramArr[i1].isVarArgs()) { + params.add(commandline.substring(j + 1).split(" +")); + continue; + } j = commandline.indexOf(' ', j + 1); //End index if (j == -1 || paramArr[i1].isAnnotationPresent(TextArg.class)) //Last parameter j = commandline.length(); @@ -142,8 +147,11 @@ public abstract class Command2 continue; } else if (Number.class.isAssignableFrom(cl) || cl.isPrimitive()) { try { + //System.out.println("Converting "+param+" param to "+cl.getSimpleName()); //noinspection unchecked - params.add(ThorpeUtils.convertNumber(NumberFormat.getInstance().parse(param), (Class) cl)); + Number n = ThorpeUtils.convertNumber(NumberFormat.getInstance().parse(param), (Class) cl); + //System.out.println(n.getClass().getSimpleName()+" with value "+n); + params.add(n); } catch (ParseException e) { sender.sendMessage("§c'" + param + "' is not a number."); return true; @@ -161,13 +169,17 @@ public abstract class Command2 params.add(cparam); } //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) //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 + try { + 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) //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 + } catch (InvocationTargetException e) { + TBMCCoreAPI.SendException("An error occurred in a command handler!", e.getCause()); + } } return false; //Didn't handle } //TODO: Add to the help