Upload folder via GUI - src
This commit is contained in:
@@ -16,14 +16,16 @@ import java.util.function.Consumer;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles BungeeCord Plugin Messaging.
|
* Handles BungeeCord Plugin Messaging.
|
||||||
* Sends players to other servers and transmits target coordinates
|
|
||||||
* so a receiving TeleportSuite instance can teleport them on arrival.
|
|
||||||
*
|
*
|
||||||
* Channel "teleportsuite:tp" payload format (DataOutputStream):
|
* Cross-server teleport flow (fixed):
|
||||||
* String targetPlayer
|
* 1. Query the target server for the exact coordinates of the target player (QUERY_LOCATION).
|
||||||
* String world
|
* 2. Target server replies with LOCATION_RESPONSE (world, x, y, z, yaw, pitch).
|
||||||
* Double x, y, z
|
* 3. We send a LOCATION payload to the target server so it teleports the mover on arrival.
|
||||||
* Float yaw, pitch
|
* 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 {
|
public class BungeeMessenger implements PluginMessageListener {
|
||||||
|
|
||||||
@@ -32,6 +34,8 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
private final TeleportSuite plugin;
|
private final TeleportSuite plugin;
|
||||||
private final Map<String, List<Consumer<String>>> pendingServerLookups = new HashMap<>();
|
private final Map<String, List<Consumer<String>>> pendingServerLookups = new HashMap<>();
|
||||||
private final Map<String, List<Consumer<List<String>>>> pendingPlayerListLookups = new HashMap<>();
|
private final Map<String, List<Consumer<List<String>>>> pendingPlayerListLookups = new HashMap<>();
|
||||||
|
// key = targetPlayer.toLowerCase()
|
||||||
|
private final Map<String, List<Consumer<org.bukkit.Location>>> pendingLocationLookups = new HashMap<>();
|
||||||
|
|
||||||
public BungeeMessenger(TeleportSuite plugin) { this.plugin = plugin; }
|
public BungeeMessenger(TeleportSuite plugin) { this.plugin = plugin; }
|
||||||
|
|
||||||
@@ -47,6 +51,10 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin);
|
plugin.getServer().getMessenger().unregisterIncomingPluginChannel(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Player-server & player-list lookups (unchanged)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
public void requestPlayerServer(Player sender, String targetPlayer, Consumer<String> callback) {
|
public void requestPlayerServer(Player sender, String targetPlayer, Consumer<String> callback) {
|
||||||
if (sender == null || !sender.isOnline()) {
|
if (sender == null || !sender.isOnline()) {
|
||||||
callback.accept(null);
|
callback.accept(null);
|
||||||
@@ -88,6 +96,61 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// 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<org.bukkit.Location> 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<Consumer<org.bukkit.Location>> callbacks = pendingLocationLookups.remove(key);
|
||||||
|
if (callbacks == null) return;
|
||||||
|
for (Consumer<org.bukkit.Location> cb : callbacks) cb.accept(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Public teleport helpers
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
public void teleportAllPlayersToLocalPlayer(Player requester) {
|
public void teleportAllPlayersToLocalPlayer(Player requester) {
|
||||||
String requesterName = requester.getName();
|
String requesterName = requester.getName();
|
||||||
requestPlayerList(requester, "ALL", players -> {
|
requestPlayerList(requester, "ALL", players -> {
|
||||||
@@ -108,6 +171,15 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
public void teleportToPlayer(Player requester, String targetPlayerName) {
|
||||||
requestPlayerServer(requester, targetPlayerName, server -> {
|
requestPlayerServer(requester, targetPlayerName, server -> {
|
||||||
if (server == null || server.isBlank()) {
|
if (server == null || server.isBlank()) {
|
||||||
@@ -117,6 +189,7 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
|
|
||||||
String localServer = plugin.getConfigManager().getServerName();
|
String localServer = plugin.getConfigManager().getServerName();
|
||||||
if (server.equalsIgnoreCase(localServer)) {
|
if (server.equalsIgnoreCase(localServer)) {
|
||||||
|
// Same server — direct teleport
|
||||||
Player target = plugin.getServer().getPlayerExact(targetPlayerName);
|
Player target = plugin.getServer().getPlayerExact(targetPlayerName);
|
||||||
if (target == null || !target.isOnline()) {
|
if (target == null || !target.isOnline()) {
|
||||||
requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName));
|
requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", targetPlayerName));
|
||||||
@@ -129,12 +202,28 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPlayerToPlayerPayload(requester, requester.getName(), targetPlayerName, server);
|
// Cross-server: get exact coordinates first, then switch
|
||||||
connectPlayerOnly(requester, server);
|
requestPlayerLocationOnServer(requester, targetPlayerName, server, loc -> {
|
||||||
requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
|
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) {
|
public void teleportPlayerToLocalPlayer(Player requester, String moverPlayerName, String localTargetPlayerName) {
|
||||||
requestPlayerServer(requester, moverPlayerName, moverServer -> {
|
requestPlayerServer(requester, moverPlayerName, moverServer -> {
|
||||||
if (moverServer == null || moverServer.isBlank()) {
|
if (moverServer == null || moverServer.isBlank()) {
|
||||||
@@ -144,7 +233,8 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
|
|
||||||
String localServer = plugin.getConfigManager().getServerName();
|
String localServer = plugin.getConfigManager().getServerName();
|
||||||
if (moverServer.equalsIgnoreCase(localServer)) {
|
if (moverServer.equalsIgnoreCase(localServer)) {
|
||||||
Player mover = plugin.getServer().getPlayerExact(moverPlayerName);
|
// Same server — direct teleport
|
||||||
|
Player mover = plugin.getServer().getPlayerExact(moverPlayerName);
|
||||||
Player target = plugin.getServer().getPlayerExact(localTargetPlayerName);
|
Player target = plugin.getServer().getPlayerExact(localTargetPlayerName);
|
||||||
if (mover == null || !mover.isOnline()) {
|
if (mover == null || !mover.isOnline()) {
|
||||||
requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName));
|
requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName));
|
||||||
@@ -161,12 +251,27 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPlayerToPlayerPayload(requester, moverPlayerName, localTargetPlayerName, localServer);
|
// 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);
|
connectOtherPlayer(requester, moverPlayerName, localServer);
|
||||||
requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
|
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) {
|
public void teleportAnyPlayerToAnyPlayer(Player requester, String moverPlayerName, String targetPlayerName) {
|
||||||
requestPlayerServer(requester, targetPlayerName, targetServer -> {
|
requestPlayerServer(requester, targetPlayerName, targetServer -> {
|
||||||
if (targetServer == null || targetServer.isBlank()) {
|
if (targetServer == null || targetServer.isBlank()) {
|
||||||
@@ -181,8 +286,10 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String localServer = plugin.getConfigManager().getServerName();
|
String localServer = plugin.getConfigManager().getServerName();
|
||||||
|
|
||||||
|
// Both on the same local server
|
||||||
if (moverServer.equalsIgnoreCase(localServer) && targetServer.equalsIgnoreCase(localServer)) {
|
if (moverServer.equalsIgnoreCase(localServer) && targetServer.equalsIgnoreCase(localServer)) {
|
||||||
Player mover = plugin.getServer().getPlayerExact(moverPlayerName);
|
Player mover = plugin.getServer().getPlayerExact(moverPlayerName);
|
||||||
Player target = plugin.getServer().getPlayerExact(targetPlayerName);
|
Player target = plugin.getServer().getPlayerExact(targetPlayerName);
|
||||||
if (mover == null || !mover.isOnline()) {
|
if (mover == null || !mover.isOnline()) {
|
||||||
requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName));
|
requester.sendMessage(plugin.getConfigManager().getMessage("player-not-found", "player", moverPlayerName));
|
||||||
@@ -199,15 +306,46 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendPlayerToPlayerPayload(requester, moverPlayerName, targetPlayerName, targetServer);
|
// Target is on this local server — we know the coordinates
|
||||||
if (!moverServer.equalsIgnoreCase(targetServer)) {
|
if (targetServer.equalsIgnoreCase(localServer)) {
|
||||||
connectOtherPlayer(requester, moverPlayerName, targetServer);
|
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;
|
||||||
}
|
}
|
||||||
requester.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
|
|
||||||
|
// 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) {
|
public void sendTpaRequestToPlayer(Player sender, String targetPlayerName) {
|
||||||
sendForwardToPlayer(sender, targetPlayerName, out -> {
|
sendForwardToPlayer(sender, targetPlayerName, out -> {
|
||||||
out.writeUTF("TPA_REQUEST");
|
out.writeUTF("TPA_REQUEST");
|
||||||
@@ -240,15 +378,14 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// -------------------------------------------------------------------------
|
||||||
* Connect a player to another BungeeCord server.
|
// Low-level BungeeCord helpers
|
||||||
* Also sends a plugin message so the target server knows where to teleport the player.
|
// -------------------------------------------------------------------------
|
||||||
*/
|
|
||||||
public void connectToServer(Player player, String server, String world, double x, double y, double z, float yaw, float pitch) {
|
|
||||||
// 1) Notify the target server about the pending teleport
|
|
||||||
sendTeleportPayload(player, player.getName(), server, world, x, y, z, yaw, pitch);
|
|
||||||
|
|
||||||
// 2) Switch server via BungeeCord
|
/** 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);
|
connectPlayerOnly(player, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,14 +412,16 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendTeleportPayload(Player sender, String targetPlayer, String server, String world,
|
/** Forward a LOCATION payload to {@code server} for {@code targetPlayer}. */
|
||||||
double x, double y, double z, float yaw, float pitch) {
|
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();
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream out = new DataOutputStream(bos)) {
|
DataOutputStream out = new DataOutputStream(bos)) {
|
||||||
out.writeUTF("Forward");
|
out.writeUTF("Forward");
|
||||||
out.writeUTF(server);
|
out.writeUTF(server);
|
||||||
out.writeUTF(TS_CHANNEL);
|
out.writeUTF(TS_CHANNEL);
|
||||||
// Sub-payload
|
|
||||||
ByteArrayOutputStream sub = new ByteArrayOutputStream();
|
ByteArrayOutputStream sub = new ByteArrayOutputStream();
|
||||||
DataOutputStream subOut = new DataOutputStream(sub);
|
DataOutputStream subOut = new DataOutputStream(sub);
|
||||||
subOut.writeUTF("LOCATION");
|
subOut.writeUTF("LOCATION");
|
||||||
@@ -293,6 +432,7 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
subOut.writeDouble(z);
|
subOut.writeDouble(z);
|
||||||
subOut.writeFloat(yaw);
|
subOut.writeFloat(yaw);
|
||||||
subOut.writeFloat(pitch);
|
subOut.writeFloat(pitch);
|
||||||
|
|
||||||
byte[] subBytes = sub.toByteArray();
|
byte[] subBytes = sub.toByteArray();
|
||||||
out.writeShort(subBytes.length);
|
out.writeShort(subBytes.length);
|
||||||
out.write(subBytes);
|
out.write(subBytes);
|
||||||
@@ -302,7 +442,12 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendPlayerToPlayerPayload(Player sender, String moverPlayer, String targetPlayer, String targetServer) {
|
/**
|
||||||
|
* 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();
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream out = new DataOutputStream(bos)) {
|
DataOutputStream out = new DataOutputStream(bos)) {
|
||||||
out.writeUTF("Forward");
|
out.writeUTF("Forward");
|
||||||
@@ -324,7 +469,8 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendForwardToPlayer(Player sender, String targetPlayer, IOConsumer<DataOutputStream> payloadWriter) {
|
private void sendForwardToPlayer(Player sender, String targetPlayer,
|
||||||
|
IOConsumer<DataOutputStream> payloadWriter) {
|
||||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
DataOutputStream out = new DataOutputStream(bos)) {
|
DataOutputStream out = new DataOutputStream(bos)) {
|
||||||
out.writeUTF("ForwardToPlayer");
|
out.writeUTF("ForwardToPlayer");
|
||||||
@@ -344,6 +490,10 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Polling fallback (kept for TP_TO_PLAYER fallback path)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
private void schedulePlayerToPlayerTeleport(String moverName, String targetName) {
|
private void schedulePlayerToPlayerTeleport(String moverName, String targetName) {
|
||||||
int maxAttempts = 100;
|
int maxAttempts = 100;
|
||||||
final int[] attempts = {0};
|
final int[] attempts = {0};
|
||||||
@@ -351,13 +501,14 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
|
|
||||||
taskId[0] = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, () -> {
|
taskId[0] = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, () -> {
|
||||||
attempts[0]++;
|
attempts[0]++;
|
||||||
Player mover = plugin.getServer().getPlayerExact(moverName);
|
Player mover = plugin.getServer().getPlayerExact(moverName);
|
||||||
Player target = plugin.getServer().getPlayerExact(targetName);
|
Player target = plugin.getServer().getPlayerExact(targetName);
|
||||||
|
|
||||||
if (mover != null && mover.isOnline() && target != null && target.isOnline()) {
|
if (mover != null && mover.isOnline() && target != null && target.isOnline()) {
|
||||||
plugin.getTeleportManager().teleport(
|
plugin.getTeleportManager().teleport(
|
||||||
mover,
|
mover,
|
||||||
new de.teleportsuite.models.TeleportLocation(target.getLocation(), plugin.getConfigManager().getServerName()),
|
new de.teleportsuite.models.TeleportLocation(
|
||||||
|
target.getLocation(), plugin.getConfigManager().getServerName()),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
plugin.getServer().getScheduler().cancelTask(taskId[0]);
|
plugin.getServer().getScheduler().cancelTask(taskId[0]);
|
||||||
@@ -370,49 +521,51 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}, 10L, 10L);
|
}, 10L, 10L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Callback flush helpers
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
private void flushServerLookupCallbacks(String key, String server) {
|
private void flushServerLookupCallbacks(String key, String server) {
|
||||||
List<Consumer<String>> callbacks = pendingServerLookups.remove(key);
|
List<Consumer<String>> callbacks = pendingServerLookups.remove(key);
|
||||||
if (callbacks == null) return;
|
if (callbacks == null) return;
|
||||||
for (Consumer<String> callback : callbacks) {
|
for (Consumer<String> callback : callbacks) callback.accept(server);
|
||||||
callback.accept(server);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void flushPlayerListCallbacks(String key, List<String> players) {
|
private void flushPlayerListCallbacks(String key, List<String> players) {
|
||||||
List<Consumer<List<String>>> callbacks = pendingPlayerListLookups.remove(key);
|
List<Consumer<List<String>>> callbacks = pendingPlayerListLookups.remove(key);
|
||||||
if (callbacks == null) return;
|
if (callbacks == null) return;
|
||||||
for (Consumer<List<String>> callback : callbacks) {
|
for (Consumer<List<String>> callback : callbacks) callback.accept(players);
|
||||||
callback.accept(players);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Incoming message handler
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
|
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
|
||||||
if (channel.equals(BUNGEE_CHANNEL)) {
|
if (channel.equals(BUNGEE_CHANNEL)) {
|
||||||
handleBungeeMessage(message);
|
handleBungeeMessage(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel.equals(TS_CHANNEL)) {
|
if (channel.equals(TS_CHANNEL)) {
|
||||||
handleTeleportSuiteMessage(message);
|
handleTeleportSuiteMessage(player, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBungeeMessage(byte[] message) {
|
private void handleBungeeMessage(byte[] message) {
|
||||||
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
|
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
|
||||||
String subChannel = in.readUTF();
|
String subChannel = in.readUTF();
|
||||||
|
|
||||||
if ("GetPlayerServer".equals(subChannel)) {
|
if ("GetPlayerServer".equals(subChannel)) {
|
||||||
String playerName = in.readUTF();
|
String playerName = in.readUTF();
|
||||||
String serverName = in.readUTF();
|
String serverName = in.readUTF();
|
||||||
if ("null".equalsIgnoreCase(serverName) || serverName.isBlank()) {
|
if ("null".equalsIgnoreCase(serverName) || serverName.isBlank()) serverName = null;
|
||||||
serverName = null;
|
|
||||||
}
|
|
||||||
flushServerLookupCallbacks(playerName.toLowerCase(Locale.ROOT), serverName);
|
flushServerLookupCallbacks(playerName.toLowerCase(Locale.ROOT), serverName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("PlayerList".equals(subChannel)) {
|
if ("PlayerList".equals(subChannel)) {
|
||||||
String scope = in.readUTF();
|
String scope = in.readUTF();
|
||||||
String playerCsv = in.readUTF();
|
String playerCsv = in.readUTF();
|
||||||
List<String> players = new ArrayList<>();
|
List<String> players = new ArrayList<>();
|
||||||
if (playerCsv != null && !playerCsv.isBlank()) {
|
if (playerCsv != null && !playerCsv.isBlank()) {
|
||||||
@@ -422,22 +575,22 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
flushPlayerListCallbacks(scope.toUpperCase(Locale.ROOT), players);
|
flushPlayerListCallbacks(scope.toUpperCase(Locale.ROOT), players);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.getLogger().warning("Fehler beim Lesen der Bungee-Nachricht: " + e.getMessage());
|
plugin.getLogger().warning("Fehler beim Lesen der Bungee-Nachricht: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTeleportSuiteMessage(byte[] message) {
|
private void handleTeleportSuiteMessage(Player channelPlayer, byte[] message) {
|
||||||
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
|
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
|
||||||
String payloadType = in.readUTF();
|
String payloadType = in.readUTF();
|
||||||
|
|
||||||
|
// ── LOCATION: teleport a named player to fixed coordinates ──────────
|
||||||
if ("LOCATION".equals(payloadType)) {
|
if ("LOCATION".equals(payloadType)) {
|
||||||
String targetName = in.readUTF();
|
String targetName = in.readUTF();
|
||||||
String world = in.readUTF();
|
String world = in.readUTF();
|
||||||
double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
|
double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
|
||||||
float yaw = in.readFloat(), pitch = in.readFloat();
|
float yaw = in.readFloat(), pitch = in.readFloat();
|
||||||
|
|
||||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||||
Player target = plugin.getServer().getPlayerExact(targetName);
|
Player target = plugin.getServer().getPlayerExact(targetName);
|
||||||
@@ -450,46 +603,102 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
return;
|
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)) {
|
if ("TP_TO_PLAYER".equals(payloadType)) {
|
||||||
String moverName = in.readUTF();
|
String moverName = in.readUTF();
|
||||||
String targetName = in.readUTF();
|
String targetName = in.readUTF();
|
||||||
schedulePlayerToPlayerTeleport(moverName, targetName);
|
schedulePlayerToPlayerTeleport(moverName, targetName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── TPA messages ─────────────────────────────────────────────────────
|
||||||
if ("TPA_REQUEST".equals(payloadType)) {
|
if ("TPA_REQUEST".equals(payloadType)) {
|
||||||
String requesterName = in.readUTF();
|
String requesterName = in.readUTF();
|
||||||
String targetName = in.readUTF();
|
String targetName = in.readUTF();
|
||||||
plugin.getTeleportManager().receiveCrossServerTpaRequest(requesterName, targetName);
|
plugin.getTeleportManager().receiveCrossServerTpaRequest(requesterName, targetName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("TPA_ACCEPT".equals(payloadType)) {
|
if ("TPA_ACCEPT".equals(payloadType)) {
|
||||||
String requesterName = in.readUTF();
|
String requesterName = in.readUTF();
|
||||||
String targetName = in.readUTF();
|
String targetName = in.readUTF();
|
||||||
plugin.getTeleportManager().receiveCrossServerTpaAccepted(requesterName, targetName);
|
plugin.getTeleportManager().receiveCrossServerTpaAccepted(requesterName, targetName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("TPA_DENY".equals(payloadType)) {
|
if ("TPA_DENY".equals(payloadType)) {
|
||||||
String requesterName = in.readUTF();
|
String requesterName = in.readUTF();
|
||||||
String targetName = in.readUTF();
|
String targetName = in.readUTF();
|
||||||
plugin.getTeleportManager().receiveCrossServerTpaDenied(requesterName, targetName);
|
plugin.getTeleportManager().receiveCrossServerTpaDenied(requesterName, targetName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("TPA_EXPIRED".equals(payloadType)) {
|
if ("TPA_EXPIRED".equals(payloadType)) {
|
||||||
String requesterName = in.readUTF();
|
String requesterName = in.readUTF();
|
||||||
String targetName = in.readUTF();
|
String targetName = in.readUTF();
|
||||||
plugin.getTeleportManager().receiveCrossServerTpaExpired(requesterName, targetName);
|
plugin.getTeleportManager().receiveCrossServerTpaExpired(requesterName, targetName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backward compatibility with old payload format
|
// ── Backward compatibility: old payload had no type prefix ────────────
|
||||||
String targetName = payloadType;
|
String targetName = payloadType; // first field WAS the player name
|
||||||
String world = in.readUTF();
|
String world = in.readUTF();
|
||||||
double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
|
double x = in.readDouble(), y = in.readDouble(), z = in.readDouble();
|
||||||
float yaw = in.readFloat(), pitch = in.readFloat();
|
float yaw = in.readFloat(), pitch = in.readFloat();
|
||||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||||
Player target = plugin.getServer().getPlayerExact(targetName);
|
Player target = plugin.getServer().getPlayerExact(targetName);
|
||||||
if (target == null || !target.isOnline()) return;
|
if (target == null || !target.isOnline()) return;
|
||||||
@@ -498,6 +707,7 @@ public class BungeeMessenger implements PluginMessageListener {
|
|||||||
plugin.getConfigManager().getServerName());
|
plugin.getConfigManager().getServerName());
|
||||||
plugin.getTeleportManager().teleport(target, loc, false);
|
plugin.getTeleportManager().teleport(target, loc, false);
|
||||||
}, 20L);
|
}, 20L);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
plugin.getLogger().warning("Fehler beim Lesen der TS-Nachricht: " + e.getMessage());
|
plugin.getLogger().warning("Fehler beim Lesen der TS-Nachricht: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,8 +73,15 @@ public class TeleportManager {
|
|||||||
private void executeTeleport(Player player, TeleportLocation dest) {
|
private void executeTeleport(Player player, TeleportLocation dest) {
|
||||||
String localServer = plugin.getConfigManager().getServerName();
|
String localServer = plugin.getConfigManager().getServerName();
|
||||||
|
|
||||||
|
// Always save last location and apply cooldown, regardless of server
|
||||||
|
plugin.getDatabaseManager().saveLastLocation(player.getUniqueId(),
|
||||||
|
new TeleportLocation(player.getLocation(), localServer));
|
||||||
|
cooldowns.put(player.getUniqueId(), System.currentTimeMillis());
|
||||||
|
|
||||||
if (!dest.isLocalServer(localServer)) {
|
if (!dest.isLocalServer(localServer)) {
|
||||||
// BungeeCord-Teleport
|
// BungeeCord cross-server teleport:
|
||||||
|
// connectToServer sends the LOCATION payload BEFORE the Connect message
|
||||||
|
// so the player arrives directly at the target coordinates.
|
||||||
if (plugin.getBungeeMessenger() != null) {
|
if (plugin.getBungeeMessenger() != null) {
|
||||||
plugin.getBungeeMessenger().connectToServer(player, dest.getServer(), dest.getWorld(),
|
plugin.getBungeeMessenger().connectToServer(player, dest.getServer(), dest.getWorld(),
|
||||||
dest.getX(), dest.getY(), dest.getZ(), dest.getYaw(), dest.getPitch());
|
dest.getX(), dest.getY(), dest.getZ(), dest.getYaw(), dest.getPitch());
|
||||||
@@ -85,16 +92,11 @@ public class TeleportManager {
|
|||||||
|
|
||||||
Location loc = dest.toBukkitLocation();
|
Location loc = dest.toBukkitLocation();
|
||||||
if (loc == null || loc.getWorld() == null) {
|
if (loc == null || loc.getWorld() == null) {
|
||||||
player.sendMessage("§cZielwelt nicht gefunden!");
|
player.sendMessage("\u00a7cZielwelt nicht gefunden!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save last location to database
|
|
||||||
plugin.getDatabaseManager().saveLastLocation(player.getUniqueId(),
|
|
||||||
new TeleportLocation(player.getLocation(), localServer));
|
|
||||||
|
|
||||||
player.teleport(loc);
|
player.teleport(loc);
|
||||||
cooldowns.put(player.getUniqueId(), System.currentTimeMillis());
|
|
||||||
player.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
|
player.sendMessage(plugin.getConfigManager().getMessage("teleport-success"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: TeleportSuite
|
name: TeleportSuite
|
||||||
version: 1.0.0
|
version: 1.0.1
|
||||||
main: de.teleportsuite.TeleportSuite
|
main: de.teleportsuite.TeleportSuite
|
||||||
api-version: 1.20
|
api-version: 1.20
|
||||||
description: BungeeCord-fähiges Teleport-Komplettpaket
|
description: BungeeCord-fähiges Teleport-Komplettpaket
|
||||||
|
|||||||
Reference in New Issue
Block a user