Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,529 @@
|
||||
package us.tss3.blockparty.arena;
|
||||
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import us.tss3.blockparty.BlockPartyPlugin;
|
||||
import us.tss3.blockparty.config.ArenaConfig;
|
||||
import us.tss3.blockparty.floor.FloorManager;
|
||||
import us.tss3.blockparty.logic.ArenaPhase;
|
||||
import us.tss3.blockparty.logic.ArenaStateMachine;
|
||||
import us.tss3.blockparty.logic.CountdownLogic;
|
||||
import us.tss3.blockparty.logic.EliminationLogic;
|
||||
import us.tss3.blockparty.logic.RoundTimeCalculator;
|
||||
import us.tss3.blockparty.logic.TargetColorSelector;
|
||||
import us.tss3.blockparty.model.PlayerState;
|
||||
import us.tss3.blockparty.session.PlayerSession;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A single running arena: owns its state machine, tasks and round lifecycle. */
|
||||
public class Arena {
|
||||
|
||||
private final BlockPartyPlugin plugin;
|
||||
private final ArenaConfig config;
|
||||
private final FloorManager floorManager;
|
||||
private final ArenaStateMachine stateMachine = new ArenaStateMachine(ArenaPhase.DISABLED);
|
||||
private final Random random = new Random();
|
||||
private final TargetColorSelector selector = new TargetColorSelector(random::nextInt);
|
||||
|
||||
private final List<UUID> players = new ArrayList<>();
|
||||
private final List<UUID> spectators = new ArrayList<>();
|
||||
|
||||
private final List<BukkitTask> tasks = new ArrayList<>();
|
||||
private BossBar bossBar;
|
||||
|
||||
private int countdownRemaining;
|
||||
private int round = 0;
|
||||
private Material currentTarget;
|
||||
private Material previousTarget;
|
||||
private int currentRoundTime;
|
||||
private int roundTimeRemaining;
|
||||
|
||||
public Arena(BlockPartyPlugin plugin, ArenaConfig config) {
|
||||
this.plugin = plugin;
|
||||
this.config = config;
|
||||
this.floorManager = new FloorManager(plugin, config);
|
||||
if (config.isEnabled()) {
|
||||
stateMachine.transition(ArenaPhase.WAITING);
|
||||
}
|
||||
}
|
||||
|
||||
public ArenaConfig getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public FloorManager getFloorManager() {
|
||||
return floorManager;
|
||||
}
|
||||
|
||||
public ArenaPhase getPhase() {
|
||||
return stateMachine.getState();
|
||||
}
|
||||
|
||||
public List<UUID> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
public List<UUID> getSpectators() {
|
||||
return spectators;
|
||||
}
|
||||
|
||||
public int getRound() {
|
||||
return round;
|
||||
}
|
||||
|
||||
public Material getCurrentTarget() {
|
||||
return currentTarget;
|
||||
}
|
||||
|
||||
public int getRoundTimeRemaining() {
|
||||
return roundTimeRemaining;
|
||||
}
|
||||
|
||||
public int getCurrentRoundTime() {
|
||||
return currentRoundTime;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return getPhase() != ArenaPhase.DISABLED;
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
if (stateMachine.transition(ArenaPhase.WAITING)) {
|
||||
config.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
cancelAllTasks();
|
||||
// Force reset players out regardless of state
|
||||
List<UUID> all = new ArrayList<>();
|
||||
all.addAll(players);
|
||||
all.addAll(spectators);
|
||||
for (UUID uuid : all) {
|
||||
removePlayerForce(uuid);
|
||||
}
|
||||
stateMachine.transition(ArenaPhase.DISABLED);
|
||||
config.setEnabled(false);
|
||||
}
|
||||
|
||||
// ---------- Join / Leave ----------
|
||||
|
||||
public boolean canJoin() {
|
||||
ArenaPhase phase = getPhase();
|
||||
if (phase != ArenaPhase.WAITING && !(phase == ArenaPhase.STARTING && config.isAllowJoinWhileStarting())) {
|
||||
return false;
|
||||
}
|
||||
return players.size() < config.getMaxPlayers();
|
||||
}
|
||||
|
||||
public void addPlayer(Player player) {
|
||||
PlayerState state = PlayerState.capture(player);
|
||||
PlayerSession session = new PlayerSession(player.getUniqueId(), config.getName(), state);
|
||||
plugin.getSessionManager().add(session);
|
||||
players.add(player.getUniqueId());
|
||||
preparePlayerForLobby(player);
|
||||
plugin.getScoreboardManager().attach(player, this);
|
||||
|
||||
maybeStartCountdown();
|
||||
}
|
||||
|
||||
private void preparePlayerForLobby(Player player) {
|
||||
player.getInventory().clear();
|
||||
player.setGameMode(GameMode.ADVENTURE);
|
||||
player.setHealth(20.0);
|
||||
player.setFoodLevel(20);
|
||||
player.setFireTicks(0);
|
||||
if (config.getLobby() != null) {
|
||||
player.teleport(config.getLobby());
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayer(UUID uuid, boolean restoreState) {
|
||||
players.remove(uuid);
|
||||
spectators.remove(uuid);
|
||||
PlayerSession session = plugin.getSessionManager().get(uuid);
|
||||
Player player = plugin.getServer().getPlayer(uuid);
|
||||
if (session != null) {
|
||||
if (restoreState && player != null) {
|
||||
session.getSavedState().restore(player);
|
||||
}
|
||||
plugin.getSessionManager().remove(uuid);
|
||||
}
|
||||
if (player != null) {
|
||||
plugin.getScoreboardManager().detach(player);
|
||||
}
|
||||
checkCountdownCancel();
|
||||
checkForWinner();
|
||||
}
|
||||
|
||||
private void removePlayerForce(UUID uuid) {
|
||||
removePlayer(uuid, true);
|
||||
}
|
||||
|
||||
private void checkCountdownCancel() {
|
||||
if (getPhase() == ArenaPhase.STARTING
|
||||
&& CountdownLogic.shouldCancel(players.size(), config.getMinPlayers(), true)) {
|
||||
cancelCountdown();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Countdown / Starting ----------
|
||||
|
||||
private void maybeStartCountdown() {
|
||||
if (getPhase() == ArenaPhase.WAITING
|
||||
&& CountdownLogic.shouldStart(players.size(), config.getMinPlayers(), false)) {
|
||||
startCountdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void startCountdown() {
|
||||
if (!stateMachine.transition(ArenaPhase.STARTING)) {
|
||||
return;
|
||||
}
|
||||
countdownRemaining = config.getCountdownDuration();
|
||||
BukkitTask task = plugin.getServer().getScheduler().runTaskTimer(plugin, () -> {
|
||||
if (CountdownLogic.isFinished(countdownRemaining)) {
|
||||
return;
|
||||
}
|
||||
broadcastCountdownTick();
|
||||
countdownRemaining = CountdownLogic.tick(countdownRemaining);
|
||||
if (CountdownLogic.isFinished(countdownRemaining)) {
|
||||
beginMatch();
|
||||
}
|
||||
}, 0L, 20L);
|
||||
tasks.add(task);
|
||||
}
|
||||
|
||||
private void cancelCountdown() {
|
||||
cancelAllTasks();
|
||||
stateMachine.transition(ArenaPhase.WAITING);
|
||||
for (UUID uuid : players) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p != null) {
|
||||
p.sendMessage(plugin.getMessages().get("countdown.cancelled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void broadcastCountdownTick() {
|
||||
Map<String, String> ph = Map.of("time", String.valueOf(countdownRemaining), "arena", config.getName());
|
||||
for (UUID uuid : players) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p == null) {
|
||||
continue;
|
||||
}
|
||||
if (plugin.getConfigManager().isActionbarEnabled()) {
|
||||
p.sendActionBar(plugin.getMessages().get("countdown.actionbar", ph));
|
||||
}
|
||||
if (plugin.getConfigManager().isTitlesEnabled() && (countdownRemaining <= 5 || countdownRemaining == config.getCountdownDuration())) {
|
||||
p.showTitle(Title.title(plugin.getMessages().get("countdown.title", ph), Component.empty()));
|
||||
}
|
||||
plugin.getSoundUtil().play(p, plugin.getConfigManager().getSound("countdown"), 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Match flow ----------
|
||||
|
||||
private void beginMatch() {
|
||||
cancelAllTasks();
|
||||
if (!stateMachine.transition(ArenaPhase.RUNNING)) {
|
||||
return;
|
||||
}
|
||||
round = 0;
|
||||
previousTarget = null;
|
||||
if (!floorManager.hasLayout()) {
|
||||
floorManager.generate(random);
|
||||
}
|
||||
floorManager.restoreFull(plugin.getConfigManager().getFloorBatchBlocksPerTick(), () -> {
|
||||
for (UUID uuid : players) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p == null) {
|
||||
continue;
|
||||
}
|
||||
p.setGameMode(GameMode.ADVENTURE);
|
||||
if (config.getSpawn() != null) {
|
||||
p.teleport(config.getSpawn());
|
||||
}
|
||||
}
|
||||
startNextRound();
|
||||
});
|
||||
}
|
||||
|
||||
private void startNextRound() {
|
||||
if (EliminationLogic.isMatchOver(players.size())) {
|
||||
endMatch(players.isEmpty() ? null : (players.isEmpty() ? null : players.get(0)));
|
||||
return;
|
||||
}
|
||||
round++;
|
||||
List<Material> available = floorManager.materialsInLayout().stream().distinct().toList();
|
||||
if (available.isEmpty()) {
|
||||
available = config.getFloorMaterials();
|
||||
}
|
||||
currentTarget = selector.selectExcluding(available, previousTarget);
|
||||
previousTarget = currentTarget;
|
||||
currentRoundTime = RoundTimeCalculator.timeForRound(
|
||||
config.getStartingRoundTime(), config.getMinimumRoundTime(), config.getRoundTimeReduction(), round);
|
||||
roundTimeRemaining = currentRoundTime;
|
||||
|
||||
announceTarget();
|
||||
setupBossBar();
|
||||
|
||||
BukkitTask task = plugin.getServer().getScheduler().runTaskTimer(plugin, () -> {
|
||||
roundTimeRemaining--;
|
||||
updateBossBar();
|
||||
if (roundTimeRemaining <= 0) {
|
||||
cancelAllTasks();
|
||||
processRoundEnd();
|
||||
}
|
||||
}, 20L, 20L);
|
||||
tasks.add(task);
|
||||
}
|
||||
|
||||
private void announceTarget() {
|
||||
Map<String, String> ph = Map.of("color", formatMaterial(currentTarget), "round", String.valueOf(round),
|
||||
"time", String.valueOf(currentRoundTime));
|
||||
ItemStack display = new ItemStack(currentTarget);
|
||||
for (UUID uuid : players) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p == null) {
|
||||
continue;
|
||||
}
|
||||
if (plugin.getConfigManager().isTitlesEnabled()) {
|
||||
p.showTitle(Title.title(plugin.getMessages().get("round.title", ph), plugin.getMessages().get("round.subtitle", ph)));
|
||||
}
|
||||
if (plugin.getConfigManager().isActionbarEnabled()) {
|
||||
p.sendActionBar(plugin.getMessages().get("round.actionbar", ph));
|
||||
}
|
||||
p.getInventory().setItem(8, display.clone());
|
||||
plugin.getSoundUtil().play(p, plugin.getConfigManager().getSound("target-select"), 1f, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupBossBar() {
|
||||
if (!plugin.getConfigManager().isBossbarEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (bossBar == null) {
|
||||
bossBar = BossBar.bossBar(Component.text("BlockParty"), 1f, BossBar.Color.YELLOW, BossBar.Overlay.PROGRESS);
|
||||
}
|
||||
bossBar.progress(1f);
|
||||
for (UUID uuid : players) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p != null) {
|
||||
p.showBossBar(bossBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBossBar() {
|
||||
if (bossBar == null || currentRoundTime <= 0) {
|
||||
return;
|
||||
}
|
||||
float progress = Math.max(0f, Math.min(1f, (float) roundTimeRemaining / (float) currentRoundTime));
|
||||
bossBar.progress(progress);
|
||||
}
|
||||
|
||||
private void processRoundEnd() {
|
||||
plugin.getSoundUtil().play(config.getSpawn(), plugin.getConfigManager().getSound("floor-disappear"), 1f, 1f);
|
||||
floorManager.removeNonTarget(currentTarget, plugin.getConfigManager().getFloorBatchBlocksPerTick(), () -> {
|
||||
BukkitTask delay = plugin.getServer().getScheduler().runTaskLater(plugin, this::evaluateEliminations,
|
||||
config.getFloorRemoveDelaySeconds() * 20L);
|
||||
tasks.add(delay);
|
||||
});
|
||||
}
|
||||
|
||||
private void evaluateEliminations() {
|
||||
List<EliminationLogic.PlayerFloorState<UUID, Material>> states = new ArrayList<>();
|
||||
for (UUID uuid : players) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
Material standing = null;
|
||||
if (p != null && p.getWorld() != null) {
|
||||
standing = floorManager.materialAtLocation(p.getWorld(), p.getLocation().getX(), p.getLocation().getY(), p.getLocation().getZ());
|
||||
}
|
||||
states.add(new EliminationLogic.PlayerFloorState<>(uuid, standing));
|
||||
}
|
||||
List<UUID> eliminated = EliminationLogic.determineEliminated(states, currentTarget);
|
||||
for (UUID uuid : eliminated) {
|
||||
eliminatePlayer(uuid);
|
||||
}
|
||||
for (UUID uuid : players) {
|
||||
PlayerSession session = plugin.getSessionManager().get(uuid);
|
||||
if (session != null && !eliminated.contains(uuid)) {
|
||||
session.incrementRoundsSurvived();
|
||||
}
|
||||
}
|
||||
|
||||
if (EliminationLogic.isMatchOver(players.size())) {
|
||||
UUID winner = players.isEmpty() ? null : players.get(0);
|
||||
if (bossBar != null) {
|
||||
for (UUID uuid : spectators) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p != null) {
|
||||
p.hideBossBar(bossBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
endMatch(winner);
|
||||
return;
|
||||
}
|
||||
|
||||
BukkitTask restoreDelay = plugin.getServer().getScheduler().runTaskLater(plugin, () ->
|
||||
floorManager.restoreFull(plugin.getConfigManager().getFloorBatchBlocksPerTick(), this::startNextRound),
|
||||
config.getFloorRestoreDelaySeconds() * 20L);
|
||||
tasks.add(restoreDelay);
|
||||
}
|
||||
|
||||
private void eliminatePlayer(UUID uuid) {
|
||||
players.remove(uuid);
|
||||
spectators.add(uuid);
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
PlayerSession session = plugin.getSessionManager().get(uuid);
|
||||
if (session != null) {
|
||||
session.setRole(PlayerSession.Role.SPECTATOR);
|
||||
session.setEliminated(true);
|
||||
}
|
||||
if (p != null) {
|
||||
p.setGameMode(GameMode.SPECTATOR);
|
||||
if (config.getSpectator() != null) {
|
||||
p.teleport(config.getSpectator());
|
||||
}
|
||||
p.sendMessage(plugin.getMessages().get("game.eliminated", Map.of("arena", config.getName(), "round", String.valueOf(round))));
|
||||
plugin.getSoundUtil().play(p, plugin.getConfigManager().getSound("eliminate"), 1f, 1f);
|
||||
if (bossBar != null) {
|
||||
p.hideBossBar(bossBar);
|
||||
}
|
||||
}
|
||||
plugin.getStatsManager().recordElimination(uuid, round);
|
||||
}
|
||||
|
||||
private void endMatch(UUID winner) {
|
||||
stateMachine.transition(ArenaPhase.ENDING);
|
||||
cancelAllTasks();
|
||||
if (winner != null) {
|
||||
Player winnerPlayer = plugin.getServer().getPlayer(winner);
|
||||
String winnerName = winnerPlayer != null ? winnerPlayer.getName() : "Unknown";
|
||||
for (UUID uuid : allParticipants()) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p == null) {
|
||||
continue;
|
||||
}
|
||||
p.showTitle(Title.title(plugin.getMessages().get("game.win-title", Map.of("player", winnerName)),
|
||||
Component.empty()));
|
||||
plugin.getSoundUtil().play(p, plugin.getConfigManager().getSound("victory"), 1f, 1f);
|
||||
}
|
||||
if (winnerPlayer != null) {
|
||||
spawnCelebration(winnerPlayer);
|
||||
}
|
||||
plugin.getStatsManager().recordWin(winner);
|
||||
plugin.getRewardManager().dispatchWinnerRewards(winnerName, config.getName(), round);
|
||||
} else {
|
||||
for (UUID uuid : allParticipants()) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
if (p != null) {
|
||||
p.sendMessage(plugin.getMessages().get("game.no-winner"));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UUID uuid : players) {
|
||||
plugin.getStatsManager().recordGamePlayed(uuid);
|
||||
}
|
||||
for (UUID uuid : spectators) {
|
||||
plugin.getStatsManager().recordGamePlayed(uuid);
|
||||
}
|
||||
|
||||
BukkitTask endTask = plugin.getServer().getScheduler().runTaskLater(plugin, this::resetToWaiting,
|
||||
config.getWinEndingDelaySeconds() * 20L);
|
||||
tasks.add(endTask);
|
||||
}
|
||||
|
||||
private void spawnCelebration(Player winner) {
|
||||
try {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
org.bukkit.entity.Firework fw = winner.getWorld().spawn(winner.getLocation(), org.bukkit.entity.Firework.class);
|
||||
org.bukkit.inventory.meta.FireworkMeta meta = fw.getFireworkMeta();
|
||||
meta.addEffect(org.bukkit.FireworkEffect.builder()
|
||||
.withColor(org.bukkit.Color.YELLOW, org.bukkit.Color.LIME)
|
||||
.with(org.bukkit.FireworkEffect.Type.BALL_LARGE)
|
||||
.trail(true)
|
||||
.build());
|
||||
meta.setPower(1);
|
||||
fw.setFireworkMeta(meta);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private List<UUID> allParticipants() {
|
||||
List<UUID> all = new ArrayList<>(players);
|
||||
all.addAll(spectators);
|
||||
return all;
|
||||
}
|
||||
|
||||
private void resetToWaiting() {
|
||||
List<UUID> all = allParticipants();
|
||||
for (UUID uuid : all) {
|
||||
removePlayer(uuid, true);
|
||||
}
|
||||
players.clear();
|
||||
spectators.clear();
|
||||
if (bossBar != null) {
|
||||
bossBar.removeViewer(plugin.getServer().getConsoleSender());
|
||||
}
|
||||
floorManager.cancelActiveTask();
|
||||
cancelAllTasks();
|
||||
round = 0;
|
||||
stateMachine.transition(ArenaPhase.WAITING);
|
||||
}
|
||||
|
||||
private void checkForWinner() {
|
||||
if (getPhase() == ArenaPhase.RUNNING && EliminationLogic.isMatchOver(players.size())) {
|
||||
cancelAllTasks();
|
||||
evaluateEliminations();
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAllTasks() {
|
||||
for (BukkitTask task : tasks) {
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
tasks.clear();
|
||||
floorManager.cancelActiveTask();
|
||||
}
|
||||
|
||||
/** Called on plugin disable / world unload to safely stop everything and restore players. */
|
||||
public void shutdown() {
|
||||
cancelAllTasks();
|
||||
List<UUID> all = allParticipants();
|
||||
for (UUID uuid : all) {
|
||||
Player p = plugin.getServer().getPlayer(uuid);
|
||||
PlayerSession session = plugin.getSessionManager().get(uuid);
|
||||
if (session != null && p != null) {
|
||||
session.getSavedState().restore(p);
|
||||
}
|
||||
plugin.getSessionManager().remove(uuid);
|
||||
}
|
||||
players.clear();
|
||||
spectators.clear();
|
||||
}
|
||||
|
||||
private String formatMaterial(Material material) {
|
||||
String name = material.name().replace("_CONCRETE", "").replace("_", " ").toLowerCase();
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package us.tss3.blockparty.arena;
|
||||
|
||||
import us.tss3.blockparty.BlockPartyPlugin;
|
||||
import us.tss3.blockparty.config.ArenaConfig;
|
||||
import us.tss3.blockparty.config.ArenaConfigLoader;
|
||||
import us.tss3.blockparty.logic.ArenaPhase;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Owns the collection of loaded arenas, keyed by lowercase name. */
|
||||
public class ArenaManager {
|
||||
|
||||
private final BlockPartyPlugin plugin;
|
||||
private final ArenaConfigLoader loader;
|
||||
private final Map<String, Arena> arenas = new LinkedHashMap<>();
|
||||
|
||||
public ArenaManager(BlockPartyPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.loader = new ArenaConfigLoader(plugin);
|
||||
}
|
||||
|
||||
public ArenaConfigLoader getLoader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
public void loadAll() {
|
||||
for (Arena arena : arenas.values()) {
|
||||
arena.shutdown();
|
||||
}
|
||||
arenas.clear();
|
||||
for (ArenaConfig cfg : loader.loadAll()) {
|
||||
arenas.put(cfg.getName().toLowerCase(), new Arena(plugin, cfg));
|
||||
}
|
||||
plugin.getLogger().info("Loaded " + arenas.size() + " arena(s).");
|
||||
}
|
||||
|
||||
/** Reload config/messages/arenas without disturbing arenas that are RUNNING or ENDING. */
|
||||
public void reloadSafely() {
|
||||
for (Map.Entry<String, Arena> entry : arenas.entrySet()) {
|
||||
Arena arena = entry.getValue();
|
||||
if (arena.getPhase() == ArenaPhase.RUNNING || arena.getPhase() == ArenaPhase.ENDING) {
|
||||
plugin.getLogger().warning("Skipping reload of arena '" + arena.getConfig().getName() + "' - match in progress.");
|
||||
continue;
|
||||
}
|
||||
ArenaConfig fresh = loader.load(new java.io.File(loader.getArenasFolder(), arena.getConfig().getName() + ".yml"));
|
||||
if (fresh != null) {
|
||||
arenas.put(entry.getKey(), new Arena(plugin, fresh));
|
||||
}
|
||||
}
|
||||
// Load any brand-new arena files not currently tracked
|
||||
for (ArenaConfig cfg : loader.loadAll()) {
|
||||
arenas.putIfAbsent(cfg.getName().toLowerCase(), new Arena(plugin, cfg));
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Arena> get(String name) {
|
||||
if (name == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.ofNullable(arenas.get(name.toLowerCase()));
|
||||
}
|
||||
|
||||
public boolean exists(String name) {
|
||||
return arenas.containsKey(name.toLowerCase());
|
||||
}
|
||||
|
||||
public Arena createArena(String name, org.bukkit.World world) {
|
||||
ArenaConfig cfg = new ArenaConfig(name);
|
||||
if (world != null) {
|
||||
cfg.setWorldName(world.getName());
|
||||
}
|
||||
cfg.setFloorMaterials(plugin.getConfigManager().getDefaultFloorMaterials().stream()
|
||||
.map(org.bukkit.Material::matchMaterial)
|
||||
.filter(java.util.Objects::nonNull)
|
||||
.toList());
|
||||
cfg.setStartingRoundTime(plugin.getConfigManager().getDefaultStartingRoundTime());
|
||||
cfg.setMinimumRoundTime(plugin.getConfigManager().getDefaultMinimumRoundTime());
|
||||
cfg.setRoundTimeReduction(plugin.getConfigManager().getDefaultRoundReduction());
|
||||
cfg.setCountdownDuration(plugin.getConfigManager().getDefaultCountdown());
|
||||
loader.save(cfg);
|
||||
Arena arena = new Arena(plugin, cfg);
|
||||
arenas.put(name.toLowerCase(), arena);
|
||||
return arena;
|
||||
}
|
||||
|
||||
public boolean deleteArena(String name) {
|
||||
Arena arena = arenas.remove(name.toLowerCase());
|
||||
if (arena != null) {
|
||||
arena.shutdown();
|
||||
}
|
||||
return loader.delete(name);
|
||||
}
|
||||
|
||||
public Collection<Arena> all() {
|
||||
return arenas.values();
|
||||
}
|
||||
|
||||
public List<String> names() {
|
||||
return arenas.values().stream().map(a -> a.getConfig().getName()).toList();
|
||||
}
|
||||
|
||||
public void save(Arena arena) {
|
||||
loader.save(arena.getConfig());
|
||||
}
|
||||
|
||||
public void shutdownAll() {
|
||||
for (Arena arena : arenas.values()) {
|
||||
arena.shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user