From dbe8febac9d2b87d86663dee8c5e85ae033619f8 Mon Sep 17 00:00:00 2001 From: thetrouper Date: Thu, 19 Jun 2025 10:42:58 -0500 Subject: [PATCH] Corrected concurrency issues in the explosion reversions. --- .../alias/server/systems/TaskManager.java | 4 + .../server/systems/burning/BlockBurner.java | 51 +++++------- .../server/systems/world/ExplosionUtils.java | 81 ++++++++----------- 3 files changed, 59 insertions(+), 77 deletions(-) diff --git a/src/main/java/me/trouper/alias/server/systems/TaskManager.java b/src/main/java/me/trouper/alias/server/systems/TaskManager.java index 79f90d2..f3f1cd9 100644 --- a/src/main/java/me/trouper/alias/server/systems/TaskManager.java +++ b/src/main/java/me/trouper/alias/server/systems/TaskManager.java @@ -35,4 +35,8 @@ public class TaskManager implements Main { tasks.keySet().forEach(Bukkit.getScheduler()::cancelTask); tasks.clear(); } + + public boolean isClosed() { + return closed; + } } diff --git a/src/main/java/me/trouper/alias/server/systems/burning/BlockBurner.java b/src/main/java/me/trouper/alias/server/systems/burning/BlockBurner.java index 039de68..5b5a79d 100644 --- a/src/main/java/me/trouper/alias/server/systems/burning/BlockBurner.java +++ b/src/main/java/me/trouper/alias/server/systems/burning/BlockBurner.java @@ -1,6 +1,7 @@ package me.trouper.alias.server.systems.burning; import me.trouper.alias.server.Main; +import me.trouper.alias.server.systems.TaskManager; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; @@ -16,22 +17,27 @@ import java.util.concurrent.ThreadLocalRandom; public class BlockBurner implements Closeable, Main { private final BurnOptions options; private final BurnPalette palette; - private boolean isClosed = false; + private final TaskManager taskManager; private final Set visited = new HashSet<>(); private final Map burning = new HashMap<>(); - private final Set tasks = new HashSet<>(); public BlockBurner(BurnOptions options) { this.options = options; this.palette = new BurnPalette(); + this.taskManager = new TaskManager(); + } + + public BlockBurner(BurnOptions options, TaskManager sharedTaskManager) { + this.options = options; + this.palette = new BurnPalette(); + this.taskManager = sharedTaskManager; } @Override public void close() { - tasks.forEach(task -> Bukkit.getScheduler().cancelTask(task)); + taskManager.close(); visited.clear(); burning.clear(); - isClosed = true; } public void burn(Block block, float heat) { @@ -47,22 +53,13 @@ public class BlockBurner implements Closeable, Main { if (block.getType().isAir() && canPlaceFireOn(blockBelow)) { if (ThreadLocalRandom.current().nextFloat() > options.getSetFireChance()) return; - if (isClosed()) return; setBlock(block, palette.getFirePalette().getFirst()); - if (isClosed()) return; - int taskId = Bukkit.getScheduler().runTaskLater(main.getPlugin(), ()->{ + taskManager.scheduleTask(() -> { if (!canPlaceFireOn(blockBelow)) { setBlock(block, Material.AIR); } - },20 * 10).getTaskId(); - - if (!isClosed()) { - tasks.add(taskId); - } else { - tasks.add(taskId); - Bukkit.getScheduler().cancelTask(taskId); - } + }, 20 * 10); return; } @@ -81,19 +78,11 @@ public class BlockBurner implements Closeable, Main { for (BurnStage stage : stages) { totalDelay += stage.getDelay(); - if (isClosed()) return; - int taskId = Bukkit.getScheduler().runTaskLater(main.getPlugin(), ()->{ + taskManager.scheduleTask(() -> { if (block.getType().isAir()) return; setBlock(block, stage.getBlockData()); - },totalDelay).getTaskId(); - - if (!isClosed()) { - tasks.add(taskId); - } else { - tasks.add(taskId); - Bukkit.getScheduler().cancelTask(taskId); - } + }, totalDelay); } } @@ -130,16 +119,20 @@ public class BlockBurner implements Closeable, Main { } private void setBlock(Block block, Material material) { - if (isClosed()) return; + if (taskManager.isClosed()) return; block.setType(material); } private void setBlock(Block block, BlockData data) { - if (isClosed()) return; + if (taskManager.isClosed()) return; block.setBlockData(data); } public boolean isClosed() { - return isClosed; + return taskManager.isClosed(); } -} + + public TaskManager getTaskManager() { + return taskManager; + } +} \ No newline at end of file diff --git a/src/main/java/me/trouper/alias/server/systems/world/ExplosionUtils.java b/src/main/java/me/trouper/alias/server/systems/world/ExplosionUtils.java index 5b47817..b6932ac 100644 --- a/src/main/java/me/trouper/alias/server/systems/world/ExplosionUtils.java +++ b/src/main/java/me/trouper/alias/server/systems/world/ExplosionUtils.java @@ -2,6 +2,7 @@ package me.trouper.alias.server.systems.world; import me.trouper.alias.server.Main; import me.trouper.alias.server.systems.Verbose; +import me.trouper.alias.server.systems.TaskManager; import me.trouper.alias.server.systems.burning.BlockBurner; import me.trouper.alias.server.systems.burning.BurnOptions; import org.bukkit.*; @@ -64,19 +65,21 @@ public class ExplosionUtils implements Main { public static class ExplosionResult { private final Map originalStates = new HashMap<>(); private final Map originalInventories = new HashMap<>(); - private final List scheduledTaskIds = new ArrayList<>(); + private final TaskManager taskManager; private final BlockBurner burner; + public ExplosionResult(TaskManager taskManager) { + this.taskManager = taskManager; + this.burner = new BlockBurner(new BurnOptions(), taskManager); + } + public ExplosionResult(BlockBurner burner) { this.burner = burner; + this.taskManager = burner.getTaskManager(); } public void cleanup() { - if (burner != null) { - burner.close(); - } - - scheduledTaskIds.forEach(task -> Bukkit.getScheduler().cancelTask(task)); + taskManager.close(); } void recordSnapshot(Block block) { @@ -88,17 +91,11 @@ public class ExplosionUtils implements Main { } } - void addScheduledTask(int taskId) { - scheduledTaskIds.add(taskId); - } - public void restore() { - for (int taskId : scheduledTaskIds) { - Bukkit.getScheduler().cancelTask(taskId); - } - + // First cleanup all tasks cleanup(); + // Then restore blocks for (Map.Entry entry : originalStates.entrySet()) { Block block = entry.getKey(); BlockState snapshot = entry.getValue(); @@ -115,6 +112,7 @@ public class ExplosionUtils implements Main { } public BlockBurner getBurner() { return burner; } + public TaskManager getTaskManager() { return taskManager; } public Map getOriginalStates() { return originalStates; @@ -123,10 +121,6 @@ public class ExplosionUtils implements Main { public Map getOriginalInventories() { return originalInventories; } - - public List getScheduledTaskIds() { - return scheduledTaskIds; - } } public static ExplosionResult createExplosion(Location center, ExplosionOptions options) { @@ -135,11 +129,13 @@ public class ExplosionUtils implements Main { Map affectedBlocks = getBlocksInRadius(center, options.getMaxBurnRadius()); - ExplosionResult result = new ExplosionResult(new BlockBurner(options.getBurnOptions())); + // Create shared task manager for this explosion + TaskManager sharedTaskManager = new TaskManager(); + BlockBurner burner = new BlockBurner(options.getBurnOptions(), sharedTaskManager); + ExplosionResult result = new ExplosionResult(burner); for (Block block : affectedBlocks.keySet()) { if (block.getType().isAir()) continue; - result.recordSnapshot(block); } @@ -149,10 +145,8 @@ public class ExplosionUtils implements Main { categorizeBlocks(affectedBlocks, options, blocksToDestroy, blocksToBurn, blocksHeatMap); - BlockBurner burner = new BlockBurner(options.getBurnOptions()); - - scheduleDestruction(blocksToDestroy, options,result); - scheduleBurning(blocksToBurn, blocksHeatMap, burner, center, options,result); + scheduleDestruction(blocksToDestroy, options, sharedTaskManager); + scheduleBurning(blocksToBurn, blocksHeatMap, burner, center, options, sharedTaskManager); if (options.isCreateParticles() || options.isPlaySound()) createExplosionEffects(center, options); @@ -229,12 +223,12 @@ public class ExplosionUtils implements Main { return (float) (options.getMinHeat() + heatRange * heatFactor); } - private static void scheduleDestruction(Set blocksToDestroy, ExplosionOptions options, ExplosionResult result) { + private static void scheduleDestruction(Set blocksToDestroy, ExplosionOptions options, TaskManager taskManager) { if (blocksToDestroy.isEmpty()) return; long destructionDelayTicks = (long) (options.getDestructionDelay() * 20); - int outerTask = Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{ + taskManager.scheduleTask(() -> { List blockList = new ArrayList<>(blocksToDestroy); Collections.shuffle(blockList); @@ -246,29 +240,26 @@ public class ExplosionUtils implements Main { if (startIndex >= blockList.size()) break; - int innerTask = Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{ + taskManager.scheduleTask(() -> { for (int i = startIndex; i < endIndex; i++) { Block block = blockList.get(i); if (!block.getType().isAir()) { block.setType(Material.AIR); } } - },wave * 2).getTaskId(); - - result.addScheduledTask(innerTask); + }, wave * 2); } - },destructionDelayTicks).getTaskId(); - - result.addScheduledTask(outerTask); + }, destructionDelayTicks); } private static void scheduleBurning(Set blocksToMaybeBurn, Map blocksHeatMap, BlockBurner burner, Location center, ExplosionOptions options, - ExplosionResult result) { + TaskManager taskManager) { if (blocksToMaybeBurn.isEmpty()) return; long burnDelayTicks = (long) (options.getBurnDelay() * 20); - int outerTask = Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{ + + taskManager.scheduleTask(() -> { List blockList = new ArrayList<>(blocksToMaybeBurn); Collections.shuffle(blockList); @@ -285,7 +276,7 @@ public class ExplosionUtils implements Main { int waveDelay = waveEntry.getKey() * 3; List waveBlocks = waveEntry.getValue(); - int middleTask = Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{ + taskManager.scheduleTask(() -> { for (Block block : waveBlocks) { if (burner.isClosed()) continue; @@ -294,21 +285,15 @@ public class ExplosionUtils implements Main { ThreadLocalRandom random = ThreadLocalRandom.current(); int randomDelay = random.nextInt(0, 10); - int innerTask = Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{ + taskManager.scheduleTask(() -> { if (!burner.isClosed() && !block.getType().isAir()) { burner.burn(block, heat); } - },randomDelay).getTaskId(); - - result.addScheduledTask(innerTask); + }, randomDelay); } - },waveDelay).getTaskId(); - - result.addScheduledTask(middleTask); + }, waveDelay); } - },burnDelayTicks).getTaskId(); - - result.addScheduledTask(outerTask); + }, burnDelayTicks); } private static void createExplosionEffects(Location center, ExplosionOptions options) { @@ -326,9 +311,9 @@ public class ExplosionUtils implements Main { world.spawnParticle(Particle.LARGE_SMOKE, center, 15, 1, 1, 1, 0.05); world.spawnParticle(Particle.FLAME, center, 30, 3, 3, 3, 0.1); - Bukkit.getScheduler().runTaskLater(main.getPlugin(),()->{ + Bukkit.getScheduler().runTaskLater(main.getPlugin(), () -> { world.spawnParticle(Particle.SMOKE, center, 50, 4, 4, 4, 0.02); - },20); + }, 20); } }