Skip to content

Instantly share code, notes, and snippets.

@ShiftSad
Created July 4, 2026 21:02
Show Gist options
  • Select an option

  • Save ShiftSad/a75eeda3d0f55d47672d818700f4ce70 to your computer and use it in GitHub Desktop.

Select an option

Save ShiftSad/a75eeda3d0f55d47672d818700f4ce70 to your computer and use it in GitHub Desktop.
BlockPlacementQueue.java
public class BlockPlacementQueue {
private static final long MAX_MS_PER_TICK = 10;
private static BlockPlacementQueue instance;
private final Plugin plugin;
private final Queue<BlockPlacementTask> taskQueue = new ConcurrentLinkedQueue<>();
private BukkitTask processingTask;
private BlockPlacementQueue(Plugin plugin) {
this.plugin = plugin;
}
public static void initialize(Plugin plugin) {
if (instance == null) {
instance = new BlockPlacementQueue(plugin);
}
}
public static BlockPlacementQueue getInstance() {
if (instance == null) {
throw new IllegalStateException("BlockPlacementQueue has not been initialized. Call initialize() first.");
}
return instance;
}
public CompletableFuture<Void> queueBlocks(BlockPlacement[] blocks) {
if (blocks.length == 0) {
return CompletableFuture.completedFuture(null);
}
CompletableFuture<Void> future = new CompletableFuture<>();
taskQueue.add(new BlockPlacementTask(blocks, 0, future));
ensureProcessingRunning();
return future;
}
private void ensureProcessingRunning() {
if (processingTask == null || processingTask.isCancelled()) {
processingTask = Bukkit.getScheduler().runTaskTimer(plugin, this::processTick, 1L, 1L);
}
}
private void processTick() {
if (taskQueue.isEmpty()) {
if (processingTask != null) {
processingTask.cancel();
processingTask = null;
}
return;
}
long startTime = System.currentTimeMillis();
while (!taskQueue.isEmpty() && (System.currentTimeMillis() - startTime) < MAX_MS_PER_TICK) {
BlockPlacementTask task = taskQueue.peek();
if (task == null) break;
while (task.currentIndex < task.blocks.length && (System.currentTimeMillis() - startTime) < MAX_MS_PER_TICK) {
BlockPlacement block = task.blocks[task.currentIndex];
block.world().getBlockAt(block.x(), block.y(), block.z()).setType(block.material(), false);
task.currentIndex++;
}
if (task.currentIndex >= task.blocks.length) {
taskQueue.poll();
task.future.complete(null);
}
}
}
public record BlockPlacement(World world, int x, int y, int z, Material material) {}
private static class BlockPlacementTask {
final BlockPlacement[] blocks;
int currentIndex;
final CompletableFuture<Void> future;
BlockPlacementTask(BlockPlacement[] blocks, int startIndex, CompletableFuture<Void> future) {
this.blocks = blocks;
this.currentIndex = startIndex;
this.future = future;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment