diff --git a/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java b/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java index a1c7d04a0..8c909ad35 100644 --- a/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java +++ b/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java @@ -1,5 +1,12 @@ package net.minestom.server.extras.bungee; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.minestom.server.entity.PlayerSkin; +import org.jetbrains.annotations.NotNull; + /** * BungeeCord forwarding support. This does not count as a security feature and you will still be required to manage your firewall. *

@@ -24,4 +31,29 @@ public final class BungeeCordProxy { public static boolean isEnabled() { return enabled; } + + public static PlayerSkin readSkin(@NotNull String json) { + JsonArray array = JsonParser.parseString(json).getAsJsonArray(); + String skinTexture = null; + String skinSignature = null; + + for (JsonElement element : array) { + JsonObject jsonObject = element.getAsJsonObject(); + final String name = jsonObject.get("name").getAsString(); + final String value = jsonObject.get("value").getAsString(); + final String signature = jsonObject.get("signature").getAsString(); + + if (name.equals("textures")) { + skinTexture = value; + skinSignature = signature; + } + + } + + if (skinTexture != null && skinSignature != null) { + return new PlayerSkin(skinTexture, skinSignature); + } else { + return null; + } + } } diff --git a/src/main/java/net/minestom/server/network/PacketProcessor.java b/src/main/java/net/minestom/server/network/PacketProcessor.java index 2b3f2b03d..01744d5a5 100644 --- a/src/main/java/net/minestom/server/network/PacketProcessor.java +++ b/src/main/java/net/minestom/server/network/PacketProcessor.java @@ -149,12 +149,20 @@ public final class PacketProcessor { * @param reader the buffer containing the packet */ private void safeRead(@NotNull PlayerConnection connection, @NotNull Readable readable, @NotNull BinaryReader reader) { + final int readableBytes = reader.getBuffer().readableBytes(); + + // Check if there is anything to read + if (readableBytes == 0) { + return; + } + try { readable.read(reader); } catch (Exception e) { final Player player = connection.getPlayer(); final String username = player != null ? player.getUsername() : "null"; LOGGER.warn("Connection " + connection.getRemoteAddress() + " (" + username + ") sent an unexpected packet."); + e.printStackTrace(); } } } diff --git a/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java b/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java index 75611ef9e..b64f08061 100644 --- a/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.client.handshake; import net.minestom.server.MinecraftServer; import net.minestom.server.chat.ChatColor; import net.minestom.server.chat.ColoredText; +import net.minestom.server.entity.PlayerSkin; import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.ClientPreplayPacket; @@ -13,6 +14,7 @@ import net.minestom.server.utils.binary.BinaryReader; import org.jetbrains.annotations.NotNull; import java.net.SocketAddress; +import java.util.UUID; public class HandshakePacket implements ClientPreplayPacket { @@ -31,7 +33,7 @@ public class HandshakePacket implements ClientPreplayPacket { @Override public void read(@NotNull BinaryReader reader) { this.protocolVersion = reader.readVarInt(); - this.serverAddress = reader.readSizedString(256); + this.serverAddress = reader.readSizedString(BungeeCordProxy.isEnabled() ? Short.MAX_VALUE : 255); this.serverPort = reader.readUnsignedShort(); this.nextState = reader.readVarInt(); } @@ -49,8 +51,25 @@ public class HandshakePacket implements ClientPreplayPacket { if (split.length == 3 || split.length == 4) { this.serverAddress = split[0]; - final SocketAddress socketAddress = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort()); + final SocketAddress socketAddress = new java.net.InetSocketAddress(split[1], + ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort()); nettyPlayerConnection.setRemoteAddress(socketAddress); + + UUID playerUuid = UUID.fromString( + split[2] + .replaceFirst( + "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5" + ) + ); + PlayerSkin playerSkin = null; + + if (split.length == 4) { + playerSkin = BungeeCordProxy.readSkin(split[3]); + } + + nettyPlayerConnection.UNSAFE_setBungeeUuid(playerUuid); + nettyPlayerConnection.UNSAFE_setBungeeSkin(playerSkin); + } else { nettyPlayerConnection.sendPacket(new LoginDisconnectPacket(INVALID_BUNGEE_FORWARDING)); nettyPlayerConnection.disconnect(); diff --git a/src/main/java/net/minestom/server/network/packet/client/login/LoginStartPacket.java b/src/main/java/net/minestom/server/network/packet/client/login/LoginStartPacket.java index 5a088174c..dd5e0a36c 100644 --- a/src/main/java/net/minestom/server/network/packet/client/login/LoginStartPacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/login/LoginStartPacket.java @@ -3,7 +3,9 @@ package net.minestom.server.network.packet.client.login; import net.minestom.server.MinecraftServer; import net.minestom.server.chat.ChatColor; import net.minestom.server.chat.ColoredText; +import net.minestom.server.entity.Player; import net.minestom.server.extras.MojangAuth; +import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.extras.velocity.VelocityProxy; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.ClientPreplayPacket; @@ -27,8 +29,10 @@ public class LoginStartPacket implements ClientPreplayPacket { @Override public void process(@NotNull PlayerConnection connection) { + final boolean isNettyClient = connection instanceof NettyPlayerConnection; + // Cache the login username and start compression if enabled - if (connection instanceof NettyPlayerConnection) { + if (isNettyClient) { NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection; nettyPlayerConnection.UNSAFE_setLoginUsername(username); @@ -40,7 +44,7 @@ public class LoginStartPacket implements ClientPreplayPacket { } // Proxy support (only for netty clients) - if (connection instanceof NettyPlayerConnection) { + if (isNettyClient) { final NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection; { @@ -65,7 +69,7 @@ public class LoginStartPacket implements ClientPreplayPacket { } - if (MojangAuth.isUsingMojangAuth() && connection instanceof NettyPlayerConnection) { + if (MojangAuth.isUsingMojangAuth() && isNettyClient) { // Mojang auth if (CONNECTION_MANAGER.getPlayer(username) != null) { connection.sendPacket(new LoginDisconnectPacket(ALREADY_CONNECTED_JSON)); @@ -79,10 +83,16 @@ public class LoginStartPacket implements ClientPreplayPacket { EncryptionRequestPacket encryptionRequestPacket = new EncryptionRequestPacket(nettyPlayerConnection); nettyPlayerConnection.sendPacket(encryptionRequestPacket); } else { + final boolean bungee = BungeeCordProxy.isEnabled(); // Offline - final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username); + final UUID playerUuid = bungee && isNettyClient ? + ((NettyPlayerConnection) connection).getBungeeUuid() : + CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username); - CONNECTION_MANAGER.startPlayState(connection, playerUuid, username); + Player player = CONNECTION_MANAGER.startPlayState(connection, playerUuid, username); + if (bungee && isNettyClient) { + player.setSkin(((NettyPlayerConnection) connection).getBungeeSkin()); + } } } diff --git a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java index 3848b5c45..62fdc947f 100644 --- a/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java +++ b/src/main/java/net/minestom/server/network/player/NettyPlayerConnection.java @@ -4,6 +4,7 @@ import io.netty.channel.Channel; import io.netty.channel.socket.SocketChannel; import lombok.Getter; import lombok.Setter; +import net.minestom.server.entity.PlayerSkin; import net.minestom.server.extras.mojangAuth.Decrypter; import net.minestom.server.extras.mojangAuth.Encrypter; import net.minestom.server.extras.mojangAuth.MojangCrypt; @@ -18,6 +19,7 @@ import org.jetbrains.annotations.Nullable; import javax.crypto.SecretKey; import java.net.SocketAddress; import java.util.Map; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** @@ -40,6 +42,7 @@ public class NettyPlayerConnection extends PlayerConnection { @Setter private byte[] nonce = new byte[4]; + // Data from client packets private String loginUsername; private String serverAddress; private int serverPort; @@ -48,6 +51,10 @@ public class NettyPlayerConnection extends PlayerConnection { // cleared once the player enters the play state private final Map pluginRequestMap = new ConcurrentHashMap<>(); + // Bungee + private UUID bungeeUuid; + private PlayerSkin bungeeSkin; + public NettyPlayerConnection(@NotNull SocketChannel channel) { super(); this.channel = channel; @@ -158,6 +165,24 @@ public class NettyPlayerConnection extends PlayerConnection { return serverPort; } + @Nullable + public UUID getBungeeUuid() { + return bungeeUuid; + } + + public void UNSAFE_setBungeeUuid(UUID bungeeUuid) { + this.bungeeUuid = bungeeUuid; + } + + @Nullable + public PlayerSkin getBungeeSkin() { + return bungeeSkin; + } + + public void UNSAFE_setBungeeSkin(PlayerSkin bungeeSkin) { + this.bungeeSkin = bungeeSkin; + } + /** * Adds an entry to the plugin request map. *

diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java index aa47ce449..d48d58588 100644 --- a/src/test/java/demo/Main.java +++ b/src/test/java/demo/Main.java @@ -6,8 +6,8 @@ import demo.blocks.UpdatableBlockDemo; import demo.commands.*; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; +import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.extras.optifine.OptifineSupport; -import net.minestom.server.extras.velocity.VelocityProxy; import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule; import net.minestom.server.storage.StorageManager; @@ -52,8 +52,8 @@ public class Main { OptifineSupport.enable(); - VelocityProxy.enable("rBeJJ79W4MVU"); - //BungeeCordProxy.enable(); + //VelocityProxy.enable("rBeJJ79W4MVU"); + BungeeCordProxy.enable(); // MojangAuth.init();