From f7979b5359f032ed4464412668a161572d8327d2 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Sat, 23 May 2026 18:07:54 +0000 Subject: [PATCH] Delete src/main/java/de/teleportsuite/bungeemessaging/BungeeMessenger.java via Git Manager GUI --- .../bungeemessaging/BungeeMessenger.java | 720 ------------------ 1 file changed, 720 deletions(-) delete mode 100644 src/main/java/de/teleportsuite/bungeemessaging/BungeeMessenger.java diff --git a/src/main/java/de/teleportsuite/bungeemessaging/BungeeMessenger.java b/src/main/java/de/teleportsuite/bungeemessaging/BungeeMessenger.java deleted file mode 100644 index 5e2bb4e..0000000 --- a/src/main/java/de/teleportsuite/bungeemessaging/BungeeMessenger.java +++ /dev/null @@ -1,720 +0,0 @@ -package de.teleportsuite.bungeemessaging; - -import de.teleportsuite.TeleportSuite; -import org.bukkit.entity.Player; -import org.bukkit.plugin.messaging.PluginMessageListener; - -import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; - -/** - * Handles BungeeCord Plugin Messaging. - * - * Cross-server teleport flow (fixed): - * 1. Query the target server for the exact coordinates of the target player (QUERY_LOCATION). - * 2. Target server replies with LOCATION_RESPONSE (world, x, y, z, yaw, pitch). - * 3. We send a LOCATION payload to the target server so it teleports the mover on arrival. - * 4. We send the BungeeCord Connect/ConnectOther to actually switch the server. - * - * Step 3 happens *before* step 4 to avoid the race condition where the player - * arrives on the target server before the teleport payload does. - * A 1-second timeout falls back to the TP_TO_PLAYER polling mechanism. - */ -public class BungeeMessenger implements PluginMessageListener { - - private static final String BUNGEE_CHANNEL = "BungeeCord"; - private static final String TS_CHANNEL = "teleportsuite:tp"; - private final TeleportSuite plugin; - private final Map>> pendingServerLookups = new HashMap<>(); - private final Map>>> pendingPlayerListLookups = new HashMap<>(); - // key = targetPlayer.toLowerCase() - private final Map>> pendingLocationLookups = new HashMap<>(); - - public BungeeMessenger(TeleportSuite plugin) { this.plugin = plugin; } - - public void register() { - plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, BUNGEE_CHANNEL); - plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, TS_CHANNEL); - plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, BUNGEE_CHANNEL, this); - plugin.getServer().getMessenger().registerIncomingPluginChannel(plugin, TS_CHANNEL, this); - } - - public void unregister() { - plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(plugin); - plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin); - } - - // ------------------------------------------------------------------------- - // Player-server & player-list lookups (unchanged) - // ------------------------------------------------------------------------- - - public void requestPlayerServer(Player sender, String targetPlayer, Consumer callback) { - if (sender == null || !sender.isOnline()) { - callback.accept(null); - return; - } - - String key = targetPlayer.toLowerCase(Locale.ROOT); - pendingServerLookups.computeIfAbsent(key, k -> new ArrayList<>()).add(callback); - - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("GetPlayerServer"); - out.writeUTF(targetPlayer); - sender.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("GetPlayerServer Fehler: " + e.getMessage()); - flushServerLookupCallbacks(key, null); - } - } - - public void requestPlayerList(Player sender, String serverScope, Consumer> callback) { - if (sender == null || !sender.isOnline()) { - callback.accept(List.of()); - return; - } - - String scope = serverScope == null || serverScope.isBlank() ? "ALL" : serverScope; - String key = scope.toUpperCase(Locale.ROOT); - pendingPlayerListLookups.computeIfAbsent(key, k -> new ArrayList<>()).add(callback); - - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("PlayerList"); - out.writeUTF(scope); - sender.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("PlayerList Fehler: " + e.getMessage()); - flushPlayerListCallbacks(key, List.of()); - } - } - - // ------------------------------------------------------------------------- - // Cross-server location query - // ------------------------------------------------------------------------- - - /** - * Sends a QUERY_LOCATION to {@code targetServer} asking for the exact - * coordinates of {@code targetPlayer}. The callback receives a Bukkit - * Location on success, or null if the player is not found / timeout fires. - */ - private void requestPlayerLocationOnServer(Player anchor, String targetPlayer, - String targetServer, - Consumer callback) { - String key = targetPlayer.toLowerCase(Locale.ROOT); - pendingLocationLookups.computeIfAbsent(key, k -> new ArrayList<>()).add(callback); - - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("Forward"); - out.writeUTF(targetServer); - out.writeUTF(TS_CHANNEL); - - ByteArrayOutputStream sub = new ByteArrayOutputStream(); - DataOutputStream subOut = new DataOutputStream(sub); - subOut.writeUTF("QUERY_LOCATION"); - subOut.writeUTF(targetPlayer); - subOut.writeUTF(plugin.getConfigManager().getServerName()); // reply-to - - byte[] subBytes = sub.toByteArray(); - out.writeShort(subBytes.length); - out.write(subBytes); - anchor.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("QUERY_LOCATION Fehler: " + e.getMessage()); - flushLocationLookupCallbacks(key, null); - return; - } - - // 1-second timeout → fall back to TP_TO_PLAYER polling - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { - if (pendingLocationLookups.containsKey(key)) { - flushLocationLookupCallbacks(key, null); - } - }, 20L); - } - - private void flushLocationLookupCallbacks(String key, org.bukkit.Location loc) { - List> callbacks = pendingLocationLookups.remove(key); - if (callbacks == null) return; - for (Consumer cb : callbacks) cb.accept(loc); - } - - // ------------------------------------------------------------------------- - // Public teleport helpers - // ------------------------------------------------------------------------- - - public void teleportAllPlayersToLocalPlayer(Player requester) { - String requesterName = requester.getName(); - requestPlayerList(requester, "ALL", players -> { - if (players == null || players.isEmpty()) { - requester.sendMessage("§cKeine Spieler gefunden."); - return; - } - - Set seen = new HashSet<>(); - for (String playerName : players) { - if (playerName == null || playerName.isBlank()) continue; - if (playerName.equalsIgnoreCase(requesterName)) continue; - if (!seen.add(playerName.toLowerCase(Locale.ROOT))) continue; - teleportPlayerToLocalPlayer(requester, playerName, requesterName); - } - - requester.sendMessage("§aAlle verfügbaren Spieler im Netzwerk werden zu dir teleportiert."); - }); - } - - /** - * Teleports {@code requester} directly to {@code targetPlayerName}. - * - * If the target is on another server: - * 1. Ask that server for the target's exact position (QUERY_LOCATION). - * 2. Send a LOCATION payload → player spawns at the right spot immediately. - * 3. Switch the requester via BungeeCord Connect. - * Fallback: if the query times out, send TP_TO_PLAYER (polling mechanism). - */ - public void teleportToPlayer(Player requester, String targetPlayerName) { - requestPlayerServer(requester, targetPlayerName, server -> { - if (server == null || server.isBlank()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName)); - return; - } - - String localServer = plugin.getConfigManager().getServerName(); - if (server.equalsIgnoreCase(localServer)) { - // Same server — direct teleport - Player target = plugin.getServer().getPlayerExact(targetPlayerName); - if (target == null || !target.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName)); - return; - } - plugin.getTeleportManager().teleport( - requester, - new de.teleportsuite.models.TeleportLocation(target.getLocation(), localServer) - ); - return; - } - - // Cross-server: get exact coordinates first, then switch - requestPlayerLocationOnServer(requester, targetPlayerName, server, loc -> { - if (loc != null) { - // Precise LOCATION payload → no intermediate spawn - sendTeleportPayload(requester, requester.getName(), server, - loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), - loc.getYaw(), loc.getPitch()); - } else { - // Fallback: target server will poll for both players - sendPlayerToPlayerPayload(requester, requester.getName(), targetPlayerName, server); - } - connectPlayerOnly(requester, server); - requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success")); - }); - }); - } - - /** - * Teleports {@code moverPlayerName} (on a remote server) to the local player - * {@code localTargetPlayerName}. The local player's current coordinates are - * known, so we can send a precise LOCATION payload immediately. - */ - public void teleportPlayerToLocalPlayer(Player requester, String moverPlayerName, String localTargetPlayerName) { - requestPlayerServer(requester, moverPlayerName, moverServer -> { - if (moverServer == null || moverServer.isBlank()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName)); - return; - } - - String localServer = plugin.getConfigManager().getServerName(); - if (moverServer.equalsIgnoreCase(localServer)) { - // Same server — direct teleport - Player mover = plugin.getServer().getPlayerExact(moverPlayerName); - Player target = plugin.getServer().getPlayerExact(localTargetPlayerName); - if (mover == null || !mover.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName)); - return; - } - if (target == null || !target.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", localTargetPlayerName)); - return; - } - plugin.getTeleportManager().teleport( - mover, - new de.teleportsuite.models.TeleportLocation(target.getLocation(), localServer) - ); - return; - } - - // Cross-server: the *target* is local, so we already know their position - Player localTarget = plugin.getServer().getPlayerExact(localTargetPlayerName); - if (localTarget == null || !localTarget.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", localTargetPlayerName)); - return; - } - - org.bukkit.Location dest = localTarget.getLocation(); - // Send LOCATION payload to mover's current server first, then switch them - sendTeleportPayload(requester, moverPlayerName, localServer, - dest.getWorld().getName(), dest.getX(), dest.getY(), dest.getZ(), - dest.getYaw(), dest.getPitch()); - connectOtherPlayer(requester, moverPlayerName, localServer); - requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success")); - }); - } - - /** - * Teleports {@code moverPlayerName} to {@code targetPlayerName} when both - * may be on different servers. - */ - public void teleportAnyPlayerToAnyPlayer(Player requester, String moverPlayerName, String targetPlayerName) { - requestPlayerServer(requester, targetPlayerName, targetServer -> { - if (targetServer == null || targetServer.isBlank()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName)); - return; - } - - requestPlayerServer(requester, moverPlayerName, moverServer -> { - if (moverServer == null || moverServer.isBlank()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName)); - return; - } - - String localServer = plugin.getConfigManager().getServerName(); - - // Both on the same local server - if (moverServer.equalsIgnoreCase(localServer) && targetServer.equalsIgnoreCase(localServer)) { - Player mover = plugin.getServer().getPlayerExact(moverPlayerName); - Player target = plugin.getServer().getPlayerExact(targetPlayerName); - if (mover == null || !mover.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName)); - return; - } - if (target == null || !target.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName)); - return; - } - plugin.getTeleportManager().teleport( - mover, - new de.teleportsuite.models.TeleportLocation(target.getLocation(), localServer) - ); - return; - } - - // Target is on this local server — we know the coordinates - if (targetServer.equalsIgnoreCase(localServer)) { - Player localTarget = plugin.getServer().getPlayerExact(targetPlayerName); - if (localTarget == null || !localTarget.isOnline()) { - requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName)); - return; - } - org.bukkit.Location dest = localTarget.getLocation(); - sendTeleportPayload(requester, moverPlayerName, localServer, - dest.getWorld().getName(), dest.getX(), dest.getY(), dest.getZ(), - dest.getYaw(), dest.getPitch()); - if (!moverServer.equalsIgnoreCase(localServer)) { - connectOtherPlayer(requester, moverPlayerName, localServer); - } - requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success")); - return; - } - - // Target is on a third (remote) server — query their location first - requestPlayerLocationOnServer(requester, targetPlayerName, targetServer, loc -> { - if (loc != null) { - sendTeleportPayload(requester, moverPlayerName, targetServer, - loc.getWorld().getName(), loc.getX(), loc.getY(), loc.getZ(), - loc.getYaw(), loc.getPitch()); - } else { - sendPlayerToPlayerPayload(requester, moverPlayerName, targetPlayerName, targetServer); - } - if (!moverServer.equalsIgnoreCase(targetServer)) { - connectOtherPlayer(requester, moverPlayerName, targetServer); - } - requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success")); - }); - }); - }); - } - - // ------------------------------------------------------------------------- - // TPA forwarding (unchanged) - // ------------------------------------------------------------------------- - - public void sendTpaRequestToPlayer(Player sender, String targetPlayerName) { - sendForwardToPlayer(sender, targetPlayerName, out -> { - out.writeUTF("TPA_REQUEST"); - out.writeUTF(sender.getName()); - out.writeUTF(targetPlayerName); - }); - } - - public void sendTpaAcceptToPlayer(Player sender, String requesterName) { - sendForwardToPlayer(sender, requesterName, out -> { - out.writeUTF("TPA_ACCEPT"); - out.writeUTF(requesterName); - out.writeUTF(sender.getName()); - }); - } - - public void sendTpaDenyToPlayer(Player sender, String requesterName) { - sendForwardToPlayer(sender, requesterName, out -> { - out.writeUTF("TPA_DENY"); - out.writeUTF(requesterName); - out.writeUTF(sender.getName()); - }); - } - - public void sendTpaExpiredToPlayer(Player sender, String targetPlayerName) { - sendForwardToPlayer(sender, targetPlayerName, out -> { - out.writeUTF("TPA_EXPIRED"); - out.writeUTF(sender.getName()); - out.writeUTF(targetPlayerName); - }); - } - - // ------------------------------------------------------------------------- - // Low-level BungeeCord helpers - // ------------------------------------------------------------------------- - - /** Send player to another server AND pre-register their destination coordinates. */ - public void connectToServer(Player player, String server, String world, - double x, double y, double z, float yaw, float pitch) { - sendTeleportPayload(player, player.getName(), server, world, x, y, z, yaw, pitch); - connectPlayerOnly(player, server); - } - - private void connectPlayerOnly(Player player, String server) { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("Connect"); - out.writeUTF(server); - player.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("BungeeCord Connect Fehler: " + e.getMessage()); - } - } - - private void connectOtherPlayer(Player anchor, String playerName, String server) { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("ConnectOther"); - out.writeUTF(playerName); - out.writeUTF(server); - anchor.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("BungeeCord ConnectOther Fehler: " + e.getMessage()); - } - } - - /** Forward a LOCATION payload to {@code server} for {@code targetPlayer}. */ - private void sendTeleportPayload(Player sender, String targetPlayer, String server, - String world, double x, double y, double z, - float yaw, float pitch) { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("Forward"); - out.writeUTF(server); - out.writeUTF(TS_CHANNEL); - - ByteArrayOutputStream sub = new ByteArrayOutputStream(); - DataOutputStream subOut = new DataOutputStream(sub); - subOut.writeUTF("LOCATION"); - subOut.writeUTF(targetPlayer); - subOut.writeUTF(world); - subOut.writeDouble(x); - subOut.writeDouble(y); - subOut.writeDouble(z); - subOut.writeFloat(yaw); - subOut.writeFloat(pitch); - - byte[] subBytes = sub.toByteArray(); - out.writeShort(subBytes.length); - out.write(subBytes); - sender.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("TS Forward Fehler: " + e.getMessage()); - } - } - - /** - * Fallback: forward a TP_TO_PLAYER payload. - * The target server will poll until both players are online. - */ - private void sendPlayerToPlayerPayload(Player sender, String moverPlayer, - String targetPlayer, String targetServer) { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("Forward"); - out.writeUTF(targetServer); - out.writeUTF(TS_CHANNEL); - - ByteArrayOutputStream sub = new ByteArrayOutputStream(); - DataOutputStream subOut = new DataOutputStream(sub); - subOut.writeUTF("TP_TO_PLAYER"); - subOut.writeUTF(moverPlayer); - subOut.writeUTF(targetPlayer); - - byte[] subBytes = sub.toByteArray(); - out.writeShort(subBytes.length); - out.write(subBytes); - sender.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("TS Player->Player Forward Fehler: " + e.getMessage()); - } - } - - private void sendForwardToPlayer(Player sender, String targetPlayer, - IOConsumer payloadWriter) { - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("ForwardToPlayer"); - out.writeUTF(targetPlayer); - out.writeUTF(TS_CHANNEL); - - ByteArrayOutputStream sub = new ByteArrayOutputStream(); - DataOutputStream subOut = new DataOutputStream(sub); - payloadWriter.accept(subOut); - - byte[] subBytes = sub.toByteArray(); - out.writeShort(subBytes.length); - out.write(subBytes); - sender.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("TS ForwardToPlayer Fehler: " + e.getMessage()); - } - } - - // ------------------------------------------------------------------------- - // Polling fallback (kept for TP_TO_PLAYER fallback path) - // ------------------------------------------------------------------------- - - private void schedulePlayerToPlayerTeleport(String moverName, String targetName) { - int maxAttempts = 100; - final int[] attempts = {0}; - final int[] taskId = {0}; - - taskId[0] = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, () -> { - attempts[0]++; - Player mover = plugin.getServer().getPlayerExact(moverName); - Player target = plugin.getServer().getPlayerExact(targetName); - - if (mover != null && mover.isOnline() && target != null && target.isOnline()) { - plugin.getTeleportManager().teleport( - mover, - new de.teleportsuite.models.TeleportLocation( - target.getLocation(), plugin.getConfigManager().getServerName()), - false - ); - plugin.getServer().getScheduler().cancelTask(taskId[0]); - return; - } - - if (attempts[0] >= maxAttempts) { - plugin.getServer().getScheduler().cancelTask(taskId[0]); - } - }, 10L, 10L); - } - - // ------------------------------------------------------------------------- - // Callback flush helpers - // ------------------------------------------------------------------------- - - private void flushServerLookupCallbacks(String key, String server) { - List> callbacks = pendingServerLookups.remove(key); - if (callbacks == null) return; - for (Consumer callback : callbacks) callback.accept(server); - } - - private void flushPlayerListCallbacks(String key, List players) { - List>> callbacks = pendingPlayerListLookups.remove(key); - if (callbacks == null) return; - for (Consumer> callback : callbacks) callback.accept(players); - } - - // ------------------------------------------------------------------------- - // Incoming message handler - // ------------------------------------------------------------------------- - - @Override - public void onPluginMessageReceived(String channel, Player player, byte[] message) { - if (channel.equals(BUNGEE_CHANNEL)) { - handleBungeeMessage(message); - return; - } - if (channel.equals(TS_CHANNEL)) { - handleTeleportSuiteMessage(player, message); - } - } - - private void handleBungeeMessage(byte[] message) { - try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) { - String subChannel = in.readUTF(); - - if ("GetPlayerServer".equals(subChannel)) { - String playerName = in.readUTF(); - String serverName = in.readUTF(); - if ("null".equalsIgnoreCase(serverName) || serverName.isBlank()) serverName = null; - flushServerLookupCallbacks(playerName.toLowerCase(Locale.ROOT), serverName); - return; - } - - if ("PlayerList".equals(subChannel)) { - String scope = in.readUTF(); - String playerCsv = in.readUTF(); - List players = new ArrayList<>(); - if (playerCsv != null && !playerCsv.isBlank()) { - for (String name : playerCsv.split(",")) { - String trimmed = name.trim(); - if (!trimmed.isEmpty()) players.add(trimmed); - } - } - flushPlayerListCallbacks(scope.toUpperCase(Locale.ROOT), players); - } - } catch (IOException e) { - plugin.getLogger().warning("Fehler beim Lesen der Bungee-Nachricht: " + e.getMessage()); - } - } - - private void handleTeleportSuiteMessage(Player channelPlayer, byte[] message) { - try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) { - String payloadType = in.readUTF(); - - // ── LOCATION: teleport a named player to fixed coordinates ────────── - if ("LOCATION".equals(payloadType)) { - String targetName = in.readUTF(); - String world = in.readUTF(); - double x = in.readDouble(), y = in.readDouble(), z = in.readDouble(); - float yaw = in.readFloat(), pitch = in.readFloat(); - - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { - Player target = plugin.getServer().getPlayerExact(targetName); - if (target == null || !target.isOnline()) return; - de.teleportsuite.models.TeleportLocation loc = - new de.teleportsuite.models.TeleportLocation(world, x, y, z, yaw, pitch, - plugin.getConfigManager().getServerName()); - plugin.getTeleportManager().teleport(target, loc, false); - }, 20L); - return; - } - - // ── QUERY_LOCATION: remote server asks for a player's coordinates ─── - if ("QUERY_LOCATION".equals(payloadType)) { - String targetName = in.readUTF(); - String replyServer = in.readUTF(); - - Player target = plugin.getServer().getPlayerExact(targetName); - if (target == null || !target.isOnline()) return; // can't answer - - // We need a live player to send the reply message through - Player anchor = plugin.getServer().getOnlinePlayers().stream().findFirst().orElse(null); - if (anchor == null) return; - - org.bukkit.Location loc = target.getLocation(); - try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(bos)) { - out.writeUTF("Forward"); - out.writeUTF(replyServer); - out.writeUTF(TS_CHANNEL); - - ByteArrayOutputStream sub = new ByteArrayOutputStream(); - DataOutputStream subOut = new DataOutputStream(sub); - subOut.writeUTF("LOCATION_RESPONSE"); - subOut.writeUTF(targetName); - subOut.writeUTF(loc.getWorld().getName()); - subOut.writeDouble(loc.getX()); - subOut.writeDouble(loc.getY()); - subOut.writeDouble(loc.getZ()); - subOut.writeFloat(loc.getYaw()); - subOut.writeFloat(loc.getPitch()); - - byte[] subBytes = sub.toByteArray(); - out.writeShort(subBytes.length); - out.write(subBytes); - anchor.sendPluginMessage(plugin, BUNGEE_CHANNEL, bos.toByteArray()); - } catch (IOException e) { - plugin.getLogger().warning("LOCATION_RESPONSE Fehler: " + e.getMessage()); - } - return; - } - - // ── LOCATION_RESPONSE: answer to our QUERY_LOCATION ───────────────── - if ("LOCATION_RESPONSE".equals(payloadType)) { - String targetName = in.readUTF(); - String world = in.readUTF(); - double x = in.readDouble(), y = in.readDouble(), z = in.readDouble(); - float yaw = in.readFloat(), pitch = in.readFloat(); - - org.bukkit.World w = plugin.getServer().getWorld(world); - // w may be null here (different server), that's fine — callers only need coords - org.bukkit.Location loc = new org.bukkit.Location(w, x, y, z, yaw, pitch); - flushLocationLookupCallbacks(targetName.toLowerCase(Locale.ROOT), loc); - return; - } - - // ── TP_TO_PLAYER: fallback polling mechanism ───────────────────────── - if ("TP_TO_PLAYER".equals(payloadType)) { - String moverName = in.readUTF(); - String targetName = in.readUTF(); - schedulePlayerToPlayerTeleport(moverName, targetName); - return; - } - - // ── TPA messages ───────────────────────────────────────────────────── - if ("TPA_REQUEST".equals(payloadType)) { - String requesterName = in.readUTF(); - String targetName = in.readUTF(); - plugin.getTeleportManager().receiveCrossServerTpaRequest(requesterName, targetName); - return; - } - - if ("TPA_ACCEPT".equals(payloadType)) { - String requesterName = in.readUTF(); - String targetName = in.readUTF(); - plugin.getTeleportManager().receiveCrossServerTpaAccepted(requesterName, targetName); - return; - } - - if ("TPA_DENY".equals(payloadType)) { - String requesterName = in.readUTF(); - String targetName = in.readUTF(); - plugin.getTeleportManager().receiveCrossServerTpaDenied(requesterName, targetName); - return; - } - - if ("TPA_EXPIRED".equals(payloadType)) { - String requesterName = in.readUTF(); - String targetName = in.readUTF(); - plugin.getTeleportManager().receiveCrossServerTpaExpired(requesterName, targetName); - return; - } - - // ── Backward compatibility: old payload had no type prefix ──────────── - String targetName = payloadType; // first field WAS the player name - String world = in.readUTF(); - double x = in.readDouble(), y = in.readDouble(), z = in.readDouble(); - float yaw = in.readFloat(), pitch = in.readFloat(); - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> { - Player target = plugin.getServer().getPlayerExact(targetName); - if (target == null || !target.isOnline()) return; - de.teleportsuite.models.TeleportLocation loc = - new de.teleportsuite.models.TeleportLocation(world, x, y, z, yaw, pitch, - plugin.getConfigManager().getServerName()); - plugin.getTeleportManager().teleport(target, loc, false); - }, 20L); - - } catch (IOException e) { - plugin.getLogger().warning("Fehler beim Lesen der TS-Nachricht: " + e.getMessage()); - } - } - - @FunctionalInterface - private interface IOConsumer { - void accept(T value) throws IOException; - } -}