BlazeBans API/Building an addon
What an addon is
An addon is an ordinary Paper plugin that depends on BlazeBans and registers itself so operators can see it. There is no special loader, no manifest key, and no sandbox.
The only thing that makes it an addon rather than a plugin that happens to use the API is that it declares itself, and behaves consistently with the rest of the BlazeBans install.
Registering
import net.blazebans.api.BlazeBansProvider;
import net.blazebans.api.addon.BlazeBansAddon;
private static final String ADDON_ID = "MyAddon";
@Override
public void onEnable() {
BlazeBansProvider.registerAddon(new BlazeBansAddon(
ADDON_ID,
"My Addon",
getPluginMeta().getVersion(),
"Adds custom punishment effects.",
"enabled"
));
}
@Override
public void onDisable() {
BlazeBansProvider.unregisterAddon(ADDON_ID);
}Your addon then appears in /blazebans addons.
The five fields
IDs are trimmed and compared case-insensitively, so MyAddon and myaddon are the same entry. Registering an ID that already exists replaces its metadata rather than adding a second row.
Both pluginId and name throw IllegalArgumentException if blank, so do not pass a config value straight in without checking it.
Use status honestly
status is free text and it is the first place an operator looks when something is not working. Make it say something.
String status = this.voiceChatHooked ? "enabled" : "waiting for Simple Voice Chat";"enabled" when everything is fine, and a specific reason when it is not, turns a support question into a self-answer.
To update it later, register again with the same ID.
Always unregister
onDisable should always remove your entry, even on a partial startup:
@Override
public void onDisable() {
BlazeBansProvider.unregisterAddon(ADDON_ID);
}This is safe when BlazeBans is already gone. It only touches a static map, so it will not throw during shutdown.
Do not start database work in onDisable. See Getting the API.
Console output
AddonConsole gives you BlazeBans' console styling so your addon does not look like a stranger in the log.
import net.blazebans.api.console.AddonConsole;
AddonConsole console = new AddonConsole(
"MyAddon",
component -> getServer().getConsoleSender().sendMessage(component)
);
console.step("Loading integration...");
console.success("Integration enabled.");
console.info("Watching 4 worlds.");
console.warning("Optional dependency was not found.");
console.error("Integration failed.", exception);
console.blank();Every line is prefixed [BlazeBans MyAddon] and coloured by level: blaze for step, green for success, amber for warning, red for error.
error(String, Throwable) prints the stack trace in the same style, which beats a raw printStackTrace() in the middle of a coloured log.
There is a three-argument constructor taking a second Consumer<String> for terminals where you want BlazeBans' 24-bit ANSI serialisation instead of Adventure components. Most addons want the two-argument form.
The addon name cannot be blank, and it should be short. It appears on every line.
Conventions worth following
None of this is enforced. It is what the shipped addons do, and matching it makes yours feel like part of the same product.
Namespace your permissions. The shipped addons use blazebans.addon.<addon>.<action>:
permissions:
blazebans.addon.myaddon.use:
description: Allows using the addon's commands.
default: op
blazebans.addon.myaddon.reload:
description: Allows reloading the addon.
default: opKeep your own config. The API does not expose BlazeBans' configuration, and you should not read its files. Ship your own settings.yml in your own data folder.
Support a reload. /<addon> reload is what operators expect, and it saves a restart while they tune.
Match the message style. If your addon sends player-facing text, MiniMessage with a configurable colour scheme keeps it consistent with BlazeBans. The shipped addons mirror the same {color_positive} and {meta_prefix_*} placeholder shape.
Fail visibly. If an optional dependency is missing, say so once in console with warning and set your status accordingly. Do not fail silently and do not warn every tick.
Hard depend, and why
depend:
- BlazeBans
softdepend:
- voicechatdepend on BlazeBans, softdepend on anything else you integrate with. That gives you a guaranteed load order for the thing you cannot work without, and graceful degradation for the things you can.
The shipped addons as reference
Two addons ship with BlazeBans, both built on this same public API:
Voice chat adds VOICE_MUTE punishments through Simple Voice Chat. It shows the pattern for an addon introducing a new punishment type and hooking a third-party plugin.
Ban effects plays an animation before a ban is enforced. It shows enforcement delays, per-effect configuration, and console commands on completion.
Both are documented in Addons. Neither uses anything you cannot.
Next
Build one end to end walks through a complete working addon from an empty directory.

