From 4e2f27527e38efa49dee8fc1c878f0eec18cc831 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Thu, 7 May 2026 19:39:30 +0000 Subject: [PATCH] Soft-delete copy _trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatConfig.java --- .../viper/status/modules/chat/ChatConfig.java | 496 ++++++++++++++++++ 1 file changed, 496 insertions(+) create mode 100644 _trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatConfig.java diff --git a/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatConfig.java b/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatConfig.java new file mode 100644 index 0000000..104b41e --- /dev/null +++ b/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/ChatConfig.java @@ -0,0 +1,496 @@ +package net.viper.status.modules.chat; + +import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; + +import java.io.*; +import java.nio.file.Files; +import java.util.*; + +/** + * Lädt und verwaltet die chat.yml Konfiguration. + * + * Fix #8: Rate-Limit-Werte aus anti-spam werden nicht mehr durch nachfolgende + * Berechnungen überschrieben. Der rate-limit.chat-Block hat jetzt Vorrang. + * Die Reihenfolge ist: erst rate-limit.chat einlesen, dann ggf. durch anti-spam + * als Fallback ergänzen, nicht umgekehrt. + */ +public class ChatConfig { + + private final Plugin plugin; + private Configuration config; + + private final Map channels = new LinkedHashMap<>(); + private String defaultChannel; + + private String helpopFormat, helpopPermission, helpopConfirm, helpopDiscordWebhook, helpopTelegramChatId; + private int helpopCooldown; + + private String broadcastFormat, broadcastPermission; + + private boolean pmEnabled; + private String pmFormatSender, pmFormatReceiver, pmFormatSpy, pmSpyPermission, pmRateLimitMessage; + private boolean pmRateLimitEnabled; + private long pmRateLimitWindowMs; + private int pmRateLimitMaxActions; + private long pmRateLimitBlockMs; + + private int defaultMuteDuration; + private String mutedMessage; + + private boolean emojiEnabled, emojiBedrockSupport; + private final Map emojiMappings = new LinkedHashMap<>(); + + private boolean discordEnabled; + private String discordBotToken, discordGuildId, discordFromFormat, discordAdminChannelId, discordEmbedColor; + private int discordPollInterval; + + private boolean telegramEnabled; + private String telegramBotToken, telegramFromFormat, telegramAdminChatId; + private int telegramPollInterval, telegramChatTopicId, telegramAdminTopicId; + + private boolean linkingEnabled; + private String linkDiscordMessage, linkTelegramMessage, linkSuccessDiscord, linkSuccessTelegram; + private String linkBotSuccessDiscord, linkBotSuccessTelegram, linkedDiscordFormat, linkedTelegramFormat; + private int telegramAdminThreadId; + + private String adminBypassPermission, adminNotifyPermission; + + private boolean chatlogEnabled; + private int chatlogRetentionDays; + + private final Map serverColors = new LinkedHashMap<>(); + private final Map serverDisplayNames = new LinkedHashMap<>(); + private String serverColorDefault; + + private boolean reportsEnabled, reportWebhookEnabled; + private String reportConfirm, reportPermission, reportClosePermission, reportViewPermission; + private String reportDiscordWebhook, reportTelegramChatId; + private int reportCooldown; + + private ChatFilter.ChatFilterConfig filterConfig = new ChatFilter.ChatFilterConfig(); + + private boolean mentionsEnabled, mentionsAllowToggle; + private String mentionsHighlightColor, mentionsSound, mentionsNotifyPrefix; + + private int historyMaxLines, historyDefaultLines; + + private boolean joinLeaveEnabled, vanishShowToAdmins; + private String joinFormat, leaveFormat, vanishJoinFormat, vanishLeaveFormat; + private String joinLeaveDiscordWebhook, joinLeaveTelegramChatId; + private int joinLeaveTelegramThreadId; + + public ChatConfig(Plugin plugin) { this.plugin = plugin; } + + public void load() { + File file = new File(plugin.getDataFolder(), "chat.yml"); + if (!file.exists()) { + plugin.getDataFolder().mkdirs(); + InputStream in = plugin.getResourceAsStream("chat.yml"); + if (in != null) { + try { Files.copy(in, file.toPath()); } + catch (IOException e) { plugin.getLogger().severe("[ChatModule] Konnte chat.yml nicht erstellen: " + e.getMessage()); } + } else { + plugin.getLogger().warning("[ChatModule] chat.yml nicht in JAR, erstelle leere Datei."); + try { file.createNewFile(); } catch (IOException ignored) {} + } + } + try { config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file); } + catch (IOException e) { + plugin.getLogger().severe("[ChatModule] Fehler beim Laden der chat.yml: " + e.getMessage()); + config = new Configuration(); + } + parseConfig(); + plugin.getLogger().info("[ChatModule] " + channels.size() + " Kanäle geladen."); + } + + private void parseConfig() { + defaultChannel = config.getString("default-channel", "global"); + + // --- Kanäle --- + channels.clear(); + Configuration chSection = config.getSection("channels"); + if (chSection != null) { + for (String id : chSection.getKeys()) { + Configuration ch = chSection.getSection(id); + if (ch == null) continue; + channels.put(id.toLowerCase(), new ChatChannel( + id.toLowerCase(), + ch.getString("name", id), + ch.getString("symbol", id.substring(0, 1).toUpperCase()), + ch.getString("permission", ""), + ch.getString("color", "&f"), + ch.getString("format", "&8[&7{server}&8] {prefix}&r{player}{suffix}&8: &f{message}"), + ch.getBoolean("local-only", false), + ch.getString("discord-webhook", ""), + ch.getString("discord-channel-id", ""), + ch.getString("telegram-chat-id", ""), + ch.getInt("telegram-thread-id", 0), + ch.getBoolean("use-admin-bridge", false) + )); + } + } + if (!channels.containsKey("global")) { + channels.put("global", new ChatChannel("global", "Global", "G", "", "&a", + "&8[&a{server}&8] {prefix}&r{player}{suffix}&8: &f{message}", false, "", "", "", 0, false)); + } + + // --- HelpOp --- + Configuration ho = config.getSection("helpop"); + if (ho != null) { + helpopFormat = ho.getString("format", "&8[&eHELPOP&8] &f{player}&8@&7{server}&8: &e{message}"); + helpopPermission = ho.getString("receive-permission", "chat.helpop.receive"); + helpopCooldown = ho.getInt("cooldown", 30); + helpopConfirm = ho.getString("confirm-message", "&aHilferuf gesendet!"); + helpopDiscordWebhook = ho.getString("discord-webhook", ""); + helpopTelegramChatId = ho.getString("telegram-chat-id", ""); + } else { + helpopFormat = "&8[&eHELPOP&8] &f{player}&8@&7{server}&8: &e{message}"; + helpopPermission = "chat.helpop.receive"; helpopCooldown = 30; + helpopConfirm = "&aHilferuf gesendet!"; helpopDiscordWebhook = ""; helpopTelegramChatId = ""; + } + + // --- Broadcast --- + Configuration bc = config.getSection("broadcast"); + broadcastFormat = bc != null ? bc.getString("format", "&c[&6Broadcast&c] &e{message}") : "&c[&6Broadcast&c] &e{message}"; + broadcastPermission = bc != null ? bc.getString("permission", "chat.broadcast") : "chat.broadcast"; + + // --- Private Messages --- + Configuration pm = config.getSection("private-messages"); + pmEnabled = pm == null || pm.getBoolean("enabled", true); + pmFormatSender = pm != null ? pm.getString("format-sender", "&8[&7Du &8→ &b{player}&8] &f{message}") : "&8[&7Du &8→ &b{player}&8] &f{message}"; + pmFormatReceiver = pm != null ? pm.getString("format-receiver", "&8[&b{player} &8→ &7Dir&8] &f{message}") : "&8[&b{player} &8→ &7Dir&8] &f{message}"; + pmFormatSpy = pm != null ? pm.getString("format-social-spy","&8[&dSPY &7{sender} &8→ &7{receiver}&8] &f{message}") : "&8[&dSPY &7{sender} &8→ &7{receiver}&8] &f{message}"; + pmSpyPermission = pm != null ? pm.getString("social-spy-permission", "chat.socialspy") : "chat.socialspy"; + + // --- Mute --- + Configuration mu = config.getSection("mute"); + defaultMuteDuration = mu != null ? mu.getInt("default-duration-minutes", 60) : 60; + mutedMessage = mu != null ? mu.getString("muted-message", "&cDu bist stummgeschaltet. Noch: &f{time}") : "&cDu bist stummgeschaltet. Noch: &f{time}"; + + // --- Emoji --- + Configuration em = config.getSection("emoji"); + if (em != null) { + emojiEnabled = em.getBoolean("enabled", true); + emojiBedrockSupport = em.getBoolean("bedrock-support", true); + emojiMappings.clear(); + Configuration map = em.getSection("mappings"); + if (map != null) { for (String key : map.getKeys()) emojiMappings.put(key, map.getString(key, key)); } + } else { emojiEnabled = true; emojiBedrockSupport = true; } + + // --- Discord --- + Configuration dc = config.getSection("discord"); + if (dc != null) { + discordEnabled = dc.getBoolean("enabled", false); + discordBotToken = dc.getString("bot-token", ""); + discordGuildId = dc.getString("guild-id", ""); + discordPollInterval = dc.getInt("poll-interval", 3); + discordFromFormat = dc.getString("from-discord-format", "&9[Discord] &b{user}&8: &f{message}"); + discordAdminChannelId = dc.getString("admin-channel-id", ""); + discordEmbedColor = dc.getString("embed-color", "5865F2"); + } else { discordEnabled = false; discordBotToken = ""; discordGuildId = ""; discordPollInterval = 3; discordFromFormat = "&9[Discord] &b{user}&8: &f{message}"; discordAdminChannelId = ""; discordEmbedColor = "5865F2"; } + + // --- Telegram --- + Configuration tg = config.getSection("telegram"); + if (tg != null) { + telegramEnabled = tg.getBoolean("enabled", false); + telegramBotToken = tg.getString("bot-token", ""); + telegramPollInterval = tg.getInt("poll-interval", 3); + telegramFromFormat = tg.getString("from-telegram-format", "&3[Telegram] &b{user}&8: &f{message}"); + telegramAdminChatId = tg.getString("admin-chat-id", ""); + telegramChatTopicId = tg.getInt("chat-topic-id", 0); + telegramAdminTopicId = tg.getInt("admin-topic-id", 0); + } else { telegramEnabled = false; telegramBotToken = ""; telegramPollInterval = 3; telegramFromFormat = "&3[Telegram] &b{user}&8: &f{message}"; telegramAdminChatId = ""; telegramChatTopicId = 0; telegramAdminTopicId = 0; } + + // --- Account-Linking --- + Configuration al = config.getSection("account-linking"); + linkingEnabled = al == null || al.getBoolean("enabled", true); + linkDiscordMessage = al != null ? al.getString("discord-link-message", "&aCode: &f{token}") : "&aCode: &f{token}"; + linkTelegramMessage = al != null ? al.getString("telegram-link-message", "&aCode: &f{token}") : "&aCode: &f{token}"; + linkSuccessDiscord = al != null ? al.getString("success-discord", "&aDiscord verknüpft!") : "&aDiscord verknüpft!"; + linkSuccessTelegram = al != null ? al.getString("success-telegram", "&aTelegram verknüpft!") : "&aTelegram verknüpft!"; + linkBotSuccessDiscord = al != null ? al.getString("bot-success-discord", "✅ Verknüpft: {player}") : "✅ Verknüpft: {player}"; + linkBotSuccessTelegram = al != null ? al.getString("bot-success-telegram", "✅ Verknüpft: {player}") : "✅ Verknüpft: {player}"; + linkedDiscordFormat = al != null ? al.getString("linked-discord-format", "&9[&bDiscord&9] &f{player} &8(&7{user}&8)&8: &f{message}") : "&9[&bDiscord&9] &f{player} &8(&7{user}&8)&8: &f{message}"; + linkedTelegramFormat = al != null ? al.getString("linked-telegram-format", "&3[&bTelegram&3] &f{player} &8(&7{user}&8)&8: &f{message}") : "&3[&bTelegram&3] &f{player} &8(&7{user}&8)&8: &f{message}"; + + // --- Chat-Filter --- + filterConfig = new ChatFilter.ChatFilterConfig(); + Configuration cf = config.getSection("chat-filter"); + if (cf != null) { + Configuration spam = cf.getSection("anti-spam"); + if (spam != null) { + filterConfig.antiSpamEnabled = spam.getBoolean("enabled", true); + filterConfig.spamCooldownMs = spam.getInt("cooldown-ms", 1500); + filterConfig.spamMaxMessages = spam.getInt("max-messages", 3); + filterConfig.spamMessage = spam.getString("message", "&cNicht so schnell!"); + // FIX #8: Fallback-Werte aus anti-spam werden NUR gesetzt wenn rate-limit.chat nicht + // konfiguriert ist. Wir setzen die Werte hier als Vorbelegung und überschreiben sie + // unten mit dem rate-limit.chat-Block wenn vorhanden. + filterConfig.globalRateLimitWindowMs = Math.max(500L, filterConfig.spamCooldownMs); + filterConfig.globalRateLimitMaxActions = Math.max(1, filterConfig.spamMaxMessages); + filterConfig.globalRateLimitBlockMs = Math.max(2000L, filterConfig.spamCooldownMs * 4L); + } + Configuration dup = cf.getSection("duplicate-check"); + if (dup != null) { + filterConfig.duplicateCheckEnabled = dup.getBoolean("enabled", true); + filterConfig.duplicateMessage = dup.getString("message", "&cKeine identischen Nachrichten."); + } + Configuration bl = cf.getSection("blacklist"); + if (bl != null) { + filterConfig.blacklistEnabled = bl.getBoolean("enabled", true); + filterConfig.blacklistWords.clear(); + loadFilterWords(filterConfig.blacklistWords); + try { + java.util.List wordList = bl.getList("words"); + if (wordList != null) { + for (Object o : wordList) { + if (o != null && !o.toString().trim().isEmpty()) { + String w = o.toString().trim(); + if (!filterConfig.blacklistWords.contains(w)) filterConfig.blacklistWords.add(w); + } + } + } + } catch (Exception ignored) {} + } + Configuration caps = cf.getSection("caps-filter"); + if (caps != null) { + filterConfig.capsFilterEnabled = caps.getBoolean("enabled", true); + filterConfig.capsMinLength = caps.getInt("min-length", 6); + filterConfig.capsMaxPercent = caps.getInt("max-percent", 70); + } + Configuration antiAd = cf.getSection("anti-ad"); + if (antiAd != null) { + filterConfig.antiAdEnabled = antiAd.getBoolean("enabled", true); + filterConfig.antiAdMessage = antiAd.getString("message", "&cWerbung ist nicht erlaubt!"); + java.util.List wl = antiAd.getList("whitelist"); + if (wl != null) { filterConfig.antiAdWhitelist.clear(); for (Object o : wl) if (o != null) filterConfig.antiAdWhitelist.add(o.toString()); } + java.util.List tlds = antiAd.getList("blocked-tlds"); + if (tlds != null) { filterConfig.antiAdBlockedTlds.clear(); for (Object o : tlds) if (o != null) filterConfig.antiAdBlockedTlds.add(o.toString()); } + } + } + + // --- Rate-Limit (FIX #8: dieser Block setzt die endgültigen Werte, hat Vorrang) --- + pmRateLimitEnabled = true; + pmRateLimitWindowMs = 5000L; + pmRateLimitMaxActions = 4; + pmRateLimitBlockMs = 10000L; + pmRateLimitMessage = "&cDu sendest zu viele private Nachrichten. Bitte warte kurz."; + + Configuration rl = config.getSection("rate-limit"); + if (rl != null) { + Configuration rlChat = rl.getSection("chat"); + if (rlChat != null) { + // FIX #8: rate-limit.chat überschreibt die anti-spam-Fallbacks vollständig + filterConfig.globalRateLimitEnabled = rlChat.getBoolean("enabled", true); + filterConfig.globalRateLimitWindowMs = rlChat.getLong("window-ms", filterConfig.globalRateLimitWindowMs); + filterConfig.globalRateLimitMaxActions = rlChat.getInt("max-actions", filterConfig.globalRateLimitMaxActions); + filterConfig.globalRateLimitBlockMs = rlChat.getLong("block-ms", filterConfig.globalRateLimitBlockMs); + filterConfig.spamMessage = rlChat.getString("message", filterConfig.spamMessage); + } + Configuration rlPm = rl.getSection("private-messages"); + if (rlPm != null) { + pmRateLimitEnabled = rlPm.getBoolean("enabled", pmRateLimitEnabled); + pmRateLimitWindowMs = rlPm.getLong("window-ms", pmRateLimitWindowMs); + pmRateLimitMaxActions = rlPm.getInt("max-actions", pmRateLimitMaxActions); + pmRateLimitBlockMs = rlPm.getLong("block-ms", pmRateLimitBlockMs); + pmRateLimitMessage = rlPm.getString("message", pmRateLimitMessage); + } + } + + // --- Mentions --- + Configuration mn = config.getSection("mentions"); + mentionsEnabled = mn == null || mn.getBoolean("enabled", true); + mentionsHighlightColor = mn != null ? mn.getString("highlight-color", "&e&l") : "&e&l"; + mentionsSound = mn != null ? mn.getString("sound", "ENTITY_EXPERIENCE_ORB_PICKUP") : "ENTITY_EXPERIENCE_ORB_PICKUP"; + mentionsAllowToggle = mn == null || mn.getBoolean("allow-toggle", true); + mentionsNotifyPrefix = mn != null ? mn.getString("notify-prefix", "&e&l[Mention] &r") : "&e&l[Mention] &r"; + + // --- Chat-History --- + Configuration ch = config.getSection("chat-history"); + historyMaxLines = ch != null ? ch.getInt("max-lines", 50) : 50; + historyDefaultLines = ch != null ? ch.getInt("default-lines", 10) : 10; + + // --- Admin --- + Configuration adm = config.getSection("admin"); + adminBypassPermission = adm != null ? adm.getString("bypass-permission", "chat.admin.bypass") : "chat.admin.bypass"; + adminNotifyPermission = adm != null ? adm.getString("notify-permission", "chat.admin.notify") : "chat.admin.notify"; + + // --- Server-Farben --- + serverColors.clear(); serverDisplayNames.clear(); + Configuration sc = config.getSection("server-colors"); + if (sc != null) { + serverColorDefault = sc.getString("default", "&7"); + for (String key : sc.getKeys()) { + if (key.equals("default")) continue; + Configuration sub = sc.getSection(key); + if (sub != null) { + serverColors.put(key.toLowerCase(), sub.getString("color", "&7")); + String display = sub.getString("display", ""); + if (!display.isEmpty()) serverDisplayNames.put(key.toLowerCase(), display); + } else { + serverColors.put(key.toLowerCase(), sc.getString(key, "&7")); + } + } + } else { serverColorDefault = "&7"; } + + // --- Chatlog --- + Configuration cl = config.getSection("chatlog"); + chatlogEnabled = cl == null || cl.getBoolean("enabled", true); + int raw = cl != null ? cl.getInt("retention-days", 7) : 7; + chatlogRetentionDays = (raw == 14) ? 14 : 7; + + // --- Reports --- + Configuration rp = config.getSection("reports"); + if (rp != null) { + reportsEnabled = rp.getBoolean("enabled", true); + reportWebhookEnabled = rp.getBoolean("webhook-enabled", false); + reportConfirm = rp.getString("confirm-message", "&aDein Report &8({id}) &awurde eingereicht. Danke!"); + reportPermission = rp.getString("report-permission", ""); + reportClosePermission = rp.getString("close-permission", "chat.admin.bypass"); + reportViewPermission = rp.getString("view-permission", "chat.admin.bypass"); + reportCooldown = rp.getInt("cooldown", 60); + reportDiscordWebhook = rp.getString("discord-webhook", ""); + reportTelegramChatId = rp.getString("telegram-chat-id", ""); + } else { + reportsEnabled = true; reportWebhookEnabled = false; + reportConfirm = "&aDein Report &8({id}) &awurde eingereicht. Danke!"; + reportPermission = ""; reportClosePermission = "chat.admin.bypass"; reportViewPermission = "chat.admin.bypass"; + reportCooldown = 60; reportDiscordWebhook = ""; reportTelegramChatId = ""; + } + + // --- Join / Leave --- + Configuration jl = config.getSection("join-leave"); + if (jl != null) { + joinLeaveEnabled = jl.getBoolean("enabled", true); + joinFormat = jl.getString("join-format", "&8[&a+&8] {prefix}&a{player}&r &7hat das Netzwerk betreten."); + leaveFormat = jl.getString("leave-format", "&8[&c-&8] {prefix}&c{player}&r &7hat das Netzwerk verlassen."); + vanishShowToAdmins = jl.getBoolean("vanish-show-to-admins", true); + vanishJoinFormat = jl.getString("vanish-join-format", "&8[&7+&8] &8{player} &7hat das Netzwerk betreten. &8(Vanish)"); + vanishLeaveFormat = jl.getString("vanish-leave-format", "&8[&7-&8] &8{player} &7hat das Netzwerk verlassen. &8(Vanish)"); + joinLeaveDiscordWebhook = jl.getString("discord-webhook", ""); + joinLeaveTelegramChatId = jl.getString("telegram-chat-id", ""); + joinLeaveTelegramThreadId = jl.getInt("telegram-thread-id", 0); + } else { + joinLeaveEnabled = true; + joinFormat = "&8[&a+&8] {prefix}&a{player}&r &7hat das Netzwerk betreten."; + leaveFormat = "&8[&c-&8] {prefix}&c{player}&r &7hat das Netzwerk verlassen."; + vanishShowToAdmins = true; + vanishJoinFormat = "&8[&7+&8] &8{player} &7hat das Netzwerk betreten. &8(Vanish)"; + vanishLeaveFormat = "&8[&7-&8] &8{player} &7hat das Netzwerk verlassen. &8(Vanish)"; + joinLeaveDiscordWebhook = ""; joinLeaveTelegramChatId = ""; joinLeaveTelegramThreadId = 0; + } + } + + private void loadFilterWords(java.util.List target) { + File filterFile = new File(plugin.getDataFolder(), "filter.yml"); + if (!filterFile.exists()) { + try { + plugin.getDataFolder().mkdirs(); + try (java.io.FileWriter fw = new java.io.FileWriter(filterFile)) { + fw.write("# StatusAPI - Wort-Blacklist\n# words:\n# - beispielwort\nwords:\n"); + } + plugin.getLogger().info("[ChatModule] filter.yml erstellt."); + } catch (IOException e) { plugin.getLogger().warning("[ChatModule] Konnte filter.yml nicht erstellen: " + e.getMessage()); } + return; + } + try { + Configuration fc = ConfigurationProvider.getProvider(YamlConfiguration.class).load(filterFile); + java.util.List words = fc.getList("words"); + if (words != null) { + for (Object o : words) { + if (o != null && !o.toString().trim().isEmpty()) target.add(o.toString().trim().toLowerCase()); + } + } + } catch (Exception e) { plugin.getLogger().warning("[ChatModule] Fehler beim Laden der filter.yml: " + e.getMessage()); } + } + + // ===== Getter ===== + + public Map getChannels() { return Collections.unmodifiableMap(channels); } + public ChatChannel getChannel(String id) { return channels.get(id == null ? defaultChannel : id.toLowerCase()); } + public ChatChannel getDefaultChannel() { return channels.getOrDefault(defaultChannel, channels.values().iterator().next()); } + public String getDefaultChannelId() { return defaultChannel; } + public String getHelpopFormat() { return helpopFormat; } + public String getHelpopPermission() { return helpopPermission; } + public int getHelpopCooldown() { return helpopCooldown; } + public String getHelpopConfirm() { return helpopConfirm; } + public String getHelpopDiscordWebhook() { return helpopDiscordWebhook; } + public String getHelpopTelegramChatId() { return helpopTelegramChatId; } + public String getBroadcastFormat() { return broadcastFormat; } + public String getBroadcastPermission() { return broadcastPermission; } + public boolean isPmEnabled() { return pmEnabled; } + public String getPmFormatSender() { return pmFormatSender; } + public String getPmFormatReceiver() { return pmFormatReceiver; } + public String getPmFormatSpy() { return pmFormatSpy; } + public String getPmSpyPermission() { return pmSpyPermission; } + public boolean isPmRateLimitEnabled() { return pmRateLimitEnabled; } + public long getPmRateLimitWindowMs() { return pmRateLimitWindowMs; } + public int getPmRateLimitMaxActions() { return pmRateLimitMaxActions; } + public long getPmRateLimitBlockMs() { return pmRateLimitBlockMs; } + public String getPmRateLimitMessage() { return pmRateLimitMessage; } + public int getDefaultMuteDuration() { return defaultMuteDuration; } + public String getMutedMessage() { return mutedMessage; } + public boolean isEmojiEnabled() { return emojiEnabled; } + public boolean isEmojiBedrockSupport() { return emojiBedrockSupport; } + public Map getEmojiMappings() { return Collections.unmodifiableMap(emojiMappings); } + public boolean isDiscordEnabled() { return discordEnabled; } + public String getDiscordBotToken() { return discordBotToken; } + public String getDiscordGuildId() { return discordGuildId; } + public int getDiscordPollInterval() { return discordPollInterval; } + public String getDiscordFromFormat() { return discordFromFormat; } + public String getDiscordAdminChannelId() { return discordAdminChannelId; } + public String getDiscordEmbedColor() { return discordEmbedColor; } + public boolean isTelegramEnabled() { return telegramEnabled; } + public String getTelegramBotToken() { return telegramBotToken; } + public int getTelegramPollInterval() { return telegramPollInterval; } + public String getTelegramFromFormat() { return telegramFromFormat; } + public String getTelegramAdminChatId() { return telegramAdminChatId; } + public int getTelegramChatTopicId() { return telegramChatTopicId; } + public int getTelegramAdminTopicId() { return telegramAdminTopicId; } + public boolean isLinkingEnabled() { return linkingEnabled; } + public String getLinkDiscordMessage() { return linkDiscordMessage; } + public String getLinkTelegramMessage() { return linkTelegramMessage; } + public String getLinkSuccessDiscord() { return linkSuccessDiscord; } + public String getLinkSuccessTelegram() { return linkSuccessTelegram; } + public String getLinkBotSuccessDiscord() { return linkBotSuccessDiscord; } + public String getLinkBotSuccessTelegram() { return linkBotSuccessTelegram; } + public String getLinkedDiscordFormat() { return linkedDiscordFormat; } + public String getLinkedTelegramFormat() { return linkedTelegramFormat; } + public String getAdminBypassPermission() { return adminBypassPermission; } + public String getAdminNotifyPermission() { return adminNotifyPermission; } + public String getServerColor(String serverName) { if (serverName == null) return serverColorDefault; String c = serverColors.get(serverName.toLowerCase()); return c != null ? c : serverColorDefault; } + public Map getServerColors() { return Collections.unmodifiableMap(serverColors); } + public String getServerColorDefault() { return serverColorDefault; } + public String getServerDisplay(String serverName) { if (serverName == null) return ""; String d = serverDisplayNames.get(serverName.toLowerCase()); return d != null ? d : serverName; } + public boolean isChatlogEnabled() { return chatlogEnabled; } + public int getChatlogRetentionDays() { return chatlogRetentionDays; } + public boolean isReportsEnabled() { return reportsEnabled; } + public String getReportConfirm() { return reportConfirm; } + public String getReportPermission() { return reportPermission; } + public String getReportClosePermission() { return reportClosePermission; } + public String getReportViewPermission() { return reportViewPermission; } + public int getReportCooldown() { return reportCooldown; } + public String getReportDiscordWebhook() { return reportDiscordWebhook; } + public String getReportTelegramChatId() { return reportTelegramChatId; } + public boolean isReportWebhookEnabled() { return reportWebhookEnabled; } + public ChatFilter.ChatFilterConfig getFilterConfig() { return filterConfig; } + public boolean isMentionsEnabled() { return mentionsEnabled; } + public String getMentionsHighlightColor() { return mentionsHighlightColor; } + public String getMentionsSound() { return mentionsSound; } + public boolean isMentionsAllowToggle() { return mentionsAllowToggle; } + public String getMentionsNotifyPrefix() { return mentionsNotifyPrefix; } + public int getHistoryMaxLines() { return historyMaxLines; } + public int getHistoryDefaultLines() { return historyDefaultLines; } + public boolean isJoinLeaveEnabled() { return joinLeaveEnabled; } + public String getJoinFormat() { return joinFormat; } + public String getLeaveFormat() { return leaveFormat; } + public boolean isVanishShowToAdmins() { return vanishShowToAdmins; } + public String getVanishJoinFormat() { return vanishJoinFormat; } + public String getVanishLeaveFormat() { return vanishLeaveFormat; } + public String getJoinLeaveDiscordWebhook() { return joinLeaveDiscordWebhook; } + public String getJoinLeaveTelegramChatId() { return joinLeaveTelegramChatId; } + public int getJoinLeaveTelegramThreadId() { return joinLeaveTelegramThreadId; } +}