Optional Integrations (Hooks)
The hook system allows DzusillCore plugins to integrate with optional third-party plugins (Vault, PlaceholderAPI, EssentialsX, …) without crashing when those plugins are absent. This is critical for a framework used across both simple and complex server setups.
How it works
Section titled “How it works”HookManager.register("Vault", VaultHook::new) └─ Bukkit.getPluginManager().isPluginEnabled("Vault") ├─ false → return empty(); factory never called, class never loaded └─ true → VaultHook hook = factory.get() hook.tryEnable() → hook.setup() hook.isActive() = trueThe factory (constructor reference) is evaluated only after the presence check, so the hook class — including the external API types it imports — is never loaded by the JVM when the target plugin is absent. This means no NoClassDefFoundError even when the server runs without Vault or any other soft-dependency.
PluginHook base class
Section titled “PluginHook base class”public abstract class PluginHook { protected PluginHook(String pluginName) { ... }
public final boolean isPresent() { ... } // checks Bukkit plugin manager public final boolean isActive() { ... } // true if setup() ran successfully public final String pluginName(){ ... }
protected abstract void setup(); // called only when plugin is present}HookManager
Section titled “HookManager”HookManager (a Service) owns and resolves all hooks:
public <T extends PluginHook> Optional<T> register(String pluginName, Supplier<T> factory)public <T extends PluginHook> Optional<T> get(Class<T> type)public boolean isActive(Class<? extends PluginHook> type)plugin.yml and pom.xml
Section titled “plugin.yml and pom.xml”Declare soft dependencies in plugin.yml:
softdepend: [Vault, PlaceholderAPI, Essentials]Keep their Maven scope provided — they must not be bundled in your JAR:
<dependency> <groupId>com.github.MilkBowl</groupId> <artifactId>VaultAPI</artifactId> <scope>provided</scope></dependency>Built-in hooks
Section titled “Built-in hooks”VaultHook
Section titled “VaultHook”hooks.register("Vault", VaultHook::new) .ifPresent(vault -> plugin.getLogger().info("Economy: " + vault.economy().getName()));hooks.get(VaultHook.class).ifPresent(vault -> { Economy eco = vault.economy(); eco.depositPlayer(player, 100.0); double balance = eco.getBalance(player);});PlaceholderApiHook
Section titled “PlaceholderApiHook”hooks.get(PlaceholderApiHook.class).ifPresent(papi -> { String parsed = papi.apply(player, "Your balance: %vault_eco_balance%"); player.sendMessage(ColorUtils.parse(parsed));});EssentialsHook
Section titled “EssentialsHook”hooks.get(EssentialsHook.class).ifPresent(ess -> { IUser user = ess.essentials().getUser(player); // access Essentials user data});Registering hooks — IntegrationModule
Section titled “Registering hooks — IntegrationModule”public final class IntegrationModule extends AbstractModule {
@Override public void onEnable() { HookManager hooks = new HookManager(plugin); hooks.register("Vault", VaultHook::new); hooks.register("PlaceholderAPI", PlaceholderApiHook::new); hooks.register("Essentials", EssentialsHook::new); provide(HookManager.class, hooks); }}Adding a custom hook
Section titled “Adding a custom hook”- Create a class extending
PluginHook:
public final class LuckPermsHook extends PluginHook {
private LuckPerms api;
public LuckPermsHook() { super("LuckPerms"); }
@Override protected void setup() { RegisteredServiceProvider<LuckPerms> provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); if (provider != null) { this.api = provider.getProvider(); } }
public LuckPerms api() { return api; }}- Add the dependency to
pom.xmlwith<scope>provided</scope>. - Add
LuckPermstosoftdependinplugin.yml. - Register lazily:
hooks.register("LuckPerms", LuckPermsHook::new);- Use safely:
hooks.get(LuckPermsHook.class).ifPresent(lp -> { User user = lp.api().getUserManager().getUser(player.getUniqueId());});