Files
Stargate/src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java

222 lines
9.0 KiB
Java

package net.knarcraft.stargate.utility;
import net.knarcraft.stargate.Stargate;
import net.knarcraft.stargate.portal.Portal;
import net.knarcraft.stargate.portal.PortalHandler;
import net.knarcraft.stargate.portal.teleporter.PlayerTeleporter;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerMoveEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* This class contains helpful functions to help with sending and receiving BungeeCord plugin messages
*/
public final class BungeeHelper {
private final static String bungeeSubChannel = "SGBungee";
private final static String bungeeChannel = "BungeeCord";
private final static String teleportMessageDelimiter = "#@#";
private final static Map<UUID, String> bungeeQueue = new HashMap<>();
private BungeeHelper() {
}
/**
* Get the plugin message channel use for BungeeCord messages
*
* @return <p>The bungee plugin channel</p>
*/
public static String getBungeeChannel() {
return bungeeChannel;
}
/**
* Removes a player from the queue of players teleporting through BungeeCord
*
* <p>Whenever a BungeeCord teleportation message is received and the player is not currently connected to this
* server, it'll be added to this queue. Once the player joins this server, the player should be removed from the
* queue and teleported to the destination.</p>
*
* @param playerUUID <p>The UUID of the player to remove</p>
* @return <p>The name of the destination portal the player should be teleported to</p>
*/
public static String removeFromQueue(UUID playerUUID) {
return bungeeQueue.remove(playerUUID);
}
/**
* Sends a plugin message to BungeeCord allowing the target server to catch it
*
* @param player <p>The teleporting player</p>
* @param entrancePortal <p>The portal the player is teleporting from</p>
* @return <p>True if the message was successfully sent</p>
*/
public static boolean sendTeleportationMessage(Player player, Portal entrancePortal) {
try {
//Build the teleportation message, format is <player identifier>delimiter<destination>
String message = player.getUniqueId() + teleportMessageDelimiter + entrancePortal.getDestinationName();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//Build the message data and send it over the SGBungee BungeeCord channel
dataOutputStream.writeUTF("Forward");
//Send the message to the server defined in the entrance portal's network line
dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
//Specify the sub-channel/tag to make it recognizable on arrival
dataOutputStream.writeUTF(bungeeSubChannel);
//Write the length of the message
dataOutputStream.writeShort(message.length());
//Write the actual message
dataOutputStream.writeBytes(message);
//Send the plugin message
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
} catch (IOException ex) {
Stargate.logSevere("Error sending BungeeCord teleport packet");
ex.printStackTrace();
return false;
}
return true;
}
/**
* Sends the bungee message necessary to make a player connect to another server
*
* @param player <p>The player to teleport</p>
* @param entrancePortal <p>The bungee portal the player is teleporting from</p>
* @return <p>True if the plugin message was sent successfully</p>
*/
public static boolean changeServer(Player player, Portal entrancePortal) {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//Send a connect-message to connect the player to the server defined in the entrance portal's network line
dataOutputStream.writeUTF("Connect");
dataOutputStream.writeUTF(stripColor(entrancePortal.getNetwork()));
//Send the plugin message
player.sendPluginMessage(Stargate.getInstance(), bungeeChannel, byteArrayOutputStream.toByteArray());
} catch (IOException ex) {
Stargate.logSevere("Error sending BungeeCord connect packet");
ex.printStackTrace();
return false;
}
return true;
}
/**
* Reads a plugin message byte array to a string if it's sent from another stargate plugin
*
* @param message <p>The byte array to read</p>
* @return <p>The message contained in the byte array, or null on failure</p>
*/
public static String readPluginMessage(byte[] message) {
byte[] data;
try {
DataInputStream dataInputStream = new DataInputStream(new ByteArrayInputStream(message));
String subChannel = dataInputStream.readUTF();
//Only listen for the SGBungee channel
if (!subChannel.equals(bungeeSubChannel)) {
return null;
}
//Get the length of the contained message
short dataLength = dataInputStream.readShort();
//Prepare a byte array for the sent message
data = new byte[dataLength];
//Read the message to the prepared array
dataInputStream.readFully(data);
} catch (IOException ex) {
Stargate.logSevere("Error receiving BungeeCord message");
ex.printStackTrace();
return null;
}
return new String(data);
}
/**
* Handles the receival of a teleport message
*
* @param receivedMessage <p>The received teleport message</p>
*/
public static void handleTeleportMessage(String receivedMessage) {
//Get the player id and destination from the message
String[] messageParts = receivedMessage.split(teleportMessageDelimiter);
UUID playerUUID = UUID.fromString(messageParts[0]);
String destination = messageParts[1];
//Check if the player is online, if so, teleport, otherwise, queue
Player player = Stargate.getInstance().getServer().getPlayer(playerUUID);
if (player == null) {
bungeeQueue.put(playerUUID, destination);
} else {
Portal destinationPortal = PortalHandler.getBungeePortal(destination);
//If teleporting to an invalid portal, let the server decide where the player arrives
if (destinationPortal == null) {
Stargate.logInfo(String.format("Bungee portal %s does not exist", destination));
return;
}
new PlayerTeleporter(destinationPortal, player).teleport(destinationPortal, null);
}
}
/**
* Teleports a player to a bungee gate
*
* @param player <p>The player to teleport</p>
* @param entrancePortal <p>The gate the player is entering from</p>
* @param event <p>The event causing the teleportation</p>
* @return <p>True if the teleportation was successful</p>
*/
public static boolean bungeeTeleport(Player player, Portal entrancePortal, PlayerMoveEvent event) {
//Check if bungee is actually enabled
if (!Stargate.getGateConfig().enableBungee()) {
if (!entrancePortal.getOptions().isSilent()) {
Stargate.getMessageSender().sendErrorMessage(player, Stargate.getString("bungeeDisabled"));
}
entrancePortal.getPortalOpener().closePortal(false);
return false;
}
//Teleport the player back to this gate, for sanity's sake
new PlayerTeleporter(entrancePortal, player).teleport(entrancePortal, event);
//Send the SGBungee packet first, it will be queued by BC if required
if (!BungeeHelper.sendTeleportationMessage(player, entrancePortal)) {
Stargate.debug("bungeeTeleport", "Unable to send teleportation message");
return false;
}
//Send the connect-message to make the player change server
if (!BungeeHelper.changeServer(player, entrancePortal)) {
Stargate.debug("bungeeTeleport", "Unable to change server");
return false;
}
Stargate.debug("bungeeTeleport", "Teleported player to another server");
return true;
}
/**
* Strips all color tags from a string
*
* @param string <p>The string to strip color from</p>
* @return <p>The string without color codes</p>
*/
private static String stripColor(String string) {
return ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', string));
}
}