package dev.loki.loparkour.ghost.service; import dev.loki.loparkour.config.core.Config; import dev.loki.loparkour.ghost.core.GhostManager; import dev.loki.loparkour.ghost.core.GhostRecorder; import dev.loki.loparkour.ghost.model.GhostData; import dev.loki.loparkour.generator.core.coordinator.ParkourGenerator; import dev.loki.loparkour.player.core.ParkourPlayer; import org.jetbrains.annotations.NotNull; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** * Plugin-owned singleton that records each player's runs as {@link GhostData} * while the server's {@code ghost-mode} is enabled and the player's per-player * {@code ghostRecording} toggle is on. */ public class GhostService { private final GhostManager manager = new GhostManager(); private final Map recorders = new ConcurrentHashMap<>(); private final Set replaying = ConcurrentHashMap.newKeySet(); public GhostManager getManager() { return manager; } private boolean serverEnabled() { return Config.CONFIG.getBoolean("ghost-mode.enabled"); } private boolean recordingEnabled(ParkourPlayer pp) { return serverEnabled() && !replaying.contains(pp.getUUID()) && Boolean.TRUE.equals(pp.ghostRecording); } public void startRun(ParkourGenerator generator) { for (final ParkourPlayer pp : generator.getPlayers()) { if (recordingEnabled(pp)) { recorders.computeIfAbsent(pp.getUUID(), k -> new GhostRecorder()) .startRecording(pp.getLocation()); } else { recorders.remove(pp.getUUID()); } } } public void recordPlayers(ParkourGenerator generator) { for (final ParkourPlayer pp : generator.getPlayers()) { final GhostRecorder recorder = recorders.get(pp.getUUID()); if (recorder != null) { recorder.recordFrame(pp.getLocation()); } } } public void endRun(ParkourGenerator generator, int score) { for (final ParkourPlayer pp : generator.getPlayers()) { final GhostRecorder recorder = recorders.remove(pp.getUUID()); if (recorder != null && recorder.isRecording()) { final String worldName = pp.getLocation().getWorld() == null ? "" : pp.getLocation().getWorld().getName(); final GhostData data = recorder.stopRecording( pp.getUUID(), pp.player.getName(), score, worldName); manager.saveRun(pp.getUUID(), data); } } } public void playerLeft(UUID uuid) { recorders.remove(uuid); } public boolean isReplaying(UUID uuid) { return replaying.contains(uuid); } public void setReplaying(UUID uuid, boolean replaying) { if (replaying) { this.replaying.add(uuid); } else { this.replaying.remove(uuid); } } public void startReplay(@NotNull org.bukkit.entity.Player viewer, @NotNull GhostData run) { playerLeft(viewer.getUniqueId()); setReplaying(viewer.getUniqueId(), true); new GhostReplay(viewer, run, () -> setReplaying(viewer.getUniqueId(), false)).start(); } public void shutdown() { recorders.clear(); } }