1.15.2 Registering a custom PluginLoader

Discussion in 'Spigot Plugin Development' started by kwill, Jul 6, 2020.

  1. I'm experimenting with adding support for building Spigot plugins in Clojure! For part of this, I'd like to add a custom PluginLoader. I'm having trouble getting the plugin manager to recognize my added PluginLoader. I have created a minimal plugin defined as so:

    Code (Java):

    public class ClojureLoaderPlugin extends JavaPlugin {

        public ClojureLoaderPlugin() {
            System.out.println("ClojureLoaderPlugin ctor.");
        }

        @Override
        public void onLoad() {
            System.out.println("ClojureLoaderPlugin onLoad");
            Bukkit.getServer().getPluginManager().registerInterface(ClojureLoader.class);
            super.onLoad();
        }

        @Override
        public void onEnable() {
            super.onEnable();
            System.out.println("enable clojure plugin");

        }
    }
     
    When starting up the server, I can verify that my onLoad method gets called. Inside ClojureLoader, I can verify that the constructor and the getPluginFileFilters method are called. However, the loadPlugin method in ClojureLoader never gets called. I am not sure why. I have also tried setting load: STARTUP in my plugin.yml with no dice.

    My current theory is that since it's executing JavaPlugin lifecycle methods, it's too late to register a new PluginLoader.

    What is the correct way to register a new PluginLoader? Is there a lower level hook that I need to use?
     
  2. Dove into the CraftServer class and found the loadPlugins() method.

    Code (Java):

    public void loadPlugins() {
        pluginManager.registerInterface(JavaPluginLoader.class);

        File pluginFolder = (File) console.options.valueOf("plugins");

        if (pluginFolder.exists()) {
            Plugin[] plugins = pluginManager.loadPlugins(pluginFolder);
            for (Plugin plugin : plugins) {
                try {
                    String message = String.format("Loading %s", plugin.getDescription().getFullName());
                    plugin.getLogger().info(message);
                    plugin.onLoad();
                } catch (Throwable ex) {
                    Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, ex.getMessage() + " initializing " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex);
                }
            }
        } else {
            pluginFolder.mkdir();
        }
    }
     
    At a first glance, it seems, unfortunately that it's not built in a way to allow the dynamic PluginLoaders :confused:
     
  3. Hi, in case you're still interested in this, I recently experimented with this myself. The issue is that Clojure uses the thread context class loader for a lot of stuff, and spigot's class loading system breaks this. You can make it work by setting the context class loader to the plugin loader and and putting clojure into its classpath (by putting it in the plugin jar for example).

    Check out
    Code (Text):
    lein new spigot-clj your-project-name
    to get a working example. See here.