From 9ba62e1711378c926545b3cd5ad20c853318f5d2 Mon Sep 17 00:00:00 2001 From: tastybento Date: Tue, 7 May 2019 07:47:38 -0700 Subject: [PATCH] WIP - reloads addons --- .../bentobox/bentobox/api/addons/Addon.java | 4 +- .../commands/BentoBoxReloadCommand.java | 32 ++-- .../bentobox/managers/AddonsManager.java | 160 +++++++++++------- 3 files changed, 126 insertions(+), 70 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/addons/Addon.java b/src/main/java/world/bentobox/bentobox/api/addons/Addon.java index ea3fb1ab7..ac32b86d9 100644 --- a/src/main/java/world/bentobox/bentobox/api/addons/Addon.java +++ b/src/main/java/world/bentobox/bentobox/api/addons/Addon.java @@ -189,12 +189,12 @@ public abstract class Addon { } /** - * Register a listener for this addon + * Register a listener for this addon. This MUST be used in order for the addon to be reloadable * * @param listener - listener */ public void registerListener(Listener listener) { - Bukkit.getPluginManager().registerEvents(listener, BentoBox.getInstance()); + BentoBox.getInstance().getAddonsManager().registerListener(this, listener); } /** diff --git a/src/main/java/world/bentobox/bentobox/commands/BentoBoxReloadCommand.java b/src/main/java/world/bentobox/bentobox/commands/BentoBoxReloadCommand.java index 29b68a4ec..be62b5e9f 100644 --- a/src/main/java/world/bentobox/bentobox/commands/BentoBoxReloadCommand.java +++ b/src/main/java/world/bentobox/bentobox/commands/BentoBoxReloadCommand.java @@ -29,19 +29,29 @@ public class BentoBoxReloadCommand extends ConfirmableCommand { @Override public boolean execute(User user, String label, List args) { - this.askConfirmation(user, () -> { - // Reload settings - getPlugin().loadSettings(); - user.sendMessage("commands.bentobox.reload.settings-reloaded"); + if (args.isEmpty()) { + this.askConfirmation(user, () -> { + // Reload settings + getPlugin().loadSettings(); + user.sendMessage("commands.bentobox.reload.settings-reloaded"); - // Reload addons - getPlugin().getAddonsManager().reloadAddons(); - user.sendMessage("commands.bentobox.reload.addons-reloaded"); + // Reload addons + getPlugin().getAddonsManager().reloadAddons(); + user.sendMessage("commands.bentobox.reload.addons-reloaded"); - // Reload locales - getPlugin().getLocalesManager().reloadLanguages(); - user.sendMessage("commands.bentobox.reload.locales-reloaded"); - }); + // Reload locales + getPlugin().getLocalesManager().reloadLanguages(); + user.sendMessage("commands.bentobox.reload.locales-reloaded"); + }); + } else if (args.size() == 1) { + if (!getPlugin().getAddonsManager().getAddonByName(args.get(0)).isPresent()) { + user.sendRawMessage("Unknown addon"); + return false; + } + this.askConfirmation(user, () -> getPlugin().getAddonsManager().getAddonByName(args.get(0)).ifPresent(getPlugin().getAddonsManager()::reloadAddon)); + } else { + showHelp(this, user); + } return true; } } diff --git a/src/main/java/world/bentobox/bentobox/managers/AddonsManager.java b/src/main/java/world/bentobox/bentobox/managers/AddonsManager.java index 6413b0c97..8a202d707 100644 --- a/src/main/java/world/bentobox/bentobox/managers/AddonsManager.java +++ b/src/main/java/world/bentobox/bentobox/managers/AddonsManager.java @@ -3,6 +3,8 @@ package world.bentobox.bentobox.managers; import org.bukkit.Bukkit; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; import org.bukkit.generator.ChunkGenerator; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; @@ -17,6 +19,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -43,12 +46,14 @@ public class AddonsManager { private final Map> classes; private BentoBox plugin; private @NonNull Map<@NonNull String, @Nullable GameModeAddon> worldNames; + private @NonNull Map> listeners; public AddonsManager(@NonNull BentoBox plugin) { this.plugin = plugin; addons = new ArrayList<>(); loaders = new HashMap<>(); classes = new HashMap<>(); + listeners = new HashMap<>(); worldNames = new HashMap<>(); } @@ -101,6 +106,9 @@ public class AddonsManager { Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.LOAD).build()); // Add it to the list of addons + if (addons.contains(addon)) { + addons.remove(addon); + } addons.add(addon); // Add to the list of loaders @@ -133,43 +141,48 @@ public class AddonsManager { public void enableAddons() { if (!getLoadedAddons().isEmpty()) { plugin.log("Enabling addons..."); - - getLoadedAddons().forEach(addon -> { - try { - // If this is a GameModeAddon create the worlds, register it and load the schems - if (addon instanceof GameModeAddon) { - GameModeAddon gameMode = (GameModeAddon) addon; - // Create the gameWorlds - gameMode.createWorlds(); - plugin.getIWM().addGameMode(gameMode); - // Register the schems - plugin.getSchemsManager().loadIslands(gameMode); - - plugin.getBlueprintsManager().extractDefaultBlueprints(gameMode); - plugin.getBlueprintsManager().loadBlueprints(gameMode); - } - addon.onEnable(); - if (addon instanceof GameModeAddon) { - GameModeAddon gameMode = (GameModeAddon) addon; - // Set the worlds for the commands - gameMode.getPlayerCommand().ifPresent(c -> c.setWorld(gameMode.getOverWorld())); - gameMode.getAdminCommand().ifPresent(c -> c.setWorld(gameMode.getOverWorld())); - } - Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.ENABLE).build()); - addon.setState(Addon.State.ENABLED); - plugin.log("Enabling " + addon.getDescription().getName() + "..."); - } catch (NoClassDefFoundError | NoSuchMethodError | NoSuchFieldError e) { - // Looks like the addon is incompatible, because it tries to refer to missing classes... - handleAddonIncompatibility(addon); - } catch (Exception e) { - // Unhandled exception. We'll give a bit of debug here. - handleAddonError(addon, e); - } - }); + getLoadedAddons().forEach(this::enableAddon); plugin.log("Addons successfully enabled."); } } + /** + * Enables an addon + * @param addon addon + */ + private void enableAddon(Addon addon) { + try { + // If this is a GameModeAddon create the worlds, register it and load the schems + if (addon instanceof GameModeAddon) { + GameModeAddon gameMode = (GameModeAddon) addon; + // Create the gameWorlds + gameMode.createWorlds(); + plugin.getIWM().addGameMode(gameMode); + // Register the schems + plugin.getSchemsManager().loadIslands(gameMode); + + plugin.getBlueprintsManager().extractDefaultBlueprints(gameMode); + plugin.getBlueprintsManager().loadBlueprints(gameMode); + } + addon.onEnable(); + if (addon instanceof GameModeAddon) { + GameModeAddon gameMode = (GameModeAddon) addon; + // Set the worlds for the commands + gameMode.getPlayerCommand().ifPresent(c -> c.setWorld(gameMode.getOverWorld())); + gameMode.getAdminCommand().ifPresent(c -> c.setWorld(gameMode.getOverWorld())); + } + Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.ENABLE).build()); + addon.setState(Addon.State.ENABLED); + plugin.log("Enabling " + addon.getDescription().getName() + "..."); + } catch (NoClassDefFoundError | NoSuchMethodError | NoSuchFieldError e) { + // Looks like the addon is incompatible, because it tries to refer to missing classes... + handleAddonIncompatibility(addon); + } catch (Exception e) { + // Unhandled exception. We'll give a bit of debug here. + handleAddonError(addon, e); + } + } + /** * Handles an addon which failed to load due to an incompatibility (missing class, missing method). * @param addon instance of the Addon. @@ -201,14 +214,19 @@ public class AddonsManager { * Reloads all the enabled addons */ public void reloadAddons() { - if (!getEnabledAddons().isEmpty()) { - plugin.log("Reloading addons..."); - getEnabledAddons().stream().filter(Addon::isEnabled).forEach(addon -> { - plugin.log("Reloading " + addon.getDescription().getName() + "..."); - addon.onReload(); - }); - plugin.log("Addons successfully reloaded."); - } + disableAddons(); + loadAddons(); + enableAddons(); + } + + /** + * Reloads one addon + * @param addon - addon + */ + public void reloadAddon(Addon addon) { + Path p = addon.getFile().toPath(); + disable(addon); + loadAddon(p.toFile()); } /** @@ -218,7 +236,7 @@ public class AddonsManager { */ @NonNull public Optional getAddonByName(@NonNull String name){ - return addons.stream().filter(a -> a.getDescription().getName().contains(name)).findFirst(); + return addons.stream().filter(a -> a.getDescription().getName().equalsIgnoreCase(name)).findFirst(); } @NonNull @@ -243,23 +261,14 @@ public class AddonsManager { if (!getEnabledAddons().isEmpty()) { plugin.log("Disabling addons..."); // Disable addons - getEnabledAddons().forEach(addon -> { - if (addon.isEnabled()) { - addon.onDisable(); - Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.DISABLE).build()); - plugin.log("Disabling " + addon.getDescription().getName() + "..."); - } - }); - - loaders.values().forEach(l -> { - try { - l.close(); - } catch (IOException ignore) { - // Ignore - } - }); + getEnabledAddons().forEach(this::disable); plugin.log("Addons successfully disabled."); } + // Clear all maps + listeners.clear(); + addons.clear(); + loaders.clear(); + classes.clear(); } @NonNull @@ -383,4 +392,41 @@ public class AddonsManager { } return null; } + + /** + * Register a listener + * @param addon - the addon registering + * @param listener - listener + */ + public void registerListener(Addon addon, Listener listener) { + Bukkit.getPluginManager().registerEvents(listener, BentoBox.getInstance()); + listeners.computeIfAbsent(addon, k -> new ArrayList<>()).add(listener); + } + + /** + * Disables an addon + * @param addon - addon + */ + private void disable(Addon addon) { + // Clear listeners + if (listeners.containsKey(addon)) { + listeners.get(addon).forEach(HandlerList::unregisterAll); + listeners.remove(addon); + } + // Disable + if (addon.isEnabled()) { + addon.onDisable(); + Bukkit.getPluginManager().callEvent(new AddonEvent().builder().addon(addon).reason(AddonEvent.Reason.DISABLE).build()); + plugin.log("Disabling " + addon.getDescription().getName() + "..."); + } + // Clear loaders + if (loaders.containsKey(addon)) { + try { + loaders.get(addon).close(); + } catch (IOException ignore) { + // Nothing + } + } + + } }