diff --git a/changelog.md b/changelog.md index 7e632aa..24dcdb2 100644 --- a/changelog.md +++ b/changelog.md @@ -23,6 +23,7 @@ These changes will (most likely) be included in the next version. - The new command `/ma ready` (`/ma rdy` for short) can be used as an alternative to the iron block for readying up. - Total experience is now correctly stored, reset, and restored on arena join/leave. This fixes a potential bug where total experience could increase in the arena, but levels and progress would still get reset at arena end. - The per-arena setting `keep-exp` returns. If enabled, any experience collected during an arena session is added as a reward on death or when the final wave is reached. +- Waves will no longer intermittently progress at double frequency in some arena sessions. This long-standing bug where waves progress at "double speed" has finally been fixed. Thanks to: - Sait for adding the /ma ready command diff --git a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java index a320b97..88329ef 100644 --- a/src/main/java/com/garbagemule/MobArena/ArenaImpl.java +++ b/src/main/java/com/garbagemule/MobArena/ArenaImpl.java @@ -996,26 +996,15 @@ public class ArenaImpl implements Arena } private void startSpawner() { - // Set the spawn flags to enable monster spawning. - world.setSpawnFlags(true, true); - //world.setDifficulty(Difficulty.NORMAL); - - // Create a spawner if one doesn't exist, otherwise reset it - if (spawnThread == null) { - spawnThread = new MASpawnThread(plugin, this); - } else { - spawnThread.reset(); + if (spawnThread != null) { + spawnThread.stop(); + spawnThread = null; } - - // Schedule it for the initial first wave delay. - scheduleTask(spawnThread, settings.getInt("first-wave-delay", 5) * 20); - - // Schedule to enable PvP if pvp-enabled: true - scheduleTask(new Runnable() { - public void run() { - eventListener.pvpActivate(); - } - }, settings.getInt("first-wave-delay", 5) * 20); + + world.setSpawnFlags(true, true); + + spawnThread = new MASpawnThread(plugin, this); + spawnThread.start(); } /** @@ -1030,9 +1019,15 @@ public class ArenaImpl implements Arena } private void stopSpawner() { + if (spawnThread == null) { + plugin.getLogger().warning("Can't stop non-existent spawner in arena " + configName() + ". This should never happen."); + return; + } + + spawnThread.stop(); + spawnThread = null; + world.setSpawnFlags(allowMonsters, allowAnimals); - eventListener.pvpDeactivate(); - //world.setDifficulty(spawnMonsters); } private void startBouncingSheep() diff --git a/src/main/java/com/garbagemule/MobArena/MASpawnThread.java b/src/main/java/com/garbagemule/MobArena/MASpawnThread.java index 947cbb7..34a4b69 100644 --- a/src/main/java/com/garbagemule/MobArena/MASpawnThread.java +++ b/src/main/java/com/garbagemule/MobArena/MASpawnThread.java @@ -16,11 +16,13 @@ import com.garbagemule.MobArena.waves.enums.WaveType; import com.garbagemule.MobArena.waves.types.BossWave; import com.garbagemule.MobArena.waves.types.SupplyWave; import com.garbagemule.MobArena.waves.types.UpgradeWave; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitTask; import java.util.ArrayList; import java.util.List; @@ -41,6 +43,8 @@ public class MASpawnThread implements Runnable private int waveInterval; private int nextWaveDelay; + private BukkitTask task; + /** * Create a new monster spawner for the input arena. * Note that the arena's WaveManager is reset @@ -75,6 +79,32 @@ public class MASpawnThread implements Runnable nextWaveDelay = arena.getSettings().getInt("next-wave-delay", 0); } + public void start() { + if (task != null) { + plugin.getLogger().warning("Starting spawner in arena " + arena.configName() + " with existing spawner still running. This should never happen."); + task.cancel(); + task = null; + } + + int delay = arena.getSettings().getInt("first-wave-delay", 5) * 20; + task = Bukkit.getScheduler().runTaskLater(plugin, () -> { + arena.getEventListener().pvpActivate(); + this.run(); + }, delay); + } + + public void stop() { + if (task == null) { + plugin.getLogger().warning("Can't stop non-existent spawner in arena " + arena.configName() + ". This should never happen."); + return; + } + + arena.getEventListener().pvpDeactivate(); + + task.cancel(); + task = null; + } + public void run() { // If the arena isn't running or if there are no players in it. if (!arena.isRunning() || arena.getPlayersInArena().isEmpty()) { @@ -109,7 +139,7 @@ public class MASpawnThread implements Runnable // Delay the next wave if (nextWaveDelay > 0) { - arena.scheduleTask(this::spawnNextWave, nextWaveDelay * 20); + task = Bukkit.getScheduler().runTaskLater(plugin, this::spawnNextWave, nextWaveDelay * 20); } else { spawnNextWave(); } @@ -146,7 +176,7 @@ public class MASpawnThread implements Runnable updateStats(nextWave); // Reschedule the spawner for the next wave. - arena.scheduleTask(this, waveInterval * 20); + task = Bukkit.getScheduler().runTaskLater(plugin, this, waveInterval * 20); } private void spawnWave(int wave) {