Creating an optional dependency

Discussion in 'Spigot Plugin Development' started by MaxKrissigo, Jun 15, 2016.

  1. I've looked around and have found threads, but don't really understand what they are doing and get a bit lost. (I don't want to copy and paste code I don't understand). How would I go about making Vault a optional dependency? So if they have it, use it, but if they don't, don't. Thanks Max.
     
    • Like Like x 1
  2. Put

    softdepend: [Vault]

    in the plugin.yml.

    and in the method of actually using Vault, check if Vault is enabled on the server first. If yes, continue, if no, return
     
    • Like Like x 1
  3. None of my commands seem to be working when I took out Vault to test if it worked. No error either. I can post my classes if needed.
     
  4. What errors?
     
  5. I didn't get any, my commands just didn't work.
     
  6. did you register them in your plugin.yml and in onEnable?
     
  7. Yes, they were all working before, but when I removed vault they stopped.
     
  8. Well, if you don't have Vault, the commands can't really work, unless you make your own economy.
     
  9. My commands don't use Vault, I'm just using it to change the balance of the player in certain methods if it is being used on the server.
     
  10. The most important part about soft dependencies is that you never ever ever have any part of a dependency class in a loaded class unless you check the dependency first. This includes importing anything.

    This is example code pulled directly from Vault's GitHub page. It will fail to run correctly if Vault is not installed.
    Code (Text):

    import net.milkbowl.vault.chat.Chat;
    import net.milkbowl.vault.economy.Economy;
    import net.milkbowl.vault.economy.EconomyResponse;
    import net.milkbowl.vault.permission.Permission;

    public class MyPlugin extends JavaPlugin {
        private static final Logger log = Logger.getLogger("Minecraft");
        public static Economy econ = null;
        public static Permission perms = null;
        public static Chat chat = null;

        @Override
        public void onEnable() {
            if (!setupEconomy() ) {
                log.severe(String.format("[%s] - Disabled due to no Vault dependency found!", getDescription().getName()));
                getServer().getPluginManager().disablePlugin(this);
                return;
            }
            setupPermissions();
            setupChat();
        }

        private boolean setupEconomy() {
            if (!Bukkit.getPluginManager().isPluginEnabled("Vault")) {
                return false;
            }
            RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
            if (rsp == null) {
                return false;
            }
            econ = rsp.getProvider();
            return econ != null;
        }

        private boolean setupChat() {
            RegisteredServiceProvider<Chat> rsp = getServer().getServicesManager().getRegistration(Chat.class);
            chat = rsp.getProvider();
            return chat != null;
        }

        private boolean setupPermissions() {
            RegisteredServiceProvider<Permission> rsp = getServer().getServicesManager().getRegistration(Permission.class);
            perms = rsp.getProvider();
            return perms != null;
        }
    }
     
    Why will this fail? Because as soon as the JVM loads up your class it will read the imports and load them too. Since the imported classes will not be there you will get a nice big fat stack trace.

    To avoid this, it is advised to place all your dependency code into another class, completely. Never load up this class if the dependency is not met.

    Code (Text):

    import net.milkbowl.vault.chat.Chat;
    import net.milkbowl.vault.economy.Economy;
    import net.milkbowl.vault.economy.EconomyResponse;
    import net.milkbowl.vault.permission.Permission;

    public class VaultHook {
        public static Economy econ = null;
        public static Permission perms = null;
        public static Chat chat = null;

        public static boolean setupEconomy() {
            RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
            if (rsp == null) {
                return false;
            }
            econ = rsp.getProvider();
            return econ != null;
        }

        public static boolean setupChat() {
            RegisteredServiceProvider<Chat> rsp = getServer().getServicesManager().getRegistration(Chat.class);
            chat = rsp.getProvider();
            return chat != null;
        }

        public static boolean setupPermissions() {
            RegisteredServiceProvider<Permission> rsp = getServer().getServicesManager().getRegistration(Permission.class);
            perms = rsp.getProvider();
            return perms != null;
        }
    }
     
    Code (Text):

    public class MyPlugin implements JavaPlugin {
        private static final Logger log = Logger.getLogger("Minecraft");

        public void on Enable() {
            if (!Bukkit.getPluginManager().isPluginEnabled("Vault")) {
                log.severe(String.format("[%s] - Disabled due to no Vault dependency found!", getDescription().getName()));
                Bukkit.getPluginManager().disablePlugin(this);
                return;
            }
            VaultHook.setupEconomy();
            VaultHook.setupPermissions();
            VaultHook.setupChat();
        }
    }
     
    Now if the dependency is not met the plugin will disable gracefully. However, you dont have to disable the plugin if you dont want. You can very well keep the plugin enabled and just never use anything from VaultHook class.

    For anything you use Vault for, make a method in VaultHook class and call it only if Vault is found and enabled (like giving currecy, checking permissions, getting the user/group prefix, etc). This will prevent the JVM from loading VaultHook class if Vault is not installed and throwing errors everywhere.

    Here is an example of me hooking into Vault as a soft dependency:

    https://bitbucket.org/BillyGalbreat...t.java?at=master&fileviewer=file-view-default

    https://bitbucket.org/BillyGalbreat...r.java?at=master&fileviewer=file-view-default

    Here I used Vault to check offline player permissions. Thus my PermManager class is the only class in the whole project to call on my Vault hook class, and the Vault hook class is the only class containing Vault stuff.

    ;)
     
    • Informative Informative x 4
    • Like Like x 2
    • Winner Winner x 1
  11. Thanks so much this perfectly explained how I would go about doing this. Would you by chance know why I am getting a NPE on this line:
    Code (Text):
            if (econ.has(p, settings.getConfig().getDouble("vault.cost"))) {
     
     
  12. econ, settings, or getConfig is null.
     
  13. I am presuming that it might be a Vault error, not too sure, because I know getConfig is not null. Is there another way to go about checking their balance?