diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/ServerUtils.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/ServerUtils.java index 375128f..f9ec40d 100644 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/ServerUtils.java +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/ServerUtils.java @@ -2,6 +2,7 @@ package net.frankheijden.serverutils.bukkit; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import net.frankheijden.serverutils.bukkit.entities.BukkitPlugin; import net.frankheijden.serverutils.bukkit.managers.BukkitPluginManager; import net.frankheijden.serverutils.bukkit.reflection.RCraftServer; @@ -65,14 +66,14 @@ public class ServerUtils extends JavaPlugin { String commandString = StringUtils.join(":", split, 1); PluginCommand pluginCommand = Bukkit.getPluginCommand(commandString); - Plugin plugin = getPlugin().getPluginManager().getPlugin(split[0]); - if (plugin == null) { + Optional pluginOptional = getPlugin().getPluginManager().getPlugin(split[0]); + if (!pluginOptional.isPresent()) { getLogger().warning("Unknown plugin '" + split[0] + "' in disabled-commands!"); continue; } else if (pluginCommand == null) { getLogger().warning("Unknown command '" + commandString + "' in disabled-commands!"); continue; - } else if (!plugin.getName().equalsIgnoreCase(pluginCommand.getPlugin().getName())) { + } else if (pluginOptional.get().getName().equalsIgnoreCase(pluginCommand.getPlugin().getName())) { // No output here, plugin didn't match! continue; } diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/commands/BukkitCommandServerUtils.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/commands/BukkitCommandServerUtils.java index 11ca083..6d93f32 100644 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/commands/BukkitCommandServerUtils.java +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/commands/BukkitCommandServerUtils.java @@ -3,6 +3,7 @@ package net.frankheijden.serverutils.bukkit.commands; import cloud.commandframework.CommandManager; import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.context.CommandContext; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,7 +19,7 @@ import net.frankheijden.serverutils.bukkit.reflection.RDedicatedServer; import net.frankheijden.serverutils.bukkit.utils.ReloadHandler; import net.frankheijden.serverutils.bukkit.utils.VersionReloadHandler; import net.frankheijden.serverutils.common.commands.CommandServerUtils; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.results.PluginResults; import net.frankheijden.serverutils.common.utils.FormatBuilder; import net.frankheijden.serverutils.common.utils.ForwardFilter; import net.frankheijden.serverutils.common.utils.ListBuilder; @@ -46,7 +47,7 @@ public class BukkitCommandServerUtils extends CommandServerUtils context) { BukkitCommandSender sender = context.getSender(); - String pluginName = context.get("plugin"); + List plugins = Arrays.asList(context.get("plugins")); - Result result = plugin.getPluginManager().enablePlugin(pluginName); - result.sendTo(sender, "enabl", pluginName); + PluginResults result = plugin.getPluginManager().enablePlugins(plugins); + result.sendTo(sender, "enabl"); } private void handleDisablePlugin(CommandContext context) { BukkitCommandSender sender = context.getSender(); - String pluginName = context.get("plugin"); + List plugins = Arrays.asList(context.get("plugins")); - Result result = plugin.getPluginManager().disablePlugin(pluginName); - result.sendTo(sender, "disabl", pluginName); + PluginResults result = plugin.getPluginManager().disablePlugins(plugins); + result.sendTo(sender, "disabl"); } private void handleReloadConfig(CommandContext context) { @@ -148,12 +149,11 @@ public class BukkitCommandServerUtils extends CommandServerUtils>, String> listBuilderFunction, - String pluginName + Plugin bukkitPlugin ) { - Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); - PluginDescriptionFile description = plugin.getDescription(); + PluginDescriptionFile description = bukkitPlugin.getDescription(); - builder.add("Name", plugin.getName()) + builder.add("Name", bukkitPlugin.getName()) .add("Full Name", description.getFullName()) .add("Version", description.getVersion()) .add("Website", description.getWebsite()) diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitLoadResult.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitLoadResult.java deleted file mode 100644 index a538a9f..0000000 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitLoadResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.frankheijden.serverutils.bukkit.entities; - -import net.frankheijden.serverutils.common.entities.LoadResult; -import net.frankheijden.serverutils.common.entities.Result; -import org.bukkit.plugin.Plugin; - -public class BukkitLoadResult extends LoadResult { - - private BukkitLoadResult(Plugin obj, Result result) { - super(obj, result); - } - - public BukkitLoadResult(Plugin obj) { - this(obj, Result.SUCCESS); - } - - public BukkitLoadResult(Result result) { - this(null, result); - } -} diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPlugin.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPlugin.java index bcaab17..2c16695 100644 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPlugin.java +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPlugin.java @@ -1,5 +1,6 @@ package net.frankheijden.serverutils.bukkit.entities; +import cloud.commandframework.bukkit.CloudBukkitCapabilities; import cloud.commandframework.execution.CommandExecutionCoordinator; import cloud.commandframework.paper.PaperCommandManager; import java.io.File; @@ -16,12 +17,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitTask; -public class BukkitPlugin extends ServerUtilsPlugin< - Plugin, - BukkitTask, - BukkitCommandSender, - CommandSender - > { +public class BukkitPlugin extends ServerUtilsPlugin { private final ServerUtils plugin; private final BukkitPluginManager pluginManager; @@ -45,8 +41,9 @@ public class BukkitPlugin extends ServerUtilsPlugin< @Override protected PaperCommandManager newCommandManager() { + PaperCommandManager commandManager; try { - return new PaperCommandManager<>( + commandManager = new PaperCommandManager<>( plugin, CommandExecutionCoordinator.simpleCoordinator(), chatProvider::get, @@ -55,6 +52,17 @@ public class BukkitPlugin extends ServerUtilsPlugin< } catch (Exception ex) { throw new RuntimeException(ex); } + + if (commandManager.queryCapability(CloudBukkitCapabilities.BRIGADIER)) { + commandManager.registerBrigadier(); + handleBrigadier(commandManager.brigadierManager()); + } + + if (commandManager.queryCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) { + commandManager.registerAsynchronousCompletions(); + } + + return commandManager; } @Override diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPluginDescription.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPluginDescription.java new file mode 100644 index 0000000..be05c28 --- /dev/null +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/entities/BukkitPluginDescription.java @@ -0,0 +1,59 @@ +package net.frankheijden.serverutils.bukkit.entities; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import org.bukkit.plugin.PluginDescriptionFile; + +public class BukkitPluginDescription implements ServerUtilsPluginDescription { + + private final PluginDescriptionFile descriptionFile; + private final File file; + private final String author; + private final Set dependencies; + + /** + * Constructs a new BukkitPluginDescription. + */ + public BukkitPluginDescription(PluginDescriptionFile descriptionFile, File file) { + this.descriptionFile = descriptionFile; + this.file = file; + this.author = String.join(", ", this.descriptionFile.getAuthors()); + this.dependencies = new HashSet<>(descriptionFile.getDepend()); + } + + @Override + public String getId() { + return this.descriptionFile.getName(); + } + + @Override + public String getName() { + return this.descriptionFile.getName(); + } + + @Override + public String getVersion() { + return this.descriptionFile.getVersion(); + } + + @Override + public String getAuthor() { + return this.author; + } + + @Override + public File getFile() { + return this.file; + } + + @Override + public Set getDependencies() { + return this.dependencies; + } + + public PluginDescriptionFile getDescriptionFile() { + return descriptionFile; + } +} diff --git a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java index f9f2cf9..fa47d45 100644 --- a/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java +++ b/Bukkit/src/main/java/net/frankheijden/serverutils/bukkit/managers/BukkitPluginManager.java @@ -9,10 +9,11 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import net.frankheijden.serverutils.bukkit.entities.BukkitLoadResult; +import net.frankheijden.serverutils.bukkit.entities.BukkitPluginDescription; import net.frankheijden.serverutils.bukkit.events.BukkitPluginDisableEvent; import net.frankheijden.serverutils.bukkit.events.BukkitPluginEnableEvent; import net.frankheijden.serverutils.bukkit.events.BukkitPluginLoadEvent; @@ -24,8 +25,10 @@ import net.frankheijden.serverutils.bukkit.reflection.RJavaPlugin; import net.frankheijden.serverutils.bukkit.reflection.RJavaPluginLoader; import net.frankheijden.serverutils.bukkit.reflection.RPluginClassLoader; import net.frankheijden.serverutils.bukkit.reflection.RSimplePluginManager; -import net.frankheijden.serverutils.common.entities.CloseableResult; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults; +import net.frankheijden.serverutils.common.entities.results.PluginResults; +import net.frankheijden.serverutils.common.entities.results.Result; +import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException; import net.frankheijden.serverutils.common.events.PluginEvent; import net.frankheijden.serverutils.common.managers.AbstractPluginManager; import org.bukkit.Bukkit; @@ -35,11 +38,11 @@ import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.plugin.InvalidDescriptionException; import org.bukkit.plugin.InvalidPluginException; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginLoader; +import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.UnknownDependencyException; -public class BukkitPluginManager implements AbstractPluginManager { +public class BukkitPluginManager extends AbstractPluginManager { private static BukkitPluginManager instance; @@ -51,122 +54,101 @@ public class BukkitPluginManager implements AbstractPluginManager { return instance; } - /** - * Loads the specified file as a plugin. - * @param jarFile The name of the file in the plugins/ folder. - * @return The result of the loading procedure. - */ @Override - public BukkitLoadResult loadPlugin(String jarFile) { - return loadPlugin(new File(getPluginsFolder(), jarFile)); - } + public PluginResults loadPluginDescriptions(List descriptions) { + PluginResults pluginResults = new PluginResults<>(); - /** - * Loads the specified file as a plugin. - * @param file The file to be loaded. - * @return The result of the loading procedure. - */ - @Override - public BukkitLoadResult loadPlugin(File file) { - if (!file.exists()) return new BukkitLoadResult(Result.NOT_EXISTS); + for (BukkitPluginDescription description : descriptions) { + String pluginId = description.getId(); - Plugin loadedPlugin = getLoadedPlugin(file); - if (loadedPlugin != null) return new BukkitLoadResult(Result.ALREADY_LOADED); - - Plugin plugin; - try { - plugin = Bukkit.getPluginManager().loadPlugin(file); - } catch (InvalidDescriptionException ex) { - return new BukkitLoadResult(Result.INVALID_DESCRIPTION); - } catch (UnknownDependencyException ex) { - return new BukkitLoadResult(Result.UNKNOWN_DEPENDENCY.arg(ex.getMessage())); - } catch (InvalidPluginException ex) { - if (ex.getCause() instanceof IllegalArgumentException) { - IllegalArgumentException e = (IllegalArgumentException) ex.getCause(); - if (e.getMessage().equalsIgnoreCase("Plugin already initialized!")) { - return new BukkitLoadResult(Result.ALREADY_ENABLED); + Plugin plugin; + try { + plugin = Bukkit.getPluginManager().loadPlugin(description.getFile()); + } catch (InvalidDescriptionException ex) { + return pluginResults.addResult(pluginId, Result.INVALID_DESCRIPTION); + } catch (UnknownDependencyException ex) { + return pluginResults.addResult(pluginId, Result.UNKNOWN_DEPENDENCY.arg(ex.getMessage())); + } catch (InvalidPluginException ex) { + if (ex.getCause() instanceof IllegalArgumentException) { + IllegalArgumentException e = (IllegalArgumentException) ex.getCause(); + if (e.getMessage().equalsIgnoreCase("Plugin already initialized!")) { + return pluginResults.addResult(pluginId, Result.ALREADY_ENABLED); + } } + ex.printStackTrace(); + return pluginResults.addResult(pluginId, Result.ERROR); } - ex.printStackTrace(); - return new BukkitLoadResult(Result.ERROR); + + if (plugin == null) return pluginResults.addResult(pluginId, Result.INVALID_PLUGIN); + Bukkit.getPluginManager().callEvent(new BukkitPluginLoadEvent(plugin, PluginEvent.Stage.PRE)); + plugin.onLoad(); + Bukkit.getPluginManager().callEvent(new BukkitPluginLoadEvent(plugin, PluginEvent.Stage.POST)); + pluginResults.addResult(pluginId, plugin); } - if (plugin == null) return new BukkitLoadResult(Result.INVALID_PLUGIN); - Bukkit.getPluginManager().callEvent(new BukkitPluginLoadEvent(plugin, PluginEvent.Stage.PRE)); - plugin.onLoad(); - Bukkit.getPluginManager().callEvent(new BukkitPluginLoadEvent(plugin, PluginEvent.Stage.POST)); - return new BukkitLoadResult(plugin); + return pluginResults; } - /** - * Disables the specified plugin by name and cleans all commands and recipes of the plugin. - * @param pluginName The plugin to disable. - * @return The result of the disable call. - */ - public Result disablePlugin(String pluginName) { - return disablePlugin(Bukkit.getPluginManager().getPlugin(pluginName)); - } - - /** - * Disables the specified plugin and cleans all commands and recipes of the plugin. - * @param plugin The plugin to disable. - * @return The result of the disable call. - */ @Override - public Result disablePlugin(Plugin plugin) { - if (plugin == null) return Result.NOT_ENABLED; - if (!plugin.isEnabled()) return Result.ALREADY_DISABLED; - Bukkit.getPluginManager().callEvent(new BukkitPluginDisableEvent(plugin, PluginEvent.Stage.PRE)); - try { - Bukkit.getPluginManager().disablePlugin(plugin); - RCraftingManager.removeRecipesFor(plugin); - } catch (Exception ex) { - ex.printStackTrace(); - return Result.ERROR; + public PluginResults disableOrderedPlugins(List plugins) { + PluginResults disableResults = new PluginResults<>(); + + for (Plugin plugin : plugins) { + String pluginId = getPluginId(plugin); + if (!isPluginEnabled(pluginId)) return disableResults.addResult(pluginId, Result.ALREADY_DISABLED); + + Bukkit.getPluginManager().callEvent(new BukkitPluginDisableEvent(plugin, PluginEvent.Stage.PRE)); + try { + Bukkit.getPluginManager().disablePlugin(plugin); + RCraftingManager.removeRecipesFor(plugin); + } catch (Exception ex) { + ex.printStackTrace(); + return disableResults.addResult(pluginId, Result.ERROR); + } + + unregisterCommands(plugin); + Bukkit.getPluginManager().callEvent(new BukkitPluginDisableEvent(plugin, PluginEvent.Stage.POST)); + + disableResults.addResult(pluginId, plugin); } - unregisterCommands(plugin); - Bukkit.getPluginManager().callEvent(new BukkitPluginDisableEvent(plugin, PluginEvent.Stage.POST)); - return Result.SUCCESS; + + return disableResults; } - /** - * Unloads the specified plugin by name and cleans all traces within bukkit. - * @param pluginName The plugin to unload. - * @return The result of the unload. - */ @Override - public CloseableResult unloadPlugin(String pluginName) { - return unloadPlugin(Bukkit.getPluginManager().getPlugin(pluginName)); - } + public CloseablePluginResults unloadOrderedPlugins(List plugins) { + CloseablePluginResults unloadResults = new CloseablePluginResults<>(); - /** - * Unloads the specified plugin and cleans all traces within bukkit. - * @param plugin The plugin to unload. - * @return The result of the unload. - */ - @Override - public CloseableResult unloadPlugin(Plugin plugin) { - if (plugin == null) return new CloseableResult(Result.NOT_EXISTS); - Bukkit.getPluginManager().callEvent(new BukkitPluginUnloadEvent(plugin, PluginEvent.Stage.PRE)); - List closeables = new ArrayList<>(); - try { - RSimplePluginManager.getPlugins(Bukkit.getPluginManager()).remove(plugin); - RSimplePluginManager.removeLookupName(Bukkit.getPluginManager(), plugin.getName()); + for (Plugin plugin : plugins) { + String pluginId = getPluginId(plugin); + Bukkit.getPluginManager().callEvent(new BukkitPluginUnloadEvent(plugin, PluginEvent.Stage.PRE)); - ClassLoader loader = RJavaPlugin.getClassLoader(plugin); - RPluginClassLoader.clearClassLoader(loader); - addIfInstance(closeables, (Closeable) () -> { - Map> classes = RPluginClassLoader.getClasses(loader); - RJavaPluginLoader.removeClasses(getPluginLoader(getPluginFile(plugin)), classes.keySet()); - }); - addIfInstance(closeables, loader); - addIfInstance(closeables, RJavaPlugin.clearJavaPlugin(plugin)); - } catch (Exception ex) { - ex.printStackTrace(); - return new CloseableResult(Result.ERROR); + List closeables = new ArrayList<>(); + try { + RSimplePluginManager.getPlugins(Bukkit.getPluginManager()).remove(plugin); + RSimplePluginManager.removeLookupName(Bukkit.getPluginManager(), pluginId); + + ClassLoader loader = RJavaPlugin.getClassLoader(plugin); + RPluginClassLoader.clearClassLoader(loader); + addIfInstance(closeables, (Closeable) () -> { + Map> classes = RPluginClassLoader.getClasses(loader); + getPluginLoader(getPluginFile(plugin)).ifPresent(pluginLoader -> { + RJavaPluginLoader.removeClasses(pluginLoader, classes.keySet()); + }); + }); + addIfInstance(closeables, loader); + addIfInstance(closeables, RJavaPlugin.clearJavaPlugin(plugin)); + } catch (Exception ex) { + ex.printStackTrace(); + return unloadResults.addResult(pluginId, Result.ERROR); + } + + Bukkit.getPluginManager().callEvent(new BukkitPluginUnloadEvent(plugin, PluginEvent.Stage.POST)); + + unloadResults.addResult(pluginId, plugin, closeables); } - Bukkit.getPluginManager().callEvent(new BukkitPluginUnloadEvent(plugin, PluginEvent.Stage.POST)); - return new CloseableResult(closeables); + + return unloadResults; } private static void addIfInstance(List list, Object obj) { @@ -175,68 +157,29 @@ public class BukkitPluginManager implements AbstractPluginManager { } } - /** - * Enables the specified plugin by name. - * @param pluginName The plugin to enable. - * @return The result of the enabling. - */ - public Result enablePlugin(String pluginName) { - return enablePlugin(Bukkit.getPluginManager().getPlugin(pluginName)); - } - - /** - * Enables the specified plugin. - * @param plugin The plugin to enable. - * @return The result of the enabling. - */ @Override - public Result enablePlugin(Plugin plugin) { - if (plugin == null) return Result.NOT_EXISTS; - if (Bukkit.getPluginManager().isPluginEnabled(plugin.getName())) return Result.ALREADY_ENABLED; + protected PluginResults enableOrderedPlugins(List plugins) { + PluginResults enableResults = new PluginResults<>(); + PluginManager bukkitPluginManager = Bukkit.getPluginManager(); + for (Plugin plugin : plugins) { + String pluginId = getPluginId(plugin); + bukkitPluginManager.callEvent(new BukkitPluginEnableEvent(plugin, PluginEvent.Stage.PRE)); + bukkitPluginManager.enablePlugin(plugin); - Bukkit.getPluginManager().callEvent(new BukkitPluginEnableEvent(plugin, PluginEvent.Stage.PRE)); - Bukkit.getPluginManager().enablePlugin(plugin); - RCraftServer.syncCommands(); - - if (!Bukkit.getPluginManager().isPluginEnabled(plugin.getName())) return Result.ERROR; - Bukkit.getPluginManager().callEvent(new BukkitPluginEnableEvent(plugin, PluginEvent.Stage.POST)); - return Result.SUCCESS; - } - - /** - * Reloads the specified plugin by name. - * @param pluginName The plugin to reload. - * @return The result of the reload. - */ - @Override - public Result reloadPlugin(String pluginName) { - Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); - if (plugin == null) return Result.NOT_EXISTS; - return reloadPlugin(plugin); - } - - /** - * Reloads the specified plugin. - * @param plugin The plugin to reload. - * @return The result of the reload. - */ - @Override - public Result reloadPlugin(Plugin plugin) { - Result disableResult = disablePlugin(plugin); - if (disableResult != Result.SUCCESS && disableResult != Result.ALREADY_DISABLED) { - return disableResult; + if (!bukkitPluginManager.isPluginEnabled(plugin.getName())) { + return enableResults.addResult(pluginId, Result.ERROR); + } + bukkitPluginManager.callEvent(new BukkitPluginEnableEvent(plugin, PluginEvent.Stage.POST)); + enableResults.addResult(pluginId, plugin); } - CloseableResult result = unloadPlugin(plugin); - if (result.getResult() != Result.SUCCESS) return result.getResult(); - result.tryClose(); + RCraftServer.syncCommands(); + return enableResults; + } - File pluginFile = getPluginFile(plugin.getName()); - if (pluginFile == null) return Result.FILE_DELETED; - - BukkitLoadResult loadResult = loadPlugin(pluginFile); - if (!loadResult.isSuccess()) return loadResult.getResult(); - return enablePlugin(loadResult.get()); + @Override + public boolean isPluginEnabled(String pluginId) { + return Bukkit.getPluginManager().isPluginEnabled(pluginId); } /** @@ -366,45 +309,30 @@ public class BukkitPluginManager implements AbstractPluginManager { * @param file The file. * @return The appropiate PluginLoader. */ - public static PluginLoader getPluginLoader(File file) { + public static Optional getPluginLoader(File file) { Map fileAssociations = getFileAssociations(); - if (fileAssociations == null) return null; - - for (Pattern filter : fileAssociations.keySet()) { - Matcher match = filter.matcher(file.getName()); - if (match.find()) { - return fileAssociations.get(filter); + if (fileAssociations != null) { + for (Map.Entry entry : fileAssociations.entrySet()) { + Matcher match = entry.getKey().matcher(file.getName()); + if (match.find()) { + return Optional.ofNullable(entry.getValue()); + } } } - return null; + return Optional.empty(); } - /** - * Retrieves a loaded plugin associated to a jar file. - * @param file The jar file. - * @return The already loaded plugin, or null if none. - */ - public static Plugin getLoadedPlugin(File file) { - PluginDescriptionFile descriptionFile; + @Override + public Optional getPluginDescription(File file) throws InvalidPluginDescriptionException { + if (!file.exists()) return Optional.empty(); + + Optional loader = getPluginLoader(file); + if (!loader.isPresent()) throw new InvalidPluginDescriptionException("Plugin loader is not present!"); try { - descriptionFile = getPluginDescription(file); + return Optional.of(new BukkitPluginDescription(loader.get().getPluginDescription(file), file)); } catch (InvalidDescriptionException ex) { - return null; + throw new InvalidPluginDescriptionException(ex); } - if (descriptionFile == null) return null; - return Bukkit.getPluginManager().getPlugin(descriptionFile.getName()); - } - - /** - * Retrieves the PluginDescriptionFile of a jar file. - * @param file The jar file. - * @return The PluginDescriptionFile. - * @throws InvalidDescriptionException Iff the PluginDescriptionFile is invalid. - */ - public static PluginDescriptionFile getPluginDescription(File file) throws InvalidDescriptionException { - PluginLoader loader = getPluginLoader(file); - if (loader == null) return null; - return loader.getPluginDescription(file); } @Override @@ -412,29 +340,14 @@ public class BukkitPluginManager implements AbstractPluginManager { return RJavaPlugin.getFile(plugin); } - /** - * Attempts to retrieve the plugin file by plugin name. - * @param pluginName The plugin name. - * @return The file, or null if invalid or not found. - */ @Override - public File getPluginFile(String pluginName) { - for (File file : getPluginJars()) { - PluginDescriptionFile descriptionFile; - try { - descriptionFile = getPluginDescription(file); - } catch (InvalidDescriptionException ex) { - return null; - } - if (descriptionFile == null) return null; - if (descriptionFile.getName().equals(pluginName)) return file; - } - return null; + public Optional getPlugin(String pluginName) { + return Optional.ofNullable(Bukkit.getPluginManager().getPlugin(pluginName)); } @Override - public Plugin getPlugin(String pluginName) { - return Bukkit.getPluginManager().getPlugin(pluginName); + public BukkitPluginDescription getLoadedPluginDescription(Plugin plugin) { + return new BukkitPluginDescription(plugin.getDescription(), getPluginFile(plugin)); } @Override @@ -455,7 +368,7 @@ public class BukkitPluginManager implements AbstractPluginManager { } @Override - public String getPluginName(Plugin plugin) { + public String getPluginId(Plugin plugin) { return plugin.getName(); } } diff --git a/Bukkit/src/main/resources/bukkit-commands.json b/Bukkit/src/main/resources/bukkit-commands.json index 6f7500c..191af7c 100644 --- a/Bukkit/src/main/resources/bukkit-commands.json +++ b/Bukkit/src/main/resources/bukkit-commands.json @@ -8,7 +8,7 @@ "ep" ], "permission": "serverutils.enableplugin", - "description": "Enables the specified plugin.", + "description": "Enables the specified plugin(s).", "display-in-help": true }, "disableplugin": { @@ -17,7 +17,7 @@ "dp" ], "permission": "serverutils.disableplugin", - "description": "Disables the specified plugin.", + "description": "Disables the specified plugin(s).", "display-in-help": true }, "reloadconfig": { diff --git a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/commands/BungeeCommandServerUtils.java b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/commands/BungeeCommandServerUtils.java index b845eb8..bf7d1fc 100644 --- a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/commands/BungeeCommandServerUtils.java +++ b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/commands/BungeeCommandServerUtils.java @@ -19,17 +19,16 @@ import net.md_5.bungee.api.plugin.PluginManager; public class BungeeCommandServerUtils extends CommandServerUtils { public BungeeCommandServerUtils(BungeePlugin plugin) { - super(plugin); + super(plugin, Plugin[]::new); } @Override protected FormatBuilder createPluginInfo( FormatBuilder builder, Function>, String> listBuilderFunction, - String pluginName + Plugin bungeePlugin ) { - Plugin container = plugin.getPluginManager().getPlugin(pluginName); - PluginDescription desc = container.getDescription(); + PluginDescription desc = bungeePlugin.getDescription(); return builder .add("Name", desc.getName()) diff --git a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeeLoadResult.java b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeeLoadResult.java deleted file mode 100644 index 19cb542..0000000 --- a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeeLoadResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.frankheijden.serverutils.bungee.entities; - -import net.frankheijden.serverutils.common.entities.LoadResult; -import net.frankheijden.serverutils.common.entities.Result; -import net.md_5.bungee.api.plugin.Plugin; - -public class BungeeLoadResult extends LoadResult { - - public BungeeLoadResult(Plugin obj, Result result) { - super(obj, result); - } - - public BungeeLoadResult(Plugin obj) { - super(obj); - } - - public BungeeLoadResult(Result result) { - super(result); - } -} diff --git a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePlugin.java b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePlugin.java index 1ca0487..8ca481f 100644 --- a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePlugin.java +++ b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePlugin.java @@ -15,12 +15,7 @@ import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.scheduler.ScheduledTask; -public class BungeePlugin extends ServerUtilsPlugin< - Plugin, - ScheduledTask, - BungeeCommandSender, - CommandSender - > { +public class BungeePlugin extends ServerUtilsPlugin { private final ServerUtils plugin; private final BungeePluginManager pluginManager; diff --git a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePluginDescription.java b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePluginDescription.java new file mode 100644 index 0000000..051bf7a --- /dev/null +++ b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/entities/BungeePluginDescription.java @@ -0,0 +1,57 @@ +package net.frankheijden.serverutils.bungee.entities; + +import java.io.File; +import java.util.HashSet; +import java.util.Set; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import net.md_5.bungee.api.plugin.PluginDescription; + +public class BungeePluginDescription implements ServerUtilsPluginDescription { + + private final PluginDescription description; + private final File file; + private final Set dependencies; + + /** + * Constructs a new BungeePluginDescription. + */ + public BungeePluginDescription(PluginDescription description) { + this.description = description; + this.file = description.getFile(); + this.dependencies = new HashSet<>(description.getDepends()); + } + + @Override + public String getId() { + return this.description.getName(); + } + + @Override + public String getName() { + return this.description.getName(); + } + + @Override + public String getVersion() { + return this.description.getVersion(); + } + + @Override + public String getAuthor() { + return this.description.getAuthor(); + } + + @Override + public File getFile() { + return this.file; + } + + @Override + public Set getDependencies() { + return this.dependencies; + } + + public PluginDescription getDescription() { + return description; + } +} diff --git a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/managers/BungeePluginManager.java b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/managers/BungeePluginManager.java index 3c4ae52..8240623 100644 --- a/Bungee/src/main/java/net/frankheijden/serverutils/bungee/managers/BungeePluginManager.java +++ b/Bungee/src/main/java/net/frankheijden/serverutils/bungee/managers/BungeePluginManager.java @@ -1,8 +1,8 @@ package net.frankheijden.serverutils.bungee.managers; -import com.google.common.base.Preconditions; import java.io.Closeable; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.URLClassLoader; import java.util.ArrayList; @@ -10,12 +10,13 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Level; import java.util.stream.Collectors; -import net.frankheijden.serverutils.bungee.entities.BungeeLoadResult; +import net.frankheijden.serverutils.bungee.entities.BungeePluginDescription; import net.frankheijden.serverutils.bungee.events.BungeePluginDisableEvent; import net.frankheijden.serverutils.bungee.events.BungeePluginEnableEvent; import net.frankheijden.serverutils.bungee.events.BungeePluginLoadEvent; @@ -23,8 +24,11 @@ import net.frankheijden.serverutils.bungee.events.BungeePluginUnloadEvent; import net.frankheijden.serverutils.bungee.reflection.RLibraryLoader; import net.frankheijden.serverutils.bungee.reflection.RPluginClassLoader; import net.frankheijden.serverutils.bungee.reflection.RPluginManager; -import net.frankheijden.serverutils.common.entities.CloseableResult; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults; +import net.frankheijden.serverutils.common.entities.results.PluginResults; +import net.frankheijden.serverutils.common.entities.results.Result; import net.frankheijden.serverutils.common.events.PluginEvent; import net.frankheijden.serverutils.common.managers.AbstractPluginManager; import net.md_5.bungee.api.ProxyServer; @@ -32,7 +36,7 @@ import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.PluginDescription; import org.yaml.snakeyaml.Yaml; -public class BungeePluginManager implements AbstractPluginManager { +public class BungeePluginManager extends AbstractPluginManager { private static final ProxyServer proxy = ProxyServer.getInstance(); @@ -65,128 +69,123 @@ public class BungeePluginManager implements AbstractPluginManager { } @Override - public BungeeLoadResult loadPlugin(String pluginFile) { - File file = getPluginFileExact(pluginFile); - if (!file.exists()) return new BungeeLoadResult(Result.NOT_EXISTS); - return loadPlugin(file); - } + public PluginResults loadPluginDescriptions(List descriptions) { + PluginResults loadResults = new PluginResults<>(); - @Override - public BungeeLoadResult loadPlugin(File file) { - PluginDescription desc; - try { - desc = getPluginDescription(file); - } catch (Exception ex) { - proxy.getLogger().log(Level.WARNING, "Could not load plugin from file " + file, ex); - return new BungeeLoadResult(Result.INVALID_DESCRIPTION); - } + for (BungeePluginDescription description : descriptions) { + PluginDescription desc = description.getDescription(); + Plugin plugin; - try { - Object libraryLoader = RPluginManager.getLibraryLoader(proxy.getPluginManager()); - ClassLoader classLoader = RLibraryLoader.createLoader(libraryLoader, desc); - URLClassLoader loader = (URLClassLoader) RPluginClassLoader.newInstance( - proxy, - desc, - desc.getFile(), - classLoader - ); + try { + Object libraryLoader = RPluginManager.getLibraryLoader(proxy.getPluginManager()); + ClassLoader classLoader = RLibraryLoader.createLoader(libraryLoader, desc); + URLClassLoader loader = (URLClassLoader) RPluginClassLoader.newInstance( + proxy, + desc, + desc.getFile(), + classLoader + ); - Class main = loader.loadClass(desc.getMain()); - Plugin plugin = (Plugin) main.getDeclaredConstructor().newInstance(); + Class main = loader.loadClass(desc.getMain()); + plugin = (Plugin) main.getDeclaredConstructor().newInstance(); + + RPluginManager.getPlugins(proxy.getPluginManager()).put(description.getId(), plugin); + proxy.getPluginManager().callEvent(new BungeePluginLoadEvent(plugin, PluginEvent.Stage.PRE)); + plugin.onLoad(); + } catch (Throwable th) { + proxy.getLogger().log(Level.WARNING, "Error loading plugin " + description.getId(), th); + return loadResults.addResult(description.getId(), Result.ERROR); + } - RPluginManager.getPlugins(proxy.getPluginManager()).put(desc.getName(), plugin); - proxy.getPluginManager().callEvent(new BungeePluginLoadEvent(plugin, PluginEvent.Stage.PRE)); - plugin.onLoad(); proxy.getLogger().log(Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[] { desc.getName(), desc.getVersion(), desc.getAuthor() }); proxy.getPluginManager().callEvent(new BungeePluginLoadEvent(plugin, PluginEvent.Stage.POST)); - return new BungeeLoadResult(plugin); - } catch (Throwable th) { - proxy.getLogger().log(Level.WARNING, "Error loading plugin " + desc.getName(), th); - return new BungeeLoadResult(Result.ERROR); + loadResults.addResult(description.getId(), plugin); } + + return loadResults; } @Override - public Result enablePlugin(Plugin plugin) { - PluginDescription desc = plugin.getDescription(); - String name = desc.getName(); - proxy.getPluginManager().callEvent(new BungeePluginEnableEvent(plugin, PluginEvent.Stage.PRE)); - try { - plugin.onEnable(); - Object[] args = new Object[] { name, desc.getVersion(), desc.getAuthor() }; + public PluginResults enableOrderedPlugins(List plugins) { + PluginResults enableResults = new PluginResults<>(); + + for (Plugin plugin : plugins) { + ServerUtilsPluginDescription description = getLoadedPluginDescription(plugin); + String pluginId = description.getId(); + + proxy.getPluginManager().callEvent(new BungeePluginEnableEvent(plugin, PluginEvent.Stage.PRE)); + try { + plugin.onEnable(); + } catch (Throwable th) { + proxy.getLogger().log(Level.WARNING, "Exception encountered when loading plugin: " + pluginId, th); + return enableResults.addResult(pluginId, Result.ERROR); + } + + Object[] args = new Object[] { description.getId(), description.getVersion(), description.getAuthor() }; proxy.getLogger().log(Level.INFO, "Enabled plugin {0} version {1} by {2}", args); proxy.getPluginManager().callEvent(new BungeePluginEnableEvent(plugin, PluginEvent.Stage.POST)); - return Result.SUCCESS; - } catch (Throwable th) { - proxy.getLogger().log(Level.WARNING, "Exception encountered when loading plugin: " + name, th); - return Result.ERROR; + enableResults.addResult(pluginId, plugin); } + + return enableResults; } @Override - public Result disablePlugin(Plugin plugin) { - PluginDescription desc = plugin.getDescription(); - String name = desc.getName(); - proxy.getPluginManager().callEvent(new BungeePluginDisableEvent(plugin, PluginEvent.Stage.PRE)); - try { - plugin.onDisable(); + public boolean isPluginEnabled(String pluginId) { + return proxy.getPluginManager().getPlugin(pluginId) != null; + } + + @Override + public PluginResults disableOrderedPlugins(List plugins) { + PluginResults disableResults = new PluginResults<>(); + + for (Plugin plugin : plugins) { + String pluginId = getPluginId(plugin); + proxy.getPluginManager().callEvent(new BungeePluginDisableEvent(plugin, PluginEvent.Stage.PRE)); + try { + plugin.onDisable(); + } catch (Throwable th) { + proxy.getLogger().log(Level.WARNING, "Exception encountered when disabling plugin: " + pluginId, th); + return disableResults.addResult(pluginId, Result.ERROR); + } + proxy.getPluginManager().callEvent(new BungeePluginDisableEvent(plugin, PluginEvent.Stage.POST)); - return Result.SUCCESS; - } catch (Throwable th) { - proxy.getLogger().log(Level.WARNING, "Exception encountered when disabling plugin: " + name, th); - return Result.ERROR; + disableResults.addResult(pluginId, plugin); } + + return disableResults; } @Override - public Result reloadPlugin(String pluginName) { - Plugin plugin = proxy.getPluginManager().getPlugin(pluginName); - if (plugin == null) return Result.NOT_ENABLED; - return reloadPlugin(plugin); - } + public CloseablePluginResults unloadOrderedPlugins(List plugins) { + CloseablePluginResults unloadResults = new CloseablePluginResults<>(); - @Override - public Result reloadPlugin(Plugin plugin) { - CloseableResult result = unloadPlugin(plugin); - if (result.getResult() != Result.SUCCESS) return result.getResult(); - result.tryClose(); + for (Plugin plugin : plugins) { + String pluginId = getPluginId(plugin); - File file = getPluginFile(plugin.getDescription().getName()); - if (file == null) return Result.FILE_DELETED; + proxy.getPluginManager().callEvent(new BungeePluginUnloadEvent(plugin, PluginEvent.Stage.PRE)); + plugin.onDisable(); + proxy.getPluginManager().unregisterCommands(plugin); + proxy.getPluginManager().unregisterListeners(plugin); + proxy.getScheduler().cancel(plugin); - BungeeLoadResult loadResult = loadPlugin(file); - if (!loadResult.isSuccess()) return loadResult.getResult(); + List closeables = new ArrayList<>(); + try { + RPluginManager.clearPlugin(proxy.getPluginManager(), plugin); + addIfInstance(closeables, RPluginClassLoader.getPluginClassLoader(plugin)); + addIfInstance(closeables, plugin.getClass().getClassLoader()); + } catch (Exception ex) { + ex.printStackTrace(); + return unloadResults.addResult(pluginId, Result.ERROR); + } - return enablePlugin(loadResult.get()); - } - - @Override - public CloseableResult unloadPlugin(String pluginName) { - Plugin plugin = proxy.getPluginManager().getPlugin(pluginName); - if (plugin == null) return new CloseableResult(Result.NOT_ENABLED); - return unloadPlugin(plugin); - } - - @Override - public CloseableResult unloadPlugin(Plugin plugin) { - proxy.getPluginManager().callEvent(new BungeePluginUnloadEvent(plugin, PluginEvent.Stage.PRE)); - plugin.onDisable(); - proxy.getPluginManager().unregisterCommands(plugin); - proxy.getPluginManager().unregisterListeners(plugin); - proxy.getScheduler().cancel(plugin); - List closeables = new ArrayList<>(); - try { - RPluginManager.clearPlugin(proxy.getPluginManager(), plugin); - addIfInstance(closeables, RPluginClassLoader.getPluginClassLoader(plugin)); - addIfInstance(closeables, plugin.getClass().getClassLoader()); - } catch (Exception ex) { - ex.printStackTrace(); - return new CloseableResult(Result.ERROR); + proxy.getPluginManager().callEvent(new BungeePluginUnloadEvent(plugin, PluginEvent.Stage.POST)); + unloadResults.addResult(pluginId, plugin, closeables); } - proxy.getPluginManager().callEvent(new BungeePluginUnloadEvent(plugin, PluginEvent.Stage.POST)); - return new CloseableResult(closeables); + + return unloadResults; } private static void addIfInstance(List list, Object obj) { @@ -195,38 +194,31 @@ public class BungeePluginManager implements AbstractPluginManager { } } - public static File getPluginFileExact(String fileName) { - return new File(proxy.getPluginsFolder(), fileName); - } - - /** - * Retrieves the File of a plugin associated with a name. - * @param pluginName The plugin name to search for. - * @return The File if the plugin exists with that name. - */ @Override - public File getPluginFile(String pluginName) { + public Optional getPluginFile(String pluginId) { for (File file : getPluginJars()) { - PluginDescription desc; + BungeePluginDescription description; try { - desc = getPluginDescription(file); + Optional descriptionOptional = getPluginDescription(file); + if (!descriptionOptional.isPresent()) continue; + description = descriptionOptional.get(); } catch (Exception ex) { continue; } - if (desc.getName().equals(pluginName)) return file; + if (description.getId().equals(pluginId)) return Optional.of(file); } - return null; + return Optional.empty(); } @Override - public File getPluginFile(Plugin plugin) { - return plugin.getFile(); + public Optional getPlugin(String pluginName) { + return Optional.ofNullable(proxy.getPluginManager().getPlugin(pluginName)); } @Override - public Plugin getPlugin(String pluginName) { - return proxy.getPluginManager().getPlugin(pluginName); + public BungeePluginDescription getLoadedPluginDescription(Plugin plugin) { + return new BungeePluginDescription(plugin.getDescription()); } @Override @@ -241,40 +233,35 @@ public class BungeePluginManager implements AbstractPluginManager { .collect(Collectors.toSet()); } - /** - * Retrieves the PluginDescription of a (plugin's) File. - * @param file The file. - * @return The PluginDescription. - * @throws Exception Iff and I/O exception occurred, or notNullChecks failed. - */ - public static PluginDescription getPluginDescription(File file) throws Exception { + @Override + public Optional getPluginDescription(File file) throws InvalidPluginDescriptionException { try (JarFile jar = new JarFile(file)) { - JarEntry entry = getPluginDescriptionEntry(jar); - Preconditions.checkNotNull(entry, "Plugin must have a plugin.yml or bungee.yml"); + JarEntry entry = jar.getJarEntry("bungee.yml"); + if (entry == null) { + entry = jar.getJarEntry("plugin.yml"); + } + + if (entry == null) { + throw new InvalidPluginDescriptionException("Plugin must have a plugin.yml or bungee.yml"); + } try (InputStream in = jar.getInputStream(entry)) { Yaml yaml = RPluginManager.getYaml(proxy.getPluginManager()); - PluginDescription desc = yaml.loadAs(in, PluginDescription.class); - Preconditions.checkNotNull(desc.getName(), "Plugin from %s has no name", file); - Preconditions.checkNotNull(desc.getMain(), "Plugin from %s has no main", file); + PluginDescription description = yaml.loadAs(in, PluginDescription.class); + if (description.getName() == null) { + throw new InvalidPluginDescriptionException("Plugin from " + file + " has no name"); + } else if (description.getMain() == null) { + throw new InvalidPluginDescriptionException("Plugin from " + file + " has no main"); + } - desc.setFile(file); - return desc; + description.setFile(file); + return Optional.of(new BungeePluginDescription(description)); } + } catch (IOException ex) { + throw new InvalidPluginDescriptionException(ex); } } - /** - * Retrieves the JarEntry which contains the Description file of the JarFile. - * @param jar The JarFile. - * @return The description JarEntry. - */ - public static JarEntry getPluginDescriptionEntry(JarFile jar) { - JarEntry entry = jar.getJarEntry("bungee.yml"); - if (entry == null) return jar.getJarEntry("plugin.yml"); - return entry; - } - @Override public File getPluginsFolder() { return proxy.getPluginsFolder(); @@ -298,11 +285,6 @@ public class BungeePluginManager implements AbstractPluginManager { .collect(Collectors.toList()); } - @Override - public String getPluginName(Plugin plugin) { - return plugin.getDataFolder().getName(); - } - /** * Retrieves the plugins sorted by their names. * @param modules Whether or not to include `module` plugins @@ -310,7 +292,7 @@ public class BungeePluginManager implements AbstractPluginManager { */ public List getPluginsSorted(boolean modules) { List plugins = getPlugins(modules); - plugins.sort(Comparator.comparing(this::getPluginName)); + plugins.sort(Comparator.comparing(this::getPluginId)); return plugins; } } diff --git a/Common/build.gradle b/Common/build.gradle index a176d13..1b3c12b 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -3,7 +3,6 @@ plugins { } group = rootProject.group + '.common' -String dependencyDir = group + '.dependencies' version = rootProject.version archivesBaseName = rootProject.name + '-Common' @@ -12,7 +11,6 @@ repositories { } dependencies { - implementation 'com.google.code.gson:gson:2.8.6' compileOnly 'com.github.FrankHeijden:ServerUtilsUpdater:v1.0.0' } @@ -25,5 +23,4 @@ shadowJar { exclude 'net/frankheijden/serverutilsupdater/**' exclude 'plugin.yml' exclude 'bungee.yml' - relocate 'com.google.gson', dependencyDir + '.gson' } \ No newline at end of file diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/ServerUtilsApp.java b/Common/src/main/java/net/frankheijden/serverutils/common/ServerUtilsApp.java index 745d977..a3ae81e 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/ServerUtilsApp.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/ServerUtilsApp.java @@ -3,13 +3,15 @@ package net.frankheijden.serverutils.common; import java.io.File; import java.io.IOException; import java.nio.file.Files; -import net.frankheijden.serverutils.common.entities.CloseableResult; -import net.frankheijden.serverutils.common.entities.Result; +import java.util.Optional; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResult; +import net.frankheijden.serverutils.common.entities.results.PluginResult; import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; import net.frankheijden.serverutils.common.tasks.UpdateCheckerTask; -public class ServerUtilsApp, P, T, C extends ServerCommandSender, S> { +public class ServerUtilsApp, P, T, C extends ServerCommandSender, S, D extends ServerUtilsPluginDescription> { public static final int BSTATS_METRICS_ID = 7790; public static final String VERSION = "{version}"; @@ -25,7 +27,14 @@ public class ServerUtilsApp, P, T, C ext this.plugin = plugin; } - public static , P, T, C extends ServerCommandSender, S> void init( + public static < + U extends ServerUtilsPlugin, + P, + T, + C extends ServerCommandSender, + S, + D extends ServerUtilsPluginDescription + > void init( Object platformPlugin, U plugin ) { @@ -42,30 +51,31 @@ public class ServerUtilsApp, P, T, C ext /** * Unloads the ServerUtilsUpdater and deletes the file. */ - public static , P, T, C extends ServerCommandSender, S> - void unloadServerUtilsUpdater() { - U plugin = getPlugin(); + public static

void unloadServerUtilsUpdater() { + ServerUtilsPlugin plugin = getPlugin(); plugin.getTaskManager().runTaskLater(() -> { String updaterName = plugin.getPlatform() == ServerUtilsPlugin.Platform.VELOCITY ? "serverutilsupdater" : "ServerUtilsUpdater"; - P updaterPlugin = plugin.getPluginManager().getPlugin(updaterName); - if (updaterPlugin == null) return; + Optional

updaterPluginOptional = plugin.getPluginManager().getPlugin(updaterName); + if (!updaterPluginOptional.isPresent()) return; + P updaterPlugin = updaterPluginOptional.get(); @SuppressWarnings("VariableDeclarationUsageDistance") File file = plugin.getPluginManager().getPluginFile(updaterPlugin); - Result result = plugin.getPluginManager().disablePlugin(updaterPlugin); - if (result != Result.SUCCESS) { - result.sendTo(plugin.getChatProvider().getConsoleSender(), "disabl", updaterName); + PluginResult

disableResult = plugin.getPluginManager().disablePlugin(updaterPlugin); + if (!disableResult.isSuccess()) { + disableResult.getResult().sendTo(plugin.getChatProvider().getConsoleSender(), "disabl", updaterName); return; } - CloseableResult closeableResult = plugin.getPluginManager().unloadPlugin(updaterName); - if (closeableResult.getResult() != Result.SUCCESS) { - closeableResult.getResult().sendTo(plugin.getChatProvider().getConsoleSender(), "unload", updaterName); + CloseablePluginResult

unloadResult = plugin.getPluginManager().unloadPlugin(disableResult.getPlugin()); + if (!unloadResult.isSuccess()) { + unloadResult.getResult().sendTo(plugin.getChatProvider().getConsoleSender(), "unload", updaterName); + return; } - closeableResult.tryClose(); + unloadResult.tryClose(); if (Files.exists(file.toPath())) { try { @@ -82,8 +92,14 @@ public class ServerUtilsApp, P, T, C ext } @SuppressWarnings("unchecked") - public static , P, T, C extends ServerCommandSender, S> - U getPlugin() { + public static < + U extends ServerUtilsPlugin, + P, + T, + C extends ServerCommandSender, + S, + D extends ServerUtilsPluginDescription + > U getPlugin() { return (U) instance.plugin; } } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandPlugins.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandPlugins.java index a614aa4..50c099f 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandPlugins.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandPlugins.java @@ -7,7 +7,7 @@ import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; import net.frankheijden.serverutils.common.utils.ListBuilder; import net.frankheijden.serverutils.common.utils.ListFormat; -public abstract class CommandPlugins, P, C extends ServerCommandSender> +public abstract class CommandPlugins, P, C extends ServerCommandSender> extends ServerUtilsCommand { protected CommandPlugins(U plugin) { diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandServerUtils.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandServerUtils.java index 484b899..c7c3684 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandServerUtils.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/CommandServerUtils.java @@ -4,14 +4,22 @@ import cloud.commandframework.Command; import cloud.commandframework.CommandManager; import cloud.commandframework.arguments.CommandArgument; import cloud.commandframework.context.CommandContext; +import java.io.File; import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.IntFunction; +import net.frankheijden.serverutils.common.commands.arguments.JarFilesArgument; +import net.frankheijden.serverutils.common.commands.arguments.PluginArgument; +import net.frankheijden.serverutils.common.commands.arguments.PluginsArgument; import net.frankheijden.serverutils.common.config.ServerUtilsConfig; -import net.frankheijden.serverutils.common.entities.AbstractResult; -import net.frankheijden.serverutils.common.entities.CloseableResult; -import net.frankheijden.serverutils.common.entities.LoadResult; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.results.AbstractResult; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults; +import net.frankheijden.serverutils.common.entities.results.PluginResult; +import net.frankheijden.serverutils.common.entities.results.PluginResults; +import net.frankheijden.serverutils.common.entities.results.Result; import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; import net.frankheijden.serverutils.common.managers.AbstractPluginManager; @@ -19,23 +27,21 @@ import net.frankheijden.serverutils.common.utils.FormatBuilder; import net.frankheijden.serverutils.common.utils.ListBuilder; import net.frankheijden.serverutils.common.utils.ListFormat; -public abstract class CommandServerUtils, P, C extends ServerCommandSender> +public abstract class CommandServerUtils, P, C extends ServerCommandSender> extends ServerUtilsCommand { - protected CommandServerUtils(U plugin) { + private final IntFunction arrayCreator; + + protected CommandServerUtils(U plugin, IntFunction arrayCreator) { super(plugin, "serverutils"); + this.arrayCreator = arrayCreator; } @Override public void register(CommandManager manager, Command.Builder builder) { - addArgument(CommandArgument.ofType(String.class, "jarFile") - .manager(manager) - .withSuggestionsProvider((context, s) -> plugin.getPluginManager().getPluginFileNames()) - .build()); - addArgument(CommandArgument.ofType(String.class, "plugin") - .manager(manager) - .withSuggestionsProvider((context, s) -> plugin.getPluginManager().getPluginNames()) - .build()); + addArgument(new JarFilesArgument<>(true, "jarFiles", plugin)); + addArgument(new PluginsArgument<>(true, "plugins", plugin, arrayCreator)); + addArgument(new PluginArgument<>(true, "plugin", plugin)); addArgument(CommandArgument.ofType(String.class, "command") .manager(manager) .withSuggestionsProvider((context, s) -> new ArrayList<>(plugin.getPluginManager().getCommands())) @@ -48,13 +54,13 @@ public abstract class CommandServerUtils manager.command(buildSubcommand(builder, "reload") .handler(this::handleReload)); manager.command(buildSubcommand(builder, "loadplugin") - .argument(getArgument("jarFile")) + .argument(getArgument("jarFiles")) .handler(this::handleLoadPlugin)); manager.command(buildSubcommand(builder, "unloadplugin") - .argument(getArgument("plugin")) + .argument(getArgument("plugins")) .handler(this::handleUnloadPlugin)); manager.command(buildSubcommand(builder, "reloadplugin") - .argument(getArgument("plugin")) + .argument(getArgument("plugins")) .handler(this::handleReloadPlugin)); manager.command(buildSubcommand(builder, "watchplugin") .argument(getArgument("plugin")) @@ -146,69 +152,78 @@ public abstract class CommandServerUtils private void handleLoadPlugin(CommandContext context) { C sender = context.getSender(); - String jarFile = context.get("jarFile"); + List jarFiles = Arrays.asList(context.get("jarFiles")); - AbstractPluginManager

pluginManager = plugin.getPluginManager(); - LoadResult

loadResult = pluginManager.loadPlugin(jarFile); - if (!loadResult.isSuccess()) { - loadResult.getResult().sendTo(sender, "load", jarFile); + AbstractPluginManager pluginManager = plugin.getPluginManager(); + PluginResults

loadResults = pluginManager.loadPlugins(jarFiles); + if (!loadResults.isSuccess()) { + PluginResult

failedResult = loadResults.last(); + failedResult.getResult().sendTo(sender, "load", failedResult.getPluginId()); return; } - P loadedPlugin = loadResult.get(); - Result result = pluginManager.enablePlugin(loadedPlugin); - result.sendTo(sender, "load", pluginManager.getPluginName(loadedPlugin)); + PluginResults

enableResults = pluginManager.enablePlugins(loadResults.getPlugins()); + enableResults.sendTo(sender, "load"); } private void handleUnloadPlugin(CommandContext context) { C sender = context.getSender(); - String pluginName = context.get("plugin"); + List

plugins = Arrays.asList(context.get("plugins")); - CloseableResult result = plugin.getPluginManager().unloadPlugin(pluginName); - result.getResult().sendTo(sender, "unload", pluginName); - result.tryClose(); + PluginResults

disableResults = plugin.getPluginManager().disablePlugins(plugins); + for (PluginResult

disableResult : disableResults.getResults()) { + if (!disableResult.isSuccess() && disableResult.getResult() != Result.ALREADY_DISABLED) { + disableResult.getResult().sendTo(sender, "disabl", disableResult.getPluginId()); + return; + } + } + + CloseablePluginResults

unloadResults = plugin.getPluginManager().unloadPlugins(plugins); + unloadResults.tryClose(); + unloadResults.sendTo(sender, "unload"); } private void handleReloadPlugin(CommandContext context) { C sender = context.getSender(); - String pluginName = context.get("plugin"); + List

plugins = Arrays.asList(context.get("plugins")); - Result result = plugin.getPluginManager().reloadPlugin(pluginName); - result.sendTo(sender, "reload", pluginName); + PluginResults

reloadResult = plugin.getPluginManager().reloadPlugins(plugins); + reloadResult.sendTo(sender, "reload"); } private void handleWatchPlugin(CommandContext context) { C sender = context.getSender(); - String pluginName = context.get("plugin"); + P pluginArg = context.get("plugin"); - AbstractResult result = plugin.getPluginManager().watchPlugin(sender, pluginName); - result.sendTo(sender, "watch", pluginName); + AbstractPluginManager pluginManager = plugin.getPluginManager(); + String pluginId = pluginManager.getPluginId(pluginArg); + + AbstractResult result = pluginManager.watchPlugin(sender, pluginId); + result.sendTo(sender, "watch", pluginId); } private void handleUnwatchPlugin(CommandContext context) { C sender = context.getSender(); - String pluginName = context.get("plugin"); + P pluginArg = context.get("plugin"); - AbstractResult result = plugin.getPluginManager().unwatchPlugin(pluginName); - result.sendTo(sender, "unwatch", pluginName); + AbstractPluginManager pluginManager = plugin.getPluginManager(); + String pluginId = pluginManager.getPluginId(pluginArg); + + AbstractResult result = pluginManager.unwatchPlugin(pluginId); + result.sendTo(sender, "unwatch", pluginId); } private void handlePluginInfo(CommandContext context) { C sender = context.getSender(); - String pluginName = context.get("plugin"); + P pluginArg = context.get("plugin"); - if (this.plugin.getPluginManager().getPlugin(pluginName) == null) { - Result.NOT_EXISTS.sendTo(sender, "fetch", pluginName); - return; - } - - createInfo(sender, "plugininfo", pluginName, this::createPluginInfo); + createInfo(sender, "plugininfo", pluginArg, this::createPluginInfo); } protected abstract FormatBuilder createPluginInfo( FormatBuilder builder, Function>, String> listBuilderFunction, - String pluginName + P pluginArg ); private void handleCommandInfo(CommandContext context) { @@ -229,7 +244,7 @@ public abstract class CommandServerUtils String commandName ); - private void createInfo(C sender, String command, String item, InfoCreator creator) { + private void createInfo(C sender, String command, T item, InfoCreator creator) { String messagePrefix = "serverutils." + command; String format = plugin.getMessagesResource().getMessage(messagePrefix + ".format"); String listFormatString = plugin.getMessagesResource().getMessage(messagePrefix + ".list_format"); @@ -256,12 +271,12 @@ public abstract class CommandServerUtils plugin.getMessagesResource().sendMessage(sender, messagePrefix + ".footer"); } - private interface InfoCreator { + private interface InfoCreator { FormatBuilder createInfo( FormatBuilder builder, Function>, String> listBuilderFunction, - String item + T item ); } } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/ServerUtilsCommand.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/ServerUtilsCommand.java index dc6d4fe..d6c9775 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/commands/ServerUtilsCommand.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/ServerUtilsCommand.java @@ -13,7 +13,7 @@ import net.frankheijden.serverutils.common.config.ServerUtilsConfig; import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; -public abstract class ServerUtilsCommand, C extends ServerCommandSender> { +public abstract class ServerUtilsCommand, C extends ServerCommandSender> { protected final U plugin; protected final String commandName; diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/JarFilesArgument.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/JarFilesArgument.java new file mode 100644 index 0000000..252566d --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/JarFilesArgument.java @@ -0,0 +1,72 @@ +package net.frankheijden.serverutils.common.commands.arguments; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.exceptions.parsing.NoInputProvidedException; +import io.leangen.geantyref.TypeToken; +import java.io.File; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; +import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; + +public class JarFilesArgument> extends CommandArgument { + + /** + * Constructs a Jar Files argument. + */ + public JarFilesArgument(boolean required, String name, ServerUtilsPlugin plugin) { + super( + required, + name, + new JarFilesParser<>(plugin), + "", + new TypeToken() {}, + null + ); + } + + public static final class JarFilesParser> implements ArgumentParser { + + private final ServerUtilsPlugin plugin; + + public JarFilesParser(ServerUtilsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public ArgumentParseResult parse(CommandContext context, Queue inputQueue) { + if (inputQueue.isEmpty()) { + return ArgumentParseResult.failure(new NoInputProvidedException(JarFilesParser.class, context)); + } + + Set pluginFiles = new HashSet<>(plugin.getPluginManager().getPluginFileNames()); + File[] files = new File[inputQueue.size()]; + for (int i = 0; i < files.length; i++) { + if (!pluginFiles.contains(inputQueue.peek())) { + return ArgumentParseResult.failure(new IllegalArgumentException( + "Plugin '" + inputQueue.peek() + "' does not exist!" + )); + } + + files[i] = new File(plugin.getPluginManager().getPluginsFolder(), inputQueue.remove()); + } + + return ArgumentParseResult.success(files); + } + + @Override + public List suggestions(CommandContext context, String input) { + return plugin.getPluginManager().getPluginFileNames(); + } + + @Override + public boolean isContextFree() { + return true; + } + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/PluginArgument.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/PluginArgument.java new file mode 100644 index 0000000..8d21ec9 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/PluginArgument.java @@ -0,0 +1,66 @@ +package net.frankheijden.serverutils.common.commands.arguments; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.exceptions.parsing.NoInputProvidedException; +import io.leangen.geantyref.TypeToken; +import java.util.List; +import java.util.Optional; +import java.util.Queue; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; +import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; + +public class PluginArgument, P> extends CommandArgument { + + /** + * Constructs a Plugin argument. + */ + public PluginArgument(boolean required, String name, ServerUtilsPlugin plugin) { + super( + required, + name, + new PluginParser<>(plugin), + "", + new TypeToken

() {}, + null + ); + } + + public static final class PluginParser, P> implements ArgumentParser { + + private final ServerUtilsPlugin plugin; + + public PluginParser(ServerUtilsPlugin plugin) { + this.plugin = plugin; + } + + @Override + public ArgumentParseResult

parse(CommandContext context, Queue inputQueue) { + if (inputQueue.isEmpty()) { + return ArgumentParseResult.failure(new NoInputProvidedException(PluginParser.class, context)); + } + + Optional

pluginOptional = plugin.getPluginManager().getPlugin(inputQueue.peek()); + if (!pluginOptional.isPresent()) { + return ArgumentParseResult.failure(new IllegalArgumentException( + "Plugin '" + inputQueue.peek() + "' does not exist!" + )); + } + + inputQueue.remove(); + return ArgumentParseResult.success(pluginOptional.get()); + } + + @Override + public List suggestions(CommandContext context, String input) { + return plugin.getPluginManager().getPluginNames(); + } + + @Override + public boolean isContextFree() { + return true; + } + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/PluginsArgument.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/PluginsArgument.java new file mode 100644 index 0000000..bcb765c --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/arguments/PluginsArgument.java @@ -0,0 +1,79 @@ +package net.frankheijden.serverutils.common.commands.arguments; + +import cloud.commandframework.arguments.CommandArgument; +import cloud.commandframework.arguments.parser.ArgumentParseResult; +import cloud.commandframework.arguments.parser.ArgumentParser; +import cloud.commandframework.context.CommandContext; +import cloud.commandframework.exceptions.parsing.NoInputProvidedException; +import io.leangen.geantyref.TypeToken; +import java.util.List; +import java.util.Optional; +import java.util.Queue; +import java.util.function.IntFunction; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; +import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; + +public class PluginsArgument, P> extends CommandArgument { + + /** + * Constructs a Plugins argument. + */ + public PluginsArgument( + boolean required, + String name, + ServerUtilsPlugin plugin, + IntFunction arrayCreator + ) { + super( + required, + name, + new PluginsParser<>(plugin, arrayCreator), + "", + new TypeToken() {}, + null + ); + } + + public static final class PluginsParser, P> implements ArgumentParser { + + private final ServerUtilsPlugin plugin; + private final IntFunction arrayCreator; + + public PluginsParser(ServerUtilsPlugin plugin, IntFunction arrayCreator) { + this.plugin = plugin; + this.arrayCreator = arrayCreator; + } + + @Override + public ArgumentParseResult parse(CommandContext context, Queue inputQueue) { + if (inputQueue.isEmpty()) { + return ArgumentParseResult.failure(new NoInputProvidedException(PluginsParser.class, context)); + } + + P[] plugins = arrayCreator.apply(inputQueue.size()); + for (int i = 0; i < plugins.length; i++) { + Optional

pluginOptional = plugin.getPluginManager().getPlugin(inputQueue.peek()); + if (!pluginOptional.isPresent()) { + return ArgumentParseResult.failure(new IllegalArgumentException( + "Plugin '" + inputQueue.peek() + "' does not exist!" + )); + } + + inputQueue.remove(); + plugins[i] = pluginOptional.get(); + } + + return ArgumentParseResult.success(plugins); + } + + @Override + public List suggestions(CommandContext context, String input) { + return plugin.getPluginManager().getPluginNames(); + } + + @Override + public boolean isContextFree() { + return true; + } + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/commands/brigadier/BrigadierHandler.java b/Common/src/main/java/net/frankheijden/serverutils/common/commands/brigadier/BrigadierHandler.java new file mode 100644 index 0000000..fec659e --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/commands/brigadier/BrigadierHandler.java @@ -0,0 +1,31 @@ +package net.frankheijden.serverutils.common.commands.brigadier; + +import cloud.commandframework.brigadier.CloudBrigadierManager; +import com.mojang.brigadier.arguments.StringArgumentType; +import io.leangen.geantyref.TypeToken; +import net.frankheijden.serverutils.common.commands.arguments.JarFilesArgument; +import net.frankheijden.serverutils.common.commands.arguments.PluginsArgument; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; + +public class BrigadierHandler, P> { + + private final CloudBrigadierManager brigadierManager; + + public BrigadierHandler(CloudBrigadierManager brigadierManager) { + this.brigadierManager = brigadierManager; + } + + /** + * Registers types with the cloud brigadier manager. + */ + public void registerTypes() { + brigadierManager.registerMapping( + new TypeToken>() {}, + builder -> builder.toConstant(StringArgumentType.greedyString()) + ); + brigadierManager.registerMapping( + new TypeToken>() {}, + builder -> builder.toConstant(StringArgumentType.greedyString()) + ); + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/config/CommandsResource.java b/Common/src/main/java/net/frankheijden/serverutils/common/config/CommandsResource.java index 5356c73..7760fe4 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/config/CommandsResource.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/config/CommandsResource.java @@ -9,7 +9,7 @@ public class CommandsResource extends ServerUtilsResource { private static final String COMMANDS_RESOURCE = "commands"; - public CommandsResource(ServerUtilsPlugin plugin) { + public CommandsResource(ServerUtilsPlugin plugin) { super(plugin, COMMANDS_RESOURCE); } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/config/ConfigResource.java b/Common/src/main/java/net/frankheijden/serverutils/common/config/ConfigResource.java index 1b08bb0..a46ada5 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/config/ConfigResource.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/config/ConfigResource.java @@ -6,7 +6,7 @@ public class ConfigResource extends ServerUtilsResource { private static final String CONFIG_RESOURCE = "config"; - public ConfigResource(ServerUtilsPlugin plugin) { + public ConfigResource(ServerUtilsPlugin plugin) { super(plugin, CONFIG_RESOURCE); } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/config/MessagesResource.java b/Common/src/main/java/net/frankheijden/serverutils/common/config/MessagesResource.java index c3220c7..ecffb7f 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/config/MessagesResource.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/config/MessagesResource.java @@ -8,7 +8,7 @@ public class MessagesResource extends ServerUtilsResource { public static final String MESSAGES_RESOURCE = "messages"; - public MessagesResource(ServerUtilsPlugin plugin) { + public MessagesResource(ServerUtilsPlugin plugin) { super(plugin, MESSAGES_RESOURCE); } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/config/ServerUtilsResource.java b/Common/src/main/java/net/frankheijden/serverutils/common/config/ServerUtilsResource.java index 2b4fbec..b40295e 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/config/ServerUtilsResource.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/config/ServerUtilsResource.java @@ -5,12 +5,12 @@ import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; public abstract class ServerUtilsResource { - protected final ServerUtilsPlugin plugin; + protected final ServerUtilsPlugin plugin; protected final ServerUtilsConfig config; protected final JsonConfig defaultConfig; protected ServerUtilsResource( - ServerUtilsPlugin plugin, + ServerUtilsPlugin plugin, ServerUtilsConfig config, JsonConfig defaultConfig ) { @@ -19,7 +19,7 @@ public abstract class ServerUtilsResource { this.defaultConfig = defaultConfig; } - protected ServerUtilsResource(ServerUtilsPlugin plugin, String resourceName) { + protected ServerUtilsResource(ServerUtilsPlugin plugin, String resourceName) { this.plugin = plugin; this.defaultConfig = JsonConfig.load(plugin.getResourceProvider(), plugin.getPlatform(), resourceName); this.config = ServerUtilsConfig.init( diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/CloseableResult.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/CloseableResult.java deleted file mode 100644 index 530b4ea..0000000 --- a/Common/src/main/java/net/frankheijden/serverutils/common/entities/CloseableResult.java +++ /dev/null @@ -1,92 +0,0 @@ -package net.frankheijden.serverutils.common.entities; - -import java.io.Closeable; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -/** - * A result which should be closed when done. - */ -public class CloseableResult implements Closeable { - - private Result result; - private final List closeables; - - /** - * Constructs a new closable result. - * Used for unloading / reloading a plugin. - * NB: The closable needs to be closed to fully ensure that the old plugin doesn't work anymore! - * @param result The result of the procedure - * @param closeables The list of closable's of the procedure. - */ - public CloseableResult(Result result, List closeables) { - this.result = result; - this.closeables = closeables; - } - - /** - * Constructs a new closable result with no closable instance. - * @param result The result of the procedure - */ - public CloseableResult(Result result) { - this(result, null); - } - - /** - * Constructs a new closable result with a closable instance and success result. - * @param closeable The closable of the procedure. - */ - public CloseableResult(Closeable closeable) { - this(Result.SUCCESS, Collections.singletonList(closeable)); - } - - /** - * Constructs a new closable result with a closable instance and success result. - * @param closeables The list of closable's of the procedure. - */ - public CloseableResult(List closeables) { - this(Result.SUCCESS, closeables); - } - - /** - * Retrieves the result. - * @return The result. - */ - public Result getResult() { - return result; - } - - /** - * Sets the result of this instance. - * @param result The result to set. - * @return The current instance. - */ - public CloseableResult set(Result result) { - this.result = result; - return this; - } - - /** - * Attempts to close the closable, essentially wrapping it with try-catch. - */ - public void tryClose() { - if (closeables == null) return; - try { - close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - - /** - * Closes the closable. - * @throws IOException Iff an I/O error occurred. - */ - @Override - public void close() throws IOException { - for (Closeable closeable : closeables) { - closeable.close(); - } - } -} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/LoadResult.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/LoadResult.java deleted file mode 100644 index 7d4fdde..0000000 --- a/Common/src/main/java/net/frankheijden/serverutils/common/entities/LoadResult.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.frankheijden.serverutils.common.entities; - -/** - * A result which contains a loaded object from a load operation. - * @param The loaded object type - */ -public class LoadResult { - - private final T obj; - private final Result result; - - /** - * Constructs a new LoadResult with an object and a result. - * @param obj The object of the load operation. - * @param result The result of the load operation. - */ - public LoadResult(T obj, Result result) { - this.obj = obj; - this.result = result; - } - - /** - * Constructs a new LoadResult with an object and a success result. - * @param obj The object of the load operation. - */ - public LoadResult(T obj) { - this(obj, Result.SUCCESS); - } - - /** - * Constructs a new LoadResult without a loaded object, just a result. - * @param result The result of the load operation. - */ - public LoadResult(Result result) { - this(null, result); - } - - /** - * Retrieves the loaded object. - * @return The loaded object. - */ - public T get() { - return obj; - } - - /** - * The result of the LoadResult. - * @return The result. - */ - public Result getResult() { - return result; - } - - /** - * Checks whether the result is a success. - * @return Whether there is success or not. - */ - public boolean isSuccess() { - return obj != null && result == Result.SUCCESS; - } -} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPlugin.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPlugin.java index 3a20111..8965299 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPlugin.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPlugin.java @@ -2,6 +2,7 @@ package net.frankheijden.serverutils.common.entities; import cloud.commandframework.Command; import cloud.commandframework.CommandManager; +import cloud.commandframework.brigadier.CloudBrigadierManager; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -9,6 +10,7 @@ import java.nio.file.Path; import java.util.Collection; import java.util.logging.Logger; import net.frankheijden.serverutils.common.ServerUtilsApp; +import net.frankheijden.serverutils.common.commands.brigadier.BrigadierHandler; import net.frankheijden.serverutils.common.config.CommandsResource; import net.frankheijden.serverutils.common.config.ConfigResource; import net.frankheijden.serverutils.common.config.MessagesResource; @@ -19,7 +21,7 @@ import net.frankheijden.serverutils.common.providers.ChatProvider; import net.frankheijden.serverutils.common.providers.ResourceProvider; import net.frankheijden.serverutils.common.utils.FileUtils; -public abstract class ServerUtilsPlugin, S> { +public abstract class ServerUtilsPlugin, S, D extends ServerUtilsPluginDescription> { private final UpdateManager updateManager = new UpdateManager(); private CommandsResource commandsResource; @@ -43,7 +45,7 @@ public abstract class ServerUtilsPlugin, return messagesResource; } - public abstract AbstractPluginManager

getPluginManager(); + public abstract AbstractPluginManager getPluginManager(); public abstract AbstractTaskManager getTaskManager(); @@ -91,6 +93,11 @@ public abstract class ServerUtilsPlugin, protected abstract CommandManager newCommandManager(); + protected void handleBrigadier(CloudBrigadierManager brigadierManager) { + BrigadierHandler handler = new BrigadierHandler<>(brigadierManager); + handler.registerTypes(); + } + /** * Enables the plugin. */ diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPluginDescription.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPluginDescription.java new file mode 100644 index 0000000..c35c264 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/ServerUtilsPluginDescription.java @@ -0,0 +1,19 @@ +package net.frankheijden.serverutils.common.entities; + +import java.io.File; +import java.util.Set; + +public interface ServerUtilsPluginDescription { + + String getId(); + + String getName(); + + String getVersion(); + + String getAuthor(); + + File getFile(); + + Set getDependencies(); +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/exceptions/InvalidPluginDescriptionException.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/exceptions/InvalidPluginDescriptionException.java new file mode 100644 index 0000000..2aa5989 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/exceptions/InvalidPluginDescriptionException.java @@ -0,0 +1,16 @@ +package net.frankheijden.serverutils.common.entities.exceptions; + +public class InvalidPluginDescriptionException extends RuntimeException { + + public InvalidPluginDescriptionException() { + super(); + } + + public InvalidPluginDescriptionException(String message) { + super(message); + } + + public InvalidPluginDescriptionException(Throwable cause) { + super(cause); + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/AbstractResult.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/AbstractResult.java similarity index 72% rename from Common/src/main/java/net/frankheijden/serverutils/common/entities/AbstractResult.java rename to Common/src/main/java/net/frankheijden/serverutils/common/entities/results/AbstractResult.java index d4b3456..ec9c35e 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/entities/AbstractResult.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/AbstractResult.java @@ -1,4 +1,6 @@ -package net.frankheijden.serverutils.common.entities; +package net.frankheijden.serverutils.common.entities.results; + +import net.frankheijden.serverutils.common.entities.ServerCommandSender; public interface AbstractResult { diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/CloseablePluginResult.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/CloseablePluginResult.java new file mode 100644 index 0000000..572ead6 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/CloseablePluginResult.java @@ -0,0 +1,43 @@ +package net.frankheijden.serverutils.common.entities.results; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +public class CloseablePluginResult extends PluginResult implements Closeable { + + private final List closeables; + + public CloseablePluginResult(String pluginId, Result result) { + super(pluginId, result); + this.closeables = Collections.emptyList(); + } + + public CloseablePluginResult(String pluginId, T plugin, Result result, List closeables) { + super(pluginId, plugin, result); + this.closeables = closeables; + } + + /** + * Attempts to close the closable, essentially wrapping it with try-catch. + */ + public void tryClose() { + if (closeables == null) return; + try { + close(); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + /** + * Closes the closable. + */ + @Override + public void close() throws IOException { + for (Closeable closeable : closeables) { + closeable.close(); + } + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/CloseablePluginResults.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/CloseablePluginResults.java new file mode 100644 index 0000000..10bf827 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/CloseablePluginResults.java @@ -0,0 +1,81 @@ +package net.frankheijden.serverutils.common.entities.results; + +import java.io.Closeable; +import java.io.IOException; +import java.util.List; + +public class CloseablePluginResults extends PluginResults implements Closeable { + + @Override + public CloseablePluginResults addResult(PluginResult pluginResult) { + if (!(pluginResult instanceof CloseablePluginResult)) { + throw new IllegalArgumentException("Not an instance of CloseablePluginResult: " + pluginResult); + } + results.add(pluginResult); + return this; + } + + @Override + public CloseablePluginResults addResult(String pluginId, Result result) { + super.addResult(pluginId, result); + return this; + } + + @Override + public CloseablePluginResults addResult(String pluginId, T plugin) { + super.addResult(pluginId, plugin); + return this; + } + + @Override + protected CloseablePluginResults addResult(String pluginId, T plugin, Result result) { + super.addResult(pluginId, plugin, result); + return this; + } + + public CloseablePluginResults addResult(String pluginId, T plugin, List closeables) { + return addResult(new CloseablePluginResult<>(pluginId, plugin, Result.SUCCESS, closeables)); + } + + @Override + public CloseablePluginResult first() { + PluginResult pluginResult = super.first(); + if (!(pluginResult instanceof CloseablePluginResult)) { + throw new IllegalArgumentException("Not an instance of CloseablePluginResult: " + pluginResult); + } + return (CloseablePluginResult) pluginResult; + } + + @Override + public CloseablePluginResult last() { + PluginResult pluginResult = super.last(); + if (!(pluginResult instanceof CloseablePluginResult)) { + throw new IllegalArgumentException("Not an instance of CloseablePluginResult: " + pluginResult); + } + return (CloseablePluginResult) pluginResult; + } + + /** + * Attempts to close the {@link CloseablePluginResult}'s enclosed. + */ + public void tryClose() { + try { + for (PluginResult pluginResult : this) { + if (pluginResult instanceof CloseablePluginResult) { + ((CloseablePluginResult) pluginResult).close(); + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + @Override + public void close() throws IOException { + for (PluginResult pluginResult : this) { + if (pluginResult instanceof CloseablePluginResult) { + ((CloseablePluginResult) pluginResult).close(); + } + } + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/PluginResult.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/PluginResult.java new file mode 100644 index 0000000..53eb674 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/PluginResult.java @@ -0,0 +1,37 @@ +package net.frankheijden.serverutils.common.entities.results; + +public class PluginResult { + + private final String pluginId; + private final T plugin; + private final Result result; + + public PluginResult(String pluginId, Result result) { + this(pluginId, null, result); + } + + /** + * Constructs a new PluginResult. + */ + public PluginResult(String pluginId, T plugin, Result result) { + this.pluginId = pluginId; + this.plugin = plugin; + this.result = result; + } + + public String getPluginId() { + return pluginId; + } + + public T getPlugin() { + return plugin; + } + + public Result getResult() { + return result; + } + + public boolean isSuccess() { + return plugin != null && result == Result.SUCCESS; + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/PluginResults.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/PluginResults.java new file mode 100644 index 0000000..6de0815 --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/PluginResults.java @@ -0,0 +1,80 @@ +package net.frankheijden.serverutils.common.entities.results; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; + +public class PluginResults implements Iterable> { + + protected final List> results; + + public PluginResults() { + this.results = new ArrayList<>(); + } + + public PluginResults addResult(String pluginId, Result result) { + addResult(pluginId, null, result); + return this; + } + + public PluginResults addResult(String pluginId, T plugin) { + addResult(pluginId, plugin, Result.SUCCESS); + return this; + } + + protected PluginResults addResult(String pluginId, T plugin, Result result) { + addResult(new PluginResult<>(pluginId, plugin, result)); + return this; + } + + public PluginResults addResult(PluginResult pluginResult) { + this.results.add(pluginResult); + return this; + } + + public boolean isSuccess() { + return results.stream().allMatch(PluginResult::isSuccess); + } + + public List> getResults() { + return results; + } + + /** + * Creates an array of all plugins. + * @throws IllegalArgumentException Iff a result was not successful (check {@link PluginResults#isSuccess()} first!) + */ + public List getPlugins() { + List plugins = new ArrayList<>(results.size()); + for (PluginResult result : results) { + if (!result.isSuccess()) throw new IllegalArgumentException( + "Result after handling plugin '" + result.getPluginId() + "' was not successful!" + ); + plugins.add(result.getPlugin()); + } + return plugins; + } + + public PluginResult first() { + return results.get(0); + } + + public PluginResult last() { + return results.get(results.size() - 1); + } + + /** + * Sends the results to given receiver. + */ + public void sendTo(ServerCommandSender sender, String action) { + for (PluginResult result : results) { + result.getResult().sendTo(sender, action, result.getPluginId()); + } + } + + @Override + public Iterator> iterator() { + return results.iterator(); + } +} diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/Result.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/Result.java similarity index 90% rename from Common/src/main/java/net/frankheijden/serverutils/common/entities/Result.java rename to Common/src/main/java/net/frankheijden/serverutils/common/entities/results/Result.java index f242443..781c35c 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/entities/Result.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/Result.java @@ -1,6 +1,7 @@ -package net.frankheijden.serverutils.common.entities; +package net.frankheijden.serverutils.common.entities.results; import net.frankheijden.serverutils.common.ServerUtilsApp; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; /** * An enum containing possible results. diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/entities/WatchResult.java b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/WatchResult.java similarity index 84% rename from Common/src/main/java/net/frankheijden/serverutils/common/entities/WatchResult.java rename to Common/src/main/java/net/frankheijden/serverutils/common/entities/results/WatchResult.java index 4e64f94..787378d 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/entities/WatchResult.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/entities/results/WatchResult.java @@ -1,6 +1,7 @@ -package net.frankheijden.serverutils.common.entities; +package net.frankheijden.serverutils.common.entities.results; import net.frankheijden.serverutils.common.ServerUtilsApp; +import net.frankheijden.serverutils.common.entities.ServerCommandSender; public enum WatchResult implements AbstractResult { diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/listeners/PlayerListener.java b/Common/src/main/java/net/frankheijden/serverutils/common/listeners/PlayerListener.java index 8d28334..53fc3b1 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/listeners/PlayerListener.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/listeners/PlayerListener.java @@ -4,7 +4,7 @@ import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; import net.frankheijden.serverutils.common.tasks.UpdateCheckerTask; -public abstract class PlayerListener, P, C extends ServerCommandSender> +public abstract class PlayerListener, P, C extends ServerCommandSender> extends ServerUtilsListener { protected PlayerListener(U plugin) { diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/listeners/ServerUtilsListener.java b/Common/src/main/java/net/frankheijden/serverutils/common/listeners/ServerUtilsListener.java index c717964..d08336d 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/listeners/ServerUtilsListener.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/listeners/ServerUtilsListener.java @@ -3,7 +3,7 @@ package net.frankheijden.serverutils.common.listeners; import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; -public abstract class ServerUtilsListener, C extends ServerCommandSender> { +public abstract class ServerUtilsListener, C extends ServerCommandSender> { protected final U plugin; diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/managers/AbstractPluginManager.java b/Common/src/main/java/net/frankheijden/serverutils/common/managers/AbstractPluginManager.java index 3713c30..3468956 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/managers/AbstractPluginManager.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/managers/AbstractPluginManager.java @@ -1,54 +1,316 @@ package net.frankheijden.serverutils.common.managers; import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import net.frankheijden.serverutils.common.ServerUtilsApp; -import net.frankheijden.serverutils.common.entities.AbstractResult; -import net.frankheijden.serverutils.common.entities.CloseableResult; -import net.frankheijden.serverutils.common.entities.LoadResult; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.results.AbstractResult; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResult; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults; +import net.frankheijden.serverutils.common.entities.results.PluginResult; +import net.frankheijden.serverutils.common.entities.results.PluginResults; +import net.frankheijden.serverutils.common.entities.results.Result; import net.frankheijden.serverutils.common.entities.ServerCommandSender; -import net.frankheijden.serverutils.common.entities.WatchResult; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import net.frankheijden.serverutils.common.entities.results.WatchResult; +import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException; import net.frankheijden.serverutils.common.providers.PluginProvider; import net.frankheijden.serverutils.common.tasks.PluginWatcherTask; +import net.frankheijden.serverutils.common.utils.DependencyUtils; -public interface AbstractPluginManager

extends PluginProvider

{ +public abstract class AbstractPluginManager implements PluginProvider { - LoadResult

loadPlugin(String pluginFile); + /** + * Loads the given plugin by their jar file. + */ + public PluginResult

loadPlugin(String pluginFile) { + File file = new File(getPluginsFolder(), pluginFile); + if (!file.exists()) return new PluginResult<>(pluginFile, Result.NOT_EXISTS); + return loadPlugin(file); + } - LoadResult

loadPlugin(File file); + public PluginResult

loadPlugin(File file) { + return loadPlugins(Collections.singletonList(file)).first(); + } - Result enablePlugin(P plugin); + /** + * Loads a list of files as plugins. + */ + public PluginResults

loadPlugins(List files) { + List descriptions = new ArrayList<>(files.size()); - Result disablePlugin(P plugin); + for (File file : files) { + D description; + try { + Optional descriptionOptional = getPluginDescription(file); + if (!descriptionOptional.isPresent()) { + return new PluginResults

().addResult(file.getName(), Result.NOT_EXISTS); + } - Result reloadPlugin(String pluginName); + description = descriptionOptional.get(); + } catch (InvalidPluginDescriptionException ex) { + return new PluginResults

().addResult(file.getName(), Result.INVALID_DESCRIPTION); + } - Result reloadPlugin(P plugin); + if (getPlugin(description.getId()).isPresent()) { + return new PluginResults

().addResult(description.getId(), Result.ALREADY_LOADED); + } - CloseableResult unloadPlugin(String pluginName); + descriptions.add(description); + } - CloseableResult unloadPlugin(P plugin); + List orderedDescriptions; + try { + orderedDescriptions = determineLoadOrder(descriptions); + } catch (IllegalStateException ex) { + ex.printStackTrace(); + + StringBuilder sb = new StringBuilder(); + for (File file : files) { + sb.append(", ").append(file.getName()); + } + + return new PluginResults

().addResult(sb.substring(2), Result.ERROR); + } + + return loadPluginDescriptions(orderedDescriptions); + } + + protected abstract PluginResults

loadPluginDescriptions(List descriptions); + + /** + * Enables the given plugin by name. + */ + public PluginResult

enablePlugin(String pluginId) { + return getPlugin(pluginId) + .map(this::enablePlugin) + .orElse(new PluginResult<>(pluginId, Result.NOT_EXISTS)); + } + + public PluginResult

enablePlugin(P plugin) { + return enablePlugins(Collections.singletonList(plugin)).first(); + } + + /** + * Enables a list of plugins. + */ + public PluginResults

enablePlugins(List

plugins) { + for (P plugin : plugins) { + String pluginId = getPluginId(plugin); + if (isPluginEnabled(pluginId)) { + return new PluginResults

().addResult(pluginId, Result.ALREADY_ENABLED); + } + } + + return enableOrderedPlugins(determineLoadOrder(plugins)); + } + + protected abstract PluginResults

enableOrderedPlugins(List

plugins); + + public boolean isPluginEnabled(P plugin) { + return isPluginEnabled(getPluginId(plugin)); + } + + public abstract boolean isPluginEnabled(String pluginId); + + /** + * Disables the given plugin by name. + */ + public PluginResult

disablePlugin(String pluginId) { + return getPlugin(pluginId) + .map(this::disablePlugin) + .orElse(new PluginResult<>(pluginId, Result.NOT_EXISTS)); + } + + public PluginResult

disablePlugin(P plugin) { + return disablePlugins(Collections.singletonList(plugin)).first(); + } + + /** + * Disables a list of plugins. + */ + public PluginResults

disablePlugins(List

plugins) { + for (P plugin : plugins) { + if (!isPluginEnabled(plugin)) { + return new PluginResults

().addResult(getPluginId(plugin), Result.ALREADY_DISABLED); + } + } + + List

orderedPlugins; + try { + orderedPlugins = determineLoadOrder(plugins); + } catch (IllegalStateException ex) { + ex.printStackTrace(); + + StringBuilder sb = new StringBuilder(); + for (P plugin : plugins) { + sb.append(", ").append(getPluginId(plugin)); + } + + return new PluginResults

().addResult(sb.substring(2), Result.ERROR); + } + + Collections.reverse(orderedPlugins); + return disableOrderedPlugins(orderedPlugins); + } + + public abstract PluginResults

disableOrderedPlugins(List

plugins); + + /** + * Reloads the given plugin by name. + */ + public PluginResult

reloadPlugin(String pluginId) { + return getPlugin(pluginId) + .map(this::reloadPlugin) + .orElse(new PluginResult<>(pluginId, Result.NOT_EXISTS)); + } + + public PluginResult

reloadPlugin(P plugin) { + return reloadPlugins(Collections.singletonList(plugin)).first(); + } + + /** + * Reloads the given plugins. + */ + public PluginResults

reloadPlugins(List

plugins) { + PluginResults

disableResults = disablePlugins(plugins); + for (PluginResult

disableResult : disableResults.getResults()) { + if (!disableResult.isSuccess() && disableResult.getResult() != Result.ALREADY_DISABLED) { + return disableResults; + } + } + + List pluginIds = new ArrayList<>(plugins.size()); + for (P plugin : plugins) { + pluginIds.add(getPluginId(plugin)); + } + + CloseablePluginResults

unloadResults = unloadPlugins(plugins); + if (!unloadResults.isSuccess()) return unloadResults; + unloadResults.tryClose(); + + List pluginFiles = new ArrayList<>(plugins.size()); + for (String pluginId : pluginIds) { + Optional pluginFile = getPluginFile(pluginId); + if (!pluginFile.isPresent()) return new PluginResults

().addResult(pluginId, Result.FILE_DELETED); + pluginFiles.add(pluginFile.get()); + } + + PluginResults

loadResults = loadPlugins(pluginFiles); + if (!loadResults.isSuccess()) return loadResults; + + List

loadedPlugins = new ArrayList<>(pluginIds.size()); + for (PluginResult

loadResult : loadResults) { + loadedPlugins.add(loadResult.getPlugin()); + } + + return enablePlugins(loadedPlugins); + } + + /** + * Unloads the given plugin by name. + */ + public CloseablePluginResult

unloadPlugin(String pluginId) { + return getPlugin(pluginId) + .map(this::unloadPlugin) + .orElse(new CloseablePluginResult<>(pluginId, Result.NOT_EXISTS)); + } + + public CloseablePluginResult

unloadPlugin(P plugin) { + return unloadPlugins(Collections.singletonList(plugin)).first(); + } + + /** + * Unloads a list of plugins. + */ + public CloseablePluginResults

unloadPlugins(List

plugins) { + List

orderedPlugins; + try { + orderedPlugins = determineLoadOrder(plugins); + } catch (IllegalStateException ex) { + ex.printStackTrace(); + + StringBuilder sb = new StringBuilder(); + for (P plugin : plugins) { + sb.append(", ").append(getPluginId(plugin)); + } + + return new CloseablePluginResults

().addResult(sb.substring(2), Result.ERROR); + } + + Collections.reverse(orderedPlugins); + return unloadOrderedPlugins(orderedPlugins); + } + + public abstract CloseablePluginResults

unloadOrderedPlugins(List

plugins); + + /** + * Determines the load order of a list of plugins. + */ + public List

determineLoadOrder(List

plugins) throws IllegalStateException { + Map descriptionMap = new HashMap<>(plugins.size()); + for (P plugin : plugins) { + descriptionMap.put(getLoadedPluginDescription(plugin), plugin); + } + + List

orderedPlugins = new ArrayList<>(plugins.size()); + for (D description : determineLoadOrder(descriptionMap.keySet())) { + orderedPlugins.add(descriptionMap.get(description)); + } + return orderedPlugins; + } + + /** + * Determines the load order for a given collection of descriptions. + * @throws IllegalStateException Iff circular dependency + */ + public List determineLoadOrder(Collection descriptions) throws IllegalStateException { + Map pluginIdToDescriptionMap = new HashMap<>(); + for (D description : descriptions) { + pluginIdToDescriptionMap.put(description.getId(), description); + } + + Map> dependencyMap = new HashMap<>(descriptions.size()); + for (D description : descriptions) { + Set dependencyStrings = description.getDependencies(); + Set dependencies = new HashSet<>(); + + for (String dependencyString : dependencyStrings) { + D dependency = pluginIdToDescriptionMap.get(dependencyString); + if (dependency != null) { + dependencies.add(dependency); + } + } + + dependencyMap.put(description, dependencies); + } + + return DependencyUtils.determineOrder(dependencyMap); + } /** * Starts watching the specified plugin for changes. * Reloads the plugin if a change is detected. - * @param pluginName The plugin to watch. - * @return The result of the action. */ - default AbstractResult watchPlugin(ServerCommandSender sender, String pluginName) { - if (getPlugin(pluginName) == null) return Result.NOT_EXISTS; + public AbstractResult watchPlugin(ServerCommandSender sender, String pluginId) { + if (getPlugin(pluginId).isPresent()) return Result.NOT_EXISTS; ServerUtilsApp.getPlugin().getTaskManager() - .runTaskAsynchronously(pluginName, new PluginWatcherTask(sender, pluginName)); + .runTaskAsynchronously(pluginId, new PluginWatcherTask(sender, pluginId)); return WatchResult.START; } /** * Stops watching the plugin for changes. - * @param pluginName The plugin to stop watching. - * @return The result of the action. */ - default AbstractResult unwatchPlugin(String pluginName) { - if (ServerUtilsApp.getPlugin().getTaskManager().cancelTask(pluginName)) return WatchResult.STOPPED; + public AbstractResult unwatchPlugin(String pluginId) { + if (ServerUtilsApp.getPlugin().getTaskManager().cancelTask(pluginId)) return WatchResult.STOPPED; return WatchResult.NOT_WATCHING; } } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/providers/PluginProvider.java b/Common/src/main/java/net/frankheijden/serverutils/common/providers/PluginProvider.java index a961e7b..3507e67 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/providers/PluginProvider.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/providers/PluginProvider.java @@ -4,11 +4,14 @@ import java.io.File; import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import net.frankheijden.serverutils.common.ServerUtilsApp; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException; -public interface PluginProvider

{ +public interface PluginProvider { default File getPluginsFolder() { return ServerUtilsApp.getPlugin().getDataFolder().getParentFile(); @@ -16,13 +19,43 @@ public interface PluginProvider

{ List

getPlugins(); - String getPluginName(P plugin); + default String getPluginId(P plugin) { + return getLoadedPluginDescription(plugin).getId(); + } - File getPluginFile(P plugin); + default File getPluginFile(P plugin) { + return getLoadedPluginDescription(plugin).getFile(); + } - File getPluginFile(String pluginName); + /** + * Attempts to find the file for a given plugin id. + */ + default Optional getPluginFile(String pluginId) { + for (File file : getPluginJars()) { + Optional pluginDescriptionOptional; + try { + pluginDescriptionOptional = getPluginDescription(file); + } catch (InvalidPluginDescriptionException ex) { + continue; + } - P getPlugin(String pluginName); + if (pluginDescriptionOptional.isPresent() && pluginDescriptionOptional.get().getId().equals(pluginId)) { + return Optional.of(file); + } + } + return Optional.empty(); + } + + Optional

getPlugin(String pluginId); + + D getLoadedPluginDescription(P plugin); + + default Optional getPluginDescription(String pluginId) throws InvalidPluginDescriptionException { + Optional fileOptional = getPluginFile(pluginId); + return fileOptional.flatMap(this::getPluginDescription); + } + + Optional getPluginDescription(File file) throws InvalidPluginDescriptionException; Object getInstance(P plugin); @@ -34,7 +67,7 @@ public interface PluginProvider

{ */ default List

getPluginsSorted() { List

plugins = getPlugins(); - plugins.sort(Comparator.comparing(this::getPluginName)); + plugins.sort(Comparator.comparing(this::getPluginId)); return plugins; } @@ -44,7 +77,7 @@ public interface PluginProvider

{ */ default List getPluginNames() { return getPlugins().stream() - .map(this::getPluginName) + .map(this::getPluginId) .collect(Collectors.toList()); } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/tasks/PluginWatcherTask.java b/Common/src/main/java/net/frankheijden/serverutils/common/tasks/PluginWatcherTask.java index 37cd7e6..3401f3e 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/tasks/PluginWatcherTask.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/tasks/PluginWatcherTask.java @@ -5,7 +5,7 @@ import net.frankheijden.serverutils.common.ServerUtilsApp; import net.frankheijden.serverutils.common.entities.AbstractTask; import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; -import net.frankheijden.serverutils.common.entities.WatchResult; +import net.frankheijden.serverutils.common.entities.results.WatchResult; import net.frankheijden.serverutils.common.managers.AbstractPluginManager; import net.frankheijden.serverutils.common.managers.AbstractTaskManager; import net.frankheijden.serverutils.common.providers.ChatProvider; @@ -28,8 +28,8 @@ public class PluginWatcherTask extends AbstractTask { StandardWatchEventKinds.ENTRY_DELETE }; - private final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin(); - private final AbstractPluginManager pluginManager = plugin.getPluginManager(); + private final ServerUtilsPlugin plugin = ServerUtilsApp.getPlugin(); + private final AbstractPluginManager pluginManager = plugin.getPluginManager(); private final ChatProvider chatProvider = plugin.getChatProvider(); @SuppressWarnings("rawtypes") private final AbstractTaskManager taskManager = plugin.getTaskManager(); @@ -52,7 +52,7 @@ public class PluginWatcherTask extends AbstractTask { public PluginWatcherTask(ServerCommandSender sender, String pluginName) { this.sender = sender; this.pluginName = pluginName; - this.file = pluginManager.getPluginFile(pluginName); + this.file = pluginManager.getPluginFile(pluginName).orElse(null); this.run = new AtomicBoolean(true); } @@ -82,7 +82,7 @@ public class PluginWatcherTask extends AbstractTask { send(WatchResult.CHANGE); pluginManager.reloadPlugin(pluginName); - file = pluginManager.getPluginFile(pluginName); + file = pluginManager.getPluginFile(pluginName).orElse(null); } }, 10L); } diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/tasks/UpdateCheckerTask.java b/Common/src/main/java/net/frankheijden/serverutils/common/tasks/UpdateCheckerTask.java index 541dd62..6bb32f7 100644 --- a/Common/src/main/java/net/frankheijden/serverutils/common/tasks/UpdateCheckerTask.java +++ b/Common/src/main/java/net/frankheijden/serverutils/common/tasks/UpdateCheckerTask.java @@ -11,8 +11,8 @@ import java.net.UnknownHostException; import java.util.logging.Level; import net.frankheijden.serverutils.common.ServerUtilsApp; import net.frankheijden.serverutils.common.config.ServerUtilsConfig; -import net.frankheijden.serverutils.common.entities.LoadResult; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.results.PluginResult; +import net.frankheijden.serverutils.common.entities.results.Result; import net.frankheijden.serverutils.common.entities.ServerCommandSender; import net.frankheijden.serverutils.common.entities.ServerUtilsPlugin; import net.frankheijden.serverutils.common.entities.http.GitHubAsset; @@ -22,7 +22,7 @@ import net.frankheijden.serverutils.common.utils.GitHubUtils; import net.frankheijden.serverutils.common.utils.VersionUtils; import net.frankheijden.serverutilsupdater.common.Updater; -public class UpdateCheckerTask, P> implements Runnable { +public class UpdateCheckerTask, P> implements Runnable { private final U plugin; private final ServerCommandSender sender; @@ -60,7 +60,7 @@ public class UpdateCheckerTask, P> imple * Checks for updates if enabled per config for the specific action. * Action must be 'login' or 'boot'. */ - public static , P> void tryStart( + public static , P> void tryStart( U plugin, ServerCommandSender sender, String action @@ -75,7 +75,7 @@ public class UpdateCheckerTask, P> imple * Checks for updates and downloads/installs if configured. * Action must be 'login' or 'boot'. */ - public static , P> void start( + public static , P> void start( U plugin, ServerCommandSender sender, String action @@ -241,21 +241,19 @@ public class UpdateCheckerTask, P> imple private void tryReloadPlugin(File pluginFile, File updaterFile) { plugin.getTaskManager().runTask(() -> { - LoadResult

loadResult = plugin.getPluginManager().loadPlugin(updaterFile); + PluginResult

loadResult = plugin.getPluginManager().loadPlugin(updaterFile); if (!loadResult.isSuccess()) { - plugin.getLogger().log(Level.INFO, UPDATER_LOAD_ERROR, - loadResult.getResult().name()); + plugin.getLogger().log(Level.INFO, UPDATER_LOAD_ERROR, loadResult.getResult().name()); return; } - P updaterPlugin = loadResult.get(); - Result result = plugin.getPluginManager().enablePlugin(updaterPlugin); - if (result != Result.SUCCESS && result != Result.ALREADY_ENABLED) { - plugin.getLogger().log(Level.INFO, UPDATER_ENABLE_ERROR, result.name()); + PluginResult

enableResult = plugin.getPluginManager().enablePlugin(loadResult.getPlugin()); + if (!enableResult.isSuccess() && enableResult.getResult() != Result.ALREADY_ENABLED) { + plugin.getLogger().log(Level.INFO, UPDATER_ENABLE_ERROR, enableResult.getResult().name()); return; } - Updater updater = (Updater) plugin.getPluginManager().getInstance(updaterPlugin); + Updater updater = (Updater) plugin.getPluginManager().getInstance(enableResult.getPlugin()); updater.update(pluginFile); updaterFile.delete(); }); diff --git a/Common/src/main/java/net/frankheijden/serverutils/common/utils/DependencyUtils.java b/Common/src/main/java/net/frankheijden/serverutils/common/utils/DependencyUtils.java new file mode 100644 index 0000000..ea0022b --- /dev/null +++ b/Common/src/main/java/net/frankheijden/serverutils/common/utils/DependencyUtils.java @@ -0,0 +1,117 @@ +package net.frankheijden.serverutils.common.utils; + +import com.google.common.graph.Graph; +import com.google.common.graph.GraphBuilder; +import com.google.common.graph.MutableGraph; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DependencyUtils { + + private DependencyUtils() {} + + /** + * Determines the topological order of a dependency map. + * Adapted from https://github.com/VelocityPowered/Velocity. + * @throws IllegalStateException Iff circular dependency. + */ + @SuppressWarnings("UnstableApiUsage") + public static List determineOrder(Map> dependencyMap) throws IllegalStateException { + MutableGraph dependencyGraph = GraphBuilder.directed().allowsSelfLoops(true).build(); + for (T node : dependencyMap.keySet()) { + dependencyGraph.addNode(node); + } + + for (Map.Entry> entry : dependencyMap.entrySet()) { + for (T dependency : entry.getValue()) { + dependencyGraph.putEdge(entry.getKey(), dependency); + } + } + + List orderedList = new ArrayList<>(dependencyMap.size()); + Map marks = new HashMap<>(dependencyMap.size()); + + for (T node : dependencyGraph.nodes()) { + visitNode(dependencyGraph, node, marks, orderedList, new LinkedList<>()); + } + + return orderedList; + } + + @SuppressWarnings("UnstableApiUsage") + private static void visitNode( + Graph dependencyGraph, + T node, + Map marks, + List orderedList, + Deque currentIteration + ) throws IllegalStateException { + Mark mark = marks.getOrDefault(node, Mark.NOT_VISITED); + if (mark == Mark.PERMANENT) { + return; + } else if (mark == Mark.TEMPORARY) { + currentIteration.addLast(node); + + StringBuilder sb = new StringBuilder(); + for (T currentNode : currentIteration) { + sb.append(" -> ").append(currentNode); + } + + throw new IllegalStateException("Circular dependency detected: " + sb.substring(4)); + } + + currentIteration.addLast(node); + marks.put(node, Mark.TEMPORARY); + + for (T successorNode : dependencyGraph.successors(node)) { + visitNode(dependencyGraph, successorNode, marks, orderedList, currentIteration); + } + + marks.put(node, Mark.PERMANENT); + currentIteration.removeLast(); + orderedList.add(node); + } + + private enum Mark { + NOT_VISITED, + TEMPORARY, + PERMANENT + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Common/src/main/resources/commands.json b/Common/src/main/resources/commands.json index db892da..b259406 100644 --- a/Common/src/main/resources/commands.json +++ b/Common/src/main/resources/commands.json @@ -41,21 +41,21 @@ "main": "loadplugin", "aliases": ["lp"], "permission": "serverutils.loadplugin", - "description": "Loads the specified jar file as a plugin.", + "description": "Loads the specified jar file(s).", "display-in-help": true }, "unloadplugin": { "main": "unloadplugin", "aliases": ["up"], "permission": "serverutils.unloadplugin", - "description": "Disables and unloads the specified plugin.", + "description": "Disables and unloads the specified plugin(s).", "display-in-help": true }, "reloadplugin": { "main": "reloadplugin", "aliases": ["rp"], "permission": "serverutils.reloadplugin", - "description": "Reloads the specified plugin.", + "description": "Reloads the specified plugin(s).", "display-in-help": true }, "watchplugin": { diff --git a/Common/src/test/java/net/frankheijden/serverutils/common/utils/DependencyUtilsTest.java b/Common/src/test/java/net/frankheijden/serverutils/common/utils/DependencyUtilsTest.java new file mode 100644 index 0000000..a1dcb34 --- /dev/null +++ b/Common/src/test/java/net/frankheijden/serverutils/common/utils/DependencyUtilsTest.java @@ -0,0 +1,127 @@ +package net.frankheijden.serverutils.common.utils; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalStateException; +import static org.junit.jupiter.params.provider.Arguments.of; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class DependencyUtilsTest { + + @ParameterizedTest(name = "dependencyMap = {0}, expected = {1}") + @MethodSource("dependencyGenerator") + void determineOrderDependencies( + Map> dependencyMap, + List expected + ) { + assertThat(DependencyUtils.determineOrder(dependencyMap)).isEqualTo(expected); + } + + @ParameterizedTest(name = "dependencyMap = {0}") + @MethodSource("circularDependencyGenerator") + void determineOrderCircularDependencies( + Map> dependencyMap + ) { + assertThatIllegalStateException().isThrownBy(() -> DependencyUtils.determineOrder(dependencyMap)); + } + + private static Stream dependencyGenerator() { + return Stream.of( + of( + mapOf( + new Pair<>("B", asSet("A")) + ), + asList("A", "B") + ), + of( + mapOf( + new Pair<>("B", asSet("A")), + new Pair<>("C", asSet("A", "B")) + ), + asList("A", "B", "C") + ), + of( + mapOf( + new Pair<>("A", asSet("B")), + new Pair<>("B", asSet("C", "D")), + new Pair<>("C", asSet()), + new Pair<>("D", asSet("C", "E")), + new Pair<>("E", asSet("F")), + new Pair<>("F", asSet("C")) + ), + asList("C", "F", "E", "D", "B", "A") + ), + of( + mapOf( + new Pair<>("A", asSet()), + new Pair<>("B", asSet()), + new Pair<>("C", asSet()), + new Pair<>("D", asSet("C")) + ), + asList("A", "B", "C", "D") + ) + ); + } + + private static Stream circularDependencyGenerator() { + return Stream.of( + of( + mapOf( + new Pair<>("A", asSet("A")) + ) + ), + of( + mapOf( + new Pair<>("A", asSet("B")), + new Pair<>("B", asSet("A")) + ) + ), + of( + mapOf( + new Pair<>("B", asSet("A")), + new Pair<>("C", asSet("A", "B")), + new Pair<>("A", asSet("C")) + ) + ), + of( + mapOf( + new Pair<>("A", asSet("B")), + new Pair<>("B", asSet("C")), + new Pair<>("C", asSet("D")), + new Pair<>("D", asSet("A")) + ) + ) + ); + } + + private static Set asSet(T... elements) { + return new HashSet<>(asList(elements)); + } + + private static Map mapOf(Pair... pairs) { + Map map = new HashMap<>(); + for (Pair pair : pairs) { + map.put(pair.first, pair.second); + } + return map; + } + + private static final class Pair { + private final A first; + private final B second; + + private Pair(A first, B second) { + this.first = first; + this.second = second; + } + } +} diff --git a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/commands/VelocityCommandServerUtils.java b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/commands/VelocityCommandServerUtils.java index d64cee6..adf828b 100644 --- a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/commands/VelocityCommandServerUtils.java +++ b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/commands/VelocityCommandServerUtils.java @@ -21,16 +21,15 @@ public class VelocityCommandServerUtils extends CommandServerUtils { public VelocityCommandServerUtils(VelocityPlugin plugin) { - super(plugin); + super(plugin, PluginContainer[]::new); } @Override protected FormatBuilder createPluginInfo( FormatBuilder builder, Function>, String> listBuilderFunction, - String pluginName + PluginContainer container ) { - PluginContainer container = plugin.getPluginManager().getPlugin(pluginName); PluginDescription desc = container.getDescription(); return builder diff --git a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityLoadResult.java b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityLoadResult.java deleted file mode 100644 index 68d8bba..0000000 --- a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityLoadResult.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.frankheijden.serverutils.velocity.entities; - -import com.velocitypowered.api.plugin.PluginContainer; -import net.frankheijden.serverutils.common.entities.LoadResult; -import net.frankheijden.serverutils.common.entities.Result; - -public class VelocityLoadResult extends LoadResult { - - public VelocityLoadResult(PluginContainer obj, Result result) { - super(obj, result); - } - - public VelocityLoadResult(PluginContainer obj) { - super(obj); - } - - public VelocityLoadResult(Result result) { - super(result); - } -} diff --git a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPlugin.java b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPlugin.java index c153748..6005cfb 100644 --- a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPlugin.java +++ b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPlugin.java @@ -15,12 +15,7 @@ import net.frankheijden.serverutils.velocity.listeners.VelocityPlayerListener; import net.frankheijden.serverutils.velocity.managers.VelocityPluginManager; import net.frankheijden.serverutils.velocity.managers.VelocityTaskManager; -public class VelocityPlugin extends ServerUtilsPlugin< - PluginContainer, - ScheduledTask, - VelocityCommandSender, - CommandSource - > { +public class VelocityPlugin extends ServerUtilsPlugin { private final ServerUtils plugin; private final VelocityPluginManager pluginManager; @@ -46,13 +41,15 @@ public class VelocityPlugin extends ServerUtilsPlugin< @Override protected VelocityCommandManager newCommandManager() { - return new VelocityCommandManager<>( + VelocityCommandManager commandManager = new VelocityCommandManager<>( plugin.getPluginContainer(), plugin.getProxy(), AsynchronousCommandExecutionCoordinator.newBuilder().build(), chatProvider::get, VelocityCommandSender::getSource ); + handleBrigadier(commandManager.brigadierManager()); + return commandManager; } @Override diff --git a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPluginDescription.java b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPluginDescription.java new file mode 100644 index 0000000..7506c50 --- /dev/null +++ b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/entities/VelocityPluginDescription.java @@ -0,0 +1,69 @@ +package net.frankheijden.serverutils.velocity.entities; + +import com.velocitypowered.api.plugin.PluginDescription; +import com.velocitypowered.api.plugin.meta.PluginDependency; +import java.io.File; +import java.nio.file.Path; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import net.frankheijden.serverutils.common.entities.ServerUtilsPluginDescription; +import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException; + +public class VelocityPluginDescription implements ServerUtilsPluginDescription { + + private final PluginDescription description; + private final File file; + private final String author; + private final Set dependencies; + + /** + * Constructs a new BungeePluginDescription. + */ + public VelocityPluginDescription(PluginDescription description) { + this.description = description; + + Optional sourceOptional = description.getSource(); + if (!sourceOptional.isPresent()) throw new InvalidPluginDescriptionException("Source path is null"); + + this.file = sourceOptional.get().toFile(); + this.author = String.join(", ", description.getAuthors()); + this.dependencies = description.getDependencies().stream() + .map(PluginDependency::getId) + .collect(Collectors.toSet()); + } + + @Override + public String getId() { + return this.description.getId(); + } + + @Override + public String getName() { + return this.description.getName().orElse(""); + } + + @Override + public String getVersion() { + return this.description.getVersion().orElse(""); + } + + @Override + public String getAuthor() { + return this.author; + } + + @Override + public File getFile() { + return this.file; + } + + @Override + public Set getDependencies() { + return this.dependencies; + } + + public PluginDescription getDescription() { + return description; + } +} diff --git a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/managers/VelocityPluginManager.java b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/managers/VelocityPluginManager.java index 250c89d..c97112e 100644 --- a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/managers/VelocityPluginManager.java +++ b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/managers/VelocityPluginManager.java @@ -26,11 +26,13 @@ import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import net.frankheijden.serverutils.common.entities.CloseableResult; -import net.frankheijden.serverutils.common.entities.Result; +import net.frankheijden.serverutils.common.entities.exceptions.InvalidPluginDescriptionException; +import net.frankheijden.serverutils.common.entities.results.CloseablePluginResults; +import net.frankheijden.serverutils.common.entities.results.PluginResults; +import net.frankheijden.serverutils.common.entities.results.Result; import net.frankheijden.serverutils.common.events.PluginEvent; import net.frankheijden.serverutils.common.managers.AbstractPluginManager; -import net.frankheijden.serverutils.velocity.entities.VelocityLoadResult; +import net.frankheijden.serverutils.velocity.entities.VelocityPluginDescription; import net.frankheijden.serverutils.velocity.events.VelocityPluginDisableEvent; import net.frankheijden.serverutils.velocity.events.VelocityPluginEnableEvent; import net.frankheijden.serverutils.velocity.events.VelocityPluginLoadEvent; @@ -44,7 +46,7 @@ import net.frankheijden.serverutils.velocity.reflection.RVelocityPluginManager; import net.frankheijden.serverutils.velocity.reflection.RVelocityScheduler; import org.slf4j.Logger; -public class VelocityPluginManager implements AbstractPluginManager { +public class VelocityPluginManager extends AbstractPluginManager { private static VelocityPluginManager instance; private final ProxyServer proxy; @@ -66,195 +68,223 @@ public class VelocityPluginManager implements AbstractPluginManager loadPluginDescriptions(List descriptions) { + PluginResults loadResults = new PluginResults<>(); - @Override - public VelocityLoadResult loadPlugin(File file) { - if (!file.exists() || file.isDirectory()) return new VelocityLoadResult(Result.NOT_EXISTS); + for (VelocityPluginDescription description : descriptions) { + Path source = description.getFile().toPath(); + Path baseDirectory = source.getParent(); - Object javaPluginLoader = RJavaPluginLoader.newInstance(proxy, file.toPath().getParent()); - PluginDescription candidate = RJavaPluginLoader.loadPluginDescription(javaPluginLoader, file.toPath()); - if (proxy.getPluginManager().isLoaded(candidate.getId())) return new VelocityLoadResult(Result.ALREADY_LOADED); + Object javaPluginLoader = RJavaPluginLoader.newInstance(proxy, baseDirectory); + PluginDescription candidate = RJavaPluginLoader.loadPluginDescription(javaPluginLoader, source); - for (PluginDependency dependency : candidate.getDependencies()) { - if (!dependency.isOptional() && !proxy.getPluginManager().isLoaded(dependency.getId())) { - logger.error( - "Can't load plugin {} due to missing dependency {}", - candidate.getId(), - dependency.getId() - ); - return new VelocityLoadResult(Result.UNKNOWN_DEPENDENCY.arg(dependency.getId())); - } - } - - PluginDescription realPlugin = RJavaPluginLoader.loadPlugin(javaPluginLoader, candidate); - PluginContainer container = RVelocityPluginContainer.newInstance(realPlugin); - proxy.getEventManager().fire(new VelocityPluginLoadEvent(container, PluginEvent.Stage.PRE)); - proxy.getEventManager().fire(new VelocityPluginLoadEvent(container, PluginEvent.Stage.POST)); - - return new VelocityLoadResult(container); - } - - @Override - public Result enablePlugin(PluginContainer container) { - proxy.getEventManager().fire(new VelocityPluginEnableEvent(container, PluginEvent.Stage.PRE)); - if (proxy.getPluginManager().isLoaded(container.getDescription().getId())) return Result.ALREADY_ENABLED; - - Object javaPluginLoader = RJavaPluginLoader.newInstance( - proxy, - container.getDescription().getSource().map(Path::getParent).orElse(null) - ); - PluginDescription realPlugin = container.getDescription(); - Module module = RJavaPluginLoader.createModule(javaPluginLoader, container); - - AbstractModule commonModule = new AbstractModule() { - @Override - protected void configure() { - bind(ProxyServer.class).toInstance(proxy); - bind(PluginManager.class).toInstance(proxy.getPluginManager()); - bind(EventManager.class).toInstance(proxy.getEventManager()); - bind(CommandManager.class).toInstance(proxy.getCommandManager()); - for (PluginContainer container : proxy.getPluginManager().getPlugins()) { - bind(PluginContainer.class) - .annotatedWith(Names.named(container.getDescription().getId())) - .toInstance(container); + dependencyCheck: + for (PluginDependency dependency : candidate.getDependencies()) { + String pluginId = dependency.getId(); + for (VelocityPluginDescription desc : descriptions) { + if (desc.getId().equals(pluginId)) continue dependencyCheck; } - bind(PluginContainer.class) - .annotatedWith(Names.named(realPlugin.getId())) - .toInstance(container); - } - }; - try { - RJavaPluginLoader.createPlugin(javaPluginLoader, container, module, commonModule); - } catch (Exception ex) { - logger.error( - String.format("Can't create plugin %s", container.getDescription().getId()), - ex - ); - return Result.ERROR; + if (!dependency.isOptional() && !proxy.getPluginManager().isLoaded(dependency.getId())) { + logger.error( + "Can't load plugin {} due to missing dependency {}", + candidate.getId(), + dependency.getId() + ); + return loadResults.addResult( + description.getId(), + Result.UNKNOWN_DEPENDENCY.arg(dependency.getId()) + ); + } + } + + PluginDescription realPlugin = RJavaPluginLoader.loadPlugin(javaPluginLoader, candidate); + PluginContainer container = RVelocityPluginContainer.newInstance(realPlugin); + proxy.getEventManager().fire(new VelocityPluginLoadEvent(container, PluginEvent.Stage.PRE)); + proxy.getEventManager().fire(new VelocityPluginLoadEvent(container, PluginEvent.Stage.POST)); + + loadResults.addResult(description.getId(), container); } - logger.info( - "Loaded plugin {} {} by {}", - realPlugin.getId(), - realPlugin.getVersion().orElse(""), - Joiner.on(", ").join(realPlugin.getAuthors()) - ); + return loadResults; + } - RVelocityPluginManager.registerPlugin(proxy.getPluginManager(), container); - container.getInstance().ifPresent(pluginInstance -> { - RVelocityEventManager.registerInternally(proxy.getEventManager(), container, pluginInstance); - RVelocityEventManager.fireForPlugin( - proxy.getEventManager(), - new ProxyInitializeEvent(), - pluginInstance - ).join(); + @Override + public PluginResults enableOrderedPlugins(List containers) { + PluginResults enableResults = new PluginResults<>(); - ConsoleCommandSource console = proxy.getConsoleCommandSource(); - PermissionsSetupEvent event = new PermissionsSetupEvent( - console, - s -> PermissionFunction.ALWAYS_TRUE + List pluginInstances = new ArrayList<>(containers.size()); + for (PluginContainer container : containers) { + String pluginId = container.getDescription().getId(); + proxy.getEventManager().fire(new VelocityPluginEnableEvent(container, PluginEvent.Stage.PRE)); + if (isPluginEnabled(pluginId)) { + return enableResults.addResult(pluginId, Result.ALREADY_ENABLED); + } + + Object javaPluginLoader = RJavaPluginLoader.newInstance( + proxy, + container.getDescription().getSource().map(Path::getParent).orElse(null) ); - PermissionFunction permissionFunction = RVelocityEventManager.fireForPlugin( - proxy.getEventManager(), - event, - pluginInstance - ).join().createFunction(console); + PluginDescription realPlugin = container.getDescription(); + Module module = RJavaPluginLoader.createModule(javaPluginLoader, container); - if (permissionFunction == null) { + AbstractModule commonModule = new AbstractModule() { + @Override + protected void configure() { + bind(ProxyServer.class).toInstance(proxy); + bind(PluginManager.class).toInstance(proxy.getPluginManager()); + bind(EventManager.class).toInstance(proxy.getEventManager()); + bind(CommandManager.class).toInstance(proxy.getCommandManager()); + for (PluginContainer container : proxy.getPluginManager().getPlugins()) { + bind(PluginContainer.class) + .annotatedWith(Names.named(container.getDescription().getId())) + .toInstance(container); + } + for (PluginContainer container : containers) { + bind(PluginContainer.class) + .annotatedWith(Names.named(container.getDescription().getId())) + .toInstance(container); + } + } + }; + + try { + RJavaPluginLoader.createPlugin(javaPluginLoader, container, module, commonModule); + } catch (Exception ex) { logger.error( - "A plugin permission provider {} provided an invalid permission function for the console." - + " This is a bug in the plugin, not in Velocity." - + " Falling back to the default permission function.", - event.getProvider().getClass().getName() + String.format("Can't create plugin %s", container.getDescription().getId()), + ex ); - permissionFunction = PermissionFunction.ALWAYS_TRUE; + return enableResults.addResult(pluginId, Result.ERROR); } - RVelocityConsole.setPermissionFunction(console, permissionFunction); - }); + logger.info( + "Loaded plugin {} {} by {}", + realPlugin.getId(), + realPlugin.getVersion().orElse(""), + Joiner.on(", ").join(realPlugin.getAuthors()) + ); - proxy.getEventManager().fire(new VelocityPluginEnableEvent(container, PluginEvent.Stage.POST)); - return Result.SUCCESS; + RVelocityPluginManager.registerPlugin(proxy.getPluginManager(), container); + Optional instanceOptional = container.getInstance(); + if (instanceOptional.isPresent()) { + Object pluginInstance = instanceOptional.get(); + RVelocityEventManager.registerInternally(proxy.getEventManager(), container, pluginInstance); + pluginInstances.add(pluginInstance); + } + } + + RVelocityEventManager.fireForPlugins( + proxy.getEventManager(), + new ProxyInitializeEvent(), + pluginInstances + ).join(); + + ConsoleCommandSource console = proxy.getConsoleCommandSource(); + PermissionsSetupEvent event = new PermissionsSetupEvent( + console, + s -> PermissionFunction.ALWAYS_TRUE + ); + PermissionFunction permissionFunction = RVelocityEventManager.fireForPlugins( + proxy.getEventManager(), + event, + pluginInstances + ).join().createFunction(console); + + if (permissionFunction == null) { + logger.error( + "A plugin permission provider {} provided an invalid permission function for the console." + + " This is a bug in the plugin, not in Velocity." + + " Falling back to the default permission function.", + event.getProvider().getClass().getName() + ); + permissionFunction = PermissionFunction.ALWAYS_TRUE; + } + + RVelocityConsole.setPermissionFunction(console, permissionFunction); + + for (PluginContainer container : containers) { + proxy.getEventManager().fire(new VelocityPluginEnableEvent(container, PluginEvent.Stage.POST)); + enableResults.addResult(container.getDescription().getId(), container); + } + + return enableResults; } @Override - public Result disablePlugin(PluginContainer container) { - proxy.getEventManager().fire(new VelocityPluginDisableEvent(container, PluginEvent.Stage.PRE)); - Object pluginInstance = container.getInstance().orElse(null); - if (pluginInstance == null) return Result.NOT_EXISTS; + public boolean isPluginEnabled(String pluginId) { + return proxy.getPluginManager().isLoaded(pluginId); + } - RVelocityEventManager.fireForPlugin( + @Override + public PluginResults disableOrderedPlugins(List containers) { + PluginResults disableResults = new PluginResults<>(); + + List pluginInstances = new ArrayList<>(containers.size()); + for (PluginContainer container : containers) { + proxy.getEventManager().fire(new VelocityPluginDisableEvent(container, PluginEvent.Stage.PRE)); + String pluginId = getPluginId(container); + Object pluginInstance = container.getInstance().orElse(null); + if (pluginInstance == null) { + return disableResults.addResult(pluginId, Result.ALREADY_DISABLED); + } + + pluginInstances.add(pluginInstance); + } + + RVelocityEventManager.fireForPlugins( proxy.getEventManager(), - pluginInstance, - new ProxyShutdownEvent() + new ProxyShutdownEvent(), + pluginInstances ); - proxy.getEventManager().fire(new VelocityPluginDisableEvent(container, PluginEvent.Stage.POST)); - return Result.SUCCESS; - } - - @Override - public Result reloadPlugin(String pluginName) { - Optional pluginOptional = proxy.getPluginManager().getPlugin(pluginName); - if (!pluginOptional.isPresent()) return Result.NOT_EXISTS; - return reloadPlugin(pluginOptional.get()); - } - - @Override - public Result reloadPlugin(PluginContainer plugin) { - CloseableResult result = unloadPlugin(plugin); - if (result.getResult() != Result.SUCCESS) return result.getResult(); - result.tryClose(); - - File file = getPluginFile(plugin.getDescription().getId()); - if (file == null) return Result.FILE_DELETED; - - VelocityLoadResult loadResult = loadPlugin(file); - if (!loadResult.isSuccess()) return loadResult.getResult(); - - return enablePlugin(loadResult.get()); - } - - @Override - public CloseableResult unloadPlugin(String pluginName) { - Optional pluginOptional = proxy.getPluginManager().getPlugin(pluginName); - if (!pluginOptional.isPresent()) return new CloseableResult(Result.NOT_EXISTS); - return unloadPlugin(pluginOptional.get()); - } - - @Override - public CloseableResult unloadPlugin(PluginContainer container) { - proxy.getEventManager().fire(new VelocityPluginUnloadEvent(container, PluginEvent.Stage.PRE)); - Optional pluginInstanceOptional = container.getInstance(); - if (!pluginInstanceOptional.isPresent()) return new CloseableResult(Result.INVALID_PLUGIN); - Object pluginInstance = pluginInstanceOptional.get(); - - proxy.getEventManager().unregisterListeners(pluginInstance); - for (ScheduledTask task : RVelocityScheduler.getTasksByPlugin(proxy.getScheduler()).removeAll(pluginInstance)) { - task.cancel(); + for (PluginContainer container : containers) { + proxy.getEventManager().fire(new VelocityPluginDisableEvent(container, PluginEvent.Stage.POST)); + disableResults.addResult(getPluginId(container), container); } - String pluginId = container.getDescription().getId(); - for (String alias : pluginCommandManager.getPluginCommands().removeAll(pluginId)) { - proxy.getCommandManager().unregister(alias); + return disableResults; + } + + @Override + public CloseablePluginResults unloadOrderedPlugins(List containers) { + CloseablePluginResults unloadResults = new CloseablePluginResults<>(); + + for (PluginContainer container : containers) { + proxy.getEventManager().fire(new VelocityPluginUnloadEvent(container, PluginEvent.Stage.PRE)); + String pluginId = getPluginId(container); + Optional pluginInstanceOptional = container.getInstance(); + if (!pluginInstanceOptional.isPresent()) { + return unloadResults.addResult(pluginId, Result.INVALID_PLUGIN); + } + + Object pluginInstance = pluginInstanceOptional.get(); + + proxy.getEventManager().unregisterListeners(pluginInstance); + for (ScheduledTask task : RVelocityScheduler.getTasksByPlugin(proxy.getScheduler()) + .removeAll(pluginInstance)) { + task.cancel(); + } + + for (String alias : pluginCommandManager.getPluginCommands().removeAll(pluginId)) { + proxy.getCommandManager().unregister(alias); + } + + RVelocityPluginManager.getPlugins(proxy.getPluginManager()).remove(pluginId); + RVelocityPluginManager.getPluginInstances(proxy.getPluginManager()).remove(pluginInstance); + + List closeables = new ArrayList<>(); + + ClassLoader loader = pluginInstance.getClass().getClassLoader(); + if (loader instanceof Closeable) { + closeables.add((Closeable) loader); + } + + proxy.getEventManager().fire(new VelocityPluginUnloadEvent(container, PluginEvent.Stage.POST)); + unloadResults.addResult(pluginId, container, closeables); } - RVelocityPluginManager.getPlugins(proxy.getPluginManager()).remove(pluginId); - RVelocityPluginManager.getPluginInstances(proxy.getPluginManager()).remove(pluginInstance); - - List closeables = new ArrayList<>(); - - ClassLoader loader = pluginInstance.getClass().getClassLoader(); - if (loader instanceof Closeable) { - closeables.add((Closeable) loader); - } - - proxy.getEventManager().fire(new VelocityPluginUnloadEvent(container, PluginEvent.Stage.POST)); - return new CloseableResult(closeables); + return unloadResults; } @Override @@ -263,7 +293,7 @@ public class VelocityPluginManager implements AbstractPluginManager getPluginFile(String pluginName) { Object javaPluginLoader = RJavaPluginLoader.newInstance(instance.proxy, getPluginsFolder().toPath()); for (File file : getPluginJars()) { PluginDescription desc = RJavaPluginLoader.loadPluginDescription(javaPluginLoader, file.toPath()); if (desc.getId().equals(pluginName)) { - return file; + return Optional.of(file); } } - return null; + return Optional.empty(); } @Override - public PluginContainer getPlugin(String pluginName) { - return proxy.getPluginManager().getPlugin(pluginName).orElse(null); + public Optional getPlugin(String pluginName) { + return proxy.getPluginManager().getPlugin(pluginName); + } + + @Override + public VelocityPluginDescription getLoadedPluginDescription(PluginContainer plugin) { + return new VelocityPluginDescription(plugin.getDescription()); + } + + @Override + public Optional getPluginDescription( + File file + ) throws InvalidPluginDescriptionException { + Path source = file.toPath(); + Path baseDirectory = source.getParent(); + + try { + Object javaPluginLoader = RJavaPluginLoader.newInstance(proxy, baseDirectory); + PluginDescription candidate = RJavaPluginLoader.loadPluginDescription(javaPluginLoader, source); + return Optional.of(new VelocityPluginDescription(candidate)); + } catch (Exception ex) { + throw new InvalidPluginDescriptionException(ex); + } } @Override diff --git a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/reflection/RVelocityEventManager.java b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/reflection/RVelocityEventManager.java index f8a7d71..0161b11 100644 --- a/Velocity/src/main/java/net/frankheijden/serverutils/velocity/reflection/RVelocityEventManager.java +++ b/Velocity/src/main/java/net/frankheijden/serverutils/velocity/reflection/RVelocityEventManager.java @@ -9,6 +9,7 @@ import dev.frankheijden.minecraftreflection.MinecraftReflection; import java.lang.reflect.Array; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; public class RVelocityEventManager { @@ -27,9 +28,14 @@ public class RVelocityEventManager { * Retrieves the registrations from a plugin for a specific event. */ @SuppressWarnings("unchecked") - public static List getRegistrationsByPlugin(EventManager manager, Object plugin, Class eventClass) { + public static List getRegistrationsByPlugins( + EventManager manager, + List plugins, + Class eventClass + ) { return (List) getHandlersByType(manager).get(eventClass).stream() - .filter(r -> RHandlerRegistration.getPlugin(r).getInstance().orElse(null) == plugin) + .filter(r -> plugins.contains(RHandlerRegistration.getPlugin(r).getInstance().orElse(null))) + .sorted(reflection.get(manager, "handlerComparator")) .collect(Collectors.toList()); } @@ -48,26 +54,27 @@ public class RVelocityEventManager { /** * Fires an event specifically for one plugin. */ - public static CompletableFuture fireForPlugin( + public static CompletableFuture fireForPlugins( EventManager manager, E event, - Object plugin + List pluginInstances ) { - List registrations = getRegistrationsByPlugin(manager, plugin, event.getClass()); + List registrations = getRegistrationsByPlugins(manager, pluginInstances, event.getClass()); CompletableFuture future = new CompletableFuture<>(); Object registrationsEmptyArray = Array.newInstance(RHandlerRegistration.reflection.getClazz(), 0); Class registrationsArrayClass = registrationsEmptyArray.getClass(); - reflection.invoke( + ExecutorService executor = reflection.invoke(manager, "getAsyncExecutor"); + executor.execute(() -> reflection.invoke( manager, "fire", ClassObject.of(CompletableFuture.class, future), ClassObject.of(Object.class, event), ClassObject.of(int.class, 0), - ClassObject.of(boolean.class, false), + ClassObject.of(boolean.class, true), ClassObject.of(registrationsArrayClass, registrations.toArray((Object[]) registrationsEmptyArray)) - ); + )); return future; } diff --git a/build.gradle b/build.gradle index a91957b..cea2d49 100644 --- a/build.gradle +++ b/build.gradle @@ -19,14 +19,19 @@ subprojects { repositories { mavenCentral() maven { url 'https://jitpack.io' } - maven { url 'https://repo.aikar.co/content/groups/aikar/' } maven { url 'https://repo.incendo.org/content/repositories/snapshots' } maven { url 'https://papermc.io/repo/repository/maven-public/' } + maven { url 'https://libraries.minecraft.net' } } dependencies { implementation 'com.github.FrankHeijden.cloud:cloud-core:fea4605277' + implementation 'com.github.FrankHeijden.cloud:cloud-brigadier:fea4605277' implementation 'com.github.FrankHeijden:MinecraftReflection:1.0.0' + implementation 'com.google.guava:guava:30.1.1-jre' + implementation 'com.google.code.gson:gson:2.8.6' + implementation 'me.lucko:commodore:1.10' + compileOnly 'com.mojang:brigadier:1.0.17' testCompile 'org.assertj:assertj-core:3.18.1' testCompile 'org.junit.jupiter:junit-jupiter-api:5.7.0' @@ -55,6 +60,28 @@ subprojects { shadowJar { exclude 'com/mojang/**' + exclude 'javax/annotation/**' + exclude 'org/checkerframework/**' + exclude 'com/google/errorprone/**' + exclude 'com/google/j2objc/**' + exclude 'com/google/thirdparty/**' + exclude 'com/google/common/annotations/**' + exclude 'com/google/common/base/**' + exclude 'com/google/common/cache/**' + exclude 'com/google/common/collect/**' + exclude 'com/google/common/escape/**' + exclude 'com/google/common/eventbus/**' + exclude 'com/google/common/hash/**' + exclude 'com/google/common/html/**' + exclude 'com/google/common/io/**' + exclude 'com/google/common/math/**' + exclude 'com/google/common/net/**' + exclude 'com/google/common/primitives/**' + exclude 'com/google/common/reflect/**' + exclude 'com/google/common/util/**' + exclude 'com/google/common/xml/**' + relocate 'com.google.gson', dependencyDir + '.gson' + relocate 'com.google.common.graph', dependencyDir + '.common.graph' relocate 'dev.frankheijden.minecraftreflection', dependencyDir + '.minecraftreflection' relocate 'cloud.commandframework', dependencyDir + '.cloud' relocate 'io.leangen.geantyref', dependencyDir + '.typetoken' diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 4a9bba5..6149d9f 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -39,7 +39,7 @@ - +