package us.tss3.blockparty.config; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import us.tss3.blockparty.logic.ArenaConfigValidator; import us.tss3.blockparty.util.LocationUtil; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; /** Loads/saves individual arena yml files. Each arena is loaded independently; a bad file is logged and skipped. */ public class ArenaConfigLoader { private final Plugin plugin; private final File arenasFolder; public ArenaConfigLoader(Plugin plugin) { this.plugin = plugin; this.arenasFolder = new File(plugin.getDataFolder(), "arenas"); if (!arenasFolder.exists()) { arenasFolder.mkdirs(); } } public File getArenasFolder() { return arenasFolder; } public List loadAll() { List arenas = new ArrayList<>(); File[] files = arenasFolder.listFiles((dir, name) -> name.endsWith(".yml")); if (files == null) { return arenas; } for (File file : files) { try { ArenaConfig cfg = load(file); if (cfg != null) { arenas.add(cfg); } } catch (Exception ex) { plugin.getLogger().log(Level.WARNING, "Failed to load arena file " + file.getName() + ": " + ex.getMessage(), ex); } } return arenas; } public ArenaConfig load(File file) { String name = file.getName().replace(".yml", ""); YamlConfiguration yml = YamlConfiguration.loadConfiguration(file); ArenaConfig cfg = new ArenaConfig(name); cfg.setWorldName(yml.getString("world")); cfg.setLobby(LocationUtil.fromSection(yml.getConfigurationSection("lobby"))); cfg.setSpawn(LocationUtil.fromSection(yml.getConfigurationSection("spawn"))); cfg.setSpectator(LocationUtil.fromSection(yml.getConfigurationSection("spectator"))); cfg.setBillboard(LocationUtil.fromSection(yml.getConfigurationSection("billboard"))); cfg.setBillboardEnabled(yml.getBoolean("billboard-enabled", true)); if (yml.contains("pos1")) { cfg.setPos1(new int[]{yml.getInt("pos1.x"), yml.getInt("pos1.y"), yml.getInt("pos1.z")}); } if (yml.contains("pos2")) { cfg.setPos2(new int[]{yml.getInt("pos2.x"), yml.getInt("pos2.y"), yml.getInt("pos2.z")}); } cfg.setMinPlayers(yml.getInt("min-players", 2)); cfg.setMaxPlayers(yml.getInt("max-players", 16)); cfg.setCountdownDuration(yml.getInt("countdown-duration", 15)); cfg.setRoundPrepDuration(yml.getInt("round-prep-duration", 5)); cfg.setFloorRemoveDelaySeconds(yml.getInt("floor-remove-delay", 1)); cfg.setFloorRestoreDelaySeconds(yml.getInt("floor-restore-delay", 3)); cfg.setStartingRoundTime(yml.getInt("starting-round-time", 20)); cfg.setMinimumRoundTime(yml.getInt("minimum-round-time", 4)); cfg.setRoundTimeReduction(yml.getInt("round-time-reduction", 1)); cfg.setWinEndingDelaySeconds(yml.getInt("win-ending-delay", 6)); cfg.setAllowJoinWhileStarting(yml.getBoolean("allow-join-while-waiting", true)); cfg.setSpectatorsAllowed(yml.getBoolean("spectators-allowed", true)); cfg.setEnabled(yml.getBoolean("enabled", false)); List materials = new ArrayList<>(); for (String matName : yml.getStringList("floor-materials")) { Material mat = Material.matchMaterial(matName); if (mat == null) { plugin.getLogger().warning("Arena '" + name + "': invalid floor material '" + matName + "' skipped."); continue; } materials.add(mat); } cfg.setFloorMaterials(materials); cfg.setGeneratedLayout(yml.getStringList("generated-layout")); return cfg; } public void save(ArenaConfig cfg) { File file = new File(arenasFolder, cfg.getName() + ".yml"); YamlConfiguration yml = new YamlConfiguration(); if (cfg.getWorldName() != null) { yml.set("world", cfg.getWorldName()); } if (cfg.getLobby() != null) { LocationUtil.toSection(yml.createSection("lobby"), cfg.getLobby()); } if (cfg.getSpawn() != null) { LocationUtil.toSection(yml.createSection("spawn"), cfg.getSpawn()); } if (cfg.getSpectator() != null) { LocationUtil.toSection(yml.createSection("spectator"), cfg.getSpectator()); } if (cfg.getBillboard() != null) { LocationUtil.toSection(yml.createSection("billboard"), cfg.getBillboard()); } yml.set("billboard-enabled", cfg.isBillboardEnabled()); if (cfg.getPos1() != null) { yml.set("pos1.x", cfg.getPos1()[0]); yml.set("pos1.y", cfg.getPos1()[1]); yml.set("pos1.z", cfg.getPos1()[2]); } if (cfg.getPos2() != null) { yml.set("pos2.x", cfg.getPos2()[0]); yml.set("pos2.y", cfg.getPos2()[1]); yml.set("pos2.z", cfg.getPos2()[2]); } yml.set("min-players", cfg.getMinPlayers()); yml.set("max-players", cfg.getMaxPlayers()); yml.set("countdown-duration", cfg.getCountdownDuration()); yml.set("round-prep-duration", cfg.getRoundPrepDuration()); yml.set("floor-remove-delay", cfg.getFloorRemoveDelaySeconds()); yml.set("floor-restore-delay", cfg.getFloorRestoreDelaySeconds()); yml.set("starting-round-time", cfg.getStartingRoundTime()); yml.set("minimum-round-time", cfg.getMinimumRoundTime()); yml.set("round-time-reduction", cfg.getRoundTimeReduction()); yml.set("win-ending-delay", cfg.getWinEndingDelaySeconds()); yml.set("allow-join-while-waiting", cfg.isAllowJoinWhileStarting()); yml.set("spectators-allowed", cfg.isSpectatorsAllowed()); yml.set("enabled", cfg.isEnabled()); List matNames = new ArrayList<>(); for (Material m : cfg.getFloorMaterials()) { matNames.add(m.name()); } yml.set("floor-materials", matNames); yml.set("generated-layout", cfg.getGeneratedLayout()); try { yml.save(file); } catch (Exception ex) { plugin.getLogger().log(Level.SEVERE, "Failed to save arena " + cfg.getName(), ex); } } public boolean delete(String name) { File file = new File(arenasFolder, name + ".yml"); return file.exists() && file.delete(); } public List validate(ArenaConfig cfg) { boolean worldOk = cfg.getWorldName() != null && Bukkit.getWorld(cfg.getWorldName()) != null; ArenaConfigValidator.Fields fields = new ArenaConfigValidator.Fields( cfg.getName(), worldOk ? cfg.getWorldName() : null, cfg.getLobby() != null, cfg.getSpawn() != null, cfg.getSpectator() != null, cfg.hasFloorRegion(), cfg.getMinPlayers(), cfg.getMaxPlayers(), cfg.getCountdownDuration(), cfg.getRoundPrepDuration(), cfg.getFloorRemoveDelaySeconds(), cfg.getFloorRestoreDelaySeconds(), cfg.getStartingRoundTime(), cfg.getMinimumRoundTime(), cfg.getRoundTimeReduction(), cfg.getWinEndingDelaySeconds(), cfg.getFloorMaterials().stream().map(Material::name).toList() ); List errors = new ArrayList<>(ArenaConfigValidator.validate(fields)); if (!worldOk && cfg.getWorldName() != null) { errors.add("world '" + cfg.getWorldName() + "' is not currently loaded"); } return errors; } }