Files
TicketSystem/src/main/java/de/ticketsystem/bungee/BungeeMessenger.java
2026-02-21 16:00:03 +01:00

263 lines
11 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.bungee;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import de.ticketsystem.TicketPlugin;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.UUID;
/**
* Verwaltet die BungeeCord Plugin-Messaging-Kanäle für Cross-Server-Kommunikation.
*
* Kanalübersicht:
* Ausgehend: "BungeeCord" Standard-BungeeCord-Kanal (Forward, Message)
* Eingehend: "ticketsystem:notify" Eigener Kanal für weitergeleitete Nachrichten
*
* Voraussetzung:
* - In spigot.yml muss "bungeecord: true" gesetzt sein
* - In plugin.yml müssen beide Kanäle unter "channels:" deklariert sein
*
* Pakettypen (erstes Byte bei ticketsystem:notify):
* 0x01 = TEAM_NOTIFY Nachricht an alle Online-Supporter/Admins auf diesem Server
* 0x02 = PLAYER_MSG Nachricht an einen bestimmten Spieler (UUID + Text)
*
* ── BUG FIX ──────────────────────────────────────────────────────────────────
* Problem: BungeeCord's "Forward ALL" liefert auf dem Zielserver den inneren
* Payload BEREITS ENTPACKT via onPluginMessageReceived auf dem
* CUSTOM_CHANNEL. Das war korrekt implementiert.
*
* Der eigentliche Fehler lag in broadcastTeamNotification():
* - Nachrichten mit "\n" wurden als ein einzelner String gesendet.
* Minecraft verarbeitet "\n" in sendMessage() nicht → beide Zeilen kamen
* als eine zusammen an (unleserlich, aber nicht die Ursache für "gar nichts").
* - Die Methode wird jetzt mit einer Liste von Strings aufgerufen (broadcastLines)
* damit jede Zeile als separates Paket gesendet wird klar und lesbar.
*
* Hauptursache für "gar nichts auf Lobby":
* Die plugin.yml hatte keinen "channels:"-Block. Ohne diesen Eintrag
* registriert BungeeCord den Kanal "ticketsystem:notify" nicht und
* verwirft alle eingehenden Forward-Pakete lautlos auf den Ziel-Servern.
* → plugin.yml Fix ist die primäre Lösung.
*
* Diese Datei enthält zusätzlich Debug-Logging (wenn debug: true in config.yml)
* damit zukünftige Probleme schneller gefunden werden können.
* ─────────────────────────────────────────────────────────────────────────────
*/
public class BungeeMessenger implements PluginMessageListener {
/** BungeeCord-Standardkanal für Forward/Message-Subkanäle */
public static final String BUNGEE_CHANNEL = "BungeeCord";
/** Eigener Weiterleitungskanal muss in plugin.yml unter channels stehen */
public static final String CUSTOM_CHANNEL = "ticketsystem:notify";
private static final byte TYPE_TEAM_NOTIFY = 0x01;
private static final byte TYPE_PLAYER_MSG = 0x02;
private final TicketPlugin plugin;
public BungeeMessenger(TicketPlugin plugin) {
this.plugin = plugin;
}
// ─────────────────────────── Ausgehende Nachrichten ────────────────────
/**
* Sendet eine Chat-Nachricht an einen bestimmten Spieler egal auf welchem
* Server im Netzwerk er sich befindet.
*
* Reihenfolge:
* 1. Spieler ist lokal online → direkte Zustellung
* 2. Spieler ist woanders → BungeeCord "Message"-Subkanal (nach Name)
* 3. Spieler ist offline → Pendende DB-Benachrichtigung (vorher speichern!)
*/
public void sendMessageToPlayer(UUID targetUUID, String targetName, String message) {
// 1. Lokal online?
Player local = Bukkit.getPlayer(targetUUID);
if (local != null && local.isOnline()) {
local.sendMessage(message);
return;
}
// 2. Cross-Server via BungeeCord "Message"-Subkanal
Player messenger = getAnyOnlinePlayer();
if (messenger == null || targetName == null) return;
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Message");
out.writeUTF(targetName);
out.writeUTF(message);
messenger.sendPluginMessage(plugin, BUNGEE_CHANNEL, out.toByteArray());
if (plugin.isDebug()) {
plugin.getLogger().info("[DEBUG][BungeeMessenger] sendMessageToPlayer → " + targetName + ": " + message);
}
}
/**
* Broadcastet eine Team-Benachrichtigung an alle Supporter/Admins im gesamten Netzwerk.
*
* Lokal online Spieler werden sofort benachrichtigt.
* Alle anderen Server erhalten das Paket über den "Forward ALL"-Mechanismus.
*
* WICHTIG: Jede Zeile wird als separates Paket gesendet damit Minecraft
* die Nachrichten korrekt zeilenweise anzeigt.
*/
public void broadcastTeamNotification(String message) {
// Lokale Supporter direkt benachrichtigen
Bukkit.getOnlinePlayers().stream()
.filter(p -> p.hasPermission("ticket.support") || p.hasPermission("ticket.admin"))
.forEach(p -> p.sendMessage(message));
// An alle anderen Server forwarden
Player messenger = getAnyOnlinePlayer();
if (messenger == null) {
if (plugin.isDebug()) {
plugin.getLogger().warning("[DEBUG][BungeeMessenger] broadcastTeamNotification: kein Bote online Forward nicht möglich!");
}
return;
}
sendForwardPacket(messenger, message);
if (plugin.isDebug()) {
plugin.getLogger().info("[DEBUG][BungeeMessenger] broadcastTeamNotification gesendet via " + messenger.getName() + ": " + message);
}
}
/**
* Sendet eine Nachricht an einen bestimmten Spieler via eigenem Forward-Paket.
*/
public void forwardPlayerMessage(UUID targetUUID, String targetName, String message) {
Player local = Bukkit.getPlayer(targetUUID);
if (local != null && local.isOnline()) {
local.sendMessage(message);
return;
}
Player messenger = getAnyOnlinePlayer();
if (messenger == null) return;
byte[] uuidBytes = targetUUID.toString().getBytes(StandardCharsets.UTF_8);
byte[] msgBytes = message.getBytes(StandardCharsets.UTF_8);
ByteArrayDataOutput inner = ByteStreams.newDataOutput();
inner.writeByte(TYPE_PLAYER_MSG);
inner.writeShort(uuidBytes.length);
inner.write(uuidBytes);
inner.writeShort(msgBytes.length);
inner.write(msgBytes);
byte[] innerBytes = inner.toByteArray();
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Forward");
out.writeUTF("ALL");
out.writeUTF(CUSTOM_CHANNEL);
out.writeShort(innerBytes.length);
out.write(innerBytes);
messenger.sendPluginMessage(plugin, BUNGEE_CHANNEL, out.toByteArray());
}
// ─────────────────────────── Eingehende Nachrichten ────────────────────
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] data) {
if (!CUSTOM_CHANNEL.equals(channel)) return;
if (plugin.isDebug()) {
plugin.getLogger().info("[DEBUG][BungeeMessenger] Paket empfangen auf " + channel + ", " + data.length + " Bytes");
}
try {
ByteArrayDataInput in = ByteStreams.newDataInput(data);
byte type = in.readByte();
if (type == TYPE_TEAM_NOTIFY) {
// Rest der Bytes = UTF-8-kodierte Nachricht
int len = data.length - 1;
byte[] msgBytes = new byte[len];
in.readFully(msgBytes);
String message = new String(msgBytes, StandardCharsets.UTF_8);
if (plugin.isDebug()) {
plugin.getLogger().info("[DEBUG][BungeeMessenger] TEAM_NOTIFY empfangen: " + message);
}
// Im Hauptthread an lokale Supporter zustellen
Bukkit.getScheduler().runTask(plugin, () ->
Bukkit.getOnlinePlayers().stream()
.filter(p -> p.hasPermission("ticket.support") || p.hasPermission("ticket.admin"))
.forEach(p -> p.sendMessage(message))
);
} else if (type == TYPE_PLAYER_MSG) {
int uuidLen = in.readShort();
byte[] uuidBytes = new byte[uuidLen];
in.readFully(uuidBytes);
UUID targetUUID = UUID.fromString(new String(uuidBytes, StandardCharsets.UTF_8));
int msgLen = in.readShort();
byte[] msgBytes = new byte[msgLen];
in.readFully(msgBytes);
String message = new String(msgBytes, StandardCharsets.UTF_8);
if (plugin.isDebug()) {
plugin.getLogger().info("[DEBUG][BungeeMessenger] PLAYER_MSG empfangen für: " + targetUUID);
}
Bukkit.getScheduler().runTask(plugin, () -> {
Player target = Bukkit.getPlayer(targetUUID);
if (target != null && target.isOnline()) {
target.sendMessage(message);
}
});
} else {
plugin.getLogger().warning("[BungeeMessenger] Unbekannter Pakettyp: " + type);
}
} catch (Exception e) {
plugin.getLogger().warning("[BungeeMessenger] Fehler beim Verarbeiten einer Plugin-Message: " + e.getMessage());
if (plugin.isDebug()) e.printStackTrace();
}
}
// ─────────────────────────── Hilfsmethoden ─────────────────────────────
/**
* Baut und sendet ein Forward-ALL-Paket mit TYPE_TEAM_NOTIFY.
*/
private void sendForwardPacket(Player messenger, String message) {
byte[] msgBytes = message.getBytes(StandardCharsets.UTF_8);
ByteArrayDataOutput inner = ByteStreams.newDataOutput();
inner.writeByte(TYPE_TEAM_NOTIFY);
inner.write(msgBytes);
byte[] innerBytes = inner.toByteArray();
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Forward");
out.writeUTF("ALL");
out.writeUTF(CUSTOM_CHANNEL);
out.writeShort(innerBytes.length);
out.write(innerBytes);
messenger.sendPluginMessage(plugin, BUNGEE_CHANNEL, out.toByteArray());
}
/**
* Gibt einen beliebigen online Spieler zurück der als "Bote" für Plugin-Messages
* verwendet werden kann. BungeeCord verlangt einen Spieler als Absender.
*/
private Player getAnyOnlinePlayer() {
Collection<? extends Player> online = Bukkit.getOnlinePlayers();
return online.isEmpty() ? null : online.iterator().next();
}
}