diff --git a/src/main/java/com/triassic/geyserdebuginfo/GeyserDebugInfo.java b/src/main/java/com/triassic/geyserdebuginfo/GeyserDebugInfo.java index b4255eb..7cc6fd0 100644 --- a/src/main/java/com/triassic/geyserdebuginfo/GeyserDebugInfo.java +++ b/src/main/java/com/triassic/geyserdebuginfo/GeyserDebugInfo.java @@ -21,7 +21,6 @@ import org.geysermc.geyser.api.extension.ExtensionLogger; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; import java.util.stream.Stream; @@ -54,7 +53,7 @@ public void onPreInitialize(GeyserPreInitializeEvent event) { return; } - this.playerDataManager = new PlayerDataManager(this.dataFolder().toFile(), logger(), false); + this.playerDataManager = new PlayerDataManager(this.dataFolder().toFile(), logger()); this.placeholderManager = new PlaceholderManager(); this.displayManager = new DisplayManager(this); this.eventBus().register(new PlayerJoinListener(this)); @@ -82,6 +81,6 @@ public void onDefineCommands(GeyserDefineCommandsEvent event) { @Subscribe public void onShutdown(GeyserShutdownEvent event) { - playerDataManager.save(); + // playerDataManager.save(); } } \ No newline at end of file diff --git a/src/main/java/com/triassic/geyserdebuginfo/listener/PlayerJoinListener.java b/src/main/java/com/triassic/geyserdebuginfo/listener/PlayerJoinListener.java index 0c9df86..611d15e 100644 --- a/src/main/java/com/triassic/geyserdebuginfo/listener/PlayerJoinListener.java +++ b/src/main/java/com/triassic/geyserdebuginfo/listener/PlayerJoinListener.java @@ -1,6 +1,8 @@ package com.triassic.geyserdebuginfo.listener; import com.triassic.geyserdebuginfo.GeyserDebugInfo; +import com.triassic.geyserdebuginfo.display.DisplayManager; +import com.triassic.geyserdebuginfo.display.DisplayType; import com.triassic.geyserdebuginfo.manager.PlayerDataManager; import org.geysermc.event.subscribe.Subscribe; import org.geysermc.geyser.api.event.bedrock.SessionDisconnectEvent; @@ -8,27 +10,33 @@ import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.session.GeyserSession; +import java.util.Set; + public class PlayerJoinListener { + private final DisplayManager displayManager; private final PlayerDataManager playerDataManager; public PlayerJoinListener( final GeyserDebugInfo instance ) { + this.displayManager = instance.getDisplayManager(); this.playerDataManager = instance.getPlayerDataManager(); } @Subscribe public void onJoin(final SessionJoinEvent event) { final GeyserSession session = (GeyserSession) event.connection(); - final SessionPlayerEntity player = session.getPlayerEntity(); + final Set enabledDisplays = playerDataManager.getEnabledDisplays(session.playerUuid()); - // TODO: Re-implement this. + for (DisplayType displayType : enabledDisplays) { + displayManager.subscribePlayer(session, displayType); + } } @Subscribe public void onDisconnect(final SessionDisconnectEvent event) { final GeyserSession session = (GeyserSession) event.connection(); - // TODO: Remove Bossbar + // TODO: Clean-up. } } diff --git a/src/main/java/com/triassic/geyserdebuginfo/manager/PlayerDataManager.java b/src/main/java/com/triassic/geyserdebuginfo/manager/PlayerDataManager.java index 01d9f5e..4a2c6ae 100644 --- a/src/main/java/com/triassic/geyserdebuginfo/manager/PlayerDataManager.java +++ b/src/main/java/com/triassic/geyserdebuginfo/manager/PlayerDataManager.java @@ -1,100 +1,104 @@ package com.triassic.geyserdebuginfo.manager; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.triassic.geyserdebuginfo.display.DisplayType; +import lombok.Getter; +import lombok.Setter; import org.geysermc.geyser.api.extension.ExtensionLogger; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.Yaml; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.io.IOException; +import java.util.*; public class PlayerDataManager { - private final File playerDataFile; + private final File playerDataFolder; private final ExtensionLogger logger; - private final Yaml yaml; - private final Map> playerDisplayStates; - private final boolean defaultEnabled; - - public PlayerDataManager( - final File dataFolder, - final ExtensionLogger logger, - final boolean defaultEnabled - ) { - this.playerDataFile = new File(dataFolder, "playerdata.yml"); + private final ObjectMapper objectMapper; + private final Map> playerDisplayStates; + + public PlayerDataManager(File dataFolder, ExtensionLogger logger) { + this.playerDataFolder = new File(dataFolder, "playerdata"); this.logger = logger; - this.yaml = new Yaml(createDumperOptions()); + this.objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT); this.playerDisplayStates = new HashMap<>(); - this.defaultEnabled = defaultEnabled; - load(); - } + if (!playerDataFolder.exists() && !playerDataFolder.mkdirs()) { + logger.error("Failed to create player data folder at " + playerDataFolder.getAbsolutePath()); + } - private DumperOptions createDumperOptions() { - DumperOptions options = new DumperOptions(); - options.setIndent(2); - options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - return options; + loadAll(); } - private void load() { - if (!playerDataFile.exists()) return; - - try (FileReader reader = new FileReader(playerDataFile)) { - Map> data = yaml.load(reader); - if (data != null) { - for (Map.Entry> entry : data.entrySet()) { - UUID playerUuid = UUID.fromString(entry.getKey()); - Map displayStates = new HashMap<>(); - for (Map.Entry stateEntry : entry.getValue().entrySet()) { - displayStates.put(DisplayType.valueOf(stateEntry.getKey()), stateEntry.getValue()); - } - playerDisplayStates.put(playerUuid, displayStates); + private void loadAll() { + File[] files = playerDataFolder.listFiles((dir, name) -> name.endsWith(".json")); + if (files == null) return; + + for (File file : files) { + try { + UUID playerUuid = UUID.fromString(file.getName().replace(".json", "")); + PlayerData data = objectMapper.readValue(file, PlayerData.class); + Set enabledDisplays = new HashSet<>(); + for (String display : data.getEnabledDisplays()) { + enabledDisplays.add(DisplayType.valueOf(display)); } + playerDisplayStates.put(playerUuid, enabledDisplays); + } catch (IOException | IllegalArgumentException e) { + logger.error("Failed to load player data from file: " + file.getName(), e); } - } catch (Throwable error) { - logger.error("Failed to load player data file", error); } } - public void save() { - try (FileWriter writer = new FileWriter(playerDataFile)) { - Map> data = new HashMap<>(); - for (Map.Entry> entry : playerDisplayStates.entrySet()) { - UUID playerUuid = entry.getKey(); - Map stateMap = new HashMap<>(); - for (Map.Entry stateEntry : entry.getValue().entrySet()) { - Boolean enabled = stateEntry.getValue(); - if (enabled != defaultEnabled) { - stateMap.put(stateEntry.getKey().name(), enabled); - } - } - if (!stateMap.isEmpty()) { - data.put(playerUuid.toString(), stateMap); - } - } - yaml.dump(data, writer); - } catch (Throwable error) { - logger.error("Failed to save player data to file", error); + public void save(UUID playerUuid) { + Set enabledDisplays = playerDisplayStates.get(playerUuid); + if (enabledDisplays == null) return; + + File playerFile = new File(playerDataFolder, playerUuid + ".json"); + try { + PlayerData data = new PlayerData(); + data.setEnabledDisplays( + enabledDisplays.stream() + .map(DisplayType::name) + .toList() + ); + objectMapper.writeValue(playerFile, data); + } catch (IOException e) { + logger.error("Failed to save player data for " + playerUuid, e); } } public void setDisplayEnabled(UUID playerUuid, DisplayType displayType, boolean enabled) { playerDisplayStates - .computeIfAbsent(playerUuid, k -> new HashMap<>()) - .put(displayType, enabled); + .computeIfAbsent(playerUuid, k -> new HashSet<>()); - save(); + if (enabled) { + playerDisplayStates.get(playerUuid).add(displayType); + } else { + playerDisplayStates.get(playerUuid).remove(displayType); + } + + save(playerUuid); } public boolean isDisplayEnabled(UUID playerUuid, DisplayType displayType) { return playerDisplayStates - .getOrDefault(playerUuid, new HashMap<>()) - .getOrDefault(displayType, defaultEnabled); + .getOrDefault(playerUuid, Collections.emptySet()) + .contains(displayType); + } + + public Set getEnabledDisplays(UUID playerUuid) { + return Collections.unmodifiableSet( + playerDisplayStates.getOrDefault(playerUuid, Collections.emptySet()) + ); + } + + @Setter + @Getter + private static class PlayerData { + private List enabledDisplays = new ArrayList<>(); + } }