diff --git a/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/PrivateMsgManager.java b/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/PrivateMsgManager.java new file mode 100644 index 0000000..ca907a3 --- /dev/null +++ b/_trash/2026-05-07T19-39-23-130Z/src/main/java/net/viper/status/modules/chat/PrivateMsgManager.java @@ -0,0 +1,163 @@ +package net.viper.status.modules.chat; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.viper.status.ratelimit.GlobalRateLimitFramework; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Verwaltet private Nachrichten (/msg, /r) und Social-Spy. + */ +public class PrivateMsgManager { + + private final BlockManager blockManager; + private final GlobalRateLimitFramework rateLimiter = GlobalRateLimitFramework.getInstance(); + + // UUID → letzte PM-Gesprächspartner UUID (für /r) + private final Map lastPartner = new ConcurrentHashMap<>(); + + // UUIDs die Social-Spy aktiviert haben + private final java.util.Set spyEnabled = + java.util.Collections.newSetFromMap(new ConcurrentHashMap<>()); + + public PrivateMsgManager(BlockManager blockManager) { + this.blockManager = blockManager; + } + + /** + * Sendet eine private Nachricht von `sender` an `receiver`. + * + * @param sender Der sendende Spieler + * @param receiver Der empfangende Spieler + * @param message Die Nachricht + * @param config Chat-Konfiguration (Formate) + * @param bypassPermission Permission für Admin-Bypass (kann nicht geblockt werden) + * @return true wenn erfolgreich gesendet + */ + public boolean send(ProxiedPlayer sender, ProxiedPlayer receiver, + String message, ChatConfig config, String bypassPermission) { + + // Selbst anschreiben verhindern + if (sender.getUniqueId().equals(receiver.getUniqueId())) { + sender.sendMessage(color("&cDu kannst dir nicht selbst schreiben.")); + return false; + } + + // Admin-Bypass: Wenn Sender Admin ist, kann er nicht geblockt werden + boolean senderIsAdmin = sender.hasPermission(bypassPermission); + + // Block-Check (nur wenn Sender kein Admin) + if (!senderIsAdmin) { + if (!blockManager.canReceive(sender.getUniqueId(), receiver.getUniqueId())) { + sender.sendMessage(color("&cDieser Spieler hat dich blockiert oder du hast ihn blockiert.")); + return false; + } + + if (config.isPmRateLimitEnabled()) { + GlobalRateLimitFramework.Result result = rateLimiter.check( + "chat.pm", + sender.getUniqueId().toString(), + new GlobalRateLimitFramework.Rule( + true, + config.getPmRateLimitWindowMs(), + config.getPmRateLimitMaxActions(), + config.getPmRateLimitBlockMs() + ) + ); + + if (result.isBlocked()) { + sender.sendMessage(color(config.getPmRateLimitMessage())); + return false; + } + } + } + + // Formatierung + String toSender = format(config.getPmFormatSender(), sender.getName(), receiver.getName(), message, true); + String toReceiver = format(config.getPmFormatReceiver(), sender.getName(), receiver.getName(), message, false); + + sender.sendMessage(color(toSender)); + receiver.sendMessage(color(toReceiver)); + + // Letzte Partner speichern (für /r) + lastPartner.put(sender.getUniqueId(), receiver.getUniqueId()); + lastPartner.put(receiver.getUniqueId(), sender.getUniqueId()); + + // Social Spy + String spyMsg = format(config.getPmFormatSpy(), sender.getName(), receiver.getName(), message, true); + broadcastSpy(spyMsg, config.getPmSpyPermission(), sender.getUniqueId(), receiver.getUniqueId()); + + return true; + } + + /** + * Antwort-Funktion (/r). + * Sucht den letzten Gesprächspartner des Senders. + */ + public void reply(ProxiedPlayer sender, String message, ChatConfig config, String bypassPermission) { + UUID partnerUuid = lastPartner.get(sender.getUniqueId()); + if (partnerUuid == null) { + sender.sendMessage(color("&cDu hast noch keine Nachricht erhalten.")); + return; + } + ProxiedPlayer partner = ProxyServer.getInstance().getPlayer(partnerUuid); + if (partner == null || !partner.isConnected()) { + sender.sendMessage(color("&cDieser Spieler ist nicht mehr online.")); + return; + } + send(sender, partner, message, config, bypassPermission); + } + + /** Social-Spy umschalten. */ + public boolean toggleSpy(UUID uuid) { + if (spyEnabled.contains(uuid)) { + spyEnabled.remove(uuid); + return false; + } else { + spyEnabled.add(uuid); + return true; + } + } + + private void broadcastSpy(String formatted, String spyPermission, UUID... exclude) { + java.util.Set excl = new java.util.HashSet<>(java.util.Arrays.asList(exclude)); + for (ProxiedPlayer p : ProxyServer.getInstance().getPlayers()) { + if (excl.contains(p.getUniqueId())) continue; + // Spy muss entweder via Permission aktiv oder manuell aktiviert haben + boolean hasPerm = p.hasPermission(spyPermission); + boolean hasToggle= spyEnabled.contains(p.getUniqueId()); + if (hasPerm || hasToggle) { + p.sendMessage(color(formatted)); + } + } + } + + /** + * Formatiert eine PM-Nachricht. + * {sender} → Name des Absenders + * {receiver} → Name des Empfängers + * {player} → Gesprächspartner aus Sicht des jeweiligen Empfängers: + * Beim Sender: der Empfänger (an wen schreibt er?) + * Beim Empfänger: der Sender (von wem kommt es?) + * + * @param viewerIsSender true wenn der aktuelle Betrachter der Absender ist + */ + private String format(String template, String sender, String receiver, + String message, boolean viewerIsSender) { + String partner = viewerIsSender ? receiver : sender; + return template + .replace("{sender}", sender) + .replace("{receiver}", receiver) + .replace("{player}", partner) // Gesprächspartner aus Sicht des Betrachters + .replace("{message}", message); + } + + private TextComponent color(String text) { + return new TextComponent(ChatColor.translateAlternateColorCodes('&', text)); + } +} \ No newline at end of file