Delete src/main/java/net/viper/status/stats/StatsModule.java via Git Manager GUI

This commit is contained in:
2026-05-24 19:43:54 +00:00
parent 096609dba9
commit d9ff16fe76

View File

@@ -1,145 +0,0 @@
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: Tracking von Spielerdaten (Playtime, Joins, Kills, Deaths).
*
* Fixes:
* - BUG-1: Crash-Recovery für currentSessionStart (verhindert falsche Spielzeit nach Absturz)
* - BUG-2: kills / deaths werden jetzt getrackt und per POST /stats/update aktualisiert
*/
public class StatsModule implements Module, Listener {
/**
* Maximale Sessionlänge nach einem Crash noch gutschreiben (24 Stunden).
* Längere Differenzen sind unrealistisch → werden ignoriert, currentSessionStart = 0 gesetzt.
*/
private static final long MAX_SESSION_SECONDS = 86_400L;
private StatsManager manager;
private StatsStorage storage;
@Override
public String getName() {
return "StatsModule";
}
@Override
public void onEnable(Plugin plugin) {
manager = new StatsManager();
storage = new StatsStorage(plugin.getDataFolder());
try {
storage.load(manager);
} catch (Exception e) {
plugin.getLogger().warning("Fehler beim Laden der Stats: " + e.getMessage());
}
// -----------------------------------------------------------------------
// FIX BUG-1: Crash-Recovery offene Sessions bereinigen.
//
// Bei normalem Shutdown setzt onDisable() currentSessionStart = 0 und speichert.
// Bei einem Crash (kill -9, OOM, etc.) passiert das nicht. Beim nächsten Start
// sind alle Spieler offline, aber currentSessionStart enthält noch den alten
// Timestamp. getPlaytimeWithCurrentSession() würde dann fälschlicherweise
// (now - alter_crash_timestamp) zur Spielzeit addieren → massiv falscher Wert.
//
// Fix: Nach dem Laden jeden Eintrag prüfen. Falls currentSessionStart > 0:
// - Plausible Differenz (≤ MAX_SESSION_SECONDS) → als echte Zeit gutschreiben
// - Unplausibel (> MAX_SESSION_SECONDS) → verwerfen, nur zurücksetzen
// - In beiden Fällen: currentSessionStart = 0 setzen
// -----------------------------------------------------------------------
long now = System.currentTimeMillis() / 1000L;
int recovered = 0;
for (PlayerStats ps : manager.all()) {
synchronized (ps) {
if (ps.currentSessionStart > 0) {
long delta = now - ps.currentSessionStart;
if (delta > 0 && delta <= MAX_SESSION_SECONDS) {
ps.totalPlaytime += delta;
recovered++;
} else if (delta > MAX_SESSION_SECONDS) {
plugin.getLogger().warning(
"[StatsModule] Unplausibler currentSessionStart für " + ps.name
+ " (delta=" + delta + "s > " + MAX_SESSION_SECONDS + "s). "
+ "Session wird ohne Gutschrift zurückgesetzt."
);
}
ps.currentSessionStart = 0;
}
}
}
if (recovered > 0) {
plugin.getLogger().info(
"[StatsModule] Crash-Recovery: " + recovered + " offene Session(en) bereinigt und gespeichert."
);
try {
storage.save(manager);
} catch (Exception e) {
plugin.getLogger().warning("Fehler beim Speichern nach Crash-Recovery: " + e.getMessage());
}
}
// -----------------------------------------------------------------------
plugin.getProxy().getPluginManager().registerListener(plugin, this);
// Auto-Save alle 5 Minuten
plugin.getProxy().getScheduler().schedule(plugin, () -> {
try {
storage.save(manager);
} 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) {
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;
}
}
}
try {
storage.save(manager);
} catch (Exception e) {
plugin.getLogger().warning("Fehler beim Speichern (Shutdown): " + e.getMessage());
}
}
}
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) {}
}
}