BlazeBans API/Reference

Recipes

Short, complete answers to the things people build most. Each assumes `this.blazeBans` holds the API and `this.plugin` is your plugin.

Check whether a player is muted

java
this.blazeBans.punishments().isMuted(player.getName(), player.getUniqueId())
    .thenAccept(muted -> {
        if (!muted) {
            return;
        }
        player.getScheduler().run(this.plugin, task ->
            player.sendMessage(Component.text("You are muted.")), null);
    });

Show a mute reason and remaining time

java
this.blazeBans.punishments().activeMute(player.getName(), player.getUniqueId())
    .thenAccept(found -> found.ifPresent(punishment -> {
        String remaining = punishment.permanent()
            ? "permanently"
            : "for " + format(Duration.between(Instant.now(), punishment.expiresAt()));

        player.getScheduler().run(this.plugin, task -> player.sendMessage(
            Component.text("Muted " + remaining + ": " + punishment.reason())), null);
    }));

private static String format(Duration duration) {
    if (duration.isNegative()) {
        return "0m";
    }
    long days = duration.toDays();
    if (days > 0) {
        return days + "d " + duration.toHoursPart() + "h";
    }
    long hours = duration.toHours();
    return hours > 0 ? hours + "h " + duration.toMinutesPart() + "m" : duration.toMinutes() + "m";
}

Count a player's active warnings

java
this.blazeBans.punishments().history(playerName)
    .thenApply(records -> records.stream()
        .filter(record -> record.type() == PunishmentType.WARN)
        .filter(Punishment::active)
        .count())
    .thenAccept(count -> getLogger().info(playerName + " has " + count + " active warnings"));

Block a feature while a player has an active warning

java
@EventHandler
public void onUseFeature(SomeEvent event) {
    Player player = event.getPlayer();
    this.blazeBans.punishments()
        .activePunishment(PunishmentType.WARN, player.getName(), player.getUniqueId())
        .thenAccept(warning -> warning.ifPresent(punishment ->
            player.getScheduler().run(this.plugin, task ->
                player.sendMessage(Component.text("Unavailable while you have an active warning.")),
                null)));
}

Note this cannot cancel the event: by the time the answer arrives, the event has already resolved. To actually gate something, keep a cached state updated from the punishment events and read that synchronously.

Keep a cached mute state

java
private final Map<UUID, Boolean> muted = new ConcurrentHashMap<>();

@EventHandler
public void onJoin(PlayerJoinEvent event) {
    UUID uuid = event.getPlayer().getUniqueId();
    this.blazeBans.punishments().isMuted(event.getPlayer().getName(), uuid)
        .thenAccept(state -> this.muted.put(uuid, state));
}

@EventHandler
public void onQuit(PlayerQuitEvent event) {
    this.muted.remove(event.getPlayer().getUniqueId());
}

@EventHandler
public void onPunishmentCreated(BlazeBansPunishmentCreatedEvent event) {
    UUID uuid = event.punishment().targetUuid();
    if (uuid != null && isMuteType(event.punishment().type())) {
        this.muted.put(uuid, true);
    }
}

@EventHandler
public void onPunishmentRevoked(BlazeBansPunishmentRevokedEvent event) {
    UUID uuid = event.punishment().targetUuid();
    if (uuid != null && isMuteType(event.punishment().type())) {
        this.muted.put(uuid, false);
    }
}

private static boolean isMuteType(PunishmentType type) {
    return type == PunishmentType.MUTE || type == PunishmentType.IP_MUTE;
}

Now this.muted.getOrDefault(uuid, false) is safe to read synchronously, which is what lets you cancel an event on it.

This misses expiry, since nothing fires when a mute lapses. Either re-check periodically or store the expiry instant instead of a boolean.

Ban a player from your own code

java
PunishmentCreateRequest request = new PunishmentCreateRequest(
    PunishmentType.BAN,
    target.getName(),
    target.getUniqueId(),
    ipOf(target),
    "MyPlugin",
    null,
    Duration.ofDays(7),
    "Automated: exploit detected",
    "",
    "server",
    this.serverId,
    false
);

this.blazeBans.punishments().createPunishment(request)
    .whenComplete((created, error) -> {
        if (error != null) {
            getLogger().warning("Ban failed: " + error.getMessage());
            return;
        }
        created.ifPresentOrElse(
            punishment -> getLogger().info("Created " + punishment.id()),
            () -> getLogger().info("Another plugin cancelled the ban.")
        );
    });

private static String ipOf(Player player) {
    return player.getAddress() == null
        ? ""
        : player.getAddress().getAddress().getHostAddress();
}

Unban when an appeal is accepted

java
public void acceptAppeal(String punishmentId, String staffName) {
    this.blazeBans.punishments()
        .revokePunishment(punishmentId, staffName, "Appeal accepted")
        .whenComplete((revoked, error) -> {
            if (error != null) {
                getLogger().warning("Revoke failed: " + error.getMessage());
                return;
            }
            revoked.ifPresentOrElse(
                punishment -> getLogger().info("Revoked " + punishment.id()),
                () -> getLogger().info("No active punishment with that ID.")
            );
        });
}

Crediting the real staff member rather than your plugin keeps /staffhistory honest.

Stop specific players being banned

java
@EventHandler(priority = EventPriority.HIGHEST)
public void onPunishmentCreate(BlazeBansPunishmentCreateEvent event) {
    if (event.request().type() != PunishmentType.BAN) {
        return;
    }
    if (this.protectedNames.contains(event.request().targetName().toLowerCase(Locale.ROOT))) {
        event.setCancelled(true);
    }
}

BlazeBans' own exempt.players does this in config, which is usually better. Use code when the condition is something only your plugin knows.

Force a minimum ban duration

java
@EventHandler(priority = EventPriority.LOW)
public void onPunishmentCreate(BlazeBansPunishmentCreateEvent event) {
    if (event.request().type() != PunishmentType.BAN) {
        return;
    }
    Duration minimum = Duration.ofDays(1);
    Duration current = event.request().duration();

    // Duration.ZERO means permanent, which is already longer than any minimum.
    if (!current.isZero() && current.compareTo(minimum) < 0) {
        event.request().duration(minimum);
    }
}

Forward every punishment to your own system

java
@EventHandler(ignoreCancelled = true)
public void onPunishmentCreated(BlazeBansPunishmentCreatedEvent event) {
    Punishment punishment = event.punishment();
    CompletableFuture.runAsync(() -> postToMyApi(
        punishment.id(),
        punishment.type().name(),
        punishment.targetName(),
        punishment.staffName(),
        punishment.reason()
    ));
}

Do the network call off the event thread. ignoreCancelled keeps punishments another plugin suppressed out of your feed.

Find every ban issued in the last week

java
this.blazeBans.punishments().activeBans()
    .thenApply(bans -> bans.stream()
        .filter(ban -> ban.createdAt().isAfter(Instant.now().minus(Duration.ofDays(7))))
        .toList())
    .thenAccept(recent -> getLogger().info(recent.size() + " bans this week"));

Look up a punishment from a command argument

java
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    if (args.length < 1) {
        return false;
    }
    // Both ABC123 and #ABC123 resolve.
    this.blazeBans.punishments().punishmentById(args[0])
        .thenAccept(found -> {
            String reply = found
                .map(punishment -> punishment.targetName() + ": " + punishment.reason()
                    + " (" + punishment.status() + ")")
                .orElse("No punishment with that ID.");
            Bukkit.getGlobalRegionScheduler().run(this.plugin, task ->
                sender.sendMessage(reply));
        });
    return true;
}

Detect a linked banned account on join

The complete version is in Players and alts.

Delay a ban to play an effect

The complete version is in Enforcement and exemptions.