Make MASpawnThread logic cancellable.
This commit changes how MASpawnThread is started. Instead of simply scheduling a task and letting it run whenever, we now explicitly tell it to stop when the arena ends. This matters, because if the scheduled task does not get cancelled, it will run at the scheduled time. MASpawnThread's run() method has an early return to stop whenever the arena isn't running, but with unlucky timing, it's possible to start a new arena session before the task runs again, meaning the same MASpawnThread keeps scheduling itself on the previous scheduling loop. Instead of this whacky approach, we now specifically have MASpawnThread track its own BukkitTask. Upon arena start, we instantiate a new MASpawnThread and call its start() method, which in turn schedules itself and stores a reference to the associated BukkitTask. Upon arena end, we call the MASpawnThread's stop() method, which explicitly calls the BukkitTask's cancel() method, effectively stopping/unscheduling the task. This fixes the (very) long-standing "double wave spawner" bug that we haven't been able to reproduce for so long. Hooray!
This commit is contained in:
parent
fc51c5eff5
commit
96c1f18517
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue