Files
Stargate/src/main/java/net/knarcraft/stargate/utility/BungeeHelper.java
EpicKnarvik97 7f08763624 Changes a lot of teleportation code to be able to teleport entities with passengers
Moves some teleportation code to the TeleportHelper class
Changes some teleportation method names
Tries to reduce some code duplication between teleporters
Recursively teleports entities to make sure the teleported entity will arrive in the same shape it entered as
Makes player checks for teleported vehicles account for any number of players riding any entity in the stack
2022-01-28 23:23:09 +01:00

222 lines
9.1 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).teleportPlayer(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));
}
}