package dev.loki.loparkour.ghost; import dev.loki.loparkour.LoParkour; import dev.loki.loparkour.config.Config; import org.bukkit.Location; import org.bukkit.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.*; public class GhostManager { private static final File GHOST_FOLDER = LoParkour.getInFolder("ghosts"); private static final int MAX_GHOSTS_PER_MODE = 3; private final Map> ghostsByMode = new HashMap<>(); private final List activeGhosts = new ArrayList<>(); public GhostManager() { if (!GHOST_FOLDER.exists()) { GHOST_FOLDER.mkdirs(); } } public void loadGhosts(@NotNull String mode) { File modeFolder = new File(GHOST_FOLDER, mode); if (!modeFolder.exists()) { return; } List ghosts = new ArrayList<>(); File[] files = modeFolder.listFiles((dir, name) -> name.endsWith(".ghost")); if (files != null) { for (File file : files) { try { GhostData data = GhostData.loadFromFile(file); ghosts.add(data); } catch (IOException e) { LoParkour.logging().error("Failed to load ghost: " + file.getName()); } } } ghosts.sort((a, b) -> Integer.compare(b.getScore(), a.getScore())); ghostsByMode.put(mode, ghosts); } public void saveGhost(@NotNull String mode, @NotNull GhostData data) { File modeFolder = new File(GHOST_FOLDER, mode); if (!modeFolder.exists()) { modeFolder.mkdirs(); } List ghosts = ghostsByMode.getOrDefault(mode, new ArrayList<>()); ghosts.add(data); ghosts.sort((a, b) -> Integer.compare(b.getScore(), a.getScore())); while (ghosts.size() > MAX_GHOSTS_PER_MODE) { GhostData removed = ghosts.remove(ghosts.size() - 1); File file = new File(modeFolder, removed.getPlayerName() + ".ghost"); file.delete(); } ghostsByMode.put(mode, ghosts); File file = new File(modeFolder, data.getPlayerName() + ".ghost"); try { data.saveToFile(file); } catch (IOException e) { LoParkour.logging().error("Failed to save ghost: " + file.getName()); } } public void spawnGhosts(@NotNull String mode, @NotNull Location startLocation, @NotNull World world) { if (!Config.CONFIG.getBoolean("ghost-mode.enabled")) { return; } stopAllGhosts(); List ghosts = ghostsByMode.get(mode); if (ghosts == null || ghosts.isEmpty()) { return; } int showTop = Math.min(Config.CONFIG.getInt("ghost-mode.show-top"), ghosts.size()); for (int i = 0; i < showTop; i++) { GhostPlayer ghost = new GhostPlayer(ghosts.get(i), world); ghost.spawn(startLocation); activeGhosts.add(ghost); } } public void stopAllGhosts() { for (GhostPlayer ghost : activeGhosts) { ghost.stop(); } activeGhosts.clear(); } @Nullable public GhostData getTopGhost(@NotNull String mode) { List ghosts = ghostsByMode.get(mode); if (ghosts == null || ghosts.isEmpty()) { return null; } return ghosts.get(0); } public List getTopGhosts(@NotNull String mode, int count) { List ghosts = ghostsByMode.get(mode); if (ghosts == null || ghosts.isEmpty()) { return Collections.emptyList(); } return ghosts.subList(0, Math.min(count, ghosts.size())); } public boolean shouldRecordGhost(@NotNull String mode, int score) { List ghosts = ghostsByMode.get(mode); if (ghosts == null || ghosts.size() < MAX_GHOSTS_PER_MODE) { return true; } GhostData lowestGhost = ghosts.get(ghosts.size() - 1); return score > lowestGhost.getScore(); } }