1.14.4 Disabling and Re-loading a Plugin From a File

Discussion in 'Spigot Plugin Development' started by Lanchester, Jan 15, 2020.

  1. Hello,

    I'm working on a resource that will allow me to disable and reload a plugin from its file, in order to hopefully allow me to make small bug-fixes and updates without having to restart the server. I've made about 10 or so different plugins for my server that all depend one foundation plugin, which is where this resource is located (the command I'm using is also located in the foundation plugin). Ideally I want to be able to reload any of these dependent plugins without interrupting the server. Here is the method I'm using to reload the plugins:

    Code (Text):
    public static boolean reloadPlugin(Plugin plugin) {
            if (plugin != null) {
                for (CrimsonPlugin cPlugin : getRegisteredPlugins()) {
                    if (cPlugin.equals(plugin)) {
                        try {
                            plugins.remove(plugin);
                            File file = getPluginFile(plugin);
                            Bukkit.getPluginManager().disablePlugin(plugin);
                            CrimsonPlugin newPlugin = (CrimsonPlugin) Bukkit.getPluginManager().loadPlugin(file);
                            Bukkit.getPluginManager().enablePlugin(newPlugin);
                            if (newPlugin != null && newPlugin.isEnabled()) {
                                plugins.add(newPlugin);
                                return true;
                            }
                        } catch (UnknownDependencyException | InvalidPluginException | InvalidDescriptionException | ClassCastException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return false;
        }
    CrimsonPlugin is just an extension of JavaPlugin that I use. Also, here is the code for getPluginFile:

    Code (Text):
    private static File getPluginFile(Plugin plugin) {
            Method method;
            try {
                method = JavaPlugin.class.getDeclaredMethod("getFile");
                method.setAccessible(true);
                return (File) method.invoke(plugin);
            } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }
    When invoking the method through a command I get no errors and the method returns true, seemingly indicating that the plugin was re-enabled and loaded successfully. The console also notes that it is both disabling and enabling the plugin. The reloaded plugin is also included in the list of plugins after invoking the method, and JavaPlugin#isEnabled() returns true for it. However when I attempt to use any commands or anything from the plugin that was reloaded, I get a CommandException that indicates that the plugin is disabled, despite everything I can find pointing to the contrary. Does anyone have any idea what may be going on? Any help would be appreciated!
     
  2. Do you want to disable and re-enable the plugin with a command of that plugin?
    If that's the case, it's impossible, after the plugin is disabled, it's not functional.
     
  3. You have to use a different plugin to handle whether it should be enabled or disabled
     
  4. Plugman's capable of this, but isn't recommended for production servers because it uses hacky methods that can cause a number of issues. Hotswapping jars can also cause issues if you take that route, so it's best to just do a full server restart. Of course you'll want to test changes on a test server or something of that likes to be sure there's no game-breaking changes.
     
  5. The command and resource that I am using to restart these plugins are in a completely separate plugin. There are 10 or so different plugins that all build off of one foundation plugin, which is where this command and method is located. I'm not trying to reload the foundation plugin, I want to be able to reload the plugins that depend on it, so that's not the issue. I've been researching this issue and every thread I can find about this end up being the same discussion, which is that you have to restart the plugins from another plugin in order to re-enable them once they're disabled. I have already done this, but for some reason the plugin is still saying it's disabled, despite plugin.isEnabled() returning true for the restarted plugin.

    I'll take a look at Plugman and see what they do, thank you. I don't plan on restarting any plugins other than the ones I've written. This may end up being a fruitless journey but since I've written everything that's involved in my plugins, I'm hoping that I'll eventually be able to continually work on them so that I can swap their jars for minor updates without issues, but we'll see