Files
TicketSystem/src/main/java/de/ticketsystem/TicketPlugin.java
2026-04-16 11:48:01 +02:00

303 lines
15 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package de.ticketsystem;
import de.ticketsystem.bungee.BungeeMessenger;
import de.ticketsystem.cache.TicketCache;
import de.ticketsystem.commands.TicketCommand;
import de.ticketsystem.database.DatabaseManager;
import de.ticketsystem.discord.DiscordWebhook;
import de.ticketsystem.gui.FaqGUI;
import de.ticketsystem.gui.TicketGUI;
import de.ticketsystem.listeners.PlayerJoinListener;
import de.ticketsystem.manager.CategoryManager;
import de.ticketsystem.manager.FaqManager;
import de.ticketsystem.manager.LanguageManager;
import de.ticketsystem.manager.TicketManager;
import de.ticketsystem.model.Ticket;
import de.ticketsystem.model.TicketPriority;
import de.ticketsystem.web.SessionManager;
import de.ticketsystem.web.WebServer;
import org.bukkit.ChatColor;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Objects;
public class TicketPlugin extends JavaPlugin {
private static TicketPlugin instance;
private boolean debug;
/**
* Name dieses Servers im BungeeCord-Netzwerk.
* Konfigurierbar in config.yml → server-name
*/
private String serverName;
private LanguageManager languageManager;
private DatabaseManager databaseManager;
private TicketManager ticketManager;
private CategoryManager categoryManager;
private FaqManager faqManager;
private TicketGUI ticketGUI;
private FaqGUI faqGUI;
private DiscordWebhook discordWebhook;
private BungeeMessenger bungeeMessenger;
private TicketCache ticketCache;
private SessionManager sessionManager;
private WebServer webServer;
@Override
public void onEnable() {
instance = this;
saveDefaultConfig();
// Ticket-Klasse für YAML-Serialisierung registrieren
Ticket.register();
// ── Sprachdatei laden (lang.yml) ──────────────────────────────────
// Muss VOR allen anderen Managern geschehen, da diese lang() nutzen.
languageManager = new LanguageManager(this);
TicketPriority.reloadLocalizedNames(this);
// ── BungeeCord Plugin-Messaging-Kanäle registrieren ───────────────
getServer().getMessenger().registerOutgoingPluginChannel(this, BungeeMessenger.BUNGEE_CHANNEL);
getServer().getMessenger().registerOutgoingPluginChannel(this, BungeeMessenger.CUSTOM_CHANNEL);
bungeeMessenger = new BungeeMessenger(this);
getServer().getMessenger().registerIncomingPluginChannel(this, BungeeMessenger.CUSTOM_CHANNEL, bungeeMessenger);
// Server-Name aus Config lesen
serverName = getConfig().getString("server-name", "unknown");
if ("unknown".equals(serverName)) {
getLogger().warning("[BungeeCord] Kein 'server-name' in der config.yml definiert!");
}
// BungeeCord-Hinweis nur bei deaktiviertem Feature und aktivem Debug ausgeben
if (getConfig().getBoolean("debug", false) && !getConfig().getBoolean("bungeecord", false)) {
getLogger().info("[BungeeCord] Cross-Server-Features deaktiviert. Setze 'bungeecord: true' um sie zu aktivieren.");
}
// Update-Checker
int resourceId = 132757;
new UpdateChecker(this, resourceId).getVersion(version -> {
String current = getDescription().getVersion();
if (!current.equals(version)) {
String msg = lang().format("update.available-line1", "{version}", version);
getLogger().warning(lang().format("update.available-console",
"{new}", version, "{current}", current));
getServer().getScheduler().runTaskLater(this, () ->
getServer().getOnlinePlayers().stream()
.filter(p -> p.hasPermission("ticket.admin"))
.forEach(p -> p.sendMessage(msg)), 20L);
}
});
// Versionsprüfung der config.yml
String configVersion = getConfig().getString("version", "");
String expectedVersion = "2.5";
if (!expectedVersion.equals(configVersion)) {
getLogger().warning("[WARNUNG] config.yml-Version (" + configVersion
+ ") stimmt nicht mit der erwarteten Version (" + expectedVersion + ") überein!");
}
debug = getConfig().getBoolean("debug", false);
// ── Performance: Ticket-Cache ──────────────────────────────────────
long cacheTtl = getConfig().getLong("cache-ttl-seconds", 60) * 1000L;
ticketCache = new TicketCache(cacheTtl);
// Regelmäßige Cache-Bereinigung alle 5 Minuten
getServer().getScheduler().runTaskTimerAsynchronously(this,
() -> ticketCache.evictExpired(), 6000L, 6000L);
// Datenbankverbindung
databaseManager = new DatabaseManager(this);
if (!databaseManager.connect()) {
getLogger().severe("Konnte keine Datenbankverbindung herstellen! Plugin läuft im Datei-Modus weiter.");
}
// Manager, GUI, FAQ & Discord-Webhook initialisieren
categoryManager = new CategoryManager(this);
ticketManager = new TicketManager(this);
faqManager = new FaqManager(this);
ticketGUI = new TicketGUI(this);
faqGUI = new FaqGUI(this);
discordWebhook = new DiscordWebhook(this);
if (getConfig().getBoolean("discord.enabled", false)) {
String url = getConfig().getString("discord.webhook-url", "");
if (url.isEmpty()) {
getLogger().warning("[DiscordWebhook] Aktiviert, aber keine Webhook-URL in config.yml eingetragen!");
}
}
// Commands & Events
TicketCommand ticketCommand = new TicketCommand(this);
Objects.requireNonNull(getCommand("ticket")).setExecutor(ticketCommand);
Objects.requireNonNull(getCommand("ticket")).setTabCompleter(ticketCommand);
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
getServer().getPluginManager().registerEvents(ticketGUI, this);
getServer().getPluginManager().registerEvents(faqGUI, this);
// Automatische Archivierung
int archiveIntervalH = getConfig().getInt("auto-archive-interval-hours", 24);
if (archiveIntervalH > 0) {
long ticks = archiveIntervalH * 60L * 60L * 20L;
getServer().getScheduler().runTaskTimer(this, () -> {
int archived = databaseManager.archiveClosedTickets();
if (archived > 0) {
getLogger().info("Automatische Archivierung: " + archived + " Tickets archiviert.");
}
}, ticks, ticks);
}
// Web-Panel starten
if (getConfig().getBoolean("web-panel.enabled", false)) {
sessionManager = new SessionManager(this);
webServer = new WebServer(this, sessionManager);
webServer.start();
}
getLogger().info("TicketSystem v" + getDescription().getVersion() + " erfolgreich gestartet!");
}
@Override
public void onDisable() {
getServer().getMessenger().unregisterOutgoingPluginChannel(this);
getServer().getMessenger().unregisterIncomingPluginChannel(this);
if (webServer != null) webServer.stop();
if (ticketCache != null) ticketCache.clear();
if (databaseManager != null) databaseManager.disconnect();
getLogger().info("TicketSystem wurde deaktiviert.");
}
// ─────────────────────────── Hilfsmethoden ─────────────────────────────
/**
* Gibt den LanguageManager zurück bevorzugte Methode für alle Texte.
*
* Verwendung:
* plugin.lang().get("ticket.created")
* plugin.lang().format("ticket.created", "{id}", String.valueOf(id))
* plugin.lang().send(player, "ticket.created", "{id}", String.valueOf(id))
*/
public LanguageManager lang() {
return languageManager;
}
/**
* Kompatibilitätsmethode für bestehenden Code.
* Liest Pfade der Form "messages.xxx" aus lang.yml (ohne "messages."-Prefix).
*
* Beispiel: formatMessage("messages.ticket-created") → lang "ticket.created"
*
* @deprecated Direkt {@link #lang()} verwenden.
*/
@Deprecated
public String formatMessage(String path) {
// "messages.ticket-created" → "ticket.created" (legacy-Mapping)
String langKey = mapLegacyPath(path);
if (langKey != null) {
return lang().formatWithPrefix(langKey);
}
// Fallback: Direkt in lang.yml nachschlagen
String value = lang().getRaw(path);
return lang().getPrefix() + lang().color(value);
}
/**
* Übersetzt &-Farbcodes in §-Farbcodes.
* Kompatibilitätsmethode bevorzugt lang().color() verwenden.
*/
public String color(String text) {
return ChatColor.translateAlternateColorCodes('&', text);
}
/**
* Mappt alte "messages.xxx"-Pfade auf neue lang.yml-Pfade.
* Muss ergänzt werden wenn neue Schlüssel im alten Stil genutzt wurden.
*/
private String mapLegacyPath(String path) {
if (path == null) return null;
return switch (path) {
case "messages.export-success" -> "system.export-success";
case "messages.export-fail" -> "system.export-fail";
case "messages.import-success" -> "system.import-success";
case "messages.import-fail" -> "system.import-fail";
case "messages.migration-success" -> "system.migration-success";
case "messages.migration-fail" -> "system.migration-fail";
case "messages.archive-success" -> "system.archive-success";
case "messages.archive-fail" -> "system.archive-fail";
case "messages.file-not-found" -> "system.file-not-found";
case "messages.unknown-mode" -> "system.unknown-mode";
case "messages.validation-warning" -> "system.validation-warning";
case "messages.ticket-created" -> "ticket.created";
case "messages.ticket-created-category" -> "ticket.created-category";
case "messages.ticket-claimed" -> "ticket.claimed";
case "messages.ticket-claimed-notify" -> "ticket.claimed-notify";
case "messages.ticket-closed" -> "ticket.closed";
case "messages.ticket-closed-notify" -> "ticket.closed-notify";
case "messages.ticket-forwarded" -> "ticket.forwarded";
case "messages.ticket-forwarded-notify" -> "ticket.forwarded-notify";
case "messages.ticket-forwarded-creator-notify" -> "ticket.forwarded-creator";
case "messages.new-ticket-notify" -> "ticket.new-notify";
case "messages.comment-saved" -> "comment.saved";
case "messages.comment-notify" -> "comment.notify-online";
case "messages.comment-no-permission" -> "comment.no-permission";
case "messages.rating-saved-good" -> "rating.saved-good";
case "messages.rating-saved-bad" -> "rating.saved-bad";
case "messages.rating-already-rated" -> "rating.already-rated";
case "messages.rating-not-yours" -> "rating.not-yours";
case "messages.rating-disabled" -> "rating.disabled";
case "messages.rating-prompt" -> "rating.prompt-title";
case "messages.blacklist-added" -> "blacklist.added";
case "messages.blacklist-removed" -> "blacklist.removed";
case "messages.blacklist-already" -> "blacklist.already";
case "messages.blacklist-not-found" -> "blacklist.not-found";
case "messages.blacklist-blocked" -> "create.blacklist-blocked";
case "messages.no-permission" -> "general.no-permission";
case "messages.no-open-tickets" -> "general.no-open-tickets";
case "messages.join-open-tickets" -> "join.open-tickets";
case "messages.already-claimed" -> "general.already-claimed";
case "messages.ticket-not-found" -> "general.ticket-not-found";
case "messages.cooldown" -> "general.cooldown";
case "messages.category-invalid" -> "create.category-invalid";
default -> null;
};
}
// ─────────────────────────── Getter ────────────────────────────────────
/**
* Aktualisiert serverName und debug-Flag aus der (bereits neu geladenen) Config.
* Muss nach plugin.reloadConfig() aufgerufen werden.
*/
public void reloadSettings() {
serverName = getConfig().getString("server-name", "unknown");
if ("unknown".equals(serverName)) {
getLogger().warning("[BungeeCord] Kein 'server-name' in der config.yml definiert!");
}
debug = getConfig().getBoolean("debug", false);
TicketPriority.reloadLocalizedNames(this);
}
public static TicketPlugin getInstance() { return instance; }
public LanguageManager getLanguageManager() { return languageManager; }
public DatabaseManager getDatabaseManager() { return databaseManager; }
public TicketManager getTicketManager() { return ticketManager; }
public CategoryManager getCategoryManager() { return categoryManager; }
public FaqManager getFaqManager() { return faqManager; }
public TicketGUI getTicketGUI() { return ticketGUI; }
public FaqGUI getFaqGUI() { return faqGUI; }
public DiscordWebhook getDiscordWebhook() { return discordWebhook; }
public BungeeMessenger getBungeeMessenger() { return bungeeMessenger; }
public TicketCache getTicketCache() { return ticketCache; }
public boolean isDebug() { return debug; }
public String getServerName() { return serverName; }
public boolean isBungeeCordEnabled() { return getConfig().getBoolean("bungeecord", false); }
public SessionManager getSessionManager() { return sessionManager; }
public WebServer getWebServer() { return webServer; }
}