Files
ServerPulse/src/main/java/de/serverpulse/spigot/alerts/AlertManager.java
2026-06-18 20:56:01 +02:00

233 lines
9.1 KiB
Java

package de.serverpulse.spigot.alerts;
import de.serverpulse.spigot.SpigotPlugin;
import de.serverpulse.models.AlertSeverity;
import de.serverpulse.spigot.utils.MsgUtil;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Monster;
import java.util.HashMap;
import java.util.Map;
/**
* Verwaltet alle Warnungen, Cooldowns und Notfallmaßnahmen.
* Verhindert Alert-Spam durch einen Cooldown-Mechanismus.
*/
public class AlertManager {
private final SpigotPlugin plugin;
private final long pluginStartTimeMs;
private final long startupGracePeriodMs;
// Cooldown: alertType -> letzter Trigger-Zeitpunkt (ms)
private final Map<String, Long> alertCooldowns = new HashMap<>();
// Standard-Cooldown: 5 Minuten
private static final long DEFAULT_COOLDOWN_MS = 5 * 60 * 1000;
// Zähler für kritische Ereignisse (für Auto-Diagnose)
private int criticalEventCount = 0;
// Item-Clear läuft gerade?
private boolean itemClearRunning = false;
public AlertManager(SpigotPlugin plugin) {
this.plugin = plugin;
this.pluginStartTimeMs = System.currentTimeMillis();
this.startupGracePeriodMs = plugin.getSpigotConfig().getStartupCheckDelayMinutes() * 60_000L;
}
// ──────────────────────────────────────────
// ALERT AUSLÖSEN
// ──────────────────────────────────────────
/**
* Löst eine Warnung aus, wenn kein Cooldown aktiv ist.
*/
public void triggerAlert(String alertType, AlertSeverity severity, String worldName,
String message, Double currentValue, Double threshold) {
if (isStartupGracePeriodActive()) {
plugin.debug("Startup-Delay aktiv: Alert unterdrückt (" + alertType + ")");
return;
}
// Cooldown prüfen
String cooldownKey = alertType + (worldName != null ? "_" + worldName : "");
long now = System.currentTimeMillis();
if (alertCooldowns.containsKey(cooldownKey)) {
long lastAlert = alertCooldowns.get(cooldownKey);
if (now - lastAlert < DEFAULT_COOLDOWN_MS) {
plugin.debug("Alert-Cooldown aktiv für: " + cooldownKey);
return;
}
}
alertCooldowns.put(cooldownKey, now);
// Alert loggen
plugin.getLogger().warning("[" + severity.getName() + "] " + message);
// In DB speichern
if (plugin.getDatabaseManager().isConnected()) {
plugin.getDatabaseManager().saveAlert(
alertType, severity.getName(), worldName, message, currentValue, threshold
);
}
// Discord-Benachrichtigung senden
if (plugin.getSpigotConfig().isDiscordEnabled()) {
plugin.getDiscordWebhook().sendAlert(alertType, severity, worldName, message, currentValue, threshold);
}
// Alert an BungeeCord weitergeben
if (plugin.getMessenger() != null) {
plugin.getMessenger().sendAlert(alertType, severity.getName(), message);
}
// Kritische Events zählen für Auto-Diagnose
if (severity == AlertSeverity.CRITICAL) {
criticalEventCount++;
if (plugin.getSpigotConfig().isAutoDiagnosisEnabled()) {
if (criticalEventCount >= plugin.getSpigotConfig().getAutoDiagnosisTrigger()) {
triggerDiagnosisReport();
criticalEventCount = 0;
}
}
}
}
// ──────────────────────────────────────────
// NOTFALLMASSNAHMEN
// ──────────────────────────────────────────
/**
* Löst einen Item-Clear mit Countdown aus
*/
public void triggerItemClear(String worldName) {
if (itemClearRunning) return;
itemClearRunning = true;
int countdown = plugin.getSpigotConfig().getItemClearCountdown();
String broadcastMsg = plugin.getSpigotConfig().getItemClearMessage();
// Countdown-Broadcasts
if (plugin.getSpigotConfig().isItemClearBroadcast()) {
for (int i = countdown; i > 0; i -= (i > 10 ? 10 : (i > 5 ? 5 : 1))) {
final int secondsLeft = i;
Bukkit.getScheduler().runTaskLater(plugin, () -> {
String msg = broadcastMsg.replace("{seconds}", String.valueOf(secondsLeft));
Bukkit.broadcastMessage(MsgUtil.colorize(msg));
}, (countdown - i) * 20L);
}
}
// Clear ausführen nach Countdown
Bukkit.getScheduler().runTaskLater(plugin, () -> {
World world = Bukkit.getWorld(worldName);
if (world != null) {
int cleared = 0;
for (Entity entity : world.getEntities()) {
if (entity instanceof Item) {
entity.remove();
cleared++;
}
}
plugin.getLogger().info("Item-Clear ausgeführt in " + worldName + ": " + cleared + " Items entfernt.");
if (plugin.getSpigotConfig().isItemClearBroadcast()) {
Bukkit.broadcastMessage(MsgUtil.colorize(
"&a[ServerPulse] Item-Clear abgeschlossen! " + cleared + " Items wurden entfernt."));
}
triggerAlert("ITEM_CLEAR_EXECUTED", AlertSeverity.INFO, worldName,
"Automatischer Item-Clear: " + cleared + " Items in " + worldName + " entfernt.",
(double) cleared, null);
}
itemClearRunning = false;
}, countdown * 20L);
}
/**
* Führt einen Mob-Clear in einer Welt durch
*/
public void triggerMobClear(String worldName) {
boolean hostileOnly = plugin.getSpigotConfig().isMobClearHostileOnly();
World world = Bukkit.getWorld(worldName);
if (world == null) return;
Bukkit.getScheduler().runTask(plugin, () -> {
int cleared = 0;
for (Entity entity : world.getEntities()) {
if (entity instanceof Monster) {
entity.remove();
cleared++;
}
}
plugin.getLogger().info("Mob-Clear ausgeführt in " + worldName + ": " + cleared + " Mobs entfernt.");
triggerAlert("MOB_CLEAR_EXECUTED", AlertSeverity.INFO, worldName,
"Automatischer Mob-Clear: " + cleared + " Mobs in " + worldName + " entfernt.",
(double) cleared, null);
});
}
/**
* Erstellt automatisch einen Diagnose-Report
*/
private void triggerDiagnosisReport() {
plugin.getLogger().warning("[ServerPulse] Erstelle automatischen Diagnose-Report...");
StringBuilder report = new StringBuilder();
report.append("=== AUTOMATISCHER DIAGNOSE-REPORT ===\n");
report.append("Zeitpunkt: ").append(MsgUtil.timestamp()).append("\n\n");
// Performance
if (plugin.getPerformanceMonitor().getLastSnapshot() != null) {
var snap = plugin.getPerformanceMonitor().getLastSnapshot();
report.append("Performance:\n");
report.append(" TPS: ").append(String.format("%.2f", snap.getTps())).append("\n");
report.append(" MSPT: ").append(String.format("%.2f", snap.getMspt())).append("ms\n");
report.append(" RAM: ").append(snap.getRamUsedMb()).append("MB / ").append(snap.getRamMaxMb()).append("MB\n");
report.append(" Spieler: ").append(snap.getOnlinePlayers()).append("\n");
report.append(" Chunks: ").append(snap.getLoadedChunks()).append("\n\n");
}
// Entities pro Welt
report.append("Entities pro Welt:\n");
for (var entry : plugin.getEntityMonitor().getAllLastSnapshots().entrySet()) {
var snap = entry.getValue();
report.append(" ").append(entry.getKey()).append(": ")
.append("Gesamt=").append(snap.getTotal())
.append(", Monster=").append(snap.getMonsters())
.append(", Items=").append(snap.getItems())
.append("\n");
}
String reportContent = report.toString();
// In DB speichern
if (plugin.getDatabaseManager().isConnected()) {
plugin.getDatabaseManager().saveReport("AUTO_DIAGNOSIS", "ServerPulse", reportContent);
}
plugin.getLogger().warning(reportContent);
}
/**
* Setzt alle Alert-Cooldowns zurück (z.B. nach reload)
*/
public void clearCooldowns() {
alertCooldowns.clear();
criticalEventCount = 0;
}
public int getCriticalEventCount() {
return criticalEventCount;
}
private boolean isStartupGracePeriodActive() {
return System.currentTimeMillis() - pluginStartTimeMs < startupGracePeriodMs;
}
}