package net.knarcraft.minigames.util; import net.knarcraft.minigames.MiniGames; import net.knarcraft.minigames.arena.ArenaGameMode; import net.knarcraft.minigames.arena.ArenaRecordsRegistry; import net.knarcraft.minigames.arena.parkour.ParkourArena; import net.knarcraft.minigames.arena.parkour.ParkourArenaData; import net.knarcraft.minigames.arena.parkour.ParkourArenaGameMode; import net.knarcraft.minigames.arena.parkour.ParkourArenaGroup; import net.knarcraft.minigames.arena.parkour.ParkourArenaRecordsRegistry; import net.knarcraft.minigames.arena.parkour.ParkourArenaStorageKey; import net.knarcraft.minigames.config.MiniGameMessage; import net.knarcraft.minigames.container.SerializableMaterial; import net.knarcraft.minigames.container.SerializableUUID; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.logging.Level; import static net.knarcraft.minigames.util.ArenaStorageHelper.getArenaDataFile; /** * A helper class for saving and loading parkour arenas */ public final class ParkourArenaStorageHelper { private ParkourArenaStorageHelper() { } private final static File dataFolder = MiniGames.getInstance().getDataFolder(); private final static String parkourArenasConfigurationSection = "parkourArenas"; private final static String parkourGroupsConfigurationSection = "parkourGroups"; private static final File parkourGroupFile = new File(dataFolder, "parkour_groups.yml"); private static final File parkourArenaFile = new File(dataFolder, "parkour_arenas.yml"); private static final File parkourArenaDataFolder = new File(dataFolder, "parkour_arena_data"); /** * Saves the given parkour arena groups * * @param arenaGroups

The arena groups to save

* @throws IOException

If unable to write to the file

*/ public static void saveParkourArenaGroups(@NotNull Set arenaGroups) throws IOException { YamlConfiguration configuration = new YamlConfiguration(); ConfigurationSection groupSection = configuration.createSection(parkourGroupsConfigurationSection); for (ParkourArenaGroup arenaGroup : arenaGroups) { groupSection.set(arenaGroup.getGroupId().toString(), arenaGroup); } configuration.save(parkourGroupFile); } /** * Loads all existing parkour arena groups * * @return

The loaded arena groups

*/ public static @NotNull Set loadParkourArenaGroups() { YamlConfiguration configuration = YamlConfiguration.loadConfiguration(parkourGroupFile); ConfigurationSection groupSection = configuration.getConfigurationSection(parkourGroupsConfigurationSection); //If no such section exists, it must be the case that there is no data to load if (groupSection == null) { return new HashSet<>(); } Set arenaGroups = new HashSet<>(); for (String sectionName : groupSection.getKeys(false)) { arenaGroups.add((ParkourArenaGroup) groupSection.get(sectionName)); } return arenaGroups; } /** * Saves the given arenas * * @param arenas

The arenas to save

* @throws IOException

If unable to write to the file

*/ public static void saveParkourArenas(@NotNull Map arenas) throws IOException { YamlConfiguration configuration = new YamlConfiguration(); ConfigurationSection arenaSection = configuration.createSection(parkourArenasConfigurationSection); for (ParkourArena arena : arenas.values()) { //Note: While the arena name is used as the key, as the key has to be sanitized, the un-sanitized arena name // must be stored as well @NotNull ConfigurationSection configSection = arenaSection.createSection(arena.getArenaId().toString()); configSection.set(ParkourArenaStorageKey.ID.getKey(), new SerializableUUID(arena.getArenaId())); configSection.set(ParkourArenaStorageKey.NAME.getKey(), arena.getArenaName()); configSection.set(ParkourArenaStorageKey.SPAWN_LOCATION.getKey(), arena.getSpawnLocation()); configSection.set(ParkourArenaStorageKey.EXIT_LOCATION.getKey(), arena.getExitLocation()); configSection.set(ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey(), new SerializableMaterial(arena.getWinBlockType())); configSection.set(ParkourArenaStorageKey.WIN_LOCATION.getKey(), arena.getWinLocation()); configSection.set(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey(), arena.getKillPlaneBlockNames()); configSection.set(ParkourArenaStorageKey.CHECKPOINTS.getKey(), arena.getCheckpoints()); saveParkourArenaData(arena.getData()); } configuration.save(parkourArenaFile); } /** * Loads all arenas * * @return

The loaded arenas, or null if the arenas configuration section is missing.

*/ public static @NotNull Map loadParkourArenas() { YamlConfiguration configuration = YamlConfiguration.loadConfiguration(parkourArenaFile); ConfigurationSection arenaSection = configuration.getConfigurationSection(parkourArenasConfigurationSection); //If no such section exists, it must be the case that there is no data to load if (arenaSection == null) { return new HashMap<>(); } Map loadedArenas = new HashMap<>(); for (String sectionName : arenaSection.getKeys(false)) { ConfigurationSection configurationSection = arenaSection.getConfigurationSection(sectionName); //I'm not sure whether this could actually happen if (configurationSection == null) { continue; } ParkourArena arena = loadParkourArena(configurationSection); if (arena != null) { loadedArenas.put(arena.getArenaId(), arena); } } return loadedArenas; } /** * Loads an arena from the given configuration section * * @param configurationSection

The configuration section containing arena data

* @return

The loaded arena, or null if invalid

*/ @SuppressWarnings("unchecked") private static @Nullable ParkourArena loadParkourArena(@NotNull ConfigurationSection configurationSection) { UUID arenaId = ((SerializableUUID) configurationSection.get(ParkourArenaStorageKey.ID.getKey(), new SerializableUUID(UUID.randomUUID()))).getRawValue(); String arenaName = configurationSection.getString(ParkourArenaStorageKey.NAME.getKey()); Location spawnLocation = (Location) configurationSection.get(ParkourArenaStorageKey.SPAWN_LOCATION.getKey()); Location exitLocation = (Location) configurationSection.get(ParkourArenaStorageKey.EXIT_LOCATION.getKey()); Location winLocation = (Location) configurationSection.get(ParkourArenaStorageKey.WIN_LOCATION.getKey()); SerializableMaterial winBlockType = (SerializableMaterial) configurationSection.get( ParkourArenaStorageKey.WIN_BLOCK_TYPE.getKey()); List killPlaneBlockNames = configurationSection.getList(ParkourArenaStorageKey.KILL_PLANE_BLOCKS.getKey()); List checkpoints = (List) configurationSection.get(ParkourArenaStorageKey.CHECKPOINTS.getKey()); // The arena name and spawn location must be present if (arenaName == null || spawnLocation == null) { MiniGames.log(Level.SEVERE, MiniGames.getInstance().getStringFormatter().replacePlaceholders( MiniGameMessage.ERROR_ARENA_NOT_LOADED, new String[]{"{section}", "{file}"}, new String[]{configurationSection.getName(), "parkour_arena"})); return null; } // Fall back to the default win block if (winBlockType == null) { winBlockType = new SerializableMaterial(Material.EMERALD_BLOCK); } // Generate new, empty arena data if not available ParkourArenaData arenaData = loadParkourArenaData(arenaId); if (arenaData == null) { MiniGames.log(Level.SEVERE, MiniGames.getInstance().getStringFormatter().replacePlaceholder( MiniGameMessage.ERROR_ARENA_DATA_NOT_LOADED, "{arena}", arenaId.toString())); arenaData = getEmptyParkourData(arenaId); } if (checkpoints == null) { checkpoints = new ArrayList<>(); } return new ParkourArena(arenaId, arenaName, spawnLocation, exitLocation, winBlockType.getRawValue(), winLocation, (Set) killPlaneBlockNames, checkpoints, arenaData, MiniGames.getInstance().getParkourArenaHandler()); } /** * Gets empty parkour data * * @param arenaId

The id to get parkour data for

* @return

Empty parkour data

*/ private static @NotNull ParkourArenaData getEmptyParkourData(@NotNull UUID arenaId) { Map recordRegistries = new HashMap<>(); Map> playersCompleted = new HashMap<>(); for (ArenaGameMode arenaGameMode : ParkourArenaGameMode.values()) { recordRegistries.put(arenaGameMode, new ParkourArenaRecordsRegistry(arenaId)); playersCompleted.put(arenaGameMode, new HashSet<>()); } return new ParkourArenaData(arenaId, recordRegistries, playersCompleted); } /** * Stores the given arena data to a file * * @param arenaData

The arena data to store

*/ public static void saveParkourArenaData(@NotNull ParkourArenaData arenaData) throws IOException { YamlConfiguration configuration = new YamlConfiguration(); configuration.set(ParkourArenaStorageKey.DATA.getKey(), arenaData); configuration.save(getParkourArenaDataFile(arenaData.getArenaId())); } /** * Loads arena data for the given arena id * * @param arenaId

The id of the arena to get data for

* @return

The loaded arena data

*/ private static @Nullable ParkourArenaData loadParkourArenaData(@NotNull UUID arenaId) { File arenaDataFile = getParkourArenaDataFile(arenaId); YamlConfiguration configuration = YamlConfiguration.loadConfiguration(arenaDataFile); return (ParkourArenaData) configuration.get(ParkourArenaStorageKey.DATA.getKey()); } /** * Removes data for the arena with the given id * * @param arenaId

The id of the arena to remove data for

* @return

True if the data was successfully removed

*/ public static boolean removeParkourArenaData(@NotNull UUID arenaId) { return getParkourArenaDataFile(arenaId).delete(); } /** * Gets the file used to store the given arena id's data * * @param arenaId

The id of the arena to get a data file for

* @return

The file the arena's data is/should be stored in

*/ private static @NotNull File getParkourArenaDataFile(@NotNull UUID arenaId) { return getArenaDataFile(parkourArenaDataFolder, arenaId); } }