Utilities
Cooldowns, human-friendly durations and a small expiring cache.
These live in bloom-api and need no server.
Cooldowns
private final Cooldowns<UUID> enderPearl = Cooldowns.of(Duration.ofSeconds(16));
boolean tryThrowPearl(Player player) {
if (!enderPearl.tryUse(player.getUniqueId())) {
Duration left = enderPearl.remaining(player.getUniqueId());
player.sendMessage("Pearl cooldown: " + Durations.format(left)); // "Pearl cooldown: 12s"
return false;
}
return true;
}tryUse is atomic per key, so two quick clicks cannot both pass. Expired entries are removed when touched and by
prune(); call it from a repeating task if many keys are never touched again. Cooldowns are kept in memory only.
Durations
Duration banLength = Durations.parse("1d 12h"); // also "90s", "1h30m", "500ms", "2w"
String shortForm = Durations.format(banLength); // "1d 12h"
String words = Durations.formatLong(banLength); // "1 day and 12 hours"Units: ms, s, m, h, d, w. A bare number means seconds. Invalid input throws an exception whose message lists
valid examples, which you can show to the player directly.
Expiring cache
ExpiringCache<UUID, String> ranks = ExpiringCache.create(Duration.ofMinutes(5), 1_000);
UUID id = UUID.randomUUID();
String rank = ranks.get(id, key -> "member"); // computes and caches on a miss
ranks.invalidate(id);A least-recently-used cache with a time-to-live and a size limit. It uses one lock, so it suits modest caches; for very hot paths, use a dedicated caching library.
Ticks
Ticks.from(Duration) rounds up to whole ticks, so a positive duration never becomes zero. Ticks.toDuration(long)
and Ticks.seconds(long) convert the other way.