Scheduling
Run code later, repeatedly or off the main thread, with tasks that are cleaned up automatically.
bloom.scheduler() returns a BloomScheduler. Every task belongs to your plugin and is cancelled by
bloom.shutdown(). If a task throws, the exception is logged with your plugin's name and other tasks keep running.
Main-thread tasks
Use sync* methods for anything that touches players, worlds, entities or inventories.
BloomScheduler scheduler = bloom.scheduler();
scheduler.sync(() -> player.sendMessage("Next tick"));
scheduler.syncLater(() -> player.sendMessage("Three seconds later"), Duration.ofSeconds(3));
ScheduledTask task = scheduler.syncRepeating(self -> player.sendMessage("Every second"), 0, 20);
task.cancel();Delays and periods are in ticks (20 per second) or Durations, which are rounded up to whole ticks. A delay of zero
means the next tick, as in Bukkit.
Repeating tasks that stop themselves
Repeating tasks receive their own handle, so they can cancel themselves without a field:
final int[] seconds = {5};
bloom.scheduler()
.syncRepeating(
task -> {
if (!player.isOnline() || seconds[0] == 0) {
task.cancel(); // a repeating task receives its own handle
return;
}
bloom.messages().actionBar(player, "&eStarting in " + seconds[0]--);
},
Duration.ZERO,
Duration.ofSeconds(1));Background work
async* methods run on background threads. Use them for files, web requests and heavy computation, then come back to
the main thread before touching the game:
bloom.scheduler()
.supplyAsync(() -> loadProfileFromWeb(player.getUniqueId())) // background thread: no Bukkit calls
.thenAcceptAsync(
profile -> player.sendMessage("Loaded " + profile), // back on the main thread
bloom.scheduler().mainThreadExecutor());Thread checks
bloom.scheduler().ensurePrimaryThread("Teleporting players");
// IllegalStateException off the main thread: "Teleporting players must be called from the main server
// thread, but was called from thread 'pool-3-thread-1'. Switch threads with scheduler().sync(...) ..."Bloom's own main-thread APIs (menus, boss bars) perform this check for you.
Reference
| Method | Runs on | Notes |
|---|---|---|
sync(Runnable) | main | next tick |
syncLater(Runnable, ticks or Duration) | main | |
syncRepeating(Consumer<ScheduledTask>, delay, period) | main | period at least one tick |
async(Runnable) / asyncLater / asyncRepeating | background | |
supplySync(Supplier) / supplyAsync(Supplier) | main / background | returns CompletableFuture; cancelled futures fail with CancellationException on shutdown |
mainThreadExecutor() / asyncExecutor() | main / background | for CompletableFuture chains |
activeTaskCount() | tasks not yet finished or cancelled |
Folia is not supported yet, because its region threads do not fit a single main thread.