233 lines
9.1 KiB
Java
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;
|
|
}
|
|
}
|