From 0174522ede06069d285bcf297654ea32b8f80efa Mon Sep 17 00:00:00 2001 From: M_Viper Date: Thu, 8 Jan 2026 14:58:17 +0000 Subject: [PATCH] Dateien nach "src/main/java/net/viper/status/stats" hochladen --- .../net/viper/status/stats/PlayerStats.java | 70 ++++++++++++ .../net/viper/status/stats/StatsManager.java | 35 ++++++ .../net/viper/status/stats/StatsModule.java | 100 ++++++++++++++++++ .../net/viper/status/stats/StatsStorage.java | 37 +++++++ 4 files changed, 242 insertions(+) create mode 100644 src/main/java/net/viper/status/stats/PlayerStats.java create mode 100644 src/main/java/net/viper/status/stats/StatsManager.java create mode 100644 src/main/java/net/viper/status/stats/StatsModule.java create mode 100644 src/main/java/net/viper/status/stats/StatsStorage.java diff --git a/src/main/java/net/viper/status/stats/PlayerStats.java b/src/main/java/net/viper/status/stats/PlayerStats.java new file mode 100644 index 0000000..9ea857d --- /dev/null +++ b/src/main/java/net/viper/status/stats/PlayerStats.java @@ -0,0 +1,70 @@ +package net.viper.status.stats; + +import java.util.UUID; + +public class PlayerStats { + public final UUID uuid; + public String name; + public long firstSeen; + public long lastSeen; + public long totalPlaytime; + public long currentSessionStart; + public int joins; + + public PlayerStats(UUID uuid, String name) { + this.uuid = uuid; + this.name = name; + long now = System.currentTimeMillis() / 1000L; + this.firstSeen = now; + this.lastSeen = now; + this.totalPlaytime = 0; + this.currentSessionStart = 0; + this.joins = 0; + } + + public synchronized void onJoin() { + long now = System.currentTimeMillis() / 1000L; + if (this.currentSessionStart == 0) this.currentSessionStart = now; + this.lastSeen = now; + this.joins++; + if (this.firstSeen == 0) this.firstSeen = now; + } + + public synchronized void onQuit() { + long now = System.currentTimeMillis() / 1000L; + if (this.currentSessionStart > 0) { + long session = now - this.currentSessionStart; + if (session > 0) this.totalPlaytime += session; + this.currentSessionStart = 0; + } + this.lastSeen = now; + } + + public synchronized long getPlaytimeWithCurrentSession() { + long now = System.currentTimeMillis() / 1000L; + if (this.currentSessionStart > 0) return totalPlaytime + (now - currentSessionStart); + return totalPlaytime; + } + + public synchronized String toLine() { + return uuid + "|" + name.replace("|", "_") + "|" + firstSeen + "|" + lastSeen + "|" + totalPlaytime + "|" + currentSessionStart + "|" + joins; + } + + public static PlayerStats fromLine(String line) { + String[] parts = line.split("\\|", -1); + if (parts.length < 7) return null; + try { + UUID uuid = UUID.fromString(parts[0]); + String name = parts[1]; + PlayerStats ps = new PlayerStats(uuid, name); + ps.firstSeen = Long.parseLong(parts[2]); + ps.lastSeen = Long.parseLong(parts[3]); + ps.totalPlaytime = Long.parseLong(parts[4]); + ps.currentSessionStart = Long.parseLong(parts[5]); + ps.joins = Integer.parseInt(parts[6]); + return ps; + } catch (Exception e) { + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/net/viper/status/stats/StatsManager.java b/src/main/java/net/viper/status/stats/StatsManager.java new file mode 100644 index 0000000..bdfeb30 --- /dev/null +++ b/src/main/java/net/viper/status/stats/StatsManager.java @@ -0,0 +1,35 @@ +package net.viper.status.stats; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class StatsManager { + private final ConcurrentHashMap map = new ConcurrentHashMap<>(); + + public PlayerStats get(UUID uuid, String name) { + return map.compute(uuid, (k, v) -> { + if (v == null) { + return new PlayerStats(uuid, name != null ? name : ""); + } else { + if (name != null && !name.isEmpty()) v.name = name; + return v; + } + }); + } + + public PlayerStats getIfPresent(UUID uuid) { + return map.get(uuid); + } + + public Iterable all() { + return map.values(); + } + + public void put(PlayerStats ps) { + map.put(ps.uuid, ps); + } + + public void remove(UUID uuid) { + map.remove(uuid); + } +} \ No newline at end of file diff --git a/src/main/java/net/viper/status/stats/StatsModule.java b/src/main/java/net/viper/status/stats/StatsModule.java new file mode 100644 index 0000000..3744f67 --- /dev/null +++ b/src/main/java/net/viper/status/stats/StatsModule.java @@ -0,0 +1,100 @@ +package net.viper.status.stats; + +import net.md_5.bungee.api.event.PlayerDisconnectEvent; +import net.md_5.bungee.api.event.PostLoginEvent; +import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; +import net.viper.status.module.Module; + +import java.util.concurrent.TimeUnit; + +/** + * StatsModule: Kümmert sich eigenständig um das Tracking der Spielerdaten. + * Implementiert Module (für das Lifecycle) und Listener (für die Events). + */ +public class StatsModule implements Module, Listener { + + private StatsManager manager; + private StatsStorage storage; + + @Override + public String getName() { + return "StatsModule"; + } + + @Override + public void onEnable(Plugin plugin) { + // Initialisierung + manager = new StatsManager(); + storage = new StatsStorage(plugin.getDataFolder()); + + // Laden + try { + storage.load(manager); + plugin.getLogger().info("Player-Stats wurden erfolgreich geladen."); + } catch (Exception e) { + plugin.getLogger().warning("Fehler beim Laden der Stats: " + e.getMessage()); + } + + // Event Listener registrieren + plugin.getProxy().getPluginManager().registerListener(plugin, this); + + // Auto-Save Task (alle 5 Minuten) + plugin.getProxy().getScheduler().schedule(plugin, () -> { + try { + storage.save(manager); + plugin.getLogger().info("Auto-Save: Player-Stats gespeichert."); + } catch (Exception e) { + plugin.getLogger().warning("Fehler beim Auto-Save: " + e.getMessage()); + } + }, 5, 5, TimeUnit.MINUTES); + } + + @Override + public void onDisable(Plugin plugin) { + if (manager != null && storage != null) { + // Laufende Sessions beenden vor dem Speichern + long now = System.currentTimeMillis() / 1000L; + for (PlayerStats ps : manager.all()) { + synchronized (ps) { + if (ps.currentSessionStart > 0) { + long delta = now - ps.currentSessionStart; + if (delta > 0) { + ps.totalPlaytime += delta; + } + ps.currentSessionStart = 0; // Session beenden + } + } + } + try { + storage.save(manager); + plugin.getLogger().info("Player-Stats beim Shutdown gespeichert."); + } catch (Exception e) { + plugin.getLogger().warning("Fehler beim Speichern (Shutdown): " + e.getMessage()); + } + } + } + + // Öffentlicher Zugriff für den WebServer + public StatsManager getManager() { + return manager; + } + + // --- Events --- + + @EventHandler + public void onJoin(PostLoginEvent e) { + try { + manager.get(e.getPlayer().getUniqueId(), e.getPlayer().getName()).onJoin(); + } catch (Exception ignored) {} + } + + @EventHandler + public void onQuit(PlayerDisconnectEvent e) { + try { + PlayerStats ps = manager.getIfPresent(e.getPlayer().getUniqueId()); + if (ps != null) ps.onQuit(); + } catch (Exception ignored) {} + } +} \ No newline at end of file diff --git a/src/main/java/net/viper/status/stats/StatsStorage.java b/src/main/java/net/viper/status/stats/StatsStorage.java new file mode 100644 index 0000000..86e649d --- /dev/null +++ b/src/main/java/net/viper/status/stats/StatsStorage.java @@ -0,0 +1,37 @@ +package net.viper.status.stats; + +import java.io.*; + +public class StatsStorage { + private final File file; + + public StatsStorage(File pluginFolder) { + if (!pluginFolder.exists()) pluginFolder.mkdirs(); + this.file = new File(pluginFolder, "stats.dat"); + } + + public void save(StatsManager manager) { + try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) { + for (PlayerStats ps : manager.all()) { + bw.write(ps.toLine()); + bw.newLine(); + } + bw.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void load(StatsManager manager) { + if (!file.exists()) return; + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line; + while ((line = br.readLine()) != null) { + PlayerStats ps = PlayerStats.fromLine(line); + if (ps != null) manager.put(ps); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file