diff --git a/src/main/java/net/viper/status/modules/globalchat/GlobalChatModule.java b/src/main/java/net/viper/status/modules/globalchat/GlobalChatModule.java deleted file mode 100644 index 2b1b685..0000000 --- a/src/main/java/net/viper/status/modules/globalchat/GlobalChatModule.java +++ /dev/null @@ -1,855 +0,0 @@ -package net.viper.status.modules.globalchat; - -import net.md_5.bungee.api.ChatColor; -import net.md_5.bungee.api.CommandSender; -import net.md_5.bungee.api.chat.ComponentBuilder; -import net.md_5.bungee.api.chat.HoverEvent; -import net.md_5.bungee.api.chat.TextComponent; -import net.md_5.bungee.api.chat.HoverEvent.Action; -import net.md_5.bungee.api.config.ServerInfo; -import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.event.ChatEvent; -import net.md_5.bungee.api.event.PostLoginEvent; -import net.md_5.bungee.api.event.PlayerDisconnectEvent; -import net.md_5.bungee.api.event.ServerConnectEvent; -import net.md_5.bungee.api.event.ServerSwitchEvent; -import net.md_5.bungee.api.plugin.Command; -import net.md_5.bungee.api.plugin.Listener; -import net.md_5.bungee.api.plugin.Plugin; -import net.md_5.bungee.chat.ComponentSerializer; -import net.md_5.bungee.event.EventHandler; -import net.viper.status.module.Module; - -import java.io.*; -import java.lang.Class; -import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.regex.Pattern; - -/** - * GlobalChatModule - Integriert Global Chat, Filter, Logs und Support in die StatusAPI. - * Nutzt die zentrale verify.properties für Chat- und Server-Einstellungen. - * Ermöglicht manuelle Ränge über UUID-Overrides. - * Nutzt REFLECTION für LuckPerms (Optional). - */ -public class GlobalChatModule implements Module, Listener { - - private static final String CHANNEL_CONTROL = "global:control"; - private static final String CHANNEL_CHAT = "global:chat"; - - private Plugin plugin; - - private List badWords = new ArrayList<>(); - private File logFolder; - private boolean chatMuted = false; - private boolean isChatEnabled = true; - - private final Map playerIsOp = new ConcurrentHashMap<>(); - private final Map lastSupportContact = new ConcurrentHashMap<>(); - private final Set suppressJoinQuit = ConcurrentHashMap.newKeySet(); - private final Set chatLockPlayers = ConcurrentHashMap.newKeySet(); - - private List welcomeMessages = new ArrayList<>(); - private Map serverDisplayNames = new HashMap<>(); - - // Map für gruppen-spezifische Formate aus der verify.properties - private Map groupFormats = new HashMap<>(); - - // NEU: Map für manuelle Ränge aus der verify.properties (Override) - private final Map manualRanks = new ConcurrentHashMap<>(); - - @Override - public String getName() { - return "GlobalChatModule"; - } - - @Override - public void onEnable(Plugin plugin) { - this.plugin = plugin; - - loadConfig(); - - if (!isChatEnabled) { - plugin.getLogger().info("§eGlobalChat ist in der verify.properties DEAKTIVERT."); - return; - } - - // Channels registrieren - try { - plugin.getProxy().registerChannel(CHANNEL_CONTROL); - plugin.getProxy().registerChannel(CHANNEL_CHAT); - } catch (Throwable ignored) { - plugin.getLogger().warning("Konnte Channels nicht registrieren."); - } - - plugin.getProxy().getPluginManager().registerListener(plugin, this); - loadFilter(); - loadWelcomeMessages(); - - logFolder = new File(plugin.getDataFolder(), "logs"); - if (!logFolder.exists()) logFolder.mkdirs(); - cleanupOldLogs(); - - // Befehle registrieren - plugin.getProxy().getPluginManager().registerCommand(plugin, new ReloadCommand()); - plugin.getProxy().getPluginManager().registerCommand(plugin, new MuteCommand()); - plugin.getProxy().getPluginManager().registerCommand(plugin, new SupportCommand()); - plugin.getProxy().getPluginManager().registerCommand(plugin, new ReplyCommand()); - plugin.getProxy().getPluginManager().registerCommand(plugin, new InfoCommand()); - plugin.getProxy().getPluginManager().registerCommand(plugin, new ChatToggleCommand()); - - // NEU: ClearChat Befehl registrieren - plugin.getProxy().getPluginManager().registerCommand(plugin, new ClearChatCommand()); - - plugin.getLogger().info("§aGlobalChatModule aktiviert (Mit Manuellen Rang-Overrides)!"); - } - - @Override - public void onDisable(Plugin plugin) { - plugin.getLogger().info("§cGlobalChatModule deaktiviert!"); - try { - plugin.getProxy().unregisterChannel(CHANNEL_CONTROL); - plugin.getProxy().unregisterChannel(CHANNEL_CHAT); - } catch (Throwable ignored) {} - } - - // =========================== - // Konfiguration laden - // =========================== - private void loadConfig() { - String fileName = "verify.properties"; - File file = new File(plugin.getDataFolder(), fileName); - - if (!file.exists()) { - plugin.getDataFolder().mkdirs(); - try (InputStream in = plugin.getResourceAsStream(fileName); - OutputStream out = new FileOutputStream(file)) { - if (in == null) { - plugin.getLogger().warning("Standard-config '" + fileName + "' nicht in JAR gefunden."); - file.createNewFile(); - return; - } - byte[] buffer = new byte[1024]; - int length; - while ((length = in.read(buffer)) > 0) { - out.write(buffer, 0, length); - } - plugin.getLogger().info("Konfigurationsdatei '" + fileName + "' erstellt."); - } catch (Exception e) { - plugin.getLogger().severe("Fehler beim Erstellen der Standard-Konfiguration: " + e.getMessage()); - return; - } - } - - try { - Properties props = new Properties(); - try (InputStream in = new FileInputStream(file)) { - props.load(in); - } - - isChatEnabled = Boolean.parseBoolean(props.getProperty("chat.enabled", "true")); - - serverDisplayNames.clear(); - groupFormats.clear(); - manualRanks.clear(); // NEU - - for (String key : props.stringPropertyNames()) { - // 1. Manuelle Overrides laden (Höchste Priorität!) - if (key.startsWith("override.")) { - String uuidStr = key.substring("override.".length()); - try { - UUID uuid = UUID.fromString(uuidStr); - String groupName = props.getProperty(key); - manualRanks.put(uuid, groupName); - plugin.getLogger().info("Manueller Override geladen: " + uuidStr + " -> " + groupName); - } catch (IllegalArgumentException ex) { - plugin.getLogger().warning("Ungültige UUID in override: " + uuidStr); - } - } - // 2. Server Aliase - else if (key.startsWith("server.")) { - String[] parts = key.split("\\."); - if (parts.length == 2) { - String serverName = parts[1]; - String displayName = props.getProperty(key); - serverDisplayNames.put(serverName, displayName); - } - } - // 3. Group Formate - else if (key.startsWith("groupformat.")) { - String groupName = key.substring("groupformat.".length()); - String format = props.getProperty(key); - groupFormats.put(groupName.toLowerCase(), format); - } - } - plugin.getLogger().info("§eGeladene Server-Displaynames: " + serverDisplayNames.size() + " (Chat aktiv: " + isChatEnabled + ")"); - plugin.getLogger().info("§eGeladene Chat-Formate: " + groupFormats.size()); - plugin.getLogger().info("§eGeladene Manuelle Overrides: " + manualRanks.size()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private String getDisplayName(String serverName) { - String displayName = serverDisplayNames.getOrDefault(serverName, serverName); - return ChatColor.translateAlternateColorCodes('&', displayName); - } - - // =========================== - // Willkommensnachrichten - // =========================== - private void loadWelcomeMessages() { - String fileName = "welcome.yml"; - File file = new File(plugin.getDataFolder(), fileName); - - if (!file.exists()) { - plugin.getDataFolder().mkdirs(); - try (InputStream in = plugin.getResourceAsStream(fileName); - OutputStream out = new FileOutputStream(file)) { - if (in == null) { - plugin.getLogger().warning("Standard 'welcome.yml' nicht in JAR gefunden."); - file.createNewFile(); - return; - } - byte[] buffer = new byte[1024]; - int length; - while ((length = in.read(buffer)) > 0) { - out.write(buffer, 0, length); - } - plugin.getLogger().info("Standard welcome.yml erstellt."); - } catch (Exception e) { - e.printStackTrace(); - } - } - - try { - List lines = Files.readAllLines(file.toPath()); - welcomeMessages.clear(); - for (String line : lines) { - line = line.trim(); - if (line.startsWith("-")) welcomeMessages.add(line.substring(1).trim()); - } - plugin.getLogger().info("§eGeladene Welcome-Nachrichten: " + welcomeMessages.size()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void sendRandomWelcomeMessage(ProxiedPlayer player) { - if (welcomeMessages.isEmpty()) return; - Random rand = new Random(); - String message = welcomeMessages.get(rand.nextInt(welcomeMessages.size())); - message = message.replace("%player%", player.getName()); - message = ChatColor.translateAlternateColorCodes('&', message); - player.sendMessage(new TextComponent(message)); - } - - // =========================== - // Global Broadcast Helper - // =========================== - private void broadcastGlobal(TextComponent component) { - if (!isChatEnabled) return; - - // Korrektur: statt PluginChannel-Relay senden wir System/Plugin-Nachrichten an alle Spieler. - for (ProxiedPlayer p : plugin.getProxy().getPlayers()) { - p.sendMessage(component); - } - } - - // =========================== - // Chatfilter & Global-Chat (RELAY MODE) - // =========================== - @EventHandler - public void onChat(ChatEvent e) { - if (!(e.getSender() instanceof ProxiedPlayer)) return; - if (e.isCommand()) return; - - ProxiedPlayer player = (ProxiedPlayer) e.getSender(); - - // CHAT LOCK / TOGGLE CHECK - if (chatLockPlayers.contains(player.getUniqueId())) { - return; - } - - String originalMsg = e.getMessage(); - - if (suppressJoinQuit.contains(player.getUniqueId()) && - (originalMsg.contains("joined§ Game") || originalMsg.contains("left§ Game"))) { - plugin.getLogger().info("Unterdrücke Join-/Quit-Nachricht für " + player.getName()); - e.setCancelled(true); - return; - } - - if (chatMuted && !player.hasPermission("globalchat.bypass")) { - player.sendMessage(new TextComponent("§cDer globale Chat ist derzeit deaktiviert!")); - e.setCancelled(true); - return; - } - - String censoredMsg = originalMsg; - for (String bad : badWords) { - if (bad == null || bad.trim().isEmpty()) continue; - censoredMsg = censoredMsg.replaceAll("(?i)" + Pattern.quote(bad), repeat("*", bad.length())); - } - - e.setCancelled(true); - - String serverName = player.getServer().getInfo().getName(); - String serverDisplay = getDisplayName(serverName); - - String[] ps = getPrefixSuffix(player); - String prefix = ps[0]; - String playerColor = ps[2]; - String chatColor = ps[3]; - - String displayTag = ""; - if (!prefix.isEmpty()) displayTag = prefix; - else if (!ps[1].isEmpty()) displayTag = ps[1]; - - if (!displayTag.isEmpty() && !displayTag.endsWith(" ")) displayTag = displayTag + " "; - - StringBuilder out = new StringBuilder(); - out.append("§7[").append(serverDisplay).append("§r§7] "); - if (!displayTag.isEmpty()) out.append(displayTag); - out.append(playerColor).append(player.getName()); - out.append("§f: ").append(chatColor).append(censoredMsg); - - String chatOut = out.toString(); - - TextComponent chatComponent = new TextComponent(chatOut); - broadcastGlobal(chatComponent); - - String logEntry = "[" + serverName + "] " + - (displayTag.isEmpty() ? "" : stripColor(displayTag) + " ") + - player.getName() + - ": " + originalMsg; - logMessage(logEntry); - } - - // =========================== - // Global Join & Quit Events - // =========================== - @EventHandler - public void onPostLogin(PostLoginEvent e) { - if (!isChatEnabled) return; - - ProxiedPlayer player = e.getPlayer(); - - // Willkommensnachricht senden - sendRandomWelcomeMessage(player); - - // Formatierung aus verify.properties nutzen - String[] ps = getPrefixSuffix(player); - String prefix = ps[0]; - String playerColor = ps[2]; // Namefarbe aus Properties - - String displayTag = ""; - if (!prefix.isEmpty()) displayTag = prefix; - if (!displayTag.isEmpty() && !displayTag.endsWith(" ")) displayTag = displayTag + " "; - - // Nachricht: "Spieler xy hat den Server betreten" - // Der Text "hat den Server betreten" bleibt Grün (Standard), Name und Prefix kommen aus der Config - TextComponent joinMsg = new TextComponent(displayTag + playerColor + player.getName() + " §a§lhat den Server betreten."); - - broadcastGlobal(joinMsg); - logMessage("[JOIN] " + player.getName() + " hat den Server betreten."); - } - - @EventHandler - public void onPlayerDisconnect(PlayerDisconnectEvent e) { - if (!isChatEnabled) return; - - ProxiedPlayer player = e.getPlayer(); - - // Formatierung aus verify.properties nutzen - String[] ps = getPrefixSuffix(player); - String prefix = ps[0]; - String playerColor = ps[2]; // Namefarbe aus Properties - - String displayTag = ""; - if (!prefix.isEmpty()) displayTag = prefix; - if (!displayTag.isEmpty() && !displayTag.endsWith(" ")) displayTag = displayTag + " "; - - // Nachricht: "Spieler xy hat den Server verlassen" - // Der Text "hat den Server verlassen" bleibt Rot (Standard), Name und Prefix kommen aus der Config - TextComponent quitMsg = new TextComponent(displayTag + playerColor + player.getName() + " §c§lhat den Server verlassen."); - - broadcastGlobal(quitMsg); - logMessage("[QUIT] " + player.getName() + " hat den Server verlassen."); - } - - // =========================== - // Server Connect & Switch - // =========================== - @EventHandler - public void onServerConnect(ServerConnectEvent e) { - if (e.isCancelled()) return; - - ProxiedPlayer player = e.getPlayer(); - ServerInfo target = e.getTarget(); - ServerInfo from = player.getServer() != null ? player.getServer().getInfo() : null; - - if (from == null || from.equals(target)) return; - - suppressJoinQuit.add(player.getUniqueId()); - plugin.getLogger().info("Markiert " + player.getName() + " für Join-/Quit-Unterdrückung"); - - try { - sendSuppressJoinQuit(from, player.getUniqueId()); - } catch (Throwable ex) { - plugin.getLogger().warning("Fehler beim Senden der Quit-Unterdrückung: " + ex.getMessage()); - } - - try { - sendSuppressJoinQuit(target, player.getUniqueId()); - } catch (Throwable ex) { - plugin.getLogger().warning("Fehler beim Senden der Join-Unterdrückung: " + ex.getMessage()); - } - - plugin.getProxy().getScheduler().schedule(plugin, () -> { - suppressJoinQuit.remove(player.getUniqueId()); - plugin.getLogger().info("Entfernte Unterdrückung für " + player.getName()); - }, 2, java.util.concurrent.TimeUnit.SECONDS); - } - - @EventHandler - public void onServerSwitch(ServerSwitchEvent e) { - ProxiedPlayer player = e.getPlayer(); - ServerInfo from = e.getFrom(); - ServerInfo to = player.getServer() != null ? player.getServer().getInfo() : null; - - if (to == null || from == null) return; - if (from.getName().equalsIgnoreCase(to.getName())) return; - - String fromName = from.getName(); - String fromDisplay = getDisplayName(fromName); - String toName = to.getName(); - String toDisplay = getDisplayName(toName); - - String[] ps = getPrefixSuffix(player); - String prefix = ps[0]; - String playerColor = ps[2]; // Namefarbe aus Properties für den Switch - - String displayTag = ""; - if (!prefix.isEmpty()) displayTag = prefix; - // Suffix wird hier ignoriert, da die || Syntax vorausgesetzt wird, aber es schadet nicht - else if (!ps[1].isEmpty()) displayTag = ps[1]; - - if (!displayTag.isEmpty() && !displayTag.endsWith(" ")) displayTag = displayTag + " "; - - StringBuilder msg = new StringBuilder(); - msg.append("§7[").append(toDisplay).append("§r§7] "); - if (!displayTag.isEmpty()) msg.append(displayTag); - // Hier wird die playerColor aus der verify.properties angewendet - msg.append(playerColor).append(player.getName()); - msg.append(" §7hat den Server gewechselt: §e") - .append(fromDisplay).append(" §7→ §e").append(toDisplay).append("§7."); - - String finalMsg = msg.toString(); - - TextComponent switchComponent = new TextComponent(finalMsg); - broadcastGlobal(switchComponent); - - String logEntry = "[" + toName + "] " + - (displayTag.isEmpty() ? "" : stripColor(displayTag) + " ") + - player.getName() + " hat den Server gewechselt: " + fromName + " -> " + toName + "."; - logMessage(logEntry); - } - - private void sendSuppressJoinQuit(ServerInfo server, UUID playerId) { - if (server == null) return; - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(baos)) { - out.writeUTF("suppress"); - out.writeUTF(playerId.toString()); - server.sendData(CHANNEL_CONTROL, baos.toByteArray()); - } catch (IOException ex) { - plugin.getLogger().warning("Fehler beim Senden der suppress-Nachricht: " + ex.getMessage()); - } - } - - private String repeat(String str, int count) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < count; i++) sb.append(str); - return sb.toString(); - } - - // =========================== - // Prefix/Suffix (Logic: Manual > LP > Perm) - // =========================== - private String[] getPrefixSuffix(ProxiedPlayer player) { - String prefix = ""; - String suffix = ""; - String playerColor = "§f"; - String chatColor = "§f"; - String groupName = "Spieler"; - - // 0. NEU: HÖCHSTE PRIO - Manueller Override aus verify.properties - if (manualRanks.containsKey(player.getUniqueId())) { - groupName = manualRanks.get(player.getUniqueId()); - // plugin.getLogger().info("Nutze manuellen Override für " + player.getName() + ": " + groupName); - } - // 1. LuckPerms via Reflection (Bungee) - else { - String lpGroup = getLuckPermsGroup(player); - if (lpGroup != null && !lpGroup.isEmpty() && !lpGroup.equalsIgnoreCase("default")) { - groupName = lpGroup; - } - } - - // 2. FALLBACK: Permission-Check - if (groupName == null || groupName.equalsIgnoreCase("default") || groupName.equalsIgnoreCase("Spieler")) { - if (player.hasPermission("group.owner")) groupName = "Owner"; - else if (player.hasPermission("group.admin")) groupName = "Admin"; - else if (player.hasPermission("group.developer")) groupName = "Developer"; - else if (player.hasPermission("group.premium")) groupName = "Premium"; - else groupName = "Spieler"; - } - - // 3. Farben aus verify.properties anwenden - if (groupName != null && groupFormats.containsKey(groupName.toLowerCase())) { - String rawFormat = groupFormats.get(groupName.toLowerCase()); - - if (rawFormat.contains(" || ")) { - String[] parts = rawFormat.split(" \\|\\| "); - prefix = ChatColor.translateAlternateColorCodes('&', parts[0]); - playerColor = ChatColor.translateAlternateColorCodes('&', parts[1]); - chatColor = ChatColor.translateAlternateColorCodes('&', parts[2]); - suffix = ""; - } else if (rawFormat.contains(": ")) { - String[] parts = rawFormat.split(": ", 2); - prefix = ChatColor.translateAlternateColorCodes('&', parts[0]); - chatColor = ChatColor.translateAlternateColorCodes('&', parts[1]); - playerColor = "§f"; - suffix = ""; - } else { - prefix = ChatColor.translateAlternateColorCodes('&', rawFormat); - suffix = ""; - playerColor = "§f"; - chatColor = "§f"; - } - - return new String[]{prefix, suffix, playerColor, chatColor}; - } - - // 4. LuckPerms Meta Fallback (Nur falls kein Config-Format da war) - try { - Class providerClass = Class.forName("net.luckperms.api.LuckPermsProvider"); - Method getMethod = providerClass.getMethod("get"); - Object api = getMethod.invoke(null); - if (api != null) { - Method getUserManagerMethod = api.getClass().getMethod("getUserManager"); - Object userManager = getUserManagerMethod.invoke(api); - Method loadUserMethod = userManager.getClass().getMethod("loadUser", UUID.class); - Object userFuture = loadUserMethod.invoke(userManager, player.getUniqueId()); - Method joinMethod = userFuture.getClass().getMethod("join"); - Object user = joinMethod.invoke(userFuture); - if (user != null) { - Class metaClass = Class.forName("net.luckperms.api.cacheddata.CachedMetaData"); - Method getMetaDataMethod = user.getClass().getMethod("getCachedData"); - Object meta = getMetaDataMethod.invoke(user); - if (meta != null) { - Method getPrefixMethod = metaClass.getMethod("getPrefix"); - Method getSuffixMethod = metaClass.getMethod("getSuffix"); - Object p = getPrefixMethod.invoke(meta); - Object s = getSuffixMethod.invoke(meta); - if (p != null) prefix = ChatColor.translateAlternateColorCodes('&', p.toString()); - if (s != null) suffix = ChatColor.translateAlternateColorCodes('&', s.toString()); - } - } - } - } catch (Throwable ignored) {} - - if (prefix == null) prefix = ""; - if (suffix == null) suffix = ""; - - return new String[]{prefix, suffix, playerColor, chatColor}; - } - - // HELPER: LuckPerms Group via Reflection - private String getLuckPermsGroup(ProxiedPlayer player) { - try { - if (plugin.getProxy().getPluginManager().getPlugin("LuckPerms") == null) return null; - - Class providerClass = Class.forName("net.luckperms.api.LuckPermsProvider"); - Method getMethod = providerClass.getMethod("get"); - Object api = getMethod.invoke(null); - - if (api != null) { - Method getUserManagerMethod = api.getClass().getMethod("getUserManager"); - Object userManager = getUserManagerMethod.invoke(api); - Method loadUserMethod = userManager.getClass().getMethod("loadUser", UUID.class); - Object userFuture = loadUserMethod.invoke(userManager, player.getUniqueId()); - Method joinMethod = userFuture.getClass().getMethod("join"); - Object user = joinMethod.invoke(userFuture); - if (user != null) { - Method getPrimaryGroupMethod = user.getClass().getMethod("getPrimaryGroup"); - return (String) getPrimaryGroupMethod.invoke(user); - } - } - } catch (ClassNotFoundException e) { - return null; - } catch (Exception e) { - plugin.getLogger().warning("Fehler beim Auslesen von LuckPerms (Reflection): " + e.getMessage()); - } - return null; - } - - private String stripColor(String s) { - if (s == null) return ""; - return ChatColor.stripColor(s); - } - - private void loadFilter() { - String fileName = "filter.yml"; - File file = new File(plugin.getDataFolder(), fileName); - - if (!file.exists()) { - plugin.getDataFolder().mkdirs(); - try (InputStream in = plugin.getResourceAsStream(fileName); - OutputStream out = new FileOutputStream(file)) { - if (in == null) { - plugin.getLogger().warning("Standard 'filter.yml' nicht in JAR gefunden."); - file.createNewFile(); - return; - } - byte[] buffer = new byte[1024]; - int length; - while ((length = in.read(buffer)) > 0) { - out.write(buffer, 0, length); - } - plugin.getLogger().info("Standard filter.yml erstellt."); - } catch (Exception e) { - e.printStackTrace(); - } - } - - try { - List lines = Files.readAllLines(file.toPath()); - badWords.clear(); - for (String line : lines) { - line = line.trim(); - if (line.startsWith("-")) badWords.add(line.substring(1).trim()); - } - plugin.getLogger().info("§eGeladene Filter-Wörter: " + badWords.size()); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void cleanupOldLogs() { - File[] files = logFolder.listFiles(); - if (files == null) return; - - long now = System.currentTimeMillis(); - long sevenDays = 1000L * 60 * 60 * 24 * 7; - - for (File f : files) { - if (now - f.lastModified() > sevenDays) { - f.delete(); - } - } - } - - private void logMessage(String message) { - String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); - File logFile = new File(logFolder, date + ".log"); - - try (BufferedWriter bw = new BufferedWriter(new FileWriter(logFile, true))) { - String time = new SimpleDateFormat("HH:mm:ss").format(new Date()); - bw.write("[" + time + "] " + message); - bw.newLine(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private boolean isStaff(ProxiedPlayer p) { - if (p == null) return false; - Boolean reportedOp = playerIsOp.get(p.getUniqueId()); - if (reportedOp != null && reportedOp) return true; - - if (p.hasPermission("team")) return true; - if (p.hasPermission("bungeecord.admin")) return true; - if (p.hasPermission("globalchat.op")) return true; - if (p.hasPermission("*")) return true; - - if (p.hasPermission("bungeecord.command.alert")) return true; - if (p.hasPermission("bungeecord.command.reload")) return true; - if (p.hasPermission("bungeecord.command.kick")) return true; - if (p.hasPermission("bungeecord.command.send")) return true; - if (p.hasPermission("bungeecord.command.perms")) return true; - - return false; - } - - // Überladene Methode für CommandSender (für Console/Check) - private boolean isStaff(CommandSender sender) { - if (sender instanceof ProxiedPlayer) { - return isStaff((ProxiedPlayer) sender); - } - return sender.hasPermission("globalchat.clear"); // Console hat meist Rechte, aber sicher ist sicher - } - - // =========================== - // Commands (Inner Classes) - // =========================== - public class ReloadCommand extends Command { - public ReloadCommand() { super("globalreload", "globalchat.reload"); } - @Override - public void execute(CommandSender sender, String[] args) { - loadFilter(); - loadConfig(); - sender.sendMessage(new TextComponent("§aFilter und Chat-Konfiguration wurden neu geladen!")); - } - } - - public class MuteCommand extends Command { - public MuteCommand() { super("globalmute", "globalchat.mute"); } - @Override - public void execute(CommandSender sender, String[] args) { - chatMuted = !chatMuted; - String status = chatMuted ? "§caktiviert" : "§aaufgehoben"; - for (ProxiedPlayer p : plugin.getProxy().getPlayers()) { - p.sendMessage(new TextComponent("§7[GlobalChat] §eDer globale Chat Mute wurde " + status + "§e!")); - } - plugin.getLogger().info("GlobalMute wurde " + (chatMuted ? "aktiviert" : "deaktiviert") + "."); - } - } - - public class SupportCommand extends Command { - public SupportCommand() { super("support"); } - @Override - public void execute(CommandSender sender, String[] args) { - if (!(sender instanceof ProxiedPlayer)) { - sender.sendMessage(new TextComponent("§cNur Spieler können Support-Nachrichten senden.")); - return; - } - - ProxiedPlayer player = (ProxiedPlayer) sender; - if (args.length == 0) { - player.sendMessage(new TextComponent("§cBitte eine Nachricht angeben: /support ")); - return; - } - - String msg = String.join(" ", args); - String serverRaw = player.getServer().getInfo().getName(); - String serverDisplay = getDisplayName(serverRaw); - - TextComponent supportMsg = new TextComponent("§7[Support] §b" + player.getName() + " §7vom Server §e" + serverDisplay + " §7: §f" + msg); - supportMsg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new ComponentBuilder("Klicke, um /reply " + player.getName() + " zu schreiben").create())); - supportMsg.setClickEvent(new net.md_5.bungee.api.chat.ClickEvent(net.md_5.bungee.api.chat.ClickEvent.Action.SUGGEST_COMMAND, "/reply " + player.getName() + " ")); - - for (ProxiedPlayer p : plugin.getProxy().getPlayers()) { - if (isStaff(p)) { - p.sendMessage(supportMsg); - lastSupportContact.put(p.getUniqueId(), player.getUniqueId()); - } - } - - player.sendMessage(new TextComponent("§aDeine Support-Nachricht wurde gesendet.")); - logMessage("[Support][" + serverRaw + "] " + player.getName() + ": " + msg); - } - } - - public class ReplyCommand extends Command { - public ReplyCommand() { super("reply"); } - @Override - public void execute(CommandSender sender, String[] args) { - if (!(sender instanceof ProxiedPlayer)) return; - - ProxiedPlayer staff = (ProxiedPlayer) sender; - UUID targetId = lastSupportContact.get(staff.getUniqueId()); - if (targetId == null) { - staff.sendMessage(new TextComponent("§cKein Spieler zum Antworten gefunden.")); - return; - } - - if (args.length == 0) { - staff.sendMessage(new TextComponent("§cBitte eine Nachricht angeben.")); - return; - } - - ProxiedPlayer target = plugin.getProxy().getPlayer(targetId); - if (target == null) { - staff.sendMessage(new TextComponent("§cSpieler ist nicht online.")); - return; - } - - String msg = String.join(" ", args); - target.sendMessage(new TextComponent("§7[Reply von §b" + staff.getName() + "§7]: §f" + msg)); - staff.sendMessage(new TextComponent("§aDeine Nachricht wurde an §b" + target.getName() + "§a gesendet.")); - } - } - - public class InfoCommand extends Command { - public InfoCommand() { super("info"); } - @Override - public void execute(CommandSender sender, String[] args) { - sender.sendMessage(new TextComponent("§8§m------------------------------")); - sender.sendMessage(new TextComponent("§6§lGlobalChat Info")); - sender.sendMessage(new TextComponent("§ePlugin-Name: §bStatusAPI (GlobalChat Module)")); - sender.sendMessage(new TextComponent("§eVersion: §b2.0 (Relay)")); - sender.sendMessage(new TextComponent("§eErsteller: §bM_Viper")); - sender.sendMessage(new TextComponent("§8§m------------------------------")); - } - } - - public class ChatToggleCommand extends Command { - public ChatToggleCommand() { super("togglechat"); } - - @Override - public void execute(CommandSender sender, String[] args) { - if (!(sender instanceof ProxiedPlayer)) { - sender.sendMessage(new TextComponent("§cNur Spieler können den Chat-Modus ändern.")); - return; - } - - ProxiedPlayer player = (ProxiedPlayer) sender; - UUID uuid = player.getUniqueId(); - - if (chatLockPlayers.contains(uuid)) { - chatLockPlayers.remove(uuid); - player.sendMessage(new TextComponent("§aGlobalChat aktiviert.")); - player.sendMessage(new TextComponent("§7Deine Nachrichten werden nun wieder global gesendet.")); - } else { - chatLockPlayers.add(uuid); - player.sendMessage(new TextComponent("§cGlobalChat deaktiviert.")); - player.sendMessage(new TextComponent("§7Deine Nachrichten gehen nur noch an den Server (z.B. für Lands oder Quests).")); - player.sendMessage(new TextComponent("§7Nutze erneut /togglechat, um den globalen Chat zu aktivieren.")); - } - } - } - - public class ClearChatCommand extends Command { - public ClearChatCommand() { - super("clearchat", "globalchat.clear", "cc"); - } - - @Override - public void execute(CommandSender sender, String[] args) { - // Prüfen, ob der Sender OP / Team ist - // Wir nutzen hier die überladene isStaff Methode für CommandSender - if (!isStaff(sender)) { - sender.sendMessage(new TextComponent("§cKeine Berechtigung!")); - return; - } - - // 100 leere Zeilen senden zum Leeren - TextComponent emptyLine = new TextComponent(" "); - for (int i = 0; i < 100; i++) { - broadcastGlobal(emptyLine); - } - - // Bestätigungsnachricht - TextComponent clearMsg = new TextComponent("§7[GlobalChat] §cDer Chat wurde von " + sender.getName() + " geleert."); - broadcastGlobal(clearMsg); - - sender.sendMessage(new TextComponent("§aChat wurde geleert.")); - } - } -}