BlazeBans API/Getting started

Getting the API

`BlazeBansProvider` is a static holder. BlazeBans registers itself into it when it enables, and clears it when it disables.

The three accessors

java
BlazeBansApi api = BlazeBansProvider.get();          // throws if unavailable
Optional<BlazeBansApi> maybe = BlazeBansProvider.optional();
boolean ready = BlazeBansProvider.available();
MethodBehaviour
get()Returns the API, or throws IllegalStateException
optional()Returns an Optional, empty when unavailable
available()Returns whether it is registered right now

Which one to use depends entirely on whether you declared a hard or soft dependency.

With a hard dependency

If your plugin.yml has depend: [BlazeBans], Paper guarantees BlazeBans enabled before you. get() is safe in onEnable, and letting it throw is the correct behaviour: something is wrong with the install and failing loudly is better than running half-broken.

java
public final class MyAddon extends JavaPlugin {
    private BlazeBansApi blazeBans;

    @Override
    public void onEnable() {
        this.blazeBans = BlazeBansProvider.get();
        getLogger().info("Hooked into BlazeBans " + this.blazeBans.version());
    }
}

There is one case a hard dependency does not cover: hooks.api: false in settings.yml. BlazeBans then enables normally but never registers the API. Handling it with a clear message saves a support conversation:

java
@Override
public void onEnable() {
    this.blazeBans = BlazeBansProvider.optional().orElse(null);
    if (this.blazeBans == null) {
        getLogger().severe("The BlazeBans API is unavailable. Set hooks.api to true in "
            + "plugins/BlazeBans/settings.yml and restart.");
        getServer().getPluginManager().disablePlugin(this);
        return;
    }
    getLogger().info("Hooked into BlazeBans " + this.blazeBans.version());
}

Disabling yourself is usually right for an addon. A plugin whose only job is extending BlazeBans has nothing to do without it, and staying enabled just moves the error to a confusing place later.

With a soft dependency

If BlazeBans support is optional in your plugin, you cannot cache the instance in onEnable and trust it. Two things can go wrong: BlazeBans may not be installed, and with softdepend it may enable after you.

Look it up at the point of use instead:

java
public final class MyPlugin extends JavaPlugin {

    private Optional<BlazeBansApi> blazeBans() {
        return BlazeBansProvider.optional();
    }

    public void onSomethingHappened(Player player) {
        blazeBans().ifPresentOrElse(
            api -> api.punishments()
                .isMuted(player.getName(), player.getUniqueId())
                .thenAccept(muted -> { /* ... */ }),
            () -> { /* BlazeBans is not here; carry on without it */ }
        );
    }
}

The lookup is a single atomic read, so calling it per use costs nothing worth optimising. Caching it is what causes the bugs.

Availability over time

MomentState
Before BlazeBans enablesUnavailable
hooks.api: falseNever becomes available
BlazeBans enabledAvailable
BlazeBans disabling, or server shutdownUnavailable again

That last row matters. During shutdown, plugins disable in reverse dependency order, so BlazeBans may already be gone by the time your onDisable runs. Do not assume the API is there:

java
@Override
public void onDisable() {
    BlazeBansProvider.unregisterAddon("MyAddon");
    // Do not call this.blazeBans.punishments() here. It may be shutting down,
    // and a database write started now is not guaranteed to finish.
}

Unregistering your addon metadata is safe and correct. Starting new work is not.

Do not register anything

java
BlazeBansProvider.register(api);    // BlazeBans only
BlazeBansProvider.unregister(api);  // BlazeBans only

These exist because BlazeBans needs them. Calling either from a consumer plugin replaces or clears the live API for every other plugin on the server.

registerAddon and unregisterAddon are the pair you are meant to call. They only touch your own metadata. See What an addon is.

Version checks

java
getLogger().info("BlazeBans " + api.version());

version() returns the running version as a string, the same one /blazebans version shows.

It is fine for logging. Do not parse it to gate features: the API is compiled against, so if a method exists at compile time it exists at runtime, and a class that would have been removed would have failed the release build. If you need to support an older BlazeBans that genuinely lacks something, catch NoSuchMethodError around the call rather than comparing version strings.

A complete safe startup

java
package com.example.myaddon;

import net.blazebans.api.BlazeBansApi;
import net.blazebans.api.BlazeBansProvider;
import net.blazebans.api.addon.BlazeBansAddon;
import org.bukkit.plugin.java.JavaPlugin;

public final class MyAddon extends JavaPlugin {
    private static final String ADDON_ID = "MyAddon";
    private BlazeBansApi blazeBans;

    @Override
    public void onEnable() {
        this.blazeBans = BlazeBansProvider.optional().orElse(null);
        if (this.blazeBans == null) {
            getLogger().severe("The BlazeBans API is unavailable. Check hooks.api in settings.yml.");
            getServer().getPluginManager().disablePlugin(this);
            return;
        }

        BlazeBansProvider.registerAddon(new BlazeBansAddon(
            ADDON_ID,
            "My Addon",
            getPluginMeta().getVersion(),
            "Does something useful with punishments.",
            "enabled"
        ));

        getServer().getPluginManager().registerEvents(new MyListener(this.blazeBans), this);
        getLogger().info("Hooked into BlazeBans " + this.blazeBans.version());
    }

    @Override
    public void onDisable() {
        BlazeBansProvider.unregisterAddon(ADDON_ID);
    }
}

Next: Threading, which is the part that decides whether your plugin is safe.