Skip to content

API reference

Every public type and member of Bloom 0.1.0, generated from the Javadoc in the source. Types under .common and .internal packages are implementation details and are not listed. The same data is available as api-manifest.json.

bloom-api

Bloom API: stable, platform-neutral contracts (platform model, capabilities, services, scheduling, text, utilities).

io.github.crownalonedev.bloom.api

BloomException class

public class BloomException extends RuntimeException

Base class for all exceptions thrown by Bloom. Bloom exceptions are unchecked and carry developer-facing messages that explain what went wrong and, where possible, how to fix it.

Since 0.1.0

2 members
public BloomException(String message)

Creates an exception with a message.

message
developer-facing description of the problem
public BloomException(String message, Throwable cause)

Creates an exception with a message and cause.

message
developer-facing description of the problem
cause
underlying cause

io.github.crownalonedev.bloom.api

BloomStartupException class

public class BloomStartupException extends BloomException

Thrown when Bloom cannot start, for example because the server version is unsupported or the required platform adapter is missing from the plugin jar. The message always names the detected platform and the corrective action.

Since 0.1.0

2 members
public BloomStartupException(String message)

Creates a startup exception.

message
developer-facing description of the problem and fix
public BloomStartupException(String message, Throwable cause)

Creates a startup exception with a cause.

message
developer-facing description of the problem and fix
cause
underlying cause

io.github.crownalonedev.bloom.api

BloomVersion class

public final class BloomVersion

The Bloom release this code was built as. Generated at build time.

Since 0.1.0

1 member
public static final String VERSION

The Bloom version string, e.g. "0.1.0" or "0.2.0-SNAPSHOT".

io.github.crownalonedev.bloom.api

UnsupportedCapabilityException class

public class UnsupportedCapabilityException extends BloomException

Thrown when code requires a platform capability that the running server does not provide, for example boss bars on a 1.8 server. Avoid this exception by checking capabilities().has(capability) first, or by choosing an API variant with a documented fallback.

Since 0.1.0

2 members
public UnsupportedCapabilityException(Capability capability, String platformDescription, String feature)

Creates the exception.

capability
the missing capability
platformDescription
human-readable description of the running platform
feature
what the caller attempted, e.g. "Messenger.actionBar"
public Capability capability()

Returns the capability that was required.

Returns the missing capability

io.github.crownalonedev.bloom.api.lifecycle

LifecycleState enum

public final enum LifecycleState

Lifecycle states of a Bloom instance.

Since 0.1.0

8 members
public static LifecycleState[] values()
public static LifecycleState valueOf(String name)
name
String
NEW

Created but not yet started.

STARTING

Starting: detecting the platform and enabling the adapter.

RUNNING

Running; all services are usable.

STOPPING

Shutting down: services are being closed.

STOPPED

Shut down. Services must not be used.

FAILED

Startup failed; the instance cannot be used.

io.github.crownalonedev.bloom.api.lifecycle

Terminable interface

public interface Terminable extends AutoCloseable

A resource that can be closed, such as a scheduled task, an event subscription or a service. Unlike AutoCloseable.close, close does not throw checked exceptions and must be idempotent: closing twice has no further effect.

Since 0.1.0

2 members
public void close()

Releases the resource. Calling this more than once has no further effect.

public boolean isClosed()

Returns whether this resource has been closed.

Returns true once close has completed

io.github.crownalonedev.bloom.api.platform

Capabilities class

public final class Capabilities

An immutable set of capabilities available on the running platform.

Since 0.1.0

8 members
public static Capabilities of(Collection<Capability> present, String platformDescription)

Creates a capability set.

present
available capabilities
platformDescription
description of the platform, used in error messages

Returns the capability set

public static Capabilities none(String platformDescription)

Creates an empty capability set.

platformDescription
description of the platform

Returns a set with no capabilities

public boolean has(Capability capability)

Returns whether a capability is available.

capability
capability to check

Returns true if available

public void require(Capability capability, String feature)

Throws if a capability is unavailable.

capability
required capability
feature
description of the feature being used, included in the error message

Throws UnsupportedCapabilityException if the capability is unavailable

public Set<Capability> available()

Returns the available capabilities.

Returns unmodifiable set

public Set<Capability> unavailable()

Returns the capabilities that are not available.

Returns unmodifiable set

public String platformDescription()

Returns the platform description used in error messages.

Returns platform description

public String toString()

io.github.crownalonedev.bloom.api.platform

Capability enum

public final enum Capability

Optional platform features whose availability depends on the server version or implementation. The active adapter decides which capabilities are present, in some cases by probing the running server (for example, legacy NBT access through reflection). Use Capabilities.has before calling features that are not universally available.

Since 0.1.0

17 members
public static Capability[] values()
public static Capability valueOf(String name)
name
String
ADVENTURE_TEXT

Native Adventure text components (Paper).

MINIMESSAGE

Full MiniMessage parsing. Legacy servers get a documented subset converted to legacy colours instead.

HEX_COLORS

RGB/hex colours in text (1.16+).

ACTION_BAR

Action bar messages. Legacy 1.8 servers require a successful NMS reflection probe.

TITLES

Title and subtitle messages.

TITLE_TIMINGS

Custom fade-in/stay/fade-out timings for titles.

BOSS_BAR

Boss bars.

COMPONENT_INVENTORY_TITLES

Component-based inventory titles (allows MiniMessage formatting and titles over 32 characters).

PERSISTENT_DATA_CONTAINER

Bukkit PersistentDataContainer on items.

ITEM_NBT_TAGS

Custom NBT tags on items through version-specific reflection (legacy).

ITEM_FLAGS

Item flags such as HIDE_ENCHANTS (1.8+).

UNBREAKABLE_ITEMS

Unbreakable items.

CUSTOM_MODEL_DATA

Custom model data on items (1.14+).

LEGACY_DATA_VALUES

Numeric data/durability values selecting item variants, e.g. WOOL:14 (pre-1.13).

public String description()

Returns a short human-readable description.

Returns description used in error messages and diagnostics

io.github.crownalonedev.bloom.api.platform

JavaRuntime class

public final class JavaRuntime

Describes the Java runtime the server is running on.

Since 0.1.0

7 members
public static JavaRuntime current()

Describes the current JVM.

Returns the current runtime

public static JavaRuntime of(String specificationVersion, String fullVersion, String vendor)

Creates a runtime description from system property values.

specificationVersion
value of java.specification.version, e.g. "1.8" or "21"
fullVersion
value of java.version
vendor
value of java.vendor

Returns the runtime description

public int featureVersion()

Returns the Java feature version.

Returns e.g. 8, 21 or 25

public String fullVersion()

Returns the full version string.

Returns e.g. "1.8.0_472" or "21.0.11"

public String vendor()

Returns the runtime vendor.

Returns vendor name

public boolean isAtLeast(int feature)

Returns whether the runtime is at least the given feature version.

feature
feature version to compare with

Returns true if featureVersion() >= feature

public String toString()

io.github.crownalonedev.bloom.api.platform

MinecraftVersion class

public final class MinecraftVersion implements Comparable<MinecraftVersion>

An immutable Minecraft release version such as 1.8.8, 1.21.11 or 26.3. Both the classic 1.x.y scheme and Mojang's year-based scheme (26.1, 26.3) are represented as major.minor.patch. Because 1 < 26, natural ordering is correct across schemes. Pre-release suffixes (-pre3, -rc1) are ignored when parsing.

Since 0.1.0

23 members
public static final MinecraftVersion V1_7_10

Minecraft 1.7.10, the only supported 1.7 release.

public static final MinecraftVersion V1_8

Minecraft 1.8 (1.8.0).

public static final MinecraftVersion V1_8_8

Minecraft 1.8.8, the most common legacy PvP version.

public static final MinecraftVersion V1_8_9

Minecraft 1.8.9, the last 1.8 release.

public static final MinecraftVersion V1_21_1

Minecraft 1.21.1.

public static final MinecraftVersion V1_21_11

Minecraft 1.21.11, the last 1.x release.

public static final MinecraftVersion V26_1

Minecraft 26.1, the first year-based release.

public static MinecraftVersion of(int major, int minor, int patch)

Creates a version.

major
major component, 1 for classic versions or the year for year-based versions
minor
minor component
patch
patch component

Returns the version

public static MinecraftVersion of(int major, int minor)

Creates a version with patch 0.

major
major component
minor
minor component

Returns the version

public static MinecraftVersion parse(String text)

Parses a version from the start of a string such as "1.8.8", "1.21.11-R0.1-SNAPSHOT" or "26.3.build.177-stable".

text
text beginning with a version

Returns the parsed version

Throws IllegalArgumentException if the text does not start with a version

public static Optional<MinecraftVersion> tryParse(String text)

Parses a version from the start of a string, returning empty instead of throwing.

text
text beginning with a version, may be null

Returns the parsed version, or empty

public static Optional<MinecraftVersion> detect(String bukkitVersion, String serverVersion)

Determines the Minecraft version from the strings a Bukkit-family server reports. The "(MC: x.y.z)" marker in Server#getVersion() is preferred because it always contains the game version; Server#getBukkitVersion() is used as a fallback.

bukkitVersion
value of Server#getBukkitVersion(), may be null
serverVersion
value of Server#getVersion(), may be null

Returns the detected version, or empty if neither string contains one

public int major()

Returns the major component.

Returns major component

public int minor()

Returns the minor component.

Returns minor component

public int patch()

Returns the patch component.

Returns patch component, 0 if the version string had none

public boolean isAtLeast(MinecraftVersion other)

Returns whether this version is the same as or newer than another.

other
version to compare with

Returns true if this >= other

public boolean isBefore(MinecraftVersion other)

Returns whether this version is older than another.

other
version to compare with

Returns true if this < other

public boolean isBetween(MinecraftVersion min, MinecraftVersion max)

Returns whether this version lies within an inclusive range.

min
inclusive lower bound
max
inclusive upper bound

Returns true if min <= this <= max

public boolean isSameLine(MinecraftVersion other)

Returns whether this version shares major and minor components with another, e.g. 1.8.3 and 1.8.8.

other
version to compare with

Returns true if both belong to the same release line

public int compareTo(MinecraftVersion o)
o
MinecraftVersion
public boolean equals(Object o)
o
Object
public int hashCode()
public String toString()

Formats the version the way Mojang does: 1.8 rather than 1.8.0.

Returns the version string

io.github.crownalonedev.bloom.api.platform

PlatformFamily enum

public final enum PlatformFamily

The platform families Bloom ships adapters for. Each family is served by one adapter module.

Since 0.1.0

6 members
public static PlatformFamily[] values()
public static PlatformFamily valueOf(String name)
name
String
LEGACY

Bukkit/Spigot 1.7.10 to 1.8.9 on Java 8. Served by bloom-legacy.

MODERN

Paper 1.21.x and 26.x on Java 21+. Served by bloom-modern.

public String id()

Returns the short identifier used in logs and configuration.

Returns "legacy" or "modern"

public String adapterModule()

Returns the Bloom artifact that contains this family's adapter.

Returns artifact id, e.g. "bloom-legacy"

io.github.crownalonedev.bloom.api.platform

PlatformInfo class

public final class PlatformInfo

Immutable description of the server Bloom is running on.

Since 0.1.0

9 members
public PlatformInfo(ServerSoftware software, String serverName, String serverVersion, String bukkitVersion, MinecraftVersion minecraftVersion, JavaRuntime javaRuntime)

Creates a platform description.

software
detected implementation
serverName
value of Server#getName()
serverVersion
value of Server#getVersion()
bukkitVersion
value of Server#getBukkitVersion()
minecraftVersion
detected game version
javaRuntime
running Java runtime
public ServerSoftware software()

Returns the detected server implementation.

Returns server software

public String serverName()

Returns the name the server reports, e.g. "Paper" or "CraftBukkit".

Returns server name

public String serverVersion()

Returns the raw server version string.

Returns e.g. "git-Spigot-db6de12-18fbb24 (MC: 1.8.8)"

public String bukkitVersion()

Returns the raw Bukkit API version string.

Returns e.g. "1.8.8-R0.1-SNAPSHOT"

public MinecraftVersion minecraftVersion()

Returns the Minecraft version.

Returns game version

public JavaRuntime javaRuntime()

Returns the Java runtime.

Returns Java runtime

public String describe()

Returns a short description such as "Paper 1.21.11 (Java 21.0.11)".

Returns description for logs and error messages

public String toString()

io.github.crownalonedev.bloom.api.platform

ServerSoftware enum

public final enum ServerSoftware

Server implementations Bloom can recognise. Recognition does not imply support; see PlatformFamily and the compatibility matrix.

Since 0.1.0

12 members
public static ServerSoftware[] values()
public static ServerSoftware valueOf(String name)
name
String
CRAFTBUKKIT

CraftBukkit without Spigot patches.

SPIGOT

Spigot.

PAPER_SPIGOT

PaperSpigot, the legacy (1.7/1.8) Paper fork of Spigot.

PAPER

Paper (1.9 and newer).

PAPER_FORK

A Paper fork such as Purpur or Pufferfish; Paper API is available.

FOLIA

Folia, Paper's regionised fork. Not supported by Bloom yet: its scheduler model differs.

MOCKBUKKIT

MockBukkit test server (implements Paper API).

UNKNOWN

Unrecognised implementation.

public String displayName()

Returns a human-readable name.

Returns display name

public boolean hasPaperApi()

Returns whether this implementation exposes the modern Paper API (Adventure, PDC, etc.).

Returns true for Paper, Paper forks, Folia and MockBukkit

io.github.crownalonedev.bloom.api.platform

SupportDecision class

public final class SupportDecision

Result of SupportPolicy.evaluate.

Since 0.1.0

4 members
public boolean isSupported()

Returns whether Bloom may start.

Returns true if an adapter family was selected

public PlatformFamily family()

Returns the selected adapter family.

Returns family

Throws IllegalStateException if unsupported

public boolean isUntested()

Returns whether the platform is newer than the supported range and was only accepted because the developer opted in.

Returns true for an explicitly allowed untested version

public String reason()

Returns why the platform is unsupported.

Returns explanation, or null if supported

io.github.crownalonedev.bloom.api.platform

SupportPolicy class

public final class SupportPolicy

The single source of truth for which platforms Bloom will start on. Runtime support ranges are deliberately conservative. Being inside a range means an adapter exists and its code was compile-verified against that API; the test status of each version is tracked separately in docs/architecture/COMPATIBILITY.md.

Since 0.1.0

6 members
public static final VersionRange LEGACY

Legacy family: 1.7.10 through 1.8.9.

public static final List<VersionRange> MODERN

Modern family ranges: Paper 1.21.1 - 1.21.11, then 26.1.x - 26.3.x.

public static final int LEGACY_MIN_JAVA

Minimum Java feature version for the legacy family.

public static final int MODERN_MIN_JAVA

Minimum Java feature version for the modern family (the modern adapter is Java 21 bytecode).

public static MinecraftVersion newestModern()

Returns the newest Minecraft version covered by a modern range.

Returns newest supported modern version (patch may be Integer.MAX_VALUE)

public static SupportDecision evaluate(ServerSoftware software, MinecraftVersion version, JavaRuntime java, boolean allowNewerUntested)

Decides whether and how Bloom can run on a platform.

software
detected server implementation
version
detected Minecraft version
java
running Java runtime
allowNewerUntested
whether the developer opted into running the modern adapter on Paper versions newer than the newest supported one

Returns the decision, never null

io.github.crownalonedev.bloom.api.platform

VersionRange class

public final class VersionRange

An inclusive range of Minecraft versions.

Since 0.1.0

6 members
public static VersionRange between(MinecraftVersion min, MinecraftVersion max)

Creates an inclusive range.

min
inclusive lower bound
max
inclusive upper bound

Returns the range

public static VersionRange lineFrom(int major, int minor, int minPatch)

Creates a range covering every patch release of one release line from a minimum patch, e.g. lineFrom(26, 3, 0) covers 26.3, 26.3.1, 26.3.2 and so on.

major
major component
minor
minor component
minPatch
first included patch

Returns the range

public MinecraftVersion min()

Returns the inclusive lower bound.

Returns lower bound

public MinecraftVersion max()

Returns the inclusive upper bound.

Returns upper bound; its patch is Integer.MAX_VALUE for open release lines

public boolean contains(MinecraftVersion version)

Tests whether a version lies in this range.

version
version to test

Returns true if included

public String toString()

io.github.crownalonedev.bloom.api.scheduler

BloomScheduler interface

public interface BloomScheduler

Plugin-owned task scheduling with automatic cleanup. Every task is owned by the Bloom instance that created it and is cancelled when Bloom shuts down. Exceptions thrown by tasks are caught and logged with the task's origin; they never kill the scheduler. Threading rules • sync* tasks run on the main server thread. Use them for anything that touches worlds, entities, players, inventories or most other Bukkit API. • async* tasks run on a background thread. Use them for I/O, computation and network calls. Never modify worlds, entities or inventories from an async task: hop back with sync or mainThreadExecutor. Delays and periods are in server ticks (20 per second at full speed) unless a Duration overload is used. A delay of 0 means "the next tick".

Since 0.1.0

15 members
public boolean isPrimaryThread()

Returns whether the calling thread is the main server thread.

Returns true on the main thread

public void ensurePrimaryThread(String operation)

Throws if not called from the main server thread. Use at the start of methods that touch game state.

operation
what the caller is doing, used in the error message

Throws IllegalStateException if called from another thread

public ScheduledTask sync(Runnable task)

Runs a task on the main thread on the next tick.

task
task to run

Returns task handle

public ScheduledTask syncLater(Runnable task, long delayTicks)

Runs a task on the main thread after a delay.

task
task to run
delayTicks
delay in ticks, >= 0

Returns task handle

public ScheduledTask syncLater(Runnable task, Duration delay)

Runs a task on the main thread after a delay.

task
task to run
delay
delay, rounded up to whole ticks

Returns task handle

public ScheduledTask syncRepeating(Consumer<ScheduledTask> task, long delayTicks, long periodTicks)

Runs a task repeatedly on the main thread. The task receives its own handle so it can cancel itself.

task
task to run; receives its handle
delayTicks
initial delay in ticks, >= 0
periodTicks
period in ticks, >= 1

Returns task handle

public ScheduledTask syncRepeating(Consumer<ScheduledTask> task, Duration delay, Duration period)

Runs a task repeatedly on the main thread.

task
task to run; receives its handle
delay
initial delay
period
period, at least one tick

Returns task handle

public ScheduledTask async(Runnable task)

Runs a task on a background thread as soon as possible.

task
task to run; must not touch game state

Returns task handle

public ScheduledTask asyncLater(Runnable task, long delayTicks)

Runs a task on a background thread after a delay.

task
task to run; must not touch game state
delayTicks
delay in ticks

Returns task handle

public ScheduledTask asyncRepeating(Consumer<ScheduledTask> task, long delayTicks, long periodTicks)

Runs a task repeatedly on a background thread.

task
task to run; receives its handle; must not touch game state
delayTicks
initial delay in ticks
periodTicks
period in ticks, >= 1

Returns task handle

public <T> CompletableFuture<T> supplySync(Supplier<T> supplier)

Computes a value on the main thread. If already on the main thread the supplier still runs on the next tick, so the behaviour is the same from every caller.

supplier
computation; may touch game state

Returns future completed on the main thread with the result or the thrown exception

public <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier)

Computes a value on a background thread.

supplier
computation; must not touch game state

Returns future completed with the result or the thrown exception

public Executor mainThreadExecutor()

Returns an executor that runs tasks on the main thread. Useful for future.thenAcceptAsync(result -> ..., scheduler.mainThreadExecutor()).

Returns main-thread executor owned by this scheduler

public Executor asyncExecutor()

Returns an executor that runs tasks on background threads owned by this scheduler.

Returns async executor

public int activeTaskCount()

Returns the number of tasks that are scheduled and not yet finished or cancelled.

Returns active task count

io.github.crownalonedev.bloom.api.scheduler

ScheduledTask interface

public interface ScheduledTask extends Terminable

Handle to a task submitted to a BloomScheduler. close is equivalent to cancel.

Since 0.1.0

7 members
public void cancel()

Cancels the task. A one-shot task that already ran is unaffected; a repeating task will not run again. Idempotent.

public boolean isCancelled()

Returns whether the task was cancelled (explicitly or by scheduler shutdown).

Returns true if cancelled

public boolean isDone()

Returns whether a one-shot task has finished running. Always false for repeating tasks that were not cancelled.

Returns true if finished

public boolean isAsync()

Returns whether the task runs off the main server thread.

Returns true for async tasks

public boolean isRepeating()

Returns whether the task repeats.

Returns true for repeating tasks

public default void close()
public default boolean isClosed()

io.github.crownalonedev.bloom.api.scheduler

Ticks class

public final class Ticks

Conversions between server ticks and Durations. One tick is 50 ms at the nominal 20 TPS.

Since 0.1.0

5 members
public static final int PER_SECOND

Nominal ticks per second.

public static final long MILLIS_PER_TICK

Nominal milliseconds per tick.

public static long from(Duration duration)

Converts a duration to ticks, rounding up so that a positive duration never becomes zero ticks.

duration
non-negative duration

Returns number of ticks

Throws IllegalArgumentException if the duration is negative

public static Duration toDuration(long ticks)

Converts ticks to a duration.

ticks
number of ticks

Returns the nominal duration

public static long seconds(long seconds)

Converts seconds to ticks.

seconds
seconds

Returns ticks

io.github.crownalonedev.bloom.api.service

ServiceRegistry interface

public interface ServiceRegistry

A simple, type-keyed registry of services owned by one Bloom instance. Services that implement Terminable or AutoCloseable are closed automatically, in reverse registration order, when Bloom shuts down. All methods are thread-safe.

Since 0.1.0

6 members
public <T> void register(Class<T> type, T service)

Registers a service.

type
the key type, usually an interface the service implements
service
the service instance

Throws IllegalStateException if a service is already registered for type or the registry is closed

public <T> Optional<T> find(Class<T> type)

Looks up a service.

type
key type

Returns the service, or empty if none is registered

public <T> T require(Class<T> type)

Looks up a service that must exist.

type
key type

Returns the service

Throws BloomException if no service is registered, with a message listing the registered services

public <T> T getOrRegister(Class<T> type, Supplier<? extends T> factory)

Returns the registered service, atomically creating and registering it first if absent.

type
key type
factory
creates the service; called at most once per type

Returns the existing or newly created service

public boolean isRegistered(Class<?> type)

Returns whether a service is registered.

type
key type

Returns true if registered

public Set<Class<?>> types()

Returns the registered key types in registration order.

Returns snapshot of registered types

io.github.crownalonedev.bloom.api.text

Placeholder class

public final class Placeholder

A {key} placeholder and the value that replaces it. Values created with of are inserted as plain text : formatting codes or tags inside the value are neutralised, so untrusted input such as player chat cannot inject colours or MiniMessage tags. Use formatted only for trusted values that intentionally contain formatting. messenger.send(player, "&dWelcome, {player}!", Placeholder.of("player", player.getName()));

Since 0.1.0

6 members
public static Placeholder of(String key, Object value)

Creates a plain-text placeholder. The value's toString() is used; null becomes "null".

key
key without braces, e.g. "player"
value
replacement value

Returns the placeholder

public static Placeholder formatted(String key, String value)

Creates a placeholder whose value is parsed with the message's format. Only use with trusted values.

key
key without braces
value
replacement containing formatting in the same TextFormat as the message

Returns the placeholder

public String key()

Returns the key without braces.

Returns key

public String value()

Returns the replacement value.

Returns value

public boolean isFormatted()

Returns whether the value is trusted formatted text rather than plain text.

Returns true if created with formatted

public String toString()

io.github.crownalonedev.bloom.api.text

TextFormat enum

public final enum TextFormat

The markup language used to write a message. Both formats work on every supported platform: • On modern Paper, MINIMESSAGE is parsed by the real MiniMessage library and LEGACY by Adventure's legacy serializer. • On legacy servers, LEGACY is native, and MINIMESSAGE is converted by Bloom's MiniMessage subset converter: named colours, hex colours (downsampled to the nearest legacy colour), decorations, <reset> and <newline>. Interactive tags (click, hover, insertion) and gradients are rendered as plain text content without their effect.

Since 0.1.0

4 members
public static TextFormat[] values()
public static TextFormat valueOf(String name)
name
String
LEGACY

Legacy colour codes with & (or §), e.g. "&dHello &lworld".

MINIMESSAGE

MiniMessage tags, e.g. "<light_purple>Hello <bold>world".

io.github.crownalonedev.bloom.api.util

Cooldowns class

public final class Cooldowns<K>

Thread-safe cooldown tracking keyed by any value, typically a player UUID. private final Cooldowns<UUID> pearl = Cooldowns.of(Duration.ofSeconds(15)); if (!pearl.tryUse(player.getUniqueId())) { player.sendMessage("Wait " + Durations.format(pearl.remaining(player.getUniqueId()))); return; } Expired entries are removed lazily when accessed and by prune. Cooldowns are kept in memory only.

Since 0.1.0

14 members
public static <K> Cooldowns<K> of(Duration defaultDuration)

Creates cooldowns with a default duration using the system clock.

defaultDuration
positive duration applied by tryUse and start

Returns a new cooldown tracker

public static <K> Cooldowns<K> of(Duration defaultDuration, Clock clock)

Creates cooldowns with a custom clock, mainly for tests.

defaultDuration
positive default duration
clock
time source

Returns a new cooldown tracker

public boolean tryUse(K key)

Starts the default cooldown if the key is not on cooldown.

key
key to use

Returns true if the key was free and the cooldown was started; false if still cooling down

public boolean tryUse(K key, Duration duration)

Starts a cooldown of a specific duration if the key is not on cooldown. Atomic per key.

key
key to use
duration
positive cooldown duration

Returns true if the cooldown was started

public void start(K key)

Starts (or restarts) the default cooldown unconditionally.

key
key
public void start(K key, Duration duration)

Starts (or restarts) a cooldown unconditionally.

key
key
duration
positive duration
public boolean isActive(K key)

Returns whether a key is cooling down.

key
key

Returns true if the cooldown has not expired

public Duration remaining(K key)

Returns the remaining cooldown time.

key
key

Returns remaining time, Duration.ZERO if not on cooldown

public Optional<Instant> expiry(K key)

Returns when the key's cooldown expires.

key
key

Returns expiry instant, or empty if not on cooldown

public void reset(K key)

Clears a key's cooldown.

key
key
public void clear()

Clears all cooldowns.

public int prune()

Removes expired entries. Call periodically if keys are rarely accessed again.

Returns number of removed entries

public int size()

Returns the number of tracked entries, including expired entries not yet pruned.

Returns entry count

public Duration defaultDuration()

Returns the default duration.

Returns default duration

io.github.crownalonedev.bloom.api.util

Durations class

public final class Durations

Parsing and formatting of human-friendly durations such as "1h30m" or "2d 4h". Supported units: ms, s, m, h, d, w. Months and years are not supported because their length varies.

Since 0.1.0

3 members
public static Duration parse(String text)

Parses a duration such as "90s", "1h30m", "2d 4h" or "500ms". A bare number is interpreted as seconds.

text
text to parse

Returns the duration

Throws IllegalArgumentException if the text is not a valid duration, with a message showing valid examples

public static String format(Duration duration)

Formats a duration compactly, e.g. "1h 5m 3s". Sub-second durations above zero format as "<1s"; zero formats as "0s".

duration
non-negative duration

Returns compact representation

public static String formatLong(Duration duration)

Formats a duration in words, e.g. "1 hour, 5 minutes and 3 seconds".

duration
non-negative duration

Returns long-form English representation

io.github.crownalonedev.bloom.api.util

ExpiringCache class

public final class ExpiringCache<K, V>

A small thread-safe cache with time-to-live expiry and a maximum size (least-recently-used eviction). Intended for modest caches such as recently looked-up player data. It uses a single lock, so it is not suitable for very hot, highly contended paths; for those use a dedicated caching library.

Since 0.1.0

9 members
public static <K, V> ExpiringCache<K,V> create(Duration ttl, int maxSize)

Creates a cache.

ttl
how long entries stay valid after being written
maxSize
maximum number of entries

Returns the cache

public static <K, V> ExpiringCache<K,V> create(Duration ttl, int maxSize, Clock clock)

Creates a cache with a custom clock, mainly for tests.

ttl
entry lifetime
maxSize
maximum number of entries
clock
time source

Returns the cache

public Optional<V> get(K key)

Returns a cached value if present and not expired.

key
key

Returns value, or empty

public V get(K key, Function<? super K,? extends V> loader)

Returns the cached value, computing and caching it when absent or expired. The loader runs while the cache lock is held, so it must be fast and must not access this cache.

key
key
loader
computes a missing value; must not return null

Returns cached or computed value

public void put(K key, V value)

Stores a value.

key
key
value
value, not null
public void invalidate(K key)

Removes a value.

key
key
public void clear()

Removes all values.

public int prune()

Removes expired entries.

Returns number of removed entries

public int size()

Returns the number of entries, including expired entries not yet pruned.

Returns size

bloom-bukkit

Bloom for Bukkit-family servers: Bloom entry point, platform detection, adapter SPI, scheduler, messaging and events.

io.github.crownalonedev.bloom.bukkit

Bloom class

public final class Bloom

The Bloom entry point for Bukkit-family plugins. public final class MyPlugin extends JavaPlugin { private Bloom bloom; @Override public void onEnable() { bloom = Bloom.enable(this); bloom.messages().send(getServer().getConsoleSender(), "&dBloom is ready on {platform}", Placeholder.of("platform", bloom.platform().describe())); } @Override public void onDisable() { if (bloom != null) { bloom.shutdown(); } } } enable detects the server, selects the matching version adapter, starts core services and logs a startup banner. If the server is not supported it throws BloomStartupException with an explanation; let it propagate from onEnable (the server then disables the plugin) or catch it to disable gracefully. In embedded mode each plugin has its own relocated copy of Bloom, so get returns the instance of the calling plugin.

Since 0.1.0

18 members
public static Bloom enable(Plugin plugin)

Starts Bloom for a plugin with default options. Call from onEnable().

plugin
the plugin that embeds Bloom

Returns the running instance

Throws BloomStartupException if the platform is unsupported or the adapter is missing

Throws IllegalStateException if Bloom is already running for this plugin

public static Bloom enable(Plugin plugin, BloomOptions options)

Starts Bloom for a plugin. Call from onEnable().

plugin
the plugin that embeds Bloom
options
startup options

Returns the running instance

Throws BloomStartupException if the platform is unsupported or the adapter is missing

Throws IllegalStateException if Bloom is already running for this plugin

public static Bloom get()

Returns the running instance.

Returns the instance created by enable

Throws IllegalStateException if Bloom is not running

public static Optional<Bloom> find()

Returns the running instance, if any.

Returns the instance, or empty if not running

public void shutdown()

Shuts Bloom down: closes feature services (open menus are closed, databases flushed), unregisters event subscriptions, cancels scheduled tasks and disables the adapter. Call from onDisable(). Idempotent.

public Plugin plugin()

Returns the owning plugin.

Returns plugin

public BloomOptions options()

Returns the options Bloom was started with.

Returns options

public LifecycleState state()

Returns the lifecycle state.

Returns state

public PlatformInfo platform()

Returns the detected platform.

Returns platform info

public Capabilities capabilities()

Returns the capabilities of the running platform.

Returns capabilities

public boolean has(Capability capability)

Shortcut for capabilities().has(capability).

capability
capability to check

Returns true if available

public PlatformAdapter adapter()

Returns the active version adapter. Advanced: intended for Bloom modules and diagnostics.

Returns adapter

public BloomScheduler scheduler()

Returns the task scheduler. Tasks are cancelled on shutdown.

Returns scheduler

public Messenger messages()

Returns the default messenger, using the text format from BloomOptions.

Returns messenger

public Events events()

Returns the event subscription service. Subscriptions are removed on shutdown.

Returns events

public ServiceRegistry services()

Returns the service registry. Feature modules register their services here on first use (for example Menus.of(bloom)); closeable services are closed on shutdown in reverse order.

Returns services

public <T> T service(Class<T> type)

Shortcut for services().require(type).

type
service key type

Returns the service

public boolean isUntestedPlatform()

Returns whether the server is newer than the supported range and Bloom only started because of BloomOptions.Builder.allowNewerUntestedVersions.

Returns true on an explicitly allowed untested version

io.github.crownalonedev.bloom.bukkit

BloomOptions class

public final class BloomOptions

Startup options for Bloom.enable. Bloom bloom = Bloom.enable(this, BloomOptions.builder() .textFormat(TextFormat.MINIMESSAGE) .unsupportedFeaturePolicy(UnsupportedFeaturePolicy.FALLBACK_TO_CHAT) .build());

Since 0.1.0

7 members
public static BloomOptions defaults()

Returns the default options.

Returns defaults: TextFormat.LEGACY, UnsupportedFeaturePolicy.SKIP, no untested versions, no debug, full startup banner

public static BloomOptions.Builder builder()

Creates a builder initialised with the defaults.

Returns a builder

public TextFormat textFormat()

Returns the default text format for bloom.messages() and item/menu text.

Returns text format

public UnsupportedFeaturePolicy unsupportedFeaturePolicy()

Returns the default policy for unsupported features.

Returns policy

public boolean allowNewerUntestedVersions()

Returns whether Bloom may start on Paper versions newer than the newest supported one.

Returns opt-in flag

public boolean debug()

Returns whether debug diagnostics are logged.

Returns debug flag

public boolean quietStartup()

Returns whether the startup banner is reduced to one line.

Returns quiet flag

io.github.crownalonedev.bloom.bukkit

BloomOptions.Builder class

public static final class Builder

Builder for BloomOptions.

6 members
public BloomOptions.Builder textFormat(TextFormat format)

Sets the default text format.

format
format used by bloom.messages() and builders that accept text

Returns this builder

public BloomOptions.Builder unsupportedFeaturePolicy(UnsupportedFeaturePolicy policy)

Sets the default unsupported-feature policy.

policy
policy

Returns this builder

public BloomOptions.Builder allowNewerUntestedVersions(boolean allow)

Allows starting on Paper versions newer than this Bloom release supports. Bloom logs a prominent warning. Use only if you test your plugin on that version yourself.

allow
opt-in flag

Returns this builder

public BloomOptions.Builder debug(boolean debug)

Enables debug diagnostics (adapter probe details, relocation details).

debug
flag

Returns this builder

public BloomOptions.Builder quietStartup(boolean quiet)

Reduces the startup banner to a single line.

quiet
flag

Returns this builder

public BloomOptions build()

Builds the options.

Returns immutable options

io.github.crownalonedev.bloom.bukkit

UnsupportedFeaturePolicy enum

public final enum UnsupportedFeaturePolicy

What Bloom does when code uses a feature the running platform lacks, such as action bars on 1.7.10.

Since 0.1.0

5 members
public static UnsupportedFeaturePolicy[] values()
public static UnsupportedFeaturePolicy valueOf(String name)
name
String
SKIP

Skip the operation and log one warning per feature. The method returns false. Default.

FALLBACK_TO_CHAT

Deliver text features (action bar, title) as a chat message instead; other features are skipped.

THROW

Throw UnsupportedCapabilityException.

io.github.crownalonedev.bloom.bukkit.event

Events class

public final class Events implements Terminable

Lambda-based event subscriptions that are automatically removed when Bloom shuts down. Events events = bloom.events(); events.subscribe(PlayerJoinEvent.class, event -> messages.send(event.getPlayer(), "&dWelcome!")); events.listen(PlayerInteractEvent.class) .priority(EventPriority.HIGH) .ignoreCancelled() .filter(event -> event.getItem() != null) .limit(1) .handler(event -> event.getPlayer().sendMessage("First interaction!")); Handlers run on the thread that fires the event: the main thread for most events, a background thread for asynchronous events such as AsyncPlayerPreLoginEvent. Exceptions thrown by handlers are reported by the server with the plugin's name, like any listener exception.

Since 0.1.0

7 members
public Events(Plugin plugin)

Creates the service. Internal: obtain it from bloom.events().

plugin
owning plugin
public <E extends Event> Subscription subscribe(Class<E> type, Consumer<? super E> handler)

Subscribes a handler at EventPriority.NORMAL, receiving cancelled events too.

type
concrete event class (must declare a HandlerList)
handler
handler

Returns the subscription

public <E extends Event> SubscriptionBuilder<E> listen(Class<E> type)

Starts building a subscription with priority, filters and limits.

type
concrete event class

Returns a builder; call SubscriptionBuilder.handler to register

public Subscription register(Listener listener)

Registers a classic Listener with @EventHandler methods, tied to Bloom's lifecycle.

listener
listener instance

Returns a subscription that unregisters the listener

public int activeCount()

Returns the number of active subscriptions created through this service.

Returns active count

public void close()

Unregisters every subscription. Idempotent.

public boolean isClosed()

io.github.crownalonedev.bloom.bukkit.event

Subscription interface

public interface Subscription extends Terminable

An active event registration. close is equivalent to unsubscribe.

Since 0.1.0

5 members
public void unsubscribe()

Stops receiving events. Idempotent and safe from any thread.

public boolean isActive()

Returns whether the subscription still receives events.

Returns true until unsubscribed

public long handledCount()

Returns how many events the handler has processed.

Returns handled event count

public default void close()
public default boolean isClosed()

io.github.crownalonedev.bloom.bukkit.event

SubscriptionBuilder class

public final class SubscriptionBuilder<E extends Event>

Configures an event subscription. Created by Events.listen.

Since 0.1.0

5 members
public SubscriptionBuilder<E> priority(EventPriority newPriority)

Sets the listener priority.

newPriority
priority (default EventPriority.NORMAL)

Returns this builder

public SubscriptionBuilder<E> ignoreCancelled()

Skips events that another listener already cancelled.

Returns this builder

public SubscriptionBuilder<E> filter(Predicate<? super E> predicate)

Only handles events that match a predicate. Multiple calls combine with logical AND.

predicate
condition

Returns this builder

public SubscriptionBuilder<E> limit(long maxCalls)

Unsubscribes automatically after the handler processed a number of (filtered) events.

maxCalls
positive number of calls

Returns this builder

public Subscription handler(Consumer<? super E> handler)

Registers the handler.

handler
event handler

Returns the active subscription

io.github.crownalonedev.bloom.bukkit.platform

AdapterContext class

public final class AdapterContext

Information passed to PlatformAdapter.enable.

Since 0.1.0

5 members
public AdapterContext(Plugin plugin, PlatformInfo platform, Logger logger, boolean debug)

Creates a context.

plugin
owning plugin
platform
detected platform
logger
plugin logger
debug
whether verbose diagnostics are enabled
public Plugin plugin()

Returns the owning plugin.

Returns plugin

public PlatformInfo platform()

Returns the detected platform.

Returns platform

public Logger logger()

Returns the plugin logger.

Returns logger

public boolean debug()

Returns whether debug diagnostics are enabled.

Returns debug flag

io.github.crownalonedev.bloom.bukkit.platform

AdapterLoader class

public final class AdapterLoader

Loads the adapter for a platform family by class name. The class name is derived from the runtime package of this class, so it stays correct when plugins relocate Bloom (e.g. to com.example.libs.bloom). Only the selected family's class is ever loaded, which keeps Java 21 adapter bytecode away from Java 8 servers.

Since 0.1.0

2 members
public static String adapterClassName(PlatformFamily family)

Returns the fully qualified adapter class name for a family, relative to Bloom's runtime root package.

family
platform family

Returns class name, e.g. io.github.crownalonedev.bloom.platform.modern.ModernPlatformAdapter

public static PlatformAdapter load(PlatformFamily family, PlatformInfo platform)

Loads and instantiates an adapter.

family
selected family
platform
detected platform, used in error messages

Returns a new adapter instance (not yet enabled)

Throws BloomStartupException if the adapter is missing or cannot be loaded, with a corrective message

io.github.crownalonedev.bloom.bukkit.platform

ItemPlatform interface

public interface ItemPlatform

Adapter SPI for item operations that differ between versions. SPI: plugin code should use bloom-items. Methods guarded by a capability are only called by Bloom when it is present.

Since 0.1.0

13 members
public Optional<ItemStack> create(String materialName, short data, int amount)

Creates an item from an exact material constant name of the running server.

materialName
exact Material constant name on this server, e.g. "RED_WOOL" (modern) or "WOOL" (legacy)
data
legacy data/durability value; must be 0 on platforms without LEGACY_DATA_VALUES
amount
stack size

Returns the item, or empty if the material does not exist on this server

public void displayName(ItemMeta meta, FormattedText name)

Sets the display name.

meta
item meta to modify
name
prepared name
public void lore(ItemMeta meta, List<FormattedText> lore)

Replaces the lore.

meta
item meta to modify
lore
prepared lore lines
public List<String> addItemFlags(ItemMeta meta, Collection<String> flagNames)

Adds item flags by Bukkit ItemFlag constant name. Requires ITEM_FLAGS.

meta
item meta to modify
flagNames
constant names, e.g. "HIDE_ENCHANTS"

Returns names that do not exist on this server and were skipped

public void unbreakable(ItemMeta meta, boolean unbreakable)

Sets the unbreakable flag. Requires UNBREAKABLE_ITEMS.

meta
item meta to modify
unbreakable
value
public void customModelData(ItemMeta meta, int value)

Sets custom model data. Requires CUSTOM_MODEL_DATA.

meta
item meta to modify
value
model data value
public void glow(ItemMeta meta)

Makes the item glow like an enchanted item without showing an enchantment. Modern servers use the native glint override; legacy servers add a hidden enchantment (visible on 1.7.10, which lacks item flags).

meta
item meta to modify
public Optional<Enchantment> enchantment(String name)

Resolves an enchantment by modern key ("sharpness", "minecraft:sharpness") or legacy Bukkit name ("DAMAGE_ALL").

name
enchantment key or name, case-insensitive

Returns the enchantment, or empty if unknown on this server

public ItemStack writeData(ItemStack item, String namespace, String key, String value)

Writes a string value into the item's persistent data. Requires PERSISTENT_DATA_CONTAINER or ITEM_NBT_TAGS.

item
source item (not modified)
namespace
owning namespace, lowercase plugin name
key
key within the namespace, [a-z0-9._-]+
value
value to store

Returns a copy of the item carrying the value

public Optional<String> readData(ItemStack item, String namespace, String key)

Reads a string value from the item's persistent data.

item
item to read
namespace
owning namespace
key
key within the namespace

Returns the value, or empty if absent

public ItemStack removeData(ItemStack item, String namespace, String key)

Removes a value from the item's persistent data.

item
source item (not modified)
namespace
owning namespace
key
key within the namespace

Returns a copy of the item without the value

public String serialize(ItemStack item)

Serialises an item to a portable string for storage on the same platform family.

item
item to serialise

Returns serialised form with a format prefix

public ItemStack deserialize(String data)

Deserialises an item produced by serialize on the same platform family.

data
serialised form

Returns the item

Throws IllegalArgumentException if the data is malformed or from another family

io.github.crownalonedev.bloom.bukkit.platform

PlatformAdapter interface

public interface PlatformAdapter

A version adapter: the only place where version-specific Bukkit/Paper/NMS behaviour lives. SPI: implemented by bloom-legacy and bloom-modern; not intended for plugin code. Implementations must have a public no-argument constructor and must not touch server state in it. Bloom loads an adapter class by name only after SupportPolicy selected its family, so classes of other adapters are never loaded.

Since 0.1.0

7 members
public PlatformFamily family()

Returns the family this adapter serves.

Returns platform family

public String description()

Returns a short description for logs, e.g. "legacy (Bukkit 1.7.10-1.8.9)".

Returns description

public Capabilities enable(AdapterContext context)

Initialises the adapter and probes optional features. Called once on the main thread.

context
startup context

Returns capabilities available on this server

public void disable()

Releases adapter resources. Called once during Bloom shutdown, on the main thread.

public TextPlatform text()

Returns text rendering and delivery.

Returns text platform

public PlayerPlatform players()

Returns player and inventory operations.

Returns player platform

public ItemPlatform items()

Returns item operations.

Returns item platform

io.github.crownalonedev.bloom.bukkit.platform

PlatformDetector class

public final class PlatformDetector

Detects the server implementation and Minecraft version from what the server reports. Implementation detection uses class probes (without initialising classes) rather than the server name alone, because forks often report custom names.

Since 0.1.0

3 members
public static PlatformInfo detect(Server server)

Detects the platform of a running server.

server
the server

Returns platform description

Throws BloomStartupException if the Minecraft version cannot be determined

public static PlatformInfo detect(String serverName, String serverVersion, String bukkitVersion, String serverClassName, PlatformDetector.ClassProbe probe, JavaRuntime java)

Detects a platform from raw values.

serverName
Server#getName()
serverVersion
Server#getVersion()
bukkitVersion
Server#getBukkitVersion()
serverClassName
runtime class name of the Server implementation
probe
class presence probe
java
Java runtime

Returns platform description

Throws BloomStartupException if the Minecraft version cannot be determined

public static ServerSoftware detectSoftware(String serverName, String serverClassName, PlatformDetector.ClassProbe probe)

Identifies the server implementation.

serverName
Server#getName()
serverClassName
runtime class name of the server implementation
probe
class presence probe

Returns the implementation

io.github.crownalonedev.bloom.bukkit.platform

PlatformDetector.ClassProbe interface

public static interface ClassProbe

Probe for class presence; abstracted so detection logic is unit-testable without a server.

1 member
public boolean exists(String className)

Tests whether a class exists.

className
fully qualified class name

Returns true if loadable

io.github.crownalonedev.bloom.bukkit.platform

PlayerPlatform interface

public interface PlayerPlatform

Adapter SPI for player and inventory operations whose binary signatures differ between server versions. Examples: Bukkit.getOnlinePlayers() returns an array on 1.7.10 and a collection on 1.8+; InventoryView is a class before 1.21 and an interface after, so calling its methods from shared code would fail with IncompatibleClassChangeError.

Since 0.1.0

4 members
public Collection<? extends Player> onlinePlayers()

Returns the online players.

Returns snapshot of online players

public Inventory openTopInventory(Player player)

Returns the top inventory of the player's open inventory view.

player
player

Returns top inventory (the player's crafting inventory when no container is open)

public InventoryHolder holder(Inventory inventory)

Returns an inventory's holder as cheaply as possible. On Paper this avoids creating block-state snapshots, which matters because menu listeners inspect every inventory click on the server.

inventory
inventory

Returns holder, or null

public Inventory createInventory(InventoryHolder holder, int size, FormattedText title)

Creates a chest inventory.

holder
holder identifying the inventory
size
slot count, a multiple of 9 between 9 and 54
title
prepared title; legacy adapters truncate to 32 characters

Returns the inventory

io.github.crownalonedev.bloom.bukkit.platform

TextPlatform interface

public interface TextPlatform

Adapter SPI for rendering and delivering text. Implemented by each platform adapter. SPI: plugin code should use Messenger. Methods guarded by a capability are only called by Bloom when that capability is present.

Since 0.1.0

5 members
public void sendMessage(CommandSender target, FormattedText text)

Sends a chat message.

target
recipient (player or console)
text
prepared text
public void sendActionBar(Player player, FormattedText text)

Sends an action bar message. Requires ACTION_BAR.

player
recipient
text
prepared text
public void sendTitle(Player player, FormattedText title, FormattedText subtitle, Duration fadeIn, Duration stay, Duration fadeOut)

Shows a title. Requires TITLES; timings are honoured only with TITLE_TIMINGS.

player
recipient
title
prepared title
subtitle
prepared subtitle
fadeIn
fade-in
stay
stay
fadeOut
fade-out
public BloomBossBar createBossBar(FormattedText title, float progress, BossBarColor color, BossBarStyle style, TextPlatform.TitleRenderer renderer)

Creates a boss bar. Requires BOSS_BAR.

title
prepared title
progress
progress 0..1
color
colour
style
style
renderer
renders later title updates given as templates in the messenger's format

Returns a functional boss bar

public String toLegacyString(FormattedText text)

Renders text to a legacy § string, e.g. for APIs that only accept strings.

text
prepared text

Returns legacy formatted string

io.github.crownalonedev.bloom.bukkit.platform

TextPlatform.TitleRenderer interface

public static interface TitleRenderer

Converts a title template into prepared text using the owning messenger's settings.

1 member
public FormattedText render(String template)

Prepares a template.

template
template text

Returns prepared text

io.github.crownalonedev.bloom.bukkit.text

BloomBossBar interface

public interface BloomBossBar extends Terminable

A boss bar shown to a set of players. Created by Messenger.bossBar. Must be used from the main thread. Closing the bar hides it from all viewers; Bloom closes open bars on shutdown. On platforms without Capability.BOSS_BAR (with the SKIP policy) a no-op bar is returned whose isFunctional is false.

Since 0.1.0

8 members
public BloomBossBar title(String title)

Sets the title.

title
title in the owning messenger's format

Returns this bar

public BloomBossBar progress(float progress)

Sets the progress.

progress
value between 0.0 and 1.0

Returns this bar

Throws IllegalArgumentException if out of range

public BloomBossBar color(BossBarColor color)

Sets the colour.

color
colour

Returns this bar

public BloomBossBar style(BossBarStyle style)

Sets the style.

style
style

Returns this bar

public BloomBossBar show(Player player)

Shows the bar to a player.

player
viewer to add

Returns this bar

public BloomBossBar hide(Player player)

Hides the bar from a player.

player
viewer to remove

Returns this bar

public Collection<UUID> viewers()

Returns the current viewers.

Returns snapshot of viewer UUIDs

public boolean isFunctional()

Returns whether this bar actually renders on the current platform.

Returns false for the no-op fallback bar

io.github.crownalonedev.bloom.bukkit.text

BossBarColor enum

public final enum BossBarColor

Boss bar colours. Mapped to the platform's boss bar API by the adapter.

Since 0.1.0

9 members
public static BossBarColor[] values()
public static BossBarColor valueOf(String name)
name
String
PINK

Pink.

BLUE

Blue.

RED

Red.

GREEN

Green.

YELLOW

Yellow.

PURPLE

Purple.

WHITE

White.

io.github.crownalonedev.bloom.bukkit.text

BossBarStyle enum

public final enum BossBarStyle

Boss bar segment styles.

Since 0.1.0

7 members
public static BossBarStyle[] values()
public static BossBarStyle valueOf(String name)
name
String
SOLID

A single solid bar.

SEGMENTED_6

Six segments.

SEGMENTED_10

Ten segments.

SEGMENTED_12

Twelve segments.

SEGMENTED_20

Twenty segments.

io.github.crownalonedev.bloom.bukkit.text

FormattedText class

public final class FormattedText

Text whose placeholders have been applied and which is ready for an adapter to render. For TextFormat.MINIMESSAGE, content is MiniMessage markup. For TextFormat.LEGACY, it is a §-formatted string (& codes already translated). Plugin code normally never creates this directly; Messenger and the item/menu builders do.

Since 0.1.0

6 members
public static FormattedText prepare(String template, TextFormat format, boolean hexSupported, Placeholder... placeholders)

Applies placeholders to a template.

template
message template in format
format
template format
hexSupported
whether &#RRGGBB may produce real RGB colours
placeholders
placeholder values

Returns prepared text

public static FormattedText ofPrepared(String content, TextFormat format)

Wraps already-prepared content.

content
prepared content (MiniMessage markup or § string)
format
format of content

Returns text

public String content()

Returns the prepared content.

Returns MiniMessage markup or a §-formatted string, depending on format

public TextFormat format()

Returns the content format.

Returns format

public boolean isEmpty()

Returns whether the content is empty.

Returns true if empty

public String toString()

io.github.crownalonedev.bloom.bukkit.text

Messenger class

public final class Messenger

Sends formatted text to players and the console on every supported platform. Obtain the default instance with bloom.messages(); derive variants with withPrefix, withFormat and withUnsupportedPolicy. Messengers are immutable and thread-safe. Messenger messages = bloom.messages().withPrefix("&d&lBloom &8» "); messages.send(player, "&7Welcome back, &f{player}&7!", Placeholder.of("player", player.getName())); messages.actionBar(player, "&aSaved!"); messages.title(player, Title.of("&dLevel up", "&7You reached level {level}"), Placeholder.of("level", 5)); Threads Chat, action bars and titles may be sent from any thread. Boss bars must be created and changed on the main thread. Unsupported features Action bars, titles and boss bars depend on capabilities. When one is missing, behaviour follows the UnsupportedFeaturePolicy: skip with a one-time warning (default), fall back to chat, or throw.

Since 0.1.0

15 members
public Messenger(TextPlatform text, PlayerPlatform players, Capabilities capabilities, Logger logger, Consumer<AutoCloseable> closeOnShutdown, TextFormat format, UnsupportedFeaturePolicy policy)

Creates a messenger. Internal: plugin code obtains messengers from bloom.messages().

text
adapter text platform
players
adapter player platform
capabilities
platform capabilities
logger
plugin logger
closeOnShutdown
registers boss bars so they are closed at shutdown
format
default format
policy
default unsupported-feature policy
public TextFormat format()

Returns the text format this messenger parses templates with.

Returns format

public String prefix()

Returns the chat prefix template.

Returns prefix, empty if none

public UnsupportedFeaturePolicy unsupportedPolicy()

Returns the unsupported-feature policy.

Returns policy

public Messenger withFormat(TextFormat newFormat)

Returns a messenger that parses templates in another format.

newFormat
format

Returns derived messenger

public Messenger withPrefix(String newPrefix)

Returns a messenger that prepends a prefix to chat messages (not to action bars, titles or boss bars). The prefix is written in this messenger's format.

newPrefix
prefix template, e.g. "&d[Shop] "

Returns derived messenger

public Messenger withUnsupportedPolicy(UnsupportedFeaturePolicy newPolicy)

Returns a messenger with another unsupported-feature policy.

newPolicy
policy

Returns derived messenger

public FormattedText render(String template, Placeholder... placeholders)

Applies placeholders to a template using this messenger's format.

template
template text
placeholders
placeholders

Returns prepared text for adapter APIs

public String legacy(String template, Placeholder... placeholders)

Renders a template to a legacy §-formatted string, for APIs that only accept strings (scoreboards, signs on old versions).

template
template text
placeholders
placeholders

Returns legacy string

public void send(CommandSender recipient, String message, Placeholder... placeholders)

Sends a chat message with this messenger's prefix.

recipient
player or console
message
message template
placeholders
placeholder values
public void send(Iterable<? extends CommandSender> recipients, String message, Placeholder... placeholders)

Sends a chat message to several recipients. The template is rendered once.

recipients
players or console
message
message template
placeholders
placeholder values
public void broadcast(String message, Placeholder... placeholders)

Sends a chat message to every online player and the console.

message
message template
placeholders
placeholder values
public boolean actionBar(Player player, String message, Placeholder... placeholders)

Shows an action bar message.

player
recipient
message
message template (no prefix is added)
placeholders
placeholder values

Returns true if delivered as an action bar or as a chat fallback

Throws UnsupportedCapabilityException if unsupported and the policy is THROW

public boolean title(Player player, Title title, Placeholder... placeholders)

Shows a title.

player
recipient
title
title and subtitle templates with timings
placeholders
placeholder values, applied to both lines

Returns true if delivered as a title or as a chat fallback

Throws UnsupportedCapabilityException if unsupported and the policy is THROW

public BloomBossBar bossBar(String title, float progress, BossBarColor color, BossBarStyle style, Placeholder... placeholders)

Creates a boss bar. Show it to players with BloomBossBar.show. Must be called on the main thread. Bloom closes the bar on shutdown.

title
title template
progress
progress between 0 and 1
color
colour
style
style
placeholders
placeholder values for the initial title

Returns a boss bar, or a non-functional bar (BloomBossBar.isFunctional is false) when boss bars are unsupported and the policy is not THROW

Throws UnsupportedCapabilityException if unsupported and the policy is THROW

io.github.crownalonedev.bloom.bukkit.text

Title class

public final class Title

A title/subtitle pair with display timings. Timings require Capability.TITLE_TIMINGS; on 1.8 servers the client's default timings are used (fade in 0.5s, stay 3.5s, fade out 1s) and custom timings are ignored. messenger.title(player, Title.of("&dWelcome", "&7to the server")); messenger.title(player, Title.of("<gold>Victory").times(Duration.ofMillis(250), Duration.ofSeconds(2), Duration.ofMillis(500)));

Since 0.1.0

11 members
public static final Duration DEFAULT_FADE_IN

Default fade-in time, matching the vanilla client.

public static final Duration DEFAULT_STAY

Default stay time, matching the vanilla client.

public static final Duration DEFAULT_FADE_OUT

Default fade-out time, matching the vanilla client.

public static Title of(String title)

Creates a title without a subtitle and with default timings.

title
title text in the messenger's format

Returns the title

public static Title of(String title, String subtitle)

Creates a title with a subtitle and default timings.

title
title text in the messenger's format
subtitle
subtitle text in the messenger's format

Returns the title

public Title times(Duration fadeIn, Duration stay, Duration fadeOut)

Returns a copy with custom timings.

fadeIn
fade-in duration
stay
stay duration
fadeOut
fade-out duration

Returns a new title

public String title()

Returns the title template.

Returns title text

public String subtitle()

Returns the subtitle template.

Returns subtitle text, possibly empty

public Duration fadeIn()

Returns the fade-in duration.

Returns fade-in

public Duration stay()

Returns the stay duration.

Returns stay

public Duration fadeOut()

Returns the fade-out duration.

Returns fade-out

bloom-items

Bloom Items: item builder, cross-version materials, persistent item identity and serialization.

io.github.crownalonedev.bloom.items

CustomItem class

public final class CustomItem

A custom item defined with Items.define.

Since 0.1.0

5 members
public String id()

Returns the custom id.

Returns id

public ItemStack create()

Creates one item.

Returns a new stack of size 1

public ItemStack create(int amount)

Creates a stack.

amount
stack size, >= 1

Returns a new stack

public boolean matches(ItemStack item)

Returns whether an item is an instance of this custom item, by persistent id (not by name or lore).

item
item, may be null

Returns true if the item carries this id

public String toString()

io.github.crownalonedev.bloom.items

ItemBuilder class

public final class ItemBuilder

Fluent, cross-version item builder. Created by Items.builder or Items.edit. Text (name, lore) uses the Bloom default TextFormat unless format is called, and renders white and non-italic unless the text sets its own colour. Features missing on the running server (e.g. custom model data on 1.8) follow the Bloom UnsupportedFeaturePolicy: skipped with a one-time warning by default. Builders are not thread-safe; build may be called repeatedly and returns a new item each time.

Since 0.1.0

17 members
public ItemBuilder amount(int newAmount)

Sets the stack size.

newAmount
amount, 1..64 (or the item's max stack size)

Returns this builder

public ItemBuilder name(String template)

Sets the display name.

template
name in the builder's text format, e.g. "&dBlossom Blade"

Returns this builder

public ItemBuilder lore(String... lines)

Replaces the lore.

lines
lore lines in the builder's text format

Returns this builder

public ItemBuilder lore(List<String> lines)

Replaces the lore.

lines
lore lines in the builder's text format

Returns this builder

public ItemBuilder addLore(String... lines)

Appends lore lines.

lines
lines to append

Returns this builder

public ItemBuilder enchant(String enchantment, int level)

Adds an enchantment by name. Accepts modern keys ("sharpness") and legacy Bukkit names ("DAMAGE_ALL"). Enchantments unknown on this server are skipped with a warning. Levels above the vanilla maximum are allowed.

enchantment
enchantment key or name
level
level, >= 1

Returns this builder

public ItemBuilder enchant(Enchantment enchantment, int level)

Adds an enchantment object from the API you compile against.

enchantment
enchantment
level
level, >= 1

Returns this builder

public ItemBuilder flags(ItemFlagKey... newFlags)

Adds item flags. Requires ITEM_FLAGS (1.8+).

newFlags
flags

Returns this builder

public ItemBuilder glow()

Makes the item glow without visible enchantments (see ItemPlatform#glow).

Returns this builder

public ItemBuilder unbreakable(boolean value)

Sets the unbreakable flag. Requires UNBREAKABLE_ITEMS.

value
unbreakable

Returns this builder

public ItemBuilder customModelData(int value)

Sets custom model data. Requires CUSTOM_MODEL_DATA (modern only).

value
model data

Returns this builder

public ItemBuilder data(String key, String value)

Stores a string in the item's persistent data under the plugin namespace.

key
key, [a-z0-9._-]+
value
value

Returns this builder

public ItemBuilder customId(String id)

Marks the item with a custom id (see Items.customId).

id
custom id

Returns this builder

public ItemBuilder placeholders(Placeholder... values)

Sets placeholders applied to the name and lore.

values
placeholders

Returns this builder

public ItemBuilder format(TextFormat textFormat)

Sets the text format for name and lore.

textFormat
format

Returns this builder

public ItemBuilder meta(Consumer<ItemMeta> editor)

Applies a custom edit to the Bukkit ItemMeta after Bloom's own settings. Use for features Bloom does not wrap (leather colour, skull owner, ...). Code here must be valid for every server version you target.

editor
meta editor

Returns this builder

public ItemStack build()

Builds a new item.

Returns the item

io.github.crownalonedev.bloom.items

ItemFlagKey enum

public final enum ItemFlagKey

Cross-version item flags. Each key maps to the Bukkit ItemFlag constant(s) that implement it on different versions; flags that do not exist on the running server are skipped. Requires Capability.ITEM_FLAGS (1.8+).

Since 0.1.0

12 members
public static ItemFlagKey[] values()
public static ItemFlagKey valueOf(String name)
name
String
HIDE_ENCHANTS

Hides enchantments.

HIDE_ATTRIBUTES

Hides attribute modifiers such as attack damage.

HIDE_UNBREAKABLE

Hides the "Unbreakable" line.

HIDE_DESTROYS

Hides "Can destroy" lines.

HIDE_PLACED_ON

Hides "Can be placed on" lines.

HIDE_ADDITIONAL_TOOLTIP

Hides potion effects and other additional tooltip lines (1.8 HIDE_POTION_EFFECTS, modern HIDE_ADDITIONAL_TOOLTIP).

HIDE_DYE

Hides leather armour dye colour (modern only).

HIDE_ARMOR_TRIM

Hides armour trims (modern only).

HIDE_STORED_ENCHANTS

Hides stored enchantments on enchanted books (modern only).

public List<String> bukkitNames()

Returns the Bukkit ItemFlag names that implement this flag, newest first.

Returns candidate constant names

io.github.crownalonedev.bloom.items

Items class

public final class Items

Cross-version item creation, identification and serialization. Items items = Items.of(bloom); ItemStack sword = items.builder("DIAMOND_SWORD") .name("&dBlossom Blade") .lore("&7Forged under falling petals.") .enchant("sharpness", 3) .flags(ItemFlagKey.HIDE_ENCHANTS) .unbreakable(true) .build(); CustomItem ruby = items.define("ruby", items.builder("RED_DYE").name("&cRuby").glow()); player.getInventory().addItem(ruby.create(3)); boolean isRuby = ruby.matches(player.getItemInHand()); Identity Custom ids and data are stored as namespaced persistent data, never in names or lore: PersistentDataContainer on modern servers, NBT on legacy servers. The namespace is the owning plugin's lowercase name. Data written on one platform family cannot be read on the other.

Since 0.1.0

22 members
public static final String ID_KEY

Data key used for custom item ids.

public static Items of(Bloom bloom)

Returns the items service of a Bloom instance, creating it on first use.

bloom
running Bloom instance

Returns the service

public ItemBuilder builder(String materialKey)

Starts building an item.

materialKey
modern material name (legacy names and NAME:DATA accepted); see MaterialMappings

Returns a builder

Throws IllegalArgumentException if the material does not exist on this server

public ItemBuilder builder(Material material)

Starts building from a Bukkit material constant of the API you compile against.

material
material

Returns a builder

public ItemBuilder edit(ItemStack item)

Starts editing a copy of an existing item. Name and lore are kept unless the builder sets them.

item
item to copy

Returns a builder

public Optional<ItemStack> create(String materialKey, int amount)

Creates a plain item.

materialKey
material key
amount
stack size

Returns the item, or empty if the material does not exist on this server

public boolean exists(String materialKey)

Returns whether a material key resolves on this server.

materialKey
material key

Returns true if create would succeed

public MaterialMappings materials()

Returns the material mappings, where custom keys can be registered.

Returns mappings

public String namespace()

Returns the persistent data namespace (lowercase plugin name).

Returns namespace

public boolean supportsData()

Returns whether items can carry persistent data on this server.

Returns true with PersistentDataContainer (modern) or NBT access (legacy)

public ItemStack setData(ItemStack item, String key, String value)

Returns a copy of an item with a string value stored under this plugin's namespace.

item
source item (unchanged)
key
key, [a-z0-9._-]+
value
value

Returns tagged copy

Throws UnsupportedCapabilityException if items cannot carry data on this server

public Optional<String> getData(ItemStack item, String key)

Reads a value stored by setData.

item
item, may be null
key
key

Returns the value, or empty

public ItemStack removeData(ItemStack item, String key)

Returns a copy of an item without a stored value.

item
source item (unchanged)
key
key

Returns copy without the key

public ItemStack tag(ItemStack item, String id)

Returns a copy of an item marked with a custom id.

item
source item
id
custom id, [a-z0-9._-]+

Returns tagged copy

public Optional<String> customId(ItemStack item)

Returns the custom id of an item.

item
item, may be null

Returns id, or empty if the item has none

public boolean isCustom(ItemStack item, String id)

Returns whether an item carries a custom id.

item
item, may be null
id
expected id

Returns true if the ids match

public CustomItem define(String id, ItemBuilder template)

Defines a custom item. The template is built once and tagged with the id; CustomItem.create returns copies.

id
unique id, [a-z0-9._-]+
template
builder describing the item

Returns the definition

Throws IllegalStateException if the id is already defined

public Optional<CustomItem> custom(String id)

Looks up a custom item definition.

id
custom id

Returns the definition, or empty

public Optional<CustomItem> match(ItemStack item)

Finds the custom item definition an item stack belongs to.

item
item, may be null

Returns the definition, or empty for plain items and unknown ids

public Collection<CustomItem> customItems()

Returns all custom item definitions.

Returns snapshot in definition order

public String serialize(ItemStack item)

Serialises an item to a string for storage (databases, configs). The format is platform-family specific.

item
non-empty item

Returns serialised item

public ItemStack deserialize(String data)

Deserialises an item created by serialize on the same platform family.

data
serialised item

Returns the item

Throws IllegalArgumentException if malformed or from the other platform family

io.github.crownalonedev.bloom.items

MaterialMappings class

public final class MaterialMappings

Resolves Bloom material keys to the material names of the running server. Keys are modern (1.13+) material names , e.g. RED_WOOL, PLAYER_HEAD, OAK_PLANKS. Legacy names (WATCH) and legacy NAME:DATA specs (WOOL:14) are accepted too. Resolution order: • legacy servers: developer mapping → built-in modern→legacy table → the key itself → NAME:DATA • modern servers: developer mapping → the key itself → built-in legacy→modern table So an ambiguous name such as MELON always means the modern item (the block) on every server. Thread-safe.

Since 0.1.0

3 members
public MaterialMappings register(String key, String modernName, String legacyName, int legacyData)

Registers or replaces a mapping for a key.

key
Bloom key used in code/configs, e.g. "SHOP_ICON" or a modern material name
modernName
material name on modern servers, or null if not available there
legacyName
material name on legacy servers, or null if not available there
legacyData
legacy data value

Returns this instance

public List<MaterialMappings.Candidate> candidates(String key, boolean legacyPlatform)

Returns the names to try, in order, for a key on the given platform family.

key
material key
legacyPlatform
whether the server uses legacy data values

Returns ordered, de-duplicated candidates (never empty)

public static int builtinSize()

Returns the number of built-in table rows (for diagnostics).

Returns number of built-in modern→legacy mappings

io.github.crownalonedev.bloom.items

MaterialMappings.Candidate class

public static final class Candidate

A concrete material name and legacy data value to try on the running server.

5 members
public String name()

Returns the server material name.

Returns material constant name

public short data()

Returns the legacy data value.

Returns data value, 0 on modern servers

public boolean equals(Object o)
o
Object
public int hashCode()
public String toString()

bloom-gui

Bloom GUI: inventory menus with buttons, layouts, pagination, navigation and duplication-safe event handling.

io.github.crownalonedev.bloom.gui

Button class

public final class Button

An item in a menu slot with an optional click handler. Buttons are immutable; the with*/on* methods return modified copies, so one button can be reused in many menus. Button heal = Button.of(items.builder("GOLDEN_APPLE").name("&aHeal").build()) .permission("shop.heal") .onClick(click -> { click.player().setHealth(20.0); click.close(); }); Button counter = Button.dynamic(view -> items.builder("PAPER") .name("&fClicks: " + view.state().getOrDefault(CLICKS, 0)).build()) .onClick(click -> { click.view().state().set(CLICKS, click.view().state().getOrDefault(CLICKS, 0) + 1); click.refresh(); });

Since 0.1.0

7 members
public static Button of(ItemStack item)

Creates a button with a fixed item and no click action (a decoration).

item
item to display (copied when rendered)

Returns the button

public static Button of(ItemStack item, Consumer<ClickContext> onClick)

Creates a button with a fixed item and a click action.

item
item to display
onClick
click handler, runs on the main thread

Returns the button

public static Button dynamic(Function<MenuView,ItemStack> icon)

Creates a button whose item is computed for each viewer on every render (open, refresh, page change).

icon
computes the item; may return null for an empty slot

Returns the button

public Button onClick(Consumer<ClickContext> onClick)

Returns a copy with a click handler. Handlers run on the main thread; exceptions are logged and do not break the menu.

onClick
click handler

Returns a new button

public Button visibleWhen(Predicate<MenuView> condition)

Returns a copy that is only shown when a condition holds (evaluated on each render). Hidden buttons leave the slot to the menu's filler.

condition
visibility condition

Returns a new button

public Button permission(String node)

Returns a copy that is hidden from players without a permission.

node
permission node

Returns a new button

public Button permission(String node, ItemStack deniedItem)

Returns a copy that shows deniedItem (without running the click handler) to players lacking a permission.

node
permission node
deniedItem
item shown instead

Returns a new button

io.github.crownalonedev.bloom.gui

ClickContext class

public final class ClickContext

Information about a button click, passed to Button.onClick handlers. The underlying Bukkit event is always cancelled; items never move in or out of a Bloom menu. Navigation methods (open, back, close) take effect on the next tick, because opening or closing inventories inside a click event is unsafe on Bukkit servers.

Since 0.1.0

11 members
public Player player()

Returns the clicking player.

Returns player

public MenuView view()

Returns the player's view of the menu (page, state).

Returns view

public Menu menu()

Returns the menu definition.

Returns menu

public int slot()

Returns the clicked slot.

Returns slot index in the menu

public ClickKind kind()

Returns the kind of click.

Returns click kind

public int hotbarButton()

Returns the number key pressed for ClickKind.NUMBER_KEY clicks.

Returns hotbar slot 0-8, or -1

public Menus menus()

Returns the menu service.

Returns menus

public void refresh()

Re-renders the current menu for this player.

public void open(Menu menu)

Opens another menu on the next tick. The current menu is kept in the history for back.

menu
menu to open
public boolean back()

Goes back to the previous menu on the next tick.

Returns true if there is a previous menu

public void close()

Closes the menu on the next tick.

io.github.crownalonedev.bloom.gui

ClickKind enum

public final enum ClickKind

Version-independent click types. Mapped from Bukkit's ClickType by name, so constants added in newer versions never cause linkage errors on older servers.

Since 0.1.0

15 members
public static ClickKind[] values()
public static ClickKind valueOf(String name)
name
String
LEFT

Left click.

RIGHT

Right click.

SHIFT_LEFT

Shift + left click.

SHIFT_RIGHT

Shift + right click.

MIDDLE

Middle click (creative pick).

NUMBER_KEY

Number key 1-9; see ClickContext.hotbarButton.

DROP

Drop key (Q).

CONTROL_DROP

Control + drop key.

SWAP_OFFHAND

Off-hand swap key (F), 1.16+.

OTHER

Any other click (creative, window border, unknown).

public boolean isLeft()

Returns whether this is a left click (with or without shift).

Returns true for LEFT and SHIFT_LEFT

public boolean isRight()

Returns whether this is a right click (with or without shift).

Returns true for RIGHT and SHIFT_RIGHT

public boolean isShift()

Returns whether shift was held.

Returns true for shift clicks

io.github.crownalonedev.bloom.gui

ConfirmMenu class

public final class ConfirmMenu

Builds yes/no confirmation dialogs. Menu confirm = ConfirmMenu.builder() .title("&cDelete home '{home}'?") .confirm(items.builder("LIME_WOOL").name("&aDelete").build(), click -> { homes.delete(click.player(), name); click.close(); }) .cancel(items.builder("RED_WOOL").name("&cKeep").build()) .build(); click.open(confirm); The default cancel action goes back to the previous menu, or closes the dialog if there is none. Clicking confirm repeatedly is guarded by the menu click debounce.

Since 0.1.0

8 members
public static ConfirmMenu builder()

Starts a dialog.

Returns builder

public ConfirmMenu title(String template)

Sets the title.

template
title template

Returns this builder

public ConfirmMenu confirm(ItemStack item, Consumer<ClickContext> action)

Sets the confirm button.

item
confirm item
action
runs when confirmed

Returns this builder

public ConfirmMenu cancel(ItemStack item)

Sets the cancel item with the default action (back, or close).

item
cancel item

Returns this builder

public ConfirmMenu cancel(ItemStack item, Consumer<ClickContext> action)

Sets the cancel button.

item
cancel item
action
runs when cancelled

Returns this builder

public ConfirmMenu info(ItemStack item)

Shows an informational item in the centre.

item
info item

Returns this builder

public ConfirmMenu fill(Button button)

Fills empty slots.

button
filler

Returns this builder

public Menu build()

Builds the dialog as a 3-row menu (confirm at slot 11, info at 13, cancel at 15).

Returns menu

io.github.crownalonedev.bloom.gui

Menu class

public final class Menu

An immutable chest menu definition. One Menu can be opened by many players at once; each gets its own MenuView with its own page and MenuState. Menu shop = Menu.builder() .title("&d&lBlossom Shop") .rows(3) .layout( "#########", "# a b #", "#########") .bind('#', Button.of(filler)) .bind('a', healButton) .bind('b', feedButton) .build(); Menus.of(bloom).open(player, shop); Titles may use {player}, {page} and {pages} placeholders. On 1.7/1.8 titles are limited to 32 characters including colour codes and are truncated with a warning.

Since 0.1.0

5 members
public static Menu.Builder builder()

Starts a menu definition.

Returns a builder (defaults: 3 rows, empty title)

public String title()

Returns the title template.

Returns title

public int rows()

Returns the number of rows.

Returns rows, 1-6

public int size()

Returns the slot count.

Returns rows() * 9

public boolean isPaginated()

Returns whether this menu has pages.

Returns true if built with Builder.paginate

io.github.crownalonedev.bloom.gui

Menu.Builder class

public static final class Builder

Builder for Menu. Not thread-safe.

20 members
public Menu.Builder title(String template)

Sets the title.

template
title template; supports {player}, {page}, {pages}

Returns this builder

public Menu.Builder rows(int count)

Sets the number of rows.

count
1 to 6

Returns this builder

public Menu.Builder format(TextFormat textFormat)

Sets the text format of the title (defaults to the Bloom default format).

textFormat
format

Returns this builder

public Menu.Builder button(int slot, Button button)

Places a button, replacing any previous button in the slot.

slot
slot index, 0..size-1
button
button

Returns this builder

public Menu.Builder button(int row, int column, Button button)

Places a button by row and column (both zero-based).

row
row, 0..rows-1
column
column, 0..8
button
button

Returns this builder

public Menu.Builder item(int slot, ItemStack item)

Places a decorative item.

slot
slot index
item
item

Returns this builder

public Menu.Builder border(Button button)

Places a button in every border slot that is still empty (first/last row and first/last column).

button
border button, usually a filler pane

Returns this builder

public Menu.Builder fill(Button button)

Sets a filler used for every slot that ends up empty after buttons, pagination and hidden buttons are resolved. Content slots of paginated menus are only filled when the current page has no item there.

button
filler button

Returns this builder

public Menu.Builder layout(String... rowPatterns)

Describes the menu with one string per row (exactly 9 characters each). Characters are bound to buttons with bind; spaces are empty slots. Also sets the row count.

rowPatterns
one pattern per row

Returns this builder

public Menu.Builder bind(char symbol, Button button)

Binds a layout character to a button.

symbol
layout character
button
button

Returns this builder

public Menu.Builder apply(MenuTemplate template)

Applies a reusable template.

template
template

Returns this builder

public Menu.Builder paginate(Function<MenuView,List<Button>> source)

Makes the menu paginated. The source is called on every render and returns all content buttons; Bloom slices them into pages.

source
content for a view (the viewer is view.player())

Returns this builder

public Menu.Builder contentSlots(int... slots)

Sets the slots that show paginated content, in order. Default: every slot without a button.

slots
content slots

Returns this builder

public Menu.Builder contentSlots(char symbol)

Uses every occurrence of a layout character as a content slot.

symbol
layout character

Returns this builder

public Menu.Builder previousPage(int slot, ItemStack item)

Shows a "previous page" button in a slot when a previous page exists.

slot
slot index
item
button item

Returns this builder

public Menu.Builder nextPage(int slot, ItemStack item)

Shows a "next page" button in a slot when a next page exists.

slot
slot index
item
button item

Returns this builder

public Menu.Builder onOpen(Consumer<MenuView> handler)

Runs code after the menu was opened for a player (main thread).

handler
handler

Returns this builder

public Menu.Builder onClose(Consumer<MenuView> handler)

Runs code after the menu was closed for a player, including when navigating to another menu, on disconnect and on plugin shutdown (main thread).

handler
handler

Returns this builder

public Menu.Builder refreshEvery(long ticks)

Re-renders the menu for each viewer every ticks ticks while it is open (e.g. countdowns).

ticks
period, >= 1

Returns this builder

public Menu build()

Builds the menu.

Returns immutable menu

io.github.crownalonedev.bloom.gui

MenuState class

public final class MenuState

Per-player state of one open menu. It survives refreshes, page changes and back-navigation to the same view, and is discarded when the player closes the menu. Main thread only.

Since 0.1.0

5 members
public <T> Optional<T> get(StateKey<T> key)

Returns a value.

key
key

Returns the value, or empty

public <T> T getOrDefault(StateKey<T> key, T fallback)

Returns a value or a default.

key
key
fallback
value returned when absent

Returns the value or fallback

public <T> void set(StateKey<T> key, T value)

Stores a value.

key
key
value
value, or null to remove
public void remove(StateKey<?> key)

Removes a value.

key
key
public boolean has(StateKey<?> key)

Returns whether a value is present.

key
key

Returns true if present

io.github.crownalonedev.bloom.gui

MenuTemplate interface

public interface MenuTemplate

A reusable piece of menu layout, applied with Menu.Builder.apply. MenuTemplate branded = builder -> builder .border(Button.of(pinkPane)) .button(4, Button.of(logo)); Menu menu = Menu.builder().rows(5).apply(branded).title("&dProfile").build();

Since 0.1.0

1 member
public void apply(Menu.Builder builder)

Applies this template to a builder.

builder
menu builder

io.github.crownalonedev.bloom.gui

MenuTemplates class

public final class MenuTemplates

Ready-made MenuTemplates.

Since 0.1.0

3 members
public static MenuTemplate border(Button button)

Fills the border with a button (only empty slots).

button
border button

Returns template

public static MenuTemplate fill(Button button)

Fills every slot that ends up empty.

button
filler button

Returns template

public static MenuTemplate paged(int rows, Button border, ItemStack previous, ItemStack next, Button close)

Standard paginated layout for rows rows: content in the inner area, a border, previous/next buttons in the bottom-left and bottom-right corners and an optional close button in the bottom centre.

rows
rows (3-6)
border
border button
previous
previous-page item
next
next-page item
close
close button, or null

Returns template; combine with Menu.Builder.paginate

io.github.crownalonedev.bloom.gui

MenuView class

public final class MenuView

One player's instance of an open Menu: the current page, per-player MenuState and the rendered inventory. Main thread only.

Since 0.1.0

13 members
public Player player()

Returns the viewer.

Returns player

public Menu menu()

Returns the menu definition.

Returns menu

public MenuState state()

Returns this view's state.

Returns state

public int page()

Returns the zero-based current page.

Returns page

public int pageCount()

Returns the number of pages computed at the last render.

Returns page count, at least 1

public boolean hasNextPage()

Returns whether a next page exists.

Returns true if page() < pageCount() - 1

public boolean hasPreviousPage()

Returns whether a previous page exists.

Returns true if page() > 0

public void page(int newPage)

Switches to a page (clamped to the valid range) and re-renders.

newPage
zero-based page
public void nextPage()

Switches to the next page if there is one.

public void previousPage()

Switches to the previous page if there is one.

public void refresh()

Re-renders the menu for this viewer. Items are updated in place; if the rendered title changed (for example a page number in the title) the inventory is reopened on the next tick, keeping navigation history.

public boolean isOpen()

Returns whether this view is currently shown to the player.

Returns true while open

public Inventory inventory()

Returns the rendered inventory.

Returns inventory, or null before the first render

io.github.crownalonedev.bloom.gui

Menus class

public final class Menus implements AutoCloseable

Opens and manages menus. Obtain with of; the service registers its own listeners, so no per-menu listener registration is needed. Safety guarantees • Every click and drag while a Bloom menu is open is cancelled (including shift-click, number-key swaps, double-click collection and clicks in the player's own inventory), and the cancellation is re-applied at HIGHEST priority if another plugin un-cancels it. Items cannot be taken out of or put into a menu. • Button handlers run at most once per click and are debounced per player (100 ms by default; see clickDebounce) to stop double-triggered purchases from spam clicking. • On legacy servers the player's inventory is resynchronised after cancelled clicks to remove client-side ghost items. • Sessions are cleaned up on close, disconnect and plugin shutdown; open menus are closed on shutdown. All methods must be called on the main thread.

Since 0.1.0

10 members
public static Menus of(Bloom bloom)

Returns the menu service of a Bloom instance, creating it (and registering its listeners) on first use.

bloom
running Bloom instance

Returns the service

public Menus clickDebounce(Duration debounce)

Sets the minimum time between two handled button clicks of the same player.

debounce
debounce, Duration.ZERO to disable

Returns this service

public MenuView open(Player player, Menu menu)

Opens a menu. If the player is viewing another Bloom menu, it is kept in the history for back. Do not call this from inside a click handler; use ClickContext.open instead.

player
viewer
menu
menu to open

Returns the player's view; MenuView.isOpen is false if another plugin cancelled the opening

public boolean back(Player player)

Returns to the previous menu in the player's history.

player
viewer

Returns true if a previous menu was opened

public void close(Player player)

Closes the player's Bloom menu, if one is open.

player
viewer
public void refresh(Player player)

Re-renders the player's open menu.

player
viewer
public int refreshAll(Menu menu)

Re-renders a menu for everyone currently viewing it.

menu
menu

Returns number of refreshed viewers

public Optional<MenuView> view(Player player)

Returns the player's open Bloom menu view.

player
player

Returns the view, or empty

public int openCount()

Returns how many players have a Bloom menu open.

Returns open view count

public void close()

Closes all open menus and unregisters the listeners. Called automatically when Bloom shuts down.

io.github.crownalonedev.bloom.gui

StateKey class

public final class StateKey<T>

A typed key for per-player menu state. static final StateKey<Integer> QUANTITY = StateKey.of("quantity", Integer.class); int quantity = view.state().getOrDefault(QUANTITY, 1); view.state().set(QUANTITY, quantity + 1);

Since 0.1.0

4 members
public static <T> StateKey<T> of(String name, Class<T> type)

Creates a key. Keys are compared by identity, so declare them as constants.

name
descriptive name used in toString()
type
value type

Returns a new key

public String name()

Returns the key name.

Returns name

public Class<T> type()

Returns the value type.

Returns type

public String toString()

bloom-config

Bloom Config: YAML configuration with defaults, validation, object mapping, comment-preserving saves and migrations.

io.github.crownalonedev.bloom.config

ConfigException class

public class ConfigException extends BloomException

Thrown for configuration problems: unreadable YAML, missing or mistyped values, failed validation or migration. Messages name the file, the key path and, when known, the line number.

Since 0.1.0

4 members
public ConfigException(String message)

Creates an exception with one problem.

message
description including file/path/line
public ConfigException(String message, Throwable cause)

Creates an exception with a cause.

message
description
cause
cause
public ConfigException(String summary, List<String> problems)

Creates an exception listing several problems (validation).

summary
first line of the message
problems
individual problems
public List<String> problems()

Returns the individual problems.

Returns problems, at least one

io.github.crownalonedev.bloom.config

ConfigKey annotation

public abstract @interface ConfigKey implements Annotation

Overrides the YAML key of a mapped field. Without it, field names are converted from camelCase to kebab-case (maxHomes → max-homes).

Since 0.1.0

1 member
public abstract String value()

Returns the YAML key.

Returns key

io.github.crownalonedev.bloom.config

ConfigMigration interface

public interface ConfigMigration

Upgrades a configuration from one version to the next. Registered with YamlConfig.Builder.migration. YamlConfig config = YamlConfig.builder(file) .defaults(() -> plugin.getResource("config.yml")) .version(3) .migration(1, m -> m.move("prefix", "messages.prefix")) // v1 -> v2 .migration(2, m -> m.set("storage.type", m.has("mysql") ? "mysql" : "sqlite")) // v2 -> v3 .build();

Since 0.1.0

1 member
public void migrate(MigrationContext context)

Applies the migration to the configuration values.

context
mutable view of the values being migrated

io.github.crownalonedev.bloom.config

ConfigSection class

public class ConfigSection

Typed, path-based access to a section of a YamlConfig. Paths are dot-separated ("database.host") and relative to this section. Defaults A value missing from the file falls back to the bundled defaults. Required getters (getString(path)) throw ConfigException when the value is missing in both; getters with a fallback argument return the fallback. Errors Type mismatches throw ConfigException naming the file, path, line and the expected type, e.g. config.yml line 7: 'limits.homes' expected a whole number but found 'ten'. All methods are thread-safe.

Since 0.1.0

26 members
public String path()

Returns this section's path from the root.

Returns path, empty for the root

public boolean has(String path)

Returns whether a value exists in the file or the defaults.

path
relative path

Returns true if present

public boolean isSet(String path)

Returns whether a value exists in the file itself (ignoring defaults).

path
relative path

Returns true if set in the file

public Set<String> keys()

Returns the keys of this section. If the section exists in the file, only the file's keys are returned (a section a user trimmed is not refilled from defaults); otherwise the defaults' keys.

Returns keys in file order

public ConfigSection section(String path)

Returns a child section.

path
relative path

Returns the section

Throws ConfigException if the path holds a value that is not a section, or is missing

public Optional<ConfigSection> optionalSection(String path)

Returns a child section if present.

path
relative path

Returns the section, or empty

public String getString(String path)

Returns a required string.

path
relative path

Returns value

public String getString(String path, String fallback)

Returns a string or a fallback.

path
relative path
fallback
returned when missing

Returns value

public int getInt(String path)

Returns a required int.

path
relative path

Returns value

public int getInt(String path, int fallback)

Returns an int or a fallback.

path
relative path
fallback
returned when missing

Returns value

public long getLong(String path)

Returns a required long.

path
relative path

Returns value

public long getLong(String path, long fallback)

Returns a long or a fallback.

path
relative path
fallback
returned when missing

Returns value

public double getDouble(String path)

Returns a required double.

path
relative path

Returns value

public double getDouble(String path, double fallback)

Returns a double or a fallback.

path
relative path
fallback
returned when missing

Returns value

public boolean getBoolean(String path)

Returns a required boolean (true/false, also yes/no, on/off).

path
relative path

Returns value

public boolean getBoolean(String path, boolean fallback)

Returns a boolean or a fallback.

path
relative path
fallback
returned when missing

Returns value

public Duration getDuration(String path)

Returns a required duration written like "30s", "1h30m", or a number of seconds.

path
relative path

Returns value

public Duration getDuration(String path, Duration fallback)

Returns a duration or a fallback.

path
relative path
fallback
returned when missing

Returns value

public <E extends Enum<E>> E getEnum(String path, Class<E> type)

Returns a required enum constant (case-insensitive; - and spaces match _).

path
relative path
type
enum class

Returns value

public List<String> getStringList(String path)

Returns a required list of strings. A single scalar is treated as a one-element list.

path
relative path

Returns unmodifiable list

public <T> List<T> getList(String path, Class<T> elementType)

Returns a required list with typed elements.

path
relative path
elementType
element type

Returns unmodifiable list

public <T> T get(String path, Class<T> type)

Returns a required value converted to any supported type: scalars, enums, UUID, Duration, types with a registered TypeSerializer, and POJOs with a no-argument constructor (fields mapped from kebab-case keys; missing keys keep field defaults).

path
relative path
type
target type

Returns value

public <T> T get(String path, Class<T> type, T fallback)

Returns a value converted to a type, or a fallback when missing. Present but invalid values still throw.

path
relative path
type
target type
fallback
returned when missing

Returns value

public <T> T as(Class<T> type)

Maps this whole section to a POJO (see get).

type
POJO type

Returns mapped object

public void set(String path, Object value)

Sets a value in memory (call YamlConfig.save to write it). Values are serialised with the registered serializers; null removes the key.

path
relative path
value
value
public void remove(String path)

Removes a value in memory.

path
relative path

io.github.crownalonedev.bloom.config

ConfigValidation class

public final class ConfigValidation

Collects validation rules and reports every problem at once. Created by YamlConfig.validate. config.validate() .require("database.type") .oneOf("database.type", "sqlite", "mysql", "mariadb") .range("limits.homes", 1, 100) .type("cooldowns.pearl", java.time.Duration.class) .check(); // throws ConfigException listing all problems with line numbers

Since 0.1.0

8 members
public ConfigValidation require(String path)

Requires a value to exist (in the file or defaults).

path
path

Returns this validation

public ConfigValidation type(String path, Class<?> type)

Requires a present value to convert to a type.

path
path
type
expected type

Returns this validation

public ConfigValidation range(String path, double min, double max)

Requires a present numeric value to lie in an inclusive range.

path
path
min
minimum
max
maximum

Returns this validation

public ConfigValidation oneOf(String path, String... allowed)

Requires a present text value to be one of the allowed values (case-insensitive).

path
path
allowed
allowed values

Returns this validation

public ConfigValidation matches(String path, Pattern pattern, String description)

Requires a present text value to match a regular expression.

path
path
pattern
pattern the whole value must match
description
human description of the expected format

Returns this validation

public <T> ConfigValidation check(String path, Class<T> type, Predicate<T> rule, String message)

Adds a custom rule on a present value.

path
path
type
type to convert the value to
rule
condition that must hold
message
problem description if the rule fails, e.g. "must be a power of two"

Returns this validation

public List<String> problems()

Returns the problems found so far.

Returns problem descriptions

public void check()

Throws if any rule failed.

Throws ConfigException listing every problem

io.github.crownalonedev.bloom.config

MigrationContext class

public final class MigrationContext

Mutable access to configuration values during a ConfigMigration. Paths are dot-separated.

Since 0.1.0

6 members
public int fromVersion()

Returns the version being migrated from.

Returns source version; the migration produces fromVersion() + 1

public boolean has(String path)

Returns whether a value exists.

path
path

Returns true if present

public Object get(String path)

Returns a raw value (string, number, boolean, list or map).

path
path

Returns value, or null

public void set(String path, Object value)

Sets a raw value; null removes it.

path
path
value
value
public void remove(String path)

Removes a value.

path
path
public void move(String from, String to)

Moves a value (including whole sections). Does nothing if the source is missing; replaces the target.

from
source path
to
target path

io.github.crownalonedev.bloom.config

TypeSerializer interface

public interface TypeSerializer<T>

Converts a custom type to and from plain YAML values (strings, numbers, booleans, lists and maps). TypeSerializer<Location> location = new TypeSerializer<Location>() { public Location deserialize(Object raw) { String[] p = raw.toString().split(","); return new Location(Bukkit.getWorld(p[0]), Double.parseDouble(p[1]), ...); } public Object serialize(Location value) { return value.getWorld().getName() + "," + value.getX() + ...; } }; YamlConfig config = YamlConfig.builder(path).serializer(Location.class, location).build();

Since 0.1.0

2 members
public T deserialize(Object raw)

Converts a YAML value to the type.

raw
value as loaded from YAML (never null)

Returns converted value

Throws IllegalArgumentException with a short reason if the value cannot be converted; Bloom adds the file, key and line to the message

public Object serialize(T value)

Converts the type to a YAML value.

value
value (never null)

Returns a string, number, boolean, list or map

io.github.crownalonedev.bloom.config

YamlConfig class

public final class YamlConfig extends ConfigSection

A YAML configuration file with bundled defaults, typed access, validation, migrations and safe writes. YamlConfig config = YamlConfig.builder(getDataFolder().toPath().resolve("config.yml")) .defaults(() -> getResource("config.yml")) .logger(getLogger()) .build(); // creates the file from defaults if missing, then loads it String prefix = config.getString("messages.prefix"); int maxHomes = config.getInt("homes.max", 3); Settings s = config.get("settings", Settings.class); // POJO mapping Safety • A missing file is created by copying the defaults resource byte-for-byte (comments included). • Existing files are never rewritten implicitly, except by migrations (which first copy the file to a timestamped .bak) and by Builder.addMissingDefaults (opt-in, also backed up). • save and migrations edit the file's YAML node tree, so comments and formatting of untouched keys are preserved. Writes are atomic (temporary file + move). • reload keeps the previous values if the new file is invalid. • A file whose version is newer than the plugin supports is rejected rather than downgraded. Values are loaded with SnakeYAML's SafeConstructor (no arbitrary object construction), duplicate keys are rejected and alias expansion is limited. Thread-safe.

Since 0.1.0

7 members
public static YamlConfig.Builder builder(Path file)

Starts configuring a YAML file.

file
path of the config file

Returns builder

public Path file()

Returns the file.

Returns path

public int version()

Returns the configured target version, or 0 when versioning is not used.

Returns version

public void reload()

Re-reads the file. On failure the previous values stay active and the exception is thrown.

Throws ConfigException if the file is invalid or a migration fails

public void save()

Writes the current values to the file, preserving comments and formatting of unchanged keys. Atomic.

Throws ConfigException on I/O failure

public ConfigValidation validate()

Starts a validation of the current values.

Returns validation builder; call ConfigValidation.check to throw on problems

public String toString()

io.github.crownalonedev.bloom.config

YamlConfig.Builder class

public static final class Builder

Builder for YamlConfig.

8 members
public YamlConfig.Builder defaults(Supplier<InputStream> source)

Sets the bundled defaults, usually () -> plugin.getResource("config.yml"). The stream is read once per load and closed.

source
supplies the defaults YAML; returning null is reported as a missing resource

Returns this builder

public YamlConfig.Builder version(int currentVersion)

Enables versioned migrations with the key config-version.

currentVersion
version this plugin writes, >= 1

Returns this builder

public YamlConfig.Builder version(String key, int currentVersion)

Enables versioned migrations with a custom key. Files without the key are treated as version 1.

key
version key at the top level
currentVersion
version this plugin writes, >= 1

Returns this builder

public YamlConfig.Builder migration(int fromVersion, ConfigMigration migration)

Registers the migration from fromVersion to fromVersion + 1.

fromVersion
source version
migration
migration

Returns this builder

public YamlConfig.Builder addMissingDefaults(boolean enabled)

Writes settings that exist in the defaults but not in the file into the file on load (with their default comments). The file is backed up first. Off by default.

enabled
flag

Returns this builder

public YamlConfig.Builder logger(Logger target)

Sets a logger for informational messages (file created, migrated).

target
logger, usually plugin.getLogger()

Returns this builder

public <T> YamlConfig.Builder serializer(Class<T> type, TypeSerializer<T> serializer)

Registers a serializer for a custom type.

type
type
serializer
serializer

Returns this builder

public YamlConfig build()

Creates the config and loads it (creating the file from defaults if needed and running migrations).

Returns the loaded config

Throws ConfigException if loading fails

bloom-storage

Bloom Storage: asynchronous JDBC (SQLite, MySQL, MariaDB) with pooling, transactions, migrations and repositories.

io.github.crownalonedev.bloom.storage

BlockingDatabase class

public final class BlockingDatabase implements SqlOperations

Synchronous database access for code that already runs off the main thread (for example inside scheduler().async(...) or a CompletableFuture chain). Obtain with Database.blocking. Every method throws IllegalStateException when called on the main server thread (as reported by the mainThreadCheck given to the database builder), because blocking JDBC calls there freeze the server.

Since 0.1.0

5 members
public int update(String sql, Object... params)
sql
String
params
Object[]
public Optional<Long> insert(String sql, Object... params)
sql
String
params
Object[]
public int[] batch(String sql, List<Object[]> rows)
sql
String
rows
List<Object[]>
public <T> List<T> query(String sql, RowMapper<T> mapper, Object... params)
sql
String
mapper
RowMapper<T>
params
Object[]
public <T> Optional<T> queryOne(String sql, RowMapper<T> mapper, Object... params)
sql
String
mapper
RowMapper<T>
params
Object[]

io.github.crownalonedev.bloom.storage

Database class

public final class Database implements Terminable

A pooled SQL database with an asynchronous API. Database db = Database.builder() .sqlite(getDataFolder().toPath().resolve("data.db")) .mainThreadCheck(bloom.scheduler()::isPrimaryThread) .logger(getLogger()) .build(); db.migrate(migrations).join(); // acceptable in onEnable: the server is not ticking yet db.queryOne("SELECT kills FROM stats WHERE uuid = ?", rs -> rs.getInt(1), player.getUniqueId()) .thenAcceptAsync(kills -> player.sendMessage("Kills: " + kills.orElse(0)), bloom.scheduler().mainThreadExecutor()); // back on the main thread Threading Operations run on a bounded pool of database threads (one per connection). Returned futures complete on those threads: switch to the main thread with thenAcceptAsync(..., mainThreadExecutor()) before touching game state. When the queue is full (default 1000 pending operations) new operations fail immediately with StorageException instead of piling up unbounded work. Shutdown close stops accepting work, waits for queued operations (default up to 10 s), fails any operation that could not run, and closes the pool. Call it in onDisable; when a Bloom instance owns it (registered in the service registry) Bloom closes it automatically.

Since 0.1.0

15 members
public static Database.Builder builder()

Starts configuring a database.

Returns builder

public Dialect dialect()

Returns the dialect.

Returns dialect

public BlockingDatabase blocking()

Returns synchronous access for code already running off the main thread.

Returns blocking API

public int pendingOperations()

Returns the number of queued operations that have not started yet.

Returns queue size

public CompletableFuture<Integer> update(String sql, Object... params)

Executes an INSERT/UPDATE/DELETE/DDL statement asynchronously.

sql
statement
params
parameters (see SqlOperations for supported types)

Returns future with the affected row count

public CompletableFuture<Optional<Long>> insert(String sql, Object... params)

Executes an INSERT asynchronously and returns the generated key.

sql
statement
params
parameters

Returns future with the generated key, if any

public CompletableFuture<int[]> batch(String sql, List<Object[]> rows)

Executes a JDBC batch asynchronously.

sql
statement
rows
parameter rows

Returns future with per-row update counts

public <T> CompletableFuture<List<T>> query(String sql, RowMapper<T> mapper, Object... params)

Runs a query asynchronously.

sql
query
mapper
row mapper (runs on a database thread)
params
parameters

Returns future with all mapped rows

public <T> CompletableFuture<Optional<T>> queryOne(String sql, RowMapper<T> mapper, Object... params)

Runs a single-row query asynchronously.

sql
query
mapper
row mapper (runs on a database thread)
params
parameters

Returns future with the first row, or empty

public <T> CompletableFuture<T> transaction(Function<Transaction,T> work)

Runs work in a transaction and returns its result. Commits when work returns, rolls back if it throws.

work
transaction body (runs on a database thread)

Returns future with the result

public CompletableFuture<Void> inTransaction(Consumer<Transaction> work)

Runs work without a result in a transaction.

work
transaction body (runs on a database thread)

Returns future completed when committed

public <T> CompletableFuture<T> withConnection(Database.ConnectionWork<T> work)

Gives raw JDBC access on a database thread. The connection is returned to the pool afterwards.

work
connection callback

Returns future with the result

public CompletableFuture<MigrationResult> migrate(List<Migration> migrations)

Applies pending migrations in version order, recording them in the history table (default bloom_schema_history; configurable with Builder.migrationTable).

migrations
all migrations of the plugin

Returns future with the result; fails if a migration fails or the database is newer than the migrations

public void close()

Stops accepting operations, waits for queued work, fails work that could not run and closes the pool. Idempotent. Blocks for at most the configured shutdown timeout.

public boolean isClosed()

io.github.crownalonedev.bloom.storage

Database.Builder class

public static final class Builder

Builder for Database.

16 members
public Database.Builder sqlite(Path file)

Uses an SQLite file. Parent directories are created. The pool has one connection by default, which serialises writes and avoids SQLITE_BUSY.

file
database file

Returns this builder

public Database.Builder mysql(String host, int port, String database, String user, String pass)

Uses MySQL.

host
host name
port
port, usually 3306
database
schema name
user
user name
pass
password

Returns this builder

public Database.Builder mariadb(String host, int port, String database, String user, String pass)

Uses MariaDB (shade org.mariadb.jdbc:mariadb-java-client into your plugin).

host
host name
port
port, usually 3306
database
schema name
user
user name
pass
password

Returns this builder

public Database.Builder jdbcUrl(String url, String user, String pass, Dialect type)

Uses a custom JDBC URL.

url
JDBC URL
user
user name, may be null
pass
password, may be null
type
dialect of the database

Returns this builder

public Database.Builder poolSize(int size)

Sets the number of connections and database threads (default 1 for SQLite, 8 otherwise).

size
pool size, >= 1

Returns this builder

public Database.Builder queueCapacity(int capacity)

Sets the maximum number of queued operations before new ones fail fast (default 1000).

capacity
queue capacity

Returns this builder

public Database.Builder connectionTimeout(Duration timeout)

Sets how long to wait for a free connection (default 10 s).

timeout
timeout

Returns this builder

public Database.Builder maxLifetime(Duration lifetime)

Sets the maximum lifetime of pooled connections (default 30 min; keep it below the server's wait_timeout).

lifetime
lifetime

Returns this builder

public Database.Builder shutdownTimeout(Duration timeout)

Sets how long Database.close waits for queued work (default 10 s).

timeout
timeout

Returns this builder

public Database.Builder poolName(String name)

Sets the pool and thread name prefix (default "Bloom"); use your plugin name.

name
pool name

Returns this builder

public Database.Builder migrationTable(String table)

Sets the migration history table (default bloom_schema_history). Plugins sharing one MySQL schema must use different tables, e.g. "myplugin_schema_history".

table
table name

Returns this builder

public Database.Builder driverClassName(String className)

Forces a JDBC driver class instead of auto-detection.

className
driver class

Returns this builder

public Database.Builder property(String key, String value)

Adds a driver/data-source property (e.g. useSSL=true).

key
property
value
value

Returns this builder

public Database.Builder mainThreadCheck(BooleanSupplier check)

Tells the database how to detect the main server thread, so BlockingDatabase can refuse to block it. With Bloom: bloom.scheduler()::isPrimaryThread.

check
returns true on the main thread

Returns this builder

public Database.Builder logger(Logger target)

Sets the logger for migrations and shutdown messages.

target
logger, usually plugin.getLogger()

Returns this builder

public Database build()

Opens the pool. Fails fast if the database is unreachable.

Returns the database

Throws StorageException with a diagnostic message if the pool cannot start

io.github.crownalonedev.bloom.storage

Database.ConnectionWork interface

public static interface ConnectionWork<T>

Raw JDBC callback for withConnection.

1 member
public T apply(Connection connection) throws SQLException

Uses the connection.

connection
pooled connection; do not close it

Returns result

Throws SQLException on JDBC errors

io.github.crownalonedev.bloom.storage

Dialect enum

public final enum Dialect

SQL dialects Bloom knows about. Used for driver defaults and small SQL helpers; Bloom does not rewrite your SQL.

Since 0.1.0

7 members
public static Dialect[] values()
public static Dialect valueOf(String name)
name
String
SQLITE

SQLite (file database).

MYSQL

MySQL. Bloom tries Connector/J 8+ first, then the 5.x driver bundled with legacy servers.

MARIADB

MariaDB (Connector/J must be shaded into your plugin).

public List<String> driverClasses()

Returns candidate JDBC driver classes, in preference order.

Returns driver class names

public String upsert(String table, List<String> columns, List<String> keyColumns)

Builds an insert-or-update statement with ? placeholders for every column, in order. • SQLite: INSERT OR REPLACE (works on the old SQLite bundled with 1.8 servers; note that it deletes and re-inserts the row, so ON DELETE CASCADE children are removed) • MySQL/MariaDB: INSERT ... ON DUPLICATE KEY UPDATE

table
table name
columns
all columns, primary key columns included
keyColumns
primary/unique key columns (not updated on conflict)

Returns SQL

io.github.crownalonedev.bloom.storage

Migration class

public final class Migration

A numbered schema change, applied once per database by Database.migrate. List<Migration> migrations = Arrays.asList( Migration.of(1, "create stats", "CREATE TABLE IF NOT EXISTS stats (uuid VARCHAR(36) PRIMARY KEY, kills INT NOT NULL DEFAULT 0)"), Migration.of(2, "add deaths", tx -> tx.update("ALTER TABLE stats ADD COLUMN deaths INT NOT NULL DEFAULT 0"))); database.migrate(migrations).join(); // blocking is acceptable in onEnable, before players join Each migration runs in its own transaction. Note that MySQL/MariaDB commit DDL statements immediately, so a failing multi-statement migration can leave earlier statements applied there; keep migrations small.

Since 0.1.0

4 members
public static Migration of(int version, String description, String... statements)

Creates a migration from SQL statements.

version
unique positive version
description
short description stored in the history table
statements
statements to execute in order

Returns migration

public static Migration of(int version, String description, Migration.Step step)

Creates a migration with custom logic (e.g. dialect-specific SQL or data transformation).

version
unique positive version
description
short description
step
migration body

Returns migration

public int version()

Returns the version.

Returns version

public String description()

Returns the description.

Returns description

io.github.crownalonedev.bloom.storage

Migration.Step interface

public static interface Step

Migration body.

1 member
public void apply(Transaction transaction)

Applies the change.

transaction
transaction to execute statements in

io.github.crownalonedev.bloom.storage

MigrationResult class

public final class MigrationResult

Outcome of Database.migrate.

Since 0.1.0

4 members
public int previousVersion()

Returns the schema version before migrating.

Returns version, 0 for a new database

public int currentVersion()

Returns the schema version after migrating.

Returns version

public List<Integer> applied()

Returns the versions applied by this run.

Returns applied versions in order

public String toString()

io.github.crownalonedev.bloom.storage

Repository interface

public interface Repository<K, V>

A minimal asynchronous repository. Bloom provides SqlRepository as a simple SQL implementation; implement this interface yourself for other stores (files, Redis, ...) so callers do not depend on the storage technology.

Since 0.1.0

4 members
public CompletableFuture<Optional<V>> find(K key)

Loads a value.

key
key

Returns future with the value, or empty

public CompletableFuture<List<V>> findAll()

Loads all values. Avoid on large tables.

Returns future with all values

public CompletableFuture<Void> save(V value)

Inserts or updates a value.

value
value

Returns future completed when saved

public CompletableFuture<Boolean> delete(K key)

Deletes a value.

key
key

Returns future with true if a value was deleted

io.github.crownalonedev.bloom.storage

RowMapper interface

public interface RowMapper<T>

Maps the current row of a ResultSet to an object. Do not call next() inside the mapper. RowMapper<PlayerStats> mapper = rs -> new PlayerStats( UUID.fromString(rs.getString("uuid")), rs.getInt("kills"), rs.getInt("deaths"));

Since 0.1.0

1 member
public T map(ResultSet row) throws SQLException

Maps the current row.

row
result set positioned on a row

Returns mapped object

Throws SQLException on column access errors

io.github.crownalonedev.bloom.storage

SqlOperations interface

public interface SqlOperations

Synchronous SQL operations. Implemented by Transaction (one connection, inside Database.transaction) and BlockingDatabase (for code already running off the main thread). Parameters ? placeholders are bound in order. Supported parameter types: null, String, numbers, Boolean, byte[], UUID (stored as its 36-character string), enums (stored by name()), java.time.Instant (stored as epoch milliseconds, a BIGINT), Duration (milliseconds) and any type the JDBC driver accepts in setObject.

Since 0.1.0

5 members
public int update(String sql, Object... params)

Executes an INSERT, UPDATE, DELETE or DDL statement.

sql
statement with ? placeholders
params
parameter values

Returns affected row count

Throws StorageException on failure

public Optional<Long> insert(String sql, Object... params)

Executes an INSERT and returns the generated key.

sql
insert statement
params
parameter values

Returns generated key, or empty if the statement generated none

Throws StorageException on failure

public int[] batch(String sql, List<Object[]> rows)

Executes a statement once per parameter row, as a JDBC batch.

sql
statement with ? placeholders
rows
parameter rows

Returns affected row counts per row (drivers may report -2, "success, count unknown")

Throws StorageException on failure

public <T> List<T> query(String sql, RowMapper<T> mapper, Object... params)

Runs a query and maps every row.

sql
query
mapper
row mapper
params
parameter values

Returns mapped rows, possibly empty

Throws StorageException on failure

public <T> Optional<T> queryOne(String sql, RowMapper<T> mapper, Object... params)

Runs a query expected to return at most one row.

sql
query
mapper
row mapper
params
parameter values

Returns the first row, or empty

Throws StorageException on failure

io.github.crownalonedev.bloom.storage

SqlRepository abstract class

public abstract class SqlRepository<K, V> implements Repository<K,V>

A Repository for one table with a single-column primary key. Subclasses describe the mapping; Bloom generates the SQL. Table and column names must be plain identifiers (they are validated to prevent accidental SQL injection through names). final class StatsRepository extends SqlRepository<UUID, PlayerStats> { StatsRepository(Database db) { super(db, "player_stats", "uuid", Arrays.asList("uuid", "kills", "deaths"), rs -> new PlayerStats(UUID.fromString(rs.getString("uuid")), rs.getInt("kills"), rs.getInt("deaths"))); } protected UUID keyOf(PlayerStats s) { return s.uuid(); } protected Object[] valuesOf(PlayerStats s) { return new Object[] {s.uuid(), s.kills(), s.deaths()}; } }

Since 0.1.0

9 members
protected SqlRepository(Database database, String table, String keyColumn, List<String> columns, RowMapper<V> mapper)

Creates the repository.

database
database
table
table name
keyColumn
primary key column
columns
all columns including the key, in the order of valuesOf
mapper
maps a row to a value
protected abstract K keyOf(V value)

Returns the key of a value.

value
value

Returns key

protected abstract Object[] valuesOf(V value)

Returns the column values of a value, in the order of the constructor's columns.

value
value

Returns column values

protected Database database()

Returns the database.

Returns database

protected String table()

Returns the table name.

Returns table

public CompletableFuture<Optional<V>> find(K key)
key
K
public CompletableFuture<List<V>> findAll()
public CompletableFuture<Void> save(V value)
value
V
public CompletableFuture<Boolean> delete(K key)
key
K

io.github.crownalonedev.bloom.storage

StorageException class

public class StorageException extends BloomException

Thrown (or used to complete futures exceptionally) when a database operation fails. The message includes the SQL statement (without parameter values) when relevant.

Since 0.1.0

2 members
public StorageException(String message)

Creates an exception.

message
description
public StorageException(String message, Throwable cause)

Creates an exception with a cause.

message
description
cause
cause, usually a SQLException

io.github.crownalonedev.bloom.storage

Transaction interface

public interface Transaction extends SqlOperations

Operations inside a database transaction. All statements share one connection; the transaction commits when the callback returns and rolls back if it throws. Only valid inside Database.transaction.

Since 0.1.0

2 members
public Dialect dialect()

Returns the database dialect.

Returns dialect

public Connection connection()

Returns the underlying connection for advanced JDBC use. Do not close it or change auto-commit.

Returns connection

bloom-testing

Bloom Testing: server-free test doubles for plugin unit tests (manual scheduler, controllable clock).

io.github.crownalonedev.bloom.testing

ManualScheduler class

public final class ManualScheduler implements BloomScheduler, AutoCloseable

A deterministic BloomScheduler for unit tests. Nothing runs until you advance time with tick / tick; "async" tasks also run on the test thread during ticks, so tests need no sleeps or latches. It has the same ownership, error-isolation and cancellation behaviour as the real Bloom scheduler. ManualScheduler scheduler = ManualScheduler.create(); MyCountdown countdown = new MyCountdown(scheduler); // code under test takes a BloomScheduler countdown.start(3); scheduler.tick(60); assertTrue(countdown.isFinished()); Not thread-safe: use from the test thread only.

Since 0.1.0

23 members
public static ManualScheduler create()

Creates a scheduler at tick 0 whose calling thread counts as the main thread.

Returns scheduler

public static ManualScheduler create(Logger logger)

Creates a scheduler that logs task failures to a specific logger.

logger
logger for task exceptions

Returns scheduler

public void tick()

Advances one tick, running every task that is due.

public void tick(long ticks)

Advances several ticks.

ticks
number of ticks
public void advance(Duration duration)

Advances by a duration (rounded up to whole ticks).

duration
time to advance
public long currentTick()

Returns the current tick.

Returns ticks advanced so far

public void primaryThread(boolean primary)

Sets what isPrimaryThread reports, to test code paths that require (or forbid) the main thread.

primary
value to report
public boolean isPrimaryThread()
public void ensurePrimaryThread(String operation)
operation
String
public ScheduledTask sync(Runnable task)
task
Runnable
public ScheduledTask syncLater(Runnable task, long delayTicks)
task
Runnable
delayTicks
long
public ScheduledTask syncLater(Runnable task, Duration delay)
task
Runnable
delay
Duration
public ScheduledTask syncRepeating(Consumer<ScheduledTask> task, long delayTicks, long periodTicks)
task
Consumer<ScheduledTask>
delayTicks
long
periodTicks
long
public ScheduledTask syncRepeating(Consumer<ScheduledTask> task, Duration delay, Duration period)
task
Consumer<ScheduledTask>
delay
Duration
period
Duration
public ScheduledTask async(Runnable task)
task
Runnable
public ScheduledTask asyncLater(Runnable task, long delayTicks)
task
Runnable
delayTicks
long
public ScheduledTask asyncRepeating(Consumer<ScheduledTask> task, long delayTicks, long periodTicks)
task
Consumer<ScheduledTask>
delayTicks
long
periodTicks
long
public <T> CompletableFuture<T> supplySync(Supplier<T> supplier)
supplier
Supplier<T>
public <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier)
supplier
Supplier<T>
public Executor mainThreadExecutor()
public Executor asyncExecutor()
public int activeTaskCount()
public void close()

Cancels all tasks, like Bloom does on shutdown.

io.github.crownalonedev.bloom.testing

TestClock class

public final class TestClock extends Clock

A Clock that only moves when told to. Pass it to Cooldowns.of(duration, clock) or ExpiringCache.create(ttl, size, clock) to test time-based logic without sleeping. TestClock clock = TestClock.start(); Cooldowns<UUID> cooldowns = Cooldowns.of(Duration.ofSeconds(10), clock); cooldowns.tryUse(id); clock.advance(Duration.ofSeconds(10)); assertTrue(cooldowns.tryUse(id));

Since 0.1.0

7 members
public static TestClock start()

Creates a clock at 2026-01-01T00:00:00Z.

Returns clock

public static TestClock at(Instant instant)

Creates a clock at a given instant.

instant
start time

Returns clock

public void advance(Duration duration)

Moves time forward.

duration
amount, may be negative to move backwards
public void set(Instant instant)

Sets the time.

instant
new time
public Instant instant()
public ZoneId getZone()
public Clock withZone(ZoneId zone)
zone
ZoneId