From a38fa8decdea81853176727d1a0d5ecd59cb09ac Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sat, 23 Sep 2023 17:28:20 +0100 Subject: [PATCH 01/41] initial work for 1.20.2 --- .../api/network/ProtocolVersion.java | 3 +- proxy/build.gradle.kts | 3 +- .../connection/MinecraftSessionHandler.java | 60 +- .../backend/BackendConfigSessionHandler.java | 54 ++ .../proxy/protocol/ProtocolUtils.java | 28 + .../proxy/protocol/StateRegistry.java | 631 +++++++++--------- .../proxy/protocol/packet/JoinGame.java | 14 + .../protocol/packet/LoginAcknowledged.java | 46 ++ .../proxy/protocol/packet/PingIdentify.java | 51 ++ .../proxy/protocol/packet/ServerLogin.java | 10 + .../packet/config/ActiveFeatures.java | 52 ++ .../packet/config/FinishedUpdate.java | 45 ++ .../protocol/packet/config/RegistrySync.java | 46 ++ .../protocol/packet/config/StartUpdate.java | 45 ++ .../protocol/packet/config/TagsUpdate.java | 80 +++ 15 files changed, 830 insertions(+), 338 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index 110b58767a..ef7024efeb 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -62,7 +62,8 @@ public enum ProtocolVersion { MINECRAFT_1_19_1(760, "1.19.1", "1.19.2"), MINECRAFT_1_19_3(761, "1.19.3"), MINECRAFT_1_19_4(762, "1.19.4"), - MINECRAFT_1_20(763, "1.20", "1.20.1"); + MINECRAFT_1_20(763, "1.20", "1.20.1"), + MINECRAFT_1_20_2(764, "1.20.2"); private static final int SNAPSHOT_BIT = 30; diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 8d6ed59453..3a3029fc59 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -12,7 +12,8 @@ application { tasks { withType { - exclude("**/com/velocitypowered/proxy/protocol/packet/**") + exclude("**/com/velocitypowered/proxy/protocol/**") + exclude("**/com/velocitypowered/proxy/connection/**") } jar { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java index ef4c362f42..a6aa30afce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java @@ -18,36 +18,7 @@ package com.velocitypowered.proxy.connection; import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.packet.AvailableCommands; -import com.velocitypowered.proxy.protocol.packet.BossBar; -import com.velocitypowered.proxy.protocol.packet.ClientSettings; -import com.velocitypowered.proxy.protocol.packet.Disconnect; -import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; -import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; -import com.velocitypowered.proxy.protocol.packet.Handshake; -import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; -import com.velocitypowered.proxy.protocol.packet.JoinGame; -import com.velocitypowered.proxy.protocol.packet.KeepAlive; -import com.velocitypowered.proxy.protocol.packet.LegacyHandshake; -import com.velocitypowered.proxy.protocol.packet.LegacyPing; -import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; -import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; -import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; -import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; -import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; -import com.velocitypowered.proxy.protocol.packet.Respawn; -import com.velocitypowered.proxy.protocol.packet.ServerData; -import com.velocitypowered.proxy.protocol.packet.ServerLogin; -import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; -import com.velocitypowered.proxy.protocol.packet.SetCompression; -import com.velocitypowered.proxy.protocol.packet.StatusPing; -import com.velocitypowered.proxy.protocol.packet.StatusRequest; -import com.velocitypowered.proxy.protocol.packet.StatusResponse; -import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; -import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; -import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.*; import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletion; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChat; @@ -55,6 +26,7 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; +import com.velocitypowered.proxy.protocol.packet.config.*; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; @@ -279,4 +251,32 @@ default boolean handle(RemovePlayerInfo packet) { default boolean handle(UpsertPlayerInfo packet) { return false; } + + default boolean handle(LoginAcknowledged packet) { + return false; + } + + default boolean handle(ActiveFeatures packet) { + return false; + } + + default boolean handle(FinishedUpdate packet) { + return false; + } + + default boolean handle(RegistrySync packet) { + return false; + } + + default boolean handle(TagsUpdate packet) { + return false; + } + + default boolean handle(StartUpdate packet) { + return false; + } + + default boolean handle(PingIdentify pingIdentify) { + return false; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java new file mode 100644 index 0000000000..6b18e449f7 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.connection.backend; + +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; +import java.util.concurrent.CompletableFuture; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * Handles the initial server configuration setup. + */ +public class BackendConfigSessionHandler implements MinecraftSessionHandler { + + private static final Logger logger = LogManager.getLogger(BackendConfigSessionHandler.class); + + private final VelocityServer server; + private final VelocityServerConnection serverConn; + private final CompletableFuture resultFuture; + private boolean informationForwarded; + + BackendConfigSessionHandler(VelocityServer server, VelocityServerConnection serverConn, + CompletableFuture resultFuture) { + this.server = server; + this.serverConn = serverConn; + this.resultFuture = resultFuture; + } + + + @Override + public boolean handle(StartUpdate packet) { + + return true; + } + +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 97b40def7b..9752eb0620 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -592,4 +592,32 @@ public enum Direction { SERVERBOUND, CLIENTBOUND } + + /** + * Reads an Integer array from the {@code buf}. + * + * @param buf the buffer to read from + * @return the Integer array from the buffer + */ + public static int[] readVarIntArray(ByteBuf buf) { + int length = readVarInt(buf); + int[] ret = new int[length]; + for (int i = 0; i < length; i++) { + ret[i] = readVarInt(buf); + } + return ret; + } + + /** + * Writes an Integer Array to the {@code buf}. + * + * @param buf the buffer to write to + * @param intArray the array to write + */ + public static void writeVarIntArray(ByteBuf buf, int[] intArray) { + writeVarInt(buf, intArray.length); + for (int i = 0; i < intArray.length; i++) { + writeVarInt(buf, intArray[i]); + } + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 9cb4aacdc0..6268bffe30 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -18,60 +18,12 @@ package com.velocitypowered.proxy.protocol; import static com.google.common.collect.Iterables.getLast; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12_1; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_15; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_2; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_4; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_17; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18_2; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_1; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_3; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_4; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9_4; -import static com.velocitypowered.api.network.ProtocolVersion.MINIMUM_VERSION; -import static com.velocitypowered.api.network.ProtocolVersion.SUPPORTED_VERSIONS; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.CLIENTBOUND; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.SERVERBOUND; import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.proxy.protocol.packet.AvailableCommands; -import com.velocitypowered.proxy.protocol.packet.BossBar; -import com.velocitypowered.proxy.protocol.packet.ClientSettings; -import com.velocitypowered.proxy.protocol.packet.Disconnect; -import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; -import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; -import com.velocitypowered.proxy.protocol.packet.Handshake; -import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; -import com.velocitypowered.proxy.protocol.packet.JoinGame; -import com.velocitypowered.proxy.protocol.packet.KeepAlive; -import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; -import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; -import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; -import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; -import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; -import com.velocitypowered.proxy.protocol.packet.Respawn; -import com.velocitypowered.proxy.protocol.packet.ServerData; -import com.velocitypowered.proxy.protocol.packet.ServerLogin; -import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; -import com.velocitypowered.proxy.protocol.packet.SetCompression; -import com.velocitypowered.proxy.protocol.packet.StatusPing; -import com.velocitypowered.proxy.protocol.packet.StatusRequest; -import com.velocitypowered.proxy.protocol.packet.StatusResponse; -import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; -import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; -import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.*; import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletion; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChat; @@ -79,6 +31,7 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; +import com.velocitypowered.proxy.protocol.packet.config.*; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; @@ -106,20 +59,53 @@ public enum StateRegistry { HANDSHAKE { { serverbound.register(Handshake.class, Handshake::new, - map(0x00, MINECRAFT_1_7_2, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); } }, STATUS { { serverbound.register(StatusRequest.class, () -> StatusRequest.INSTANCE, - map(0x00, MINECRAFT_1_7_2, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); serverbound.register(StatusPing.class, StatusPing::new, - map(0x01, MINECRAFT_1_7_2, false)); + map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); clientbound.register(StatusResponse.class, StatusResponse::new, - map(0x00, MINECRAFT_1_7_2, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); clientbound.register(StatusPing.class, StatusPing::new, - map(0x01, MINECRAFT_1_7_2, false)); + map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + } + }, + CONFIG { + { + serverbound.register(PluginMessage.class, PluginMessage::new, + map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register(FinishedUpdate.class, FinishedUpdate::new, + map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register(KeepAlive.class, KeepAlive::new, + map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register(PingIdentify.class, PingIdentify::new, + map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register(ResourcePackResponse.class, ResourcePackResponse::new, + map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + + clientbound.register(PluginMessage.class, PluginMessage::new, + map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(Disconnect.class, Disconnect::new, + map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(FinishedUpdate.class, FinishedUpdate::new, + map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(KeepAlive.class, KeepAlive::new, + map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(PingIdentify.class, PingIdentify::new, + map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(RegistrySync.class, RegistrySync::new, + map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new, + map(0x06, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(ActiveFeatures.class, ActiveFeatures::new, + map(0x07, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(TagsUpdate.class, TagsUpdate::new, + map(0x08, ProtocolVersion.MINECRAFT_1_20_2, false)); } }, PLAY { @@ -128,300 +114,332 @@ public enum StateRegistry { clientbound.fallback = false; serverbound.register(TabCompleteRequest.class, TabCompleteRequest::new, - map(0x14, MINECRAFT_1_7_2, false), - map(0x01, MINECRAFT_1_9, false), - map(0x02, MINECRAFT_1_12, false), - map(0x01, MINECRAFT_1_12_1, false), - map(0x05, MINECRAFT_1_13, false), - map(0x06, MINECRAFT_1_14, false), - map(0x08, MINECRAFT_1_19, false), - map(0x09, MINECRAFT_1_19_1, false), - map(0x08, MINECRAFT_1_19_3, false), - map(0x09, MINECRAFT_1_19_4, false)); + map(0x14, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x01, ProtocolVersion.MINECRAFT_1_9, false), + map(0x02, ProtocolVersion.MINECRAFT_1_12, false), + map(0x01, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x05, ProtocolVersion.MINECRAFT_1_13, false), + map(0x06, ProtocolVersion.MINECRAFT_1_14, false), + map(0x08, ProtocolVersion.MINECRAFT_1_19, false), + map(0x09, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x08, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x09, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x0A, ProtocolVersion.MINECRAFT_1_20_2, false)); serverbound.register(LegacyChat.class, LegacyChat::new, - map(0x01, MINECRAFT_1_7_2, false), - map(0x02, MINECRAFT_1_9, false), - map(0x03, MINECRAFT_1_12, false), - map(0x02, MINECRAFT_1_12_1, false), - map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false)); + map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x02, ProtocolVersion.MINECRAFT_1_9, false), + map(0x03, ProtocolVersion.MINECRAFT_1_12, false), + map(0x02, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x03, ProtocolVersion.MINECRAFT_1_14, ProtocolVersion.MINECRAFT_1_18_2, false)); serverbound.register(KeyedPlayerCommand.class, KeyedPlayerCommand::new, - map(0x03, MINECRAFT_1_19, false), - map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + map(0x03, ProtocolVersion.MINECRAFT_1_19, false), + map(0x04, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); serverbound.register(KeyedPlayerChat.class, KeyedPlayerChat::new, - map(0x04, MINECRAFT_1_19, false), - map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + map(0x04, ProtocolVersion.MINECRAFT_1_19, false), + map(0x05, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); serverbound.register(SessionPlayerCommand.class, SessionPlayerCommand::new, - map(0x04, MINECRAFT_1_19_3, false)); + map(0x04, ProtocolVersion.MINECRAFT_1_19_3, false)); serverbound.register(SessionPlayerChat.class, SessionPlayerChat::new, - map(0x05, MINECRAFT_1_19_3, false)); + map(0x05, ProtocolVersion.MINECRAFT_1_19_3, ProtocolVersion.MINECRAFT_1_20_2, false)); serverbound.register(ClientSettings.class, ClientSettings::new, - map(0x15, MINECRAFT_1_7_2, false), - map(0x04, MINECRAFT_1_9, false), - map(0x05, MINECRAFT_1_12, false), - map(0x04, MINECRAFT_1_12_1, false), - map(0x05, MINECRAFT_1_14, false), - map(0x07, MINECRAFT_1_19, false), - map(0x08, MINECRAFT_1_19_1, false), - map(0x07, MINECRAFT_1_19_3, false), - map(0x08, MINECRAFT_1_19_4, false)); + map(0x15, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x04, ProtocolVersion.MINECRAFT_1_9, false), + map(0x05, ProtocolVersion.MINECRAFT_1_12, false), + map(0x04, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x05, ProtocolVersion.MINECRAFT_1_14, false), + map(0x07, ProtocolVersion.MINECRAFT_1_19, false), + map(0x08, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x07, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x08, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); serverbound.register(PluginMessage.class, PluginMessage::new, - map(0x17, MINECRAFT_1_7_2, false), - map(0x09, MINECRAFT_1_9, false), - map(0x0A, MINECRAFT_1_12, false), - map(0x09, MINECRAFT_1_12_1, false), - map(0x0A, MINECRAFT_1_13, false), - map(0x0B, MINECRAFT_1_14, false), - map(0x0A, MINECRAFT_1_17, false), - map(0x0C, MINECRAFT_1_19, false), - map(0x0D, MINECRAFT_1_19_1, false), - map(0x0C, MINECRAFT_1_19_3, false), - map(0x0D, MINECRAFT_1_19_4, false)); + map(0x17, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x09, ProtocolVersion.MINECRAFT_1_9, false), + map(0x0A, ProtocolVersion.MINECRAFT_1_12, false), + map(0x09, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x0A, ProtocolVersion.MINECRAFT_1_13, false), + map(0x0B, ProtocolVersion.MINECRAFT_1_14, false), + map(0x0A, ProtocolVersion.MINECRAFT_1_17, false), + map(0x0C, ProtocolVersion.MINECRAFT_1_19, false), + map(0x0D, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x0C, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x0D, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x0F, ProtocolVersion.MINECRAFT_1_20_2, false)); serverbound.register(KeepAlive.class, KeepAlive::new, - map(0x00, MINECRAFT_1_7_2, false), - map(0x0B, MINECRAFT_1_9, false), - map(0x0C, MINECRAFT_1_12, false), - map(0x0B, MINECRAFT_1_12_1, false), - map(0x0E, MINECRAFT_1_13, false), - map(0x0F, MINECRAFT_1_14, false), - map(0x10, MINECRAFT_1_16, false), - map(0x0F, MINECRAFT_1_17, false), - map(0x11, MINECRAFT_1_19, false), - map(0x12, MINECRAFT_1_19_1, false), - map(0x11, MINECRAFT_1_19_3, false), - map(0x12, MINECRAFT_1_19_4, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x0B, ProtocolVersion.MINECRAFT_1_9, false), + map(0x0C, ProtocolVersion.MINECRAFT_1_12, false), + map(0x0B, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x0E, ProtocolVersion.MINECRAFT_1_13, false), + map(0x0F, ProtocolVersion.MINECRAFT_1_14, false), + map(0x10, ProtocolVersion.MINECRAFT_1_16, false), + map(0x0F, ProtocolVersion.MINECRAFT_1_17, false), + map(0x11, ProtocolVersion.MINECRAFT_1_19, false), + map(0x12, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x11, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x12, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x14, ProtocolVersion.MINECRAFT_1_20_2, false)); serverbound.register(ResourcePackResponse.class, ResourcePackResponse::new, - map(0x19, MINECRAFT_1_8, false), - map(0x16, MINECRAFT_1_9, false), - map(0x18, MINECRAFT_1_12, false), - map(0x1D, MINECRAFT_1_13, false), - map(0x1F, MINECRAFT_1_14, false), - map(0x20, MINECRAFT_1_16, false), - map(0x21, MINECRAFT_1_16_2, false), - map(0x23, MINECRAFT_1_19, false), - map(0x24, MINECRAFT_1_19_1, false)); + map(0x19, ProtocolVersion.MINECRAFT_1_8, false), + map(0x16, ProtocolVersion.MINECRAFT_1_9, false), + map(0x18, ProtocolVersion.MINECRAFT_1_12, false), + map(0x1D, ProtocolVersion.MINECRAFT_1_13, false), + map(0x1F, ProtocolVersion.MINECRAFT_1_14, false), + map(0x20, ProtocolVersion.MINECRAFT_1_16, false), + map(0x21, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x23, ProtocolVersion.MINECRAFT_1_19, false), + map(0x24, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x27, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register(FinishedUpdate.class, FinishedUpdate::new, + map(0x0B, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(BossBar.class, BossBar::new, - map(0x0C, MINECRAFT_1_9, false), - map(0x0D, MINECRAFT_1_15, false), - map(0x0C, MINECRAFT_1_16, false), - map(0x0D, MINECRAFT_1_17, false), - map(0x0A, MINECRAFT_1_19, false), - map(0x0B, MINECRAFT_1_19_4, false)); + map(0x0C, ProtocolVersion.MINECRAFT_1_9, false), + map(0x0D, ProtocolVersion.MINECRAFT_1_15, false), + map(0x0C, ProtocolVersion.MINECRAFT_1_16, false), + map(0x0D, ProtocolVersion.MINECRAFT_1_17, false), + map(0x0A, ProtocolVersion.MINECRAFT_1_19, false), + map(0x0B, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x0A, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(LegacyChat.class, LegacyChat::new, - map(0x02, MINECRAFT_1_7_2, true), - map(0x0F, MINECRAFT_1_9, true), - map(0x0E, MINECRAFT_1_13, true), - map(0x0F, MINECRAFT_1_15, true), - map(0x0E, MINECRAFT_1_16, true), - map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, true)); + map(0x02, ProtocolVersion.MINECRAFT_1_7_2, true), + map(0x0F, ProtocolVersion.MINECRAFT_1_9, true), + map(0x0E, ProtocolVersion.MINECRAFT_1_13, true), + map(0x0F, ProtocolVersion.MINECRAFT_1_15, true), + map(0x0E, ProtocolVersion.MINECRAFT_1_16, true), + map(0x0F, ProtocolVersion.MINECRAFT_1_17, ProtocolVersion.MINECRAFT_1_18_2, true)); clientbound.register(TabCompleteResponse.class, TabCompleteResponse::new, - map(0x3A, MINECRAFT_1_7_2, false), - map(0x0E, MINECRAFT_1_9, false), - map(0x10, MINECRAFT_1_13, false), - map(0x11, MINECRAFT_1_15, false), - map(0x10, MINECRAFT_1_16, false), - map(0x0F, MINECRAFT_1_16_2, false), - map(0x11, MINECRAFT_1_17, false), - map(0x0E, MINECRAFT_1_19, false), - map(0x0D, MINECRAFT_1_19_3, false), - map(0x0F, MINECRAFT_1_19_4, false)); + map(0x3A, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x0E, ProtocolVersion.MINECRAFT_1_9, false), + map(0x10, ProtocolVersion.MINECRAFT_1_13, false), + map(0x11, ProtocolVersion.MINECRAFT_1_15, false), + map(0x10, ProtocolVersion.MINECRAFT_1_16, false), + map(0x0F, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x11, ProtocolVersion.MINECRAFT_1_17, false), + map(0x0E, ProtocolVersion.MINECRAFT_1_19, false), + map(0x0D, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x0F, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x10, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(AvailableCommands.class, AvailableCommands::new, - map(0x11, MINECRAFT_1_13, false), - map(0x12, MINECRAFT_1_15, false), - map(0x11, MINECRAFT_1_16, false), - map(0x10, MINECRAFT_1_16_2, false), - map(0x12, MINECRAFT_1_17, false), - map(0x0F, MINECRAFT_1_19, false), - map(0x0E, MINECRAFT_1_19_3, false), - map(0x10, MINECRAFT_1_19_4, false)); + map(0x11, ProtocolVersion.MINECRAFT_1_13, false), + map(0x12, ProtocolVersion.MINECRAFT_1_15, false), + map(0x11, ProtocolVersion.MINECRAFT_1_16, false), + map(0x10, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x12, ProtocolVersion.MINECRAFT_1_17, false), + map(0x0F, ProtocolVersion.MINECRAFT_1_19, false), + map(0x0E, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x10, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x11, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(PluginMessage.class, PluginMessage::new, - map(0x3F, MINECRAFT_1_7_2, false), - map(0x18, MINECRAFT_1_9, false), - map(0x19, MINECRAFT_1_13, false), - map(0x18, MINECRAFT_1_14, false), - map(0x19, MINECRAFT_1_15, false), - map(0x18, MINECRAFT_1_16, false), - map(0x17, MINECRAFT_1_16_2, false), - map(0x18, MINECRAFT_1_17, false), - map(0x15, MINECRAFT_1_19, false), - map(0x16, MINECRAFT_1_19_1, false), - map(0x15, MINECRAFT_1_19_3, false), - map(0x17, MINECRAFT_1_19_4, false)); + map(0x3F, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x18, ProtocolVersion.MINECRAFT_1_9, false), + map(0x19, ProtocolVersion.MINECRAFT_1_13, false), + map(0x18, ProtocolVersion.MINECRAFT_1_14, false), + map(0x19, ProtocolVersion.MINECRAFT_1_15, false), + map(0x18, ProtocolVersion.MINECRAFT_1_16, false), + map(0x17, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x18, ProtocolVersion.MINECRAFT_1_17, false), + map(0x15, ProtocolVersion.MINECRAFT_1_19, false), + map(0x16, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x15, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x17, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x18, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(Disconnect.class, Disconnect::new, - map(0x40, MINECRAFT_1_7_2, false), - map(0x1A, MINECRAFT_1_9, false), - map(0x1B, MINECRAFT_1_13, false), - map(0x1A, MINECRAFT_1_14, false), - map(0x1B, MINECRAFT_1_15, false), - map(0x1A, MINECRAFT_1_16, false), - map(0x19, MINECRAFT_1_16_2, false), - map(0x1A, MINECRAFT_1_17, false), - map(0x17, MINECRAFT_1_19, false), - map(0x19, MINECRAFT_1_19_1, false), - map(0x17, MINECRAFT_1_19_3, false), - map(0x1A, MINECRAFT_1_19_4, false)); + map(0x40, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x1A, ProtocolVersion.MINECRAFT_1_9, false), + map(0x1B, ProtocolVersion.MINECRAFT_1_13, false), + map(0x1A, ProtocolVersion.MINECRAFT_1_14, false), + map(0x1B, ProtocolVersion.MINECRAFT_1_15, false), + map(0x1A, ProtocolVersion.MINECRAFT_1_16, false), + map(0x19, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x1A, ProtocolVersion.MINECRAFT_1_17, false), + map(0x17, ProtocolVersion.MINECRAFT_1_19, false), + map(0x19, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x17, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x1A, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x1B, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(KeepAlive.class, KeepAlive::new, - map(0x00, MINECRAFT_1_7_2, false), - map(0x1F, MINECRAFT_1_9, false), - map(0x21, MINECRAFT_1_13, false), - map(0x20, MINECRAFT_1_14, false), - map(0x21, MINECRAFT_1_15, false), - map(0x20, MINECRAFT_1_16, false), - map(0x1F, MINECRAFT_1_16_2, false), - map(0x21, MINECRAFT_1_17, false), - map(0x1E, MINECRAFT_1_19, false), - map(0x20, MINECRAFT_1_19_1, false), - map(0x1F, MINECRAFT_1_19_3, false), - map(0x23, MINECRAFT_1_19_4, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x1F, ProtocolVersion.MINECRAFT_1_9, false), + map(0x21, ProtocolVersion.MINECRAFT_1_13, false), + map(0x20, ProtocolVersion.MINECRAFT_1_14, false), + map(0x21, ProtocolVersion.MINECRAFT_1_15, false), + map(0x20, ProtocolVersion.MINECRAFT_1_16, false), + map(0x1F, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x21, ProtocolVersion.MINECRAFT_1_17, false), + map(0x1E, ProtocolVersion.MINECRAFT_1_19, false), + map(0x20, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x1F, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x23, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x24, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(JoinGame.class, JoinGame::new, - map(0x01, MINECRAFT_1_7_2, false), - map(0x23, MINECRAFT_1_9, false), - map(0x25, MINECRAFT_1_13, false), - map(0x25, MINECRAFT_1_14, false), - map(0x26, MINECRAFT_1_15, false), - map(0x25, MINECRAFT_1_16, false), - map(0x24, MINECRAFT_1_16_2, false), - map(0x26, MINECRAFT_1_17, false), - map(0x23, MINECRAFT_1_19, false), - map(0x25, MINECRAFT_1_19_1, false), - map(0x24, MINECRAFT_1_19_3, false), - map(0x28, MINECRAFT_1_19_4, false)); + map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x23, ProtocolVersion.MINECRAFT_1_9, false), + map(0x25, ProtocolVersion.MINECRAFT_1_13, false), + map(0x25, ProtocolVersion.MINECRAFT_1_14, false), + map(0x26, ProtocolVersion.MINECRAFT_1_15, false), + map(0x25, ProtocolVersion.MINECRAFT_1_16, false), + map(0x24, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x26, ProtocolVersion.MINECRAFT_1_17, false), + map(0x23, ProtocolVersion.MINECRAFT_1_19, false), + map(0x25, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x24, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x28, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x29, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(Respawn.class, Respawn::new, - map(0x07, MINECRAFT_1_7_2, true), - map(0x33, MINECRAFT_1_9, true), - map(0x34, MINECRAFT_1_12, true), - map(0x35, MINECRAFT_1_12_1, true), - map(0x38, MINECRAFT_1_13, true), - map(0x3A, MINECRAFT_1_14, true), - map(0x3B, MINECRAFT_1_15, true), - map(0x3A, MINECRAFT_1_16, true), - map(0x39, MINECRAFT_1_16_2, true), - map(0x3D, MINECRAFT_1_17, true), - map(0x3B, MINECRAFT_1_19, true), - map(0x3E, MINECRAFT_1_19_1, true), - map(0x3D, MINECRAFT_1_19_3, true), - map(0x41, MINECRAFT_1_19_4, true)); + map(0x07, ProtocolVersion.MINECRAFT_1_7_2, true), + map(0x33, ProtocolVersion.MINECRAFT_1_9, true), + map(0x34, ProtocolVersion.MINECRAFT_1_12, true), + map(0x35, ProtocolVersion.MINECRAFT_1_12_1, true), + map(0x38, ProtocolVersion.MINECRAFT_1_13, true), + map(0x3A, ProtocolVersion.MINECRAFT_1_14, true), + map(0x3B, ProtocolVersion.MINECRAFT_1_15, true), + map(0x3A, ProtocolVersion.MINECRAFT_1_16, true), + map(0x39, ProtocolVersion.MINECRAFT_1_16_2, true), + map(0x3D, ProtocolVersion.MINECRAFT_1_17, true), + map(0x3B, ProtocolVersion.MINECRAFT_1_19, true), + map(0x3E, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x3D, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x41, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x43, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new, - map(0x48, MINECRAFT_1_8, false), - map(0x32, MINECRAFT_1_9, false), - map(0x33, MINECRAFT_1_12, false), - map(0x34, MINECRAFT_1_12_1, false), - map(0x37, MINECRAFT_1_13, false), - map(0x39, MINECRAFT_1_14, false), - map(0x3A, MINECRAFT_1_15, false), - map(0x39, MINECRAFT_1_16, false), - map(0x38, MINECRAFT_1_16_2, false), - map(0x3C, MINECRAFT_1_17, false), - map(0x3A, MINECRAFT_1_19, false), - map(0x3D, MINECRAFT_1_19_1, false), - map(0x3C, MINECRAFT_1_19_3, false), - map(0x40, MINECRAFT_1_19_4, false)); + map(0x48, ProtocolVersion.MINECRAFT_1_8, false), + map(0x32, ProtocolVersion.MINECRAFT_1_9, false), + map(0x33, ProtocolVersion.MINECRAFT_1_12, false), + map(0x34, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x37, ProtocolVersion.MINECRAFT_1_13, false), + map(0x39, ProtocolVersion.MINECRAFT_1_14, false), + map(0x3A, ProtocolVersion.MINECRAFT_1_15, false), + map(0x39, ProtocolVersion.MINECRAFT_1_16, false), + map(0x38, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x3C, ProtocolVersion.MINECRAFT_1_17, false), + map(0x3A, ProtocolVersion.MINECRAFT_1_19, false), + map(0x3D, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x3C, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x40, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x06, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(HeaderAndFooter.class, HeaderAndFooter::new, - map(0x47, MINECRAFT_1_8, true), - map(0x48, MINECRAFT_1_9, true), - map(0x47, MINECRAFT_1_9_4, true), - map(0x49, MINECRAFT_1_12, true), - map(0x4A, MINECRAFT_1_12_1, true), - map(0x4E, MINECRAFT_1_13, true), - map(0x53, MINECRAFT_1_14, true), - map(0x54, MINECRAFT_1_15, true), - map(0x53, MINECRAFT_1_16, true), - map(0x5E, MINECRAFT_1_17, true), - map(0x5F, MINECRAFT_1_18, true), - map(0x60, MINECRAFT_1_19, true), - map(0x63, MINECRAFT_1_19_1, true), - map(0x61, MINECRAFT_1_19_3, true), - map(0x65, MINECRAFT_1_19_4, true)); + map(0x47, ProtocolVersion.MINECRAFT_1_8, true), + map(0x48, ProtocolVersion.MINECRAFT_1_9, true), + map(0x47, ProtocolVersion.MINECRAFT_1_9_4, true), + map(0x49, ProtocolVersion.MINECRAFT_1_12, true), + map(0x4A, ProtocolVersion.MINECRAFT_1_12_1, true), + map(0x4E, ProtocolVersion.MINECRAFT_1_13, true), + map(0x53, ProtocolVersion.MINECRAFT_1_14, true), + map(0x54, ProtocolVersion.MINECRAFT_1_15, true), + map(0x53, ProtocolVersion.MINECRAFT_1_16, true), + map(0x5E, ProtocolVersion.MINECRAFT_1_17, true), + map(0x5F, ProtocolVersion.MINECRAFT_1_18, true), + map(0x60, ProtocolVersion.MINECRAFT_1_19, true), + map(0x63, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x61, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x65, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x68, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(LegacyTitlePacket.class, LegacyTitlePacket::new, - map(0x45, MINECRAFT_1_8, true), - map(0x45, MINECRAFT_1_9, true), - map(0x47, MINECRAFT_1_12, true), - map(0x48, MINECRAFT_1_12_1, true), - map(0x4B, MINECRAFT_1_13, true), - map(0x4F, MINECRAFT_1_14, true), - map(0x50, MINECRAFT_1_15, true), - map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true)); + map(0x45, ProtocolVersion.MINECRAFT_1_8, true), + map(0x45, ProtocolVersion.MINECRAFT_1_9, true), + map(0x47, ProtocolVersion.MINECRAFT_1_12, true), + map(0x48, ProtocolVersion.MINECRAFT_1_12_1, true), + map(0x4B, ProtocolVersion.MINECRAFT_1_13, true), + map(0x4F, ProtocolVersion.MINECRAFT_1_14, true), + map(0x50, ProtocolVersion.MINECRAFT_1_15, true), + map(0x4F, ProtocolVersion.MINECRAFT_1_16, ProtocolVersion.MINECRAFT_1_16_4, true)); clientbound.register(TitleSubtitlePacket.class, TitleSubtitlePacket::new, - map(0x57, MINECRAFT_1_17, true), - map(0x58, MINECRAFT_1_18, true), - map(0x5B, MINECRAFT_1_19_1, true), - map(0x59, MINECRAFT_1_19_3, true), - map(0x5D, MINECRAFT_1_19_4, true)); + map(0x57, ProtocolVersion.MINECRAFT_1_17, true), + map(0x58, ProtocolVersion.MINECRAFT_1_18, true), + map(0x5B, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x59, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x5D, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x5F, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(TitleTextPacket.class, TitleTextPacket::new, - map(0x59, MINECRAFT_1_17, true), - map(0x5A, MINECRAFT_1_18, true), - map(0x5D, MINECRAFT_1_19_1, true), - map(0x5B, MINECRAFT_1_19_3, true), - map(0x5F, MINECRAFT_1_19_4, true)); + map(0x59, ProtocolVersion.MINECRAFT_1_17, true), + map(0x5A, ProtocolVersion.MINECRAFT_1_18, true), + map(0x5D, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x5B, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x5F, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x61, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(TitleActionbarPacket.class, TitleActionbarPacket::new, - map(0x41, MINECRAFT_1_17, true), - map(0x40, MINECRAFT_1_19, true), - map(0x43, MINECRAFT_1_19_1, true), - map(0x42, MINECRAFT_1_19_3, true), - map(0x46, MINECRAFT_1_19_4, true)); + map(0x41, ProtocolVersion.MINECRAFT_1_17, true), + map(0x40, ProtocolVersion.MINECRAFT_1_19, true), + map(0x43, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x42, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x46, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x48, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(TitleTimesPacket.class, TitleTimesPacket::new, - map(0x5A, MINECRAFT_1_17, true), - map(0x5B, MINECRAFT_1_18, true), - map(0x5E, MINECRAFT_1_19_1, true), - map(0x5C, MINECRAFT_1_19_3, true), - map(0x60, MINECRAFT_1_19_4, true)); + map(0x5A, ProtocolVersion.MINECRAFT_1_17, true), + map(0x5B, ProtocolVersion.MINECRAFT_1_18, true), + map(0x5E, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x5C, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x60, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x62, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(TitleClearPacket.class, TitleClearPacket::new, - map(0x10, MINECRAFT_1_17, true), - map(0x0D, MINECRAFT_1_19, true), - map(0x0C, MINECRAFT_1_19_3, true), - map(0x0E, MINECRAFT_1_19_4, true)); + map(0x10, ProtocolVersion.MINECRAFT_1_17, true), + map(0x0D, ProtocolVersion.MINECRAFT_1_19, true), + map(0x0C, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x0E, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x0F, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(LegacyPlayerListItem.class, LegacyPlayerListItem::new, - map(0x38, MINECRAFT_1_7_2, false), - map(0x2D, MINECRAFT_1_9, false), - map(0x2E, MINECRAFT_1_12_1, false), - map(0x30, MINECRAFT_1_13, false), - map(0x33, MINECRAFT_1_14, false), - map(0x34, MINECRAFT_1_15, false), - map(0x33, MINECRAFT_1_16, false), - map(0x32, MINECRAFT_1_16_2, false), - map(0x36, MINECRAFT_1_17, false), - map(0x34, MINECRAFT_1_19, false), - map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + map(0x38, ProtocolVersion.MINECRAFT_1_7_2, false), + map(0x2D, ProtocolVersion.MINECRAFT_1_9, false), + map(0x2E, ProtocolVersion.MINECRAFT_1_12_1, false), + map(0x30, ProtocolVersion.MINECRAFT_1_13, false), + map(0x33, ProtocolVersion.MINECRAFT_1_14, false), + map(0x34, ProtocolVersion.MINECRAFT_1_15, false), + map(0x33, ProtocolVersion.MINECRAFT_1_16, false), + map(0x32, ProtocolVersion.MINECRAFT_1_16_2, false), + map(0x36, ProtocolVersion.MINECRAFT_1_17, false), + map(0x34, ProtocolVersion.MINECRAFT_1_19, false), + map(0x37, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); clientbound.register(RemovePlayerInfo.class, RemovePlayerInfo::new, - map(0x35, MINECRAFT_1_19_3, false), - map(0x39, MINECRAFT_1_19_4, false)); + map(0x35, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x39, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x3B, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(UpsertPlayerInfo.class, UpsertPlayerInfo::new, - map(0x36, MINECRAFT_1_19_3, false), - map(0x3A, MINECRAFT_1_19_4, false)); + map(0x36, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x3A, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x3C, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(SystemChat.class, SystemChat::new, - map(0x5F, MINECRAFT_1_19, true), - map(0x62, MINECRAFT_1_19_1, true), - map(0x60, MINECRAFT_1_19_3, true), - map(0x64, MINECRAFT_1_19_4, true)); + map(0x5F, ProtocolVersion.MINECRAFT_1_19, true), + map(0x62, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x60, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x64, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x67, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(PlayerChatCompletion.class, PlayerChatCompletion::new, - map(0x15, MINECRAFT_1_19_1, true), - map(0x14, MINECRAFT_1_19_3, true), - map(0x16, MINECRAFT_1_19_4, true)); + map(0x15, ProtocolVersion.MINECRAFT_1_19_1, true), + map(0x14, ProtocolVersion.MINECRAFT_1_19_3, true), + map(0x16, ProtocolVersion.MINECRAFT_1_19_4, true), + map(0x17, ProtocolVersion.MINECRAFT_1_20_2, true)); clientbound.register(ServerData.class, ServerData::new, - map(0x3F, MINECRAFT_1_19, false), - map(0x42, MINECRAFT_1_19_1, false), - map(0x41, MINECRAFT_1_19_3, false), - map(0x45, MINECRAFT_1_19_4, false)); + map(0x3F, ProtocolVersion.MINECRAFT_1_19, false), + map(0x42, ProtocolVersion.MINECRAFT_1_19_1, false), + map(0x41, ProtocolVersion.MINECRAFT_1_19_3, false), + map(0x45, ProtocolVersion.MINECRAFT_1_19_4, false), + map(0x47, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(StartUpdate.class, StartUpdate::new, + map(0x65, ProtocolVersion.MINECRAFT_1_20_2, false)); } }, LOGIN { { serverbound.register(ServerLogin.class, ServerLogin::new, - map(0x00, MINECRAFT_1_7_2, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); serverbound.register(EncryptionResponse.class, EncryptionResponse::new, - map(0x01, MINECRAFT_1_7_2, false)); + map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); serverbound.register(LoginPluginResponse.class, LoginPluginResponse::new, - map(0x02, MINECRAFT_1_13, false)); + map(0x02, ProtocolVersion.MINECRAFT_1_13, false)); + serverbound.register(LoginAcknowledged.class, LoginAcknowledged::new, + map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register(Disconnect.class, Disconnect::new, - map(0x00, MINECRAFT_1_7_2, false)); + map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); clientbound.register(EncryptionRequest.class, EncryptionRequest::new, - map(0x01, MINECRAFT_1_7_2, false)); + map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); clientbound.register(ServerLoginSuccess.class, ServerLoginSuccess::new, - map(0x02, MINECRAFT_1_7_2, false)); + map(0x02, ProtocolVersion.MINECRAFT_1_7_2, false)); clientbound.register(SetCompression.class, SetCompression::new, - map(0x03, MINECRAFT_1_8, false)); + map(0x03, ProtocolVersion.MINECRAFT_1_8, false)); clientbound.register(LoginPluginMessage.class, LoginPluginMessage::new, - map(0x04, MINECRAFT_1_13, false)); + map(0x04, ProtocolVersion.MINECRAFT_1_13, false)); } }; @@ -461,7 +479,7 @@ ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) { ProtocolRegistry registry = versions.get(version); if (registry == null) { if (fallback) { - return getProtocolRegistry(MINIMUM_VERSION); + return getProtocolRegistry(ProtocolVersion.MINIMUM_VERSION); } throw new IllegalArgumentException("Could not find data for protocol version " + version); } @@ -490,9 +508,10 @@

void register(Class

clazz, Supplier

packetSupp } } ProtocolVersion to = current == next ? lastValid != null - ? lastValid : getLast(SUPPORTED_VERSIONS) : next.protocolVersion; + ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS) : next.protocolVersion; - ProtocolVersion lastInList = lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS); + ProtocolVersion lastInList = + lastValid != null ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS); if (from.compareTo(to) >= 0 && from != lastInList) { throw new IllegalArgumentException(String.format( diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index cfbecce319..35d6fc888e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -42,6 +42,7 @@ public class JoinGame implements MinecraftPacket { private int viewDistance; // 1.14+ private boolean reducedDebugInfo; private boolean showRespawnScreen; + private boolean doLimitedCrafting; private ImmutableSet levelNames; // 1.16+ private CompoundBinaryTag registry; // 1.16+ private DimensionInfo dimensionInfo; // 1.16+ @@ -143,6 +144,14 @@ public void setIsHardcore(boolean isHardcore) { this.isHardcore = isHardcore; } + public boolean getDoLimitedCrafting() { + return doLimitedCrafting; + } + + public void setDoLimitedCrafting(boolean doLimitedCrafting) { + this.doLimitedCrafting = doLimitedCrafting; + } + public CompoundBinaryTag getCurrentDimensionData() { return currentDimensionData; } @@ -189,6 +198,7 @@ public String toString() { + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo + ", showRespawnScreen=" + showRespawnScreen + + ", doLimitedCrafting=" + doLimitedCrafting + ", levelNames=" + levelNames + ", registry='" + registry + '\'' + ", dimensionInfo='" + dimensionInfo + '\'' @@ -280,6 +290,9 @@ private void decode116Up(ByteBuf buf, ProtocolVersion version) { this.reducedDebugInfo = buf.readBoolean(); this.showRespawnScreen = buf.readBoolean(); + if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) { + this.doLimitedCrafting = buf.readBoolean(); + } boolean isDebug = buf.readBoolean(); boolean isFlat = buf.readBoolean(); @@ -376,6 +389,7 @@ private void encode116Up(ByteBuf buf, ProtocolVersion version) { buf.writeBoolean(reducedDebugInfo); buf.writeBoolean(showRespawnScreen); + buf.writeBoolean(doLimitedCrafting); buf.writeBoolean(dimensionInfo.isDebugType()); buf.writeBoolean(dimensionInfo.isFlat()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java new file mode 100644 index 0000000000..257901b3bd --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class LoginAcknowledged implements MinecraftPacket { + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + } + + + @Override + public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 0; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java new file mode 100644 index 0000000000..62da66e0e7 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018-2021 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class PingIdentify implements MinecraftPacket { + + private int id; + + @Override + public String toString() { + return "Ping{" + + "id=" + id + + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + id = buf.readInt(); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + buf.writeInt(id); + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java index 0cd589ee9e..1aafc67cef 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java @@ -98,6 +98,11 @@ public void decode(ByteBuf buf, Direction direction, ProtocolVersion version) { } } + if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) { + this.holderUuid = ProtocolUtils.readUuid(buf); + return; + } + if (version.compareTo(ProtocolVersion.MINECRAFT_1_19_1) >= 0) { if (buf.readBoolean()) { holderUuid = ProtocolUtils.readUuid(buf); @@ -125,6 +130,11 @@ public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersi } } + if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) { + ProtocolUtils.writeUuid(buf, this.holderUuid); + return; + } + if (version.compareTo(ProtocolVersion.MINECRAFT_1_19_1) >= 0) { if (playerKey != null && playerKey.getSignatureHolder() != null) { buf.writeBoolean(true); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java new file mode 100644 index 0000000000..cdb15b6012 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet.config; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class ActiveFeatures implements MinecraftPacket { + + private String[] activeFeatures; + + public ActiveFeatures(){ + this.activeFeatures = new String[0]; + } + + public ActiveFeatures(String[] activeFeatures) { + this.activeFeatures = activeFeatures; + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + activeFeatures = ProtocolUtils.readStringArray(buf); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeStringArray(buf, activeFeatures); + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java new file mode 100644 index 0000000000..5d7b183d73 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet.config; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class FinishedUpdate implements MinecraftPacket { + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + } + + @Override + public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 0; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java new file mode 100644 index 0000000000..ecc7dedf67 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet.config; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; +import net.kyori.adventure.nbt.BinaryTagIO; +import net.kyori.adventure.nbt.CompoundBinaryTag; + +public class RegistrySync implements MinecraftPacket { + + private CompoundBinaryTag registryData; + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + registryData = ProtocolUtils.readCompoundTag(buf, BinaryTagIO.reader()); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeCompoundTag(buf, registryData); + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java new file mode 100644 index 0000000000..015d4c64e8 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet.config; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class StartUpdate implements MinecraftPacket { + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + } + + @Override + public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 0; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java new file mode 100644 index 0000000000..1c57156671 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.protocol.packet.config; + +import com.google.common.collect.ImmutableMap; +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +import java.util.Map; + +public class TagsUpdate implements MinecraftPacket { + + private Map> tags; + + public TagsUpdate(Map> tags) { + this.tags = tags; + } + + public TagsUpdate() { + this.tags = Map.of(); + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ImmutableMap.Builder> builder = ImmutableMap.builder(); + int size = ProtocolUtils.readVarInt(buf); + for (int i = 0; i < size; i++) { + String key = ProtocolUtils.readString(buf); + + int innerSize = ProtocolUtils.readVarInt(buf); + ImmutableMap.Builder innerBuilder = ImmutableMap.builder(); + for (int j = 0; j < innerSize; j++) { + String innerKey = ProtocolUtils.readString(buf); + int[] innerValue = ProtocolUtils.readVarIntArray(buf); + innerBuilder.put(innerKey, innerValue); + } + + builder.put(key, innerBuilder.build()); + } + tags = builder.build(); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, tags.size()); + for (Map.Entry> entry : tags.entrySet()) { + ProtocolUtils.writeString(buf, entry.getKey()); + // Oh, joy + ProtocolUtils.writeVarInt(buf, entry.getValue().size()); + for (Map.Entry innerEntry : entry.getValue().entrySet()) { + // Yea, object oriented programming be damned + ProtocolUtils.writeString(buf, innerEntry.getKey()); + ProtocolUtils.writeVarIntArray(buf, innerEntry.getValue()); + } + } + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} \ No newline at end of file From 0adc6f0ed73c2f617632e867fc281933244bf7bd Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 02:54:00 +0100 Subject: [PATCH 02/41] update --- .../proxy/connection/MinecraftConnection.java | 136 +++-- .../backend/BackendPlaySessionHandler.java | 2 +- .../backend/ConfigSessionHandler.java | 227 ++++++++ .../backend/LoginSessionHandler.java | 79 +-- .../backend/TransitionSessionHandler.java | 109 ++-- .../backend/VelocityServerConnection.java | 90 ++-- .../connection/client/AuthSessionHandler.java | 169 +++--- .../client/ClientConfigSessionHandler.java | 157 ++++++ .../client/ClientPlaySessionHandler.java | 224 ++++---- .../connection/client/ConnectedPlayer.java | 484 +++++++++--------- .../client/HandshakeSessionHandler.java | 27 +- .../client/InitialLoginSessionHandler.java | 123 ++--- .../LegacyForgeHandshakeClientPhase.java | 28 +- .../connection/registry/ClientConfigData.java | 117 +++++ .../proxy/connection/registry/DataTag.java | 79 +++ .../network/ServerChannelInitializer.java | 25 +- .../proxy/protocol/ProtocolUtils.java | 160 ++++-- .../proxy/protocol/StateRegistry.java | 12 +- .../proxy/protocol/packet/JoinGame.java | 2 +- .../protocol/packet/ResourcePackRequest.java | 35 +- .../packet/config/ActiveFeatures.java | 19 +- .../protocol/packet/config/RegistrySync.java | 7 +- .../proxy/server/PingSessionHandler.java | 8 +- .../server/VelocityRegisteredServer.java | 66 +-- .../proxy/util/collect/CappedSet.java | 70 +++ 25 files changed, 1683 insertions(+), 772 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 9145ff133a..4b1d852e6b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -60,6 +60,9 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.security.GeneralSecurityException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -78,7 +81,8 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { private final Channel channel; private SocketAddress remoteAddress; private StateRegistry state; - private @Nullable MinecraftSessionHandler sessionHandler; + private Map sessionHandlers; + private @Nullable MinecraftSessionHandler activeSessionHandler; private ProtocolVersion protocolVersion; private @Nullable MinecraftConnectionAssociation association; public final VelocityServer server; @@ -96,12 +100,14 @@ public MinecraftConnection(Channel channel, VelocityServer server) { this.remoteAddress = channel.remoteAddress(); this.server = server; this.state = StateRegistry.HANDSHAKE; + + this.sessionHandlers = new HashMap<>(); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { - if (sessionHandler != null) { - sessionHandler.connected(); + if (activeSessionHandler != null) { + activeSessionHandler.connected(); } if (association != null && server.getConfiguration().isLogPlayerConnections()) { @@ -111,13 +117,13 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (sessionHandler != null) { - sessionHandler.disconnected(); + if (activeSessionHandler != null) { + activeSessionHandler.disconnected(); } if (association != null && !knownDisconnect - && !(sessionHandler instanceof StatusSessionHandler) - && server.getConfiguration().isLogPlayerConnections()) { + && !(activeSessionHandler instanceof StatusSessionHandler) + && server.getConfiguration().isLogPlayerConnections()) { logger.info("{} has disconnected", association); } } @@ -125,12 +131,12 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { - if (sessionHandler == null) { + if (activeSessionHandler == null) { // No session handler available, do nothing return; } - if (sessionHandler.beforeHandle()) { + if (activeSessionHandler.beforeHandle()) { return; } @@ -140,15 +146,15 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception if (msg instanceof MinecraftPacket) { MinecraftPacket pkt = (MinecraftPacket) msg; - if (!pkt.handle(sessionHandler)) { - sessionHandler.handleGeneric((MinecraftPacket) msg); + if (!pkt.handle(activeSessionHandler)) { + activeSessionHandler.handleGeneric((MinecraftPacket) msg); } } else if (msg instanceof HAProxyMessage) { HAProxyMessage proxyMessage = (HAProxyMessage) msg; this.remoteAddress = new InetSocketAddress(proxyMessage.sourceAddress(), - proxyMessage.sourcePort()); + proxyMessage.sourcePort()); } else if (msg instanceof ByteBuf) { - sessionHandler.handleUnknown((ByteBuf) msg); + activeSessionHandler.handleUnknown((ByteBuf) msg); } } finally { ReferenceCountUtil.release(msg); @@ -157,20 +163,20 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { - if (sessionHandler != null) { - sessionHandler.readCompleted(); + if (activeSessionHandler != null) { + activeSessionHandler.readCompleted(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { if (ctx.channel().isActive()) { - if (sessionHandler != null) { + if (activeSessionHandler != null) { try { - sessionHandler.exception(cause); + activeSessionHandler.exception(cause); } catch (Exception ex) { logger.error("{}: exception handling exception in {}", - (association != null ? association : channel.remoteAddress()), sessionHandler, cause); + (association != null ? association : channel.remoteAddress()), activeSessionHandler, cause); } } @@ -178,13 +184,13 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E if (cause instanceof ReadTimeoutException) { logger.error("{}: read timed out", association); } else { - boolean frontlineHandler = sessionHandler instanceof InitialLoginSessionHandler - || sessionHandler instanceof HandshakeSessionHandler - || sessionHandler instanceof StatusSessionHandler; + boolean frontlineHandler = activeSessionHandler instanceof InitialLoginSessionHandler + || activeSessionHandler instanceof HandshakeSessionHandler + || activeSessionHandler instanceof StatusSessionHandler; boolean isQuietDecoderException = cause instanceof QuietDecoderException; boolean willLog = !isQuietDecoderException && !frontlineHandler; if (willLog) { - logger.error("{}: exception encountered in {}", association, sessionHandler, cause); + logger.error("{}: exception encountered in {}", association, activeSessionHandler, cause); } else { knownDisconnect = true; } @@ -197,8 +203,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E @Override public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { - if (sessionHandler != null) { - sessionHandler.writabilityChanged(); + if (activeSessionHandler != null) { + activeSessionHandler.writabilityChanged(); } } @@ -253,7 +259,7 @@ public void flush() { public void closeWith(Object msg) { if (channel.isActive()) { boolean is17 = this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 - && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; + && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; if (is17 && this.getState() != StateRegistry.STATUS) { channel.eventLoop().execute(() -> { // 1.7.x versions have a race condition with switching protocol states, so just explicitly @@ -341,12 +347,8 @@ public void setAutoReading(boolean autoReading) { } } - /** - * Changes the state of the Minecraft connection. - * - * @param state the new state - */ - public void setState(StateRegistry state) { + // Ideally only used by the state switch + private void setState(StateRegistry state) { ensureInEventLoop(); this.state = state; @@ -382,25 +384,73 @@ public void setProtocolVersion(ProtocolVersion protocolVersion) { } } - public @Nullable MinecraftSessionHandler getSessionHandler() { - return sessionHandler; + public @Nullable MinecraftSessionHandler getActiveSessionHandler() { + return activeSessionHandler; + } + + public @Nullable MinecraftSessionHandler getSessionHandlerForRegistry(StateRegistry registry) { + return this.sessionHandlers.getOrDefault(registry, null); } /** * Sets the session handler for this connection. * + * @param registry the registry of the handler * @param sessionHandler the handler to use */ - public void setSessionHandler(MinecraftSessionHandler sessionHandler) { + public void setActiveSessionHandler(StateRegistry registry, MinecraftSessionHandler sessionHandler) { + Preconditions.checkNotNull(registry); ensureInEventLoop(); - if (this.sessionHandler != null) { - this.sessionHandler.deactivated(); + if (this.activeSessionHandler != null) { + this.activeSessionHandler.deactivated(); } - this.sessionHandler = sessionHandler; + this.sessionHandlers.put(registry, sessionHandler); + this.activeSessionHandler = sessionHandler; + setState(registry); sessionHandler.activated(); } + /** + * Switches the active session handler to the respective registry one. + * + * @param registry the registry of the handler + * @return true if successful and handler is present + */ + public boolean setActiveSessionHandler(StateRegistry registry) { + Preconditions.checkNotNull(registry); + ensureInEventLoop(); + + MinecraftSessionHandler handler = getSessionHandlerForRegistry(registry); + if (handler != null) { + boolean flag = true; + if (this.activeSessionHandler != null + && (flag = !Objects.equals(handler, this.activeSessionHandler))) { + this.activeSessionHandler.deactivated(); + } + this.activeSessionHandler = handler; + setState(registry); + if (flag) { + handler.activated(); + } + } + return handler != null; + } + + /** + * Adds a secondary session handler for this connection. + * + * @param registry the registry of the handler + * @param sessionHandler the handler to use + */ + public void addSessionHandler(StateRegistry registry, MinecraftSessionHandler sessionHandler) { + Preconditions.checkNotNull(registry); + Preconditions.checkArgument(registry != state, "Handler would overwrite handler"); + ensureInEventLoop(); + + this.sessionHandlers.put(registry, sessionHandler); + } + private void ensureOpen() { Preconditions.checkState(!isClosed(), "Connection is closed."); } @@ -421,14 +471,14 @@ public void setCompressionThreshold(int threshold) { if (removedDecoder != null && removedEncoder != null) { channel.pipeline().addBefore(MINECRAFT_DECODER, FRAME_ENCODER, - MinecraftVarintLengthEncoder.INSTANCE); + MinecraftVarintLengthEncoder.INSTANCE); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.COMPRESSION_DISABLED); } } else { MinecraftCompressDecoder decoder = (MinecraftCompressDecoder) channel.pipeline() - .get(COMPRESSION_DECODER); + .get(COMPRESSION_DECODER); MinecraftCompressorAndLengthEncoder encoder = - (MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER); + (MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER); if (decoder != null && encoder != null) { decoder.setThreshold(threshold); encoder.setThreshold(threshold); @@ -464,9 +514,9 @@ public void enableEncryption(byte[] secret) throws GeneralSecurityException { VelocityCipher decryptionCipher = factory.forDecryption(key); VelocityCipher encryptionCipher = factory.forEncryption(key); channel.pipeline() - .addBefore(FRAME_DECODER, CIPHER_DECODER, new MinecraftCipherDecoder(decryptionCipher)); + .addBefore(FRAME_DECODER, CIPHER_DECODER, new MinecraftCipherDecoder(decryptionCipher)); channel.pipeline() - .addBefore(FRAME_ENCODER, CIPHER_ENCODER, new MinecraftCipherEncoder(encryptionCipher)); + .addBefore(FRAME_ENCODER, CIPHER_ENCODER, new MinecraftCipherEncoder(encryptionCipher)); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.ENCRYPTION_ENABLED); } @@ -498,4 +548,4 @@ public void setType(ConnectionType connectionType) { this.connectionType = connectionType; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index ff777f5f9c..f931348178 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -86,7 +86,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { this.serverConn = serverConn; this.playerConnection = serverConn.getPlayer().getConnection(); - MinecraftSessionHandler psh = playerConnection.getSessionHandler(); + MinecraftSessionHandler psh = playerConnection.getActiveSessionHandler(); if (!(psh instanceof ClientPlaySessionHandler)) { throw new IllegalStateException( "Initializing BackendPlaySessionHandler with no backing client play session handler!"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java new file mode 100644 index 0000000000..cd0c1238ca --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2019-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.connection.backend; + +import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent; +import com.velocitypowered.api.event.player.ServerResourcePackSendEvent; +import com.velocitypowered.api.proxy.player.ResourcePackInfo; +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.connection.client.ClientConfigSessionHandler; +import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo; +import com.velocitypowered.proxy.connection.util.ConnectionMessages; +import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; +import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.Disconnect; +import com.velocitypowered.proxy.protocol.packet.KeepAlive; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; +import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; +import jdk.jfr.Experimental; +import net.kyori.adventure.text.Component; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.concurrent.CompletableFuture; + +/** + * A special session handler that catches "last minute" disconnects. + * This version is to accommodate 1.20.2+ switching. + * Yes, some of this is exceptionally stupid. + */ +@Experimental +public class ConfigSessionHandler implements MinecraftSessionHandler { + + private static final Logger logger = LogManager.getLogger(ConfigSessionHandler.class); + + private final VelocityServer server; + private final VelocityServerConnection serverConn; + private final CompletableFuture resultFuture; + + + private State state; + + /** + * Creates the new transition handler. + * + * @param server the Velocity server instance + * @param serverConn the server connection + * @param resultFuture the result future + */ + ConfigSessionHandler(VelocityServer server, + VelocityServerConnection serverConn, + CompletableFuture resultFuture) { + this.server = server; + this.serverConn = serverConn; + this.resultFuture = resultFuture; + this.state = State.START; + } + + @Override + public void deactivated() { + } + + @Override + public boolean beforeHandle() { + if (!serverConn.isActive()) { + // Obsolete connection + serverConn.disconnect(); + return true; + } + return false; + } + + @Override + public boolean handle(KeepAlive packet) { + serverConn.ensureConnected().write(packet); + return true; + } + + @Override + public boolean handle(ResourcePackRequest packet) { + final MinecraftConnection playerConnection = serverConn.getPlayer().getConnection(); + + ServerResourcePackSendEvent event = new ServerResourcePackSendEvent( + packet.toServerPromptedPack(), this.serverConn); + + server.getEventManager().fire(event).thenAcceptAsync(serverResourcePackSendEvent -> { + if (playerConnection.isClosed()) { + return; + } + if (serverResourcePackSendEvent.getResult().isAllowed()) { + ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); + if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { + ((VelocityResourcePackInfo) toSend) + .setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + } + + serverConn.getPlayer().queueResourcePack(toSend); + } else if (serverConn.getConnection() != null) { + serverConn.getConnection().write(new ResourcePackResponse( + packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED + )); + } + }, playerConnection.eventLoop()).exceptionally((ex) -> { + if (serverConn.getConnection() != null) { + serverConn.getConnection().write(new ResourcePackResponse( + packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED + )); + } + logger.error("Exception while handling resource pack send for {}", playerConnection, ex); + return null; + }); + + return true; + } + + @Override + public boolean handle(FinishedUpdate packet) { + + ClientConfigSessionHandler configHandler = + (ClientConfigSessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler(); + + configHandler.handleBackendFinishUpdate(serverConn).thenAcceptAsync((unused) -> { + serverConn.ensureConnected().write(new FinishedUpdate()); + serverConn.ensureConnected().setActiveSessionHandler(StateRegistry.PLAY, + new TransitionSessionHandler(server, serverConn, resultFuture)); + }, serverConn.ensureConnected().eventLoop()); + return true; + } + + + private void switchFailure(Throwable cause) { + logger.error("Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + serverConn.getPlayer().getUsername(), cause); + serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + resultFuture.completeExceptionally(cause); + } + /* + private ClientConfigSessionHandler getClientConfigSessionHandler(ConnectedPlayer player) { + ClientPlaySessionHandler playHandler; + if (player.getConnection().getSessionHandler() instanceof ClientPlaySessionHandler) { + playHandler = (ClientPlaySessionHandler) player.getConnection().getSessionHandler(); + } else { + playHandler = new ClientPlaySessionHandler(server, player); + } + + ClientConfigSessionHandler configHandler; + if (player.getConnection().getSessionHandler() instanceof ClientConfigSessionHandler) { + configHandler = (ClientConfigSessionHandler) player.getConnection().getSessionHandler(); + } else { + configHandler = new ClientConfigSessionHandler(server, player, playHandler); + } + return configHandler; + } + */ + @Override + public boolean handle(Disconnect packet) { + serverConn.disconnect(); + resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); + return true; + } + + @Override + public boolean handle(PluginMessage packet) { + if (PluginMessageUtil.isMcBrand(packet)) { + serverConn.getPlayer().getConnection().write( + PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), + serverConn.getPlayer().getProtocolVersion())); + } else { + // TODO: Change this so its usable for mod loaders + serverConn.disconnect(); + resultFuture.complete(ConnectionRequestResults.forDisconnect( + Component.translatable("multiplayer.disconnect.missing_tags"), serverConn.getServer())); + } + return true; + } + + @Override + public void disconnected() { + resultFuture + .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + } + + @Override + public boolean handle(RegistrySync packet) { + serverConn.getPlayer().getConnection().write(packet.retain()); + return true; + } + + @Override + public void handleGeneric(MinecraftPacket packet) { + serverConn.getPlayer().getConnection().write(packet); + } + + public static enum State{ + START, + NEGOTIATING, + PLUGIN_MESSAGE_INTERRUPT, + RESOURCE_PACK_INTERRUPT, + COMPLETE + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index 90a9a1300b..e2389f9bed 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -27,6 +27,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.VelocityConstants; +import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; @@ -34,6 +35,7 @@ import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; +import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; @@ -60,7 +62,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); private static final Component MODERN_IP_FORWARDING_FAILURE = Component - .translatable("velocity.error.modern-forwarding-failed"); + .translatable("velocity.error.modern-forwarding-failed"); private final VelocityServer server; private final VelocityServerConnection serverConn; @@ -68,7 +70,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private boolean informationForwarded; LoginSessionHandler(VelocityServer server, VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -84,7 +86,7 @@ public boolean handle(LoginPluginMessage packet) { MinecraftConnection mc = serverConn.ensureConnected(); VelocityConfiguration configuration = server.getConfiguration(); if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN - && packet.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) { + && packet.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) { int requestedForwardingVersion = VelocityConstants.MODERN_FORWARDING_DEFAULT; // Check version @@ -92,8 +94,8 @@ public boolean handle(LoginPluginMessage packet) { requestedForwardingVersion = packet.content().readByte(); } ByteBuf forwardingData = createForwardingData(configuration.getForwardingSecret(), - serverConn.getPlayerRemoteAddressAsString(), serverConn.getPlayer(), - requestedForwardingVersion); + serverConn.getPlayerRemoteAddressAsString(), serverConn.getPlayer(), + requestedForwardingVersion); LoginPluginResponse response = new LoginPluginResponse(packet.getId(), true, forwardingData); mc.write(response); @@ -107,17 +109,17 @@ public boolean handle(LoginPluginMessage packet) { final byte[] contents = ByteBufUtil.getBytes(packet.content()); final MinecraftChannelIdentifier identifier = MinecraftChannelIdentifier - .from(packet.getChannel()); + .from(packet.getChannel()); this.server.getEventManager().fire(new ServerLoginPluginMessageEvent(serverConn, identifier, - contents, packet.getId())) - .thenAcceptAsync(event -> { - if (event.getResult().isAllowed()) { - mc.write(new LoginPluginResponse(packet.getId(), true, Unpooled - .wrappedBuffer(event.getResult().getResponse()))); - } else { - mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); - } - }, mc.eventLoop()); + contents, packet.getId())) + .thenAcceptAsync(event -> { + if (event.getResult().isAllowed()) { + mc.write(new LoginPluginResponse(packet.getId(), true, Unpooled + .wrappedBuffer(event.getResult().getResponse()))); + } else { + mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); + } + }, mc.eventLoop()); } return true; } @@ -138,9 +140,9 @@ public boolean handle(SetCompression packet) { @Override public boolean handle(ServerLoginSuccess packet) { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN - && !informationForwarded) { + && !informationForwarded) { resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE, - serverConn.getServer())); + serverConn.getServer())); serverConn.disconnect(); return true; } @@ -150,10 +152,23 @@ public boolean handle(ServerLoginSuccess packet) { // Move into the PLAY phase. MinecraftConnection smc = serverConn.ensureConnected(); - smc.setState(StateRegistry.PLAY); + if (smc.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { + smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture)); + } else { + CompletableFuture switchFuture; + if (serverConn.getPlayer().getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler) { + switchFuture = ((ClientPlaySessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler()) + .doSwitch(); + } else { + switchFuture = CompletableFuture.completedFuture(null); + } + switchFuture.thenAcceptAsync((unused) -> { + smc.write(new LoginAcknowledged()); + //Sync backend + smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); + }, smc.eventLoop()); + } - // Switch to the transition handler. - smc.setSessionHandler(new TransitionSessionHandler(server, serverConn, resultFuture)); return true; } @@ -166,14 +181,14 @@ public void exception(Throwable throwable) { public void disconnected() { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) { resultFuture.completeExceptionally( - new QuietRuntimeException("The connection to the remote server was unexpectedly closed.\n" - + "This is usually because the remote server does not have BungeeCord IP forwarding " - + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " - + "for instructions on how to configure player info forwarding correctly.") + new QuietRuntimeException("The connection to the remote server was unexpectedly closed.\n" + + "This is usually because the remote server does not have BungeeCord IP forwarding " + + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " + + "for instructions on how to configure player info forwarding correctly.") ); } else { resultFuture.completeExceptionally( - new QuietRuntimeException("The connection to the remote server was unexpectedly closed.") + new QuietRuntimeException("The connection to the remote server was unexpectedly closed.") ); } } @@ -184,8 +199,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) if (requested > VelocityConstants.MODERN_FORWARDING_DEFAULT) { if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { return requested >= VelocityConstants.MODERN_LAZY_SESSION - ? VelocityConstants.MODERN_LAZY_SESSION - : VelocityConstants.MODERN_FORWARDING_DEFAULT; + ? VelocityConstants.MODERN_LAZY_SESSION + : VelocityConstants.MODERN_FORWARDING_DEFAULT; } if (player.getIdentifiedKey() != null) { // No enhanced switch on java 11 @@ -195,8 +210,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) // Since V2 is not backwards compatible we have to throw the key if v2 and requested is v1 case LINKED_V2: return requested >= VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 - ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 - : VelocityConstants.MODERN_FORWARDING_DEFAULT; + ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 + : VelocityConstants.MODERN_FORWARDING_DEFAULT; default: return VelocityConstants.MODERN_FORWARDING_DEFAULT; } @@ -208,7 +223,7 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) } private static ByteBuf createForwardingData(byte[] hmacSecret, String address, - ConnectedPlayer player, int requestedVersion) { + ConnectedPlayer player, int requestedVersion) { ByteBuf forwarded = Unpooled.buffer(2048); try { int actualVersion = findForwardingVersion(requestedVersion, player); @@ -222,7 +237,7 @@ private static ByteBuf createForwardingData(byte[] hmacSecret, String address, // This serves as additional redundancy. The key normally is stored in the // login start to the server, but some setups require this. if (actualVersion >= VelocityConstants.MODERN_FORWARDING_WITH_KEY - && actualVersion < VelocityConstants.MODERN_LAZY_SESSION) { + && actualVersion < VelocityConstants.MODERN_LAZY_SESSION) { IdentifiedKey key = player.getIdentifiedKey(); assert key != null; ProtocolUtils.writePlayerKey(forwarded, key); @@ -258,4 +273,4 @@ private static ByteBuf createForwardingData(byte[] hmacSecret, String address, throw new AssertionError(e); } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 5fe6886dca..19edba1476 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -32,10 +32,12 @@ import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; +import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.JoinGame; import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import java.io.IOException; import java.util.concurrent.CompletableFuture; import org.apache.logging.log4j.LogManager; @@ -61,13 +63,13 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { * @param resultFuture the result future */ TransitionSessionHandler(VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; this.bungeecordMessageResponder = new BungeeCordMessageResponder(server, - serverConn.getPlayer()); + serverConn.getPlayer()); } @Override @@ -109,48 +111,49 @@ public boolean handle(JoinGame packet) { // The goods are in hand! We got JoinGame. Let's transition completely to the new state. smc.setAutoReading(false); server.getEventManager() - .fire(new ServerConnectedEvent(player, serverConn.getServer(), previousServer)) - .thenRunAsync(() -> { - // Make sure we can still transition (player might have disconnected here). - if (!serverConn.isActive()) { - // Connection is obsolete. - serverConn.disconnect(); - return; - } - - // Change the client to use the ClientPlaySessionHandler if required. - ClientPlaySessionHandler playHandler; - if (player.getConnection().getSessionHandler() instanceof ClientPlaySessionHandler) { - playHandler = (ClientPlaySessionHandler) player.getConnection().getSessionHandler(); - } else { - playHandler = new ClientPlaySessionHandler(server, player); - player.getConnection().setSessionHandler(playHandler); - } - playHandler.handleBackendJoinGame(packet, serverConn); - - // Set the new play session handler for the server. We will have nothing more to do - // with this connection once this task finishes up. - smc.setSessionHandler(new BackendPlaySessionHandler(server, serverConn)); - - // Clean up disabling auto-read while the connected event was being processed. - smc.setAutoReading(true); - - // Now set the connected server. - serverConn.getPlayer().setConnectedServer(serverConn); - - // We're done! :) - server.getEventManager().fireAndForget(new ServerPostConnectEvent(player, - previousServer)); - resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer())); - }, smc.eventLoop()) - .exceptionally(exc -> { - logger.error("Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - player.getUsername(), exc); - player.disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - resultFuture.completeExceptionally(exc); - return null; - }); + .fire(new ServerConnectedEvent(player, serverConn.getServer(), previousServer)) + .thenRunAsync(() -> { + // Make sure we can still transition (player might have disconnected here). + if (!serverConn.isActive()) { + // Connection is obsolete. + serverConn.disconnect(); + return; + } + + // Change the client to use the ClientPlaySessionHandler if required. + ClientPlaySessionHandler playHandler; + if (player.getConnection().setActiveSessionHandler(StateRegistry.PLAY)) { + playHandler = (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); + } else { + playHandler = new ClientPlaySessionHandler(server, player); + player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, playHandler); + } + assert playHandler != null; + playHandler.handleBackendJoinGame(packet, serverConn); + + // Set the new play session handler for the server. We will have nothing more to do + // with this connection once this task finishes up. + smc.setActiveSessionHandler(StateRegistry.PLAY, new BackendPlaySessionHandler(server, serverConn)); + + // Clean up disabling auto-read while the connected event was being processed. + smc.setAutoReading(true); + + // Now set the connected server. + serverConn.getPlayer().setConnectedServer(serverConn); + + // We're done! :) + server.getEventManager().fireAndForget(new ServerPostConnectEvent(player, + previousServer)); + resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer())); + }, smc.eventLoop()) + .exceptionally(exc -> { + logger.error("Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + player.getUsername(), exc); + player.disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + resultFuture.completeExceptionally(exc); + return null; + }); return true; } @@ -163,9 +166,9 @@ public boolean handle(Disconnect packet) { // If we were in the middle of the Forge handshake, it is not safe to proceed. We must kick // the client. if (connection.getType() == ConnectionTypes.LEGACY_FORGE - && !serverConn.getPhase().consideredComplete()) { + && !serverConn.getPhase().consideredComplete()) { resultFuture.complete(ConnectionRequestResults.forUnsafeDisconnect(packet, - serverConn.getServer())); + serverConn.getServer())); } else { resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); } @@ -179,6 +182,12 @@ public boolean handle(PluginMessage packet) { return true; } + if (PluginMessageUtil.isRegister(packet)) { + serverConn.getPlayer().getKnownChannels().addAll(PluginMessageUtil.getChannels(packet)); + } else if (PluginMessageUtil.isUnregister(packet)) { + serverConn.getPlayer().getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet)); + } + // We always need to handle plugin messages, for Forge compatibility. if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) { // Handled, but check the server connection phase. @@ -190,7 +199,7 @@ public boolean handle(PluginMessage packet) { // Tell the player that we're leaving and we just aren't coming back. existingConnection.getPhase().onDepartForNewServer(existingConnection, - serverConn.getPlayer()); + serverConn.getPlayer()); } } return true; @@ -203,6 +212,6 @@ public boolean handle(PluginMessage packet) { @Override public void disconnected() { resultFuture - .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index a2300b9780..edd84eda69 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -34,6 +34,7 @@ import com.velocitypowered.proxy.connection.ConnectionTypes; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.StateRegistry; @@ -80,8 +81,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, * @param server the Velocity proxy instance */ public VelocityServerConnection(VelocityRegisteredServer registeredServer, - @Nullable VelocityRegisteredServer previousServer, - ConnectedPlayer proxyPlayer, VelocityServer server) { + @Nullable VelocityRegisteredServer previousServer, + ConnectedPlayer proxyPlayer, VelocityServer server) { this.registeredServer = registeredServer; this.previousServer = previousServer; this.proxyPlayer = proxyPlayer; @@ -99,27 +100,30 @@ public CompletableFuture connect() { // Note: we use the event loop for the connection the player is on. This reduces context // switches. server.createBootstrap(proxyPlayer.getConnection().eventLoop()) - .handler(server.getBackendChannelInitializer()) - .connect(registeredServer.getServerInfo().getAddress()) - .addListener((ChannelFutureListener) future -> { - if (future.isSuccess()) { - connection = new MinecraftConnection(future.channel(), server); - connection.setAssociation(VelocityServerConnection.this); - future.channel().pipeline().addLast(HANDLER, connection); - - // Kick off the connection process - connection.setSessionHandler( - new LoginSessionHandler(server, VelocityServerConnection.this, result)); - - // Set the connection phase, which may, for future forge (or whatever), be determined - // at this point already - connectionPhase = connection.getType().getInitialBackendPhase(); - startHandshake(); - } else { - // Complete the result immediately. ConnectedPlayer will reset the in-flight connection. - result.completeExceptionally(future.cause()); - } - }); + .handler(server.getBackendChannelInitializer()) + .connect(registeredServer.getServerInfo().getAddress()) + .addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + connection = new MinecraftConnection(future.channel(), server); + connection.setAssociation(VelocityServerConnection.this); + future.channel().pipeline().addLast(HANDLER, connection); + + // Kick off the connection process + if (!connection.setActiveSessionHandler(StateRegistry.HANDSHAKE)) { + MinecraftSessionHandler handler = new LoginSessionHandler(server, VelocityServerConnection.this, result); + connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, handler); + connection.addSessionHandler(StateRegistry.LOGIN, handler); + } + + // Set the connection phase, which may, for future forge (or whatever), be determined + // at this point already + connectionPhase = connection.getType().getInitialBackendPhase(); + startHandshake(); + } else { + // Complete the result immediately. ConnectedPlayer will reset the in-flight connection. + result.completeExceptionally(future.cause()); + } + }); return result; } @@ -138,16 +142,16 @@ private String createLegacyForwardingAddress(UnaryOperator> prope // separated by \0 (the null byte). In order, you send the original host, the player's IP, their // UUID (undashed), and if you are in online-mode, their login properties (from Mojang). StringBuilder data = new StringBuilder() - .append(proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString()) - .append('\0') - .append(getPlayerRemoteAddressAsString()) - .append('\0') - .append(proxyPlayer.getGameProfile().getUndashedId()) - .append('\0'); + .append(proxyPlayer.getVirtualHost() + .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + .getHostString()) + .append('\0') + .append(getPlayerRemoteAddressAsString()) + .append('\0') + .append(proxyPlayer.getGameProfile().getUndashedId()) + .append('\0'); GENERAL_GSON - .toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); + .toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); return data.toString(); } @@ -158,11 +162,11 @@ private String createLegacyForwardingAddress() { private String createBungeeGuardForwardingAddress(byte[] forwardingSecret) { // Append forwarding secret as a BungeeGuard token. Property property = new Property("bungeeguard-token", - new String(forwardingSecret, StandardCharsets.UTF_8), ""); + new String(forwardingSecret, StandardCharsets.UTF_8), ""); return createLegacyForwardingAddress(properties -> ImmutableList.builder() - .addAll(properties) - .add(property) - .build()); + .addAll(properties) + .add(property) + .build()); } private void startHandshake() { @@ -172,8 +176,8 @@ private void startHandshake() { // Initiate the handshake. ProtocolVersion protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); String playerVhost = proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString(); + .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + .getHostString(); Handshake handshake = new Handshake(); handshake.setNextStatus(StateRegistry.LOGIN_ID); @@ -193,9 +197,9 @@ private void startHandshake() { mc.delayedWrite(handshake); mc.setProtocolVersion(protocolVersion); - mc.setState(StateRegistry.LOGIN); + mc.setActiveSessionHandler(StateRegistry.LOGIN); if (proxyPlayer.getIdentifiedKey() == null - && proxyPlayer.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { + && proxyPlayer.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { mc.delayedWrite(new ServerLogin(proxyPlayer.getUsername(), proxyPlayer.getUniqueId())); } else { mc.delayedWrite(new ServerLogin(proxyPlayer.getUsername(), proxyPlayer.getIdentifiedKey())); @@ -254,7 +258,7 @@ public void disconnect() { @Override public String toString() { return "[server connection] " + proxyPlayer.getGameProfile().getName() + " -> " - + registeredServer.getServerInfo().getName(); + + registeredServer.getServerInfo().getName(); } @Override @@ -312,7 +316,7 @@ public Map getPendingPings() { */ public boolean isActive() { return connection != null && !connection.isClosed() && !gracefulDisconnect - && proxyPlayer.isActive(); + && proxyPlayer.isActive(); } /** @@ -351,4 +355,4 @@ public CompoundBinaryTag getActiveDimensionRegistry() { public void setActiveDimensionRegistry(CompoundBinaryTag activeDimensionRegistry) { this.activeDimensionRegistry = activeDimensionRegistry; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index f68d3bb595..79ff40c362 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -26,6 +26,7 @@ import com.velocitypowered.api.event.permission.PermissionsSetupEvent; import com.velocitypowered.api.event.player.GameProfileRequestEvent; import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent; +import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.permission.PermissionFunction; import com.velocitypowered.api.proxy.crypto.IdentifiedKey; import com.velocitypowered.api.proxy.server.RegisteredServer; @@ -38,6 +39,7 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.crypto.IdentifiedKeyImpl; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; import com.velocitypowered.proxy.protocol.packet.SetCompression; import io.netty.buffer.ByteBuf; @@ -64,9 +66,10 @@ public class AuthSessionHandler implements MinecraftSessionHandler { private GameProfile profile; private @MonotonicNonNull ConnectedPlayer connectedPlayer; private final boolean onlineMode; + private State loginState = State.START; // 1.20.2+ AuthSessionHandler(VelocityServer server, LoginInboundConnection inbound, - GameProfile profile, boolean onlineMode) { + GameProfile profile, boolean onlineMode) { this.server = Preconditions.checkNotNull(server, "server"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.profile = Preconditions.checkNotNull(profile, "profile"); @@ -78,9 +81,9 @@ public class AuthSessionHandler implements MinecraftSessionHandler { public void activated() { // Some connection types may need to alter the game profile. profile = mcConnection.getType().addGameProfileTokensIfRequired(profile, - server.getConfiguration().getPlayerInfoForwardingMode()); + server.getConfiguration().getPlayerInfoForwardingMode()); GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile, - onlineMode); + onlineMode); final GameProfile finalProfile = profile; server.getEventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> { @@ -91,43 +94,43 @@ public void activated() { // Initiate a regular connection and move over to it. ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(), - mcConnection, inbound.getVirtualHost().orElse(null), onlineMode, - inbound.getIdentifiedKey()); + mcConnection, inbound.getVirtualHost().orElse(null), onlineMode, + inbound.getIdentifiedKey()); this.connectedPlayer = player; if (!server.canRegisterConnection(player)) { player.disconnect0(Component.translatable("velocity.error.already-connected-proxy", - NamedTextColor.RED), true); + NamedTextColor.RED), true); return CompletableFuture.completedFuture(null); } logger.info("{} has connected", player); return server.getEventManager() - .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) - .thenAcceptAsync(event -> { - if (!mcConnection.isClosed()) { - // wait for permissions to load, then set the players permission function - final PermissionFunction function = event.createFunction(player); - if (function == null) { - logger.error( - "A plugin permission provider {} provided an invalid permission function" - + " for player {}. This is a bug in the plugin, not in Velocity. Falling" - + " back to the default permission function.", - event.getProvider().getClass().getName(), - player.getUsername()); - } else { - player.setPermissionFunction(function); - } - completeLoginProtocolPhaseAndInitialize(player); - } - }, mcConnection.eventLoop()); + .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) + .thenAcceptAsync(event -> { + if (!mcConnection.isClosed()) { + // wait for permissions to load, then set the players permission function + final PermissionFunction function = event.createFunction(player); + if (function == null) { + logger.error( + "A plugin permission provider {} provided an invalid permission function" + + " for player {}. This is a bug in the plugin, not in Velocity. Falling" + + " back to the default permission function.", + event.getProvider().getClass().getName(), + player.getUsername()); + } else { + player.setPermissionFunction(function); + } + startLoginCompletion(player); + } + }, mcConnection.eventLoop()); }, mcConnection.eventLoop()).exceptionally((ex) -> { logger.error("Exception during connection of {}", finalProfile, ex); return null; }); } - private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { + private void startLoginCompletion(ConnectedPlayer player) { int threshold = server.getConfiguration().getCompressionThreshold(); if (threshold >= 0 && mcConnection.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { mcConnection.write(new SetCompression(threshold)); @@ -148,7 +151,7 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { if (!unlinkedKey.internalAddHolder(player.getUniqueId())) { if (onlineMode) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key")); + Component.translatable("multiplayer.disconnect.invalid_public_key")); return; } else { logger.warn("Key for player " + player.getUsername() + " could not be verified!"); @@ -160,7 +163,7 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { } else { if (!Objects.equals(playerKey.getSignatureHolder(), playerUniqueId)) { logger.warn("UUID for Player " + player.getUsername() + " mismatches! " - + "Chat/Commands signatures will not work correctly for this player!"); + + "Chat/Commands signatures will not work correctly for this player!"); } } } @@ -171,58 +174,82 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { success.setUuid(playerUniqueId); mcConnection.write(success); + if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { + completeLoginProtocolPhaseAndInitialize(player); + } else { + loginState = State.SUCCESS_SENT; + } + } + + @Override + public boolean handle(LoginAcknowledged packet) { + if (loginState != State.SUCCESS_SENT) { + inbound.disconnect( + Component.translatable("multiplayer.disconnect.invalid_player_data")); + } else { + loginState = State.ACKNOWLEDGED; + completeLoginProtocolPhaseAndInitialize(connectedPlayer); + } + return true; + } + + private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { mcConnection.setAssociation(player); - mcConnection.setState(StateRegistry.PLAY); server.getEventManager().fire(new LoginEvent(player)) - .thenAcceptAsync(event -> { - if (mcConnection.isClosed()) { - // The player was disconnected - server.getEventManager().fireAndForget(new DisconnectEvent(player, - DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); - return; - } + .thenAcceptAsync(event -> { + if (mcConnection.isClosed()) { + // The player was disconnected + server.getEventManager().fireAndForget(new DisconnectEvent(player, + DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); + return; + } - Optional reason = event.getResult().getReasonComponent(); - if (reason.isPresent()) { - player.disconnect0(reason.get(), true); - } else { - if (!server.registerConnection(player)) { - player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), - true); - return; - } + Optional reason = event.getResult().getReasonComponent(); + if (reason.isPresent()) { + player.disconnect0(reason.get(), true); + } else { + if (!server.registerConnection(player)) { + player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), + true); + return; + } - mcConnection.setSessionHandler(new InitialConnectSessionHandler(player, server)); - server.getEventManager().fire(new PostLoginEvent(player)) - .thenCompose((ignored) -> connectToInitialServer(player)) - .exceptionally((ex) -> { - logger.error("Exception while connecting {} to initial server", player, ex); - return null; - }); - } - }, mcConnection.eventLoop()) - .exceptionally((ex) -> { - logger.error("Exception while completing login initialisation phase for {}", player, ex); - return null; - }); + if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) > 0) { + mcConnection.setActiveSessionHandler(StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); + } else { + mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); + } + + server.getEventManager().fire(new PostLoginEvent(player)) + .thenCompose((ignored) -> connectToInitialServer(player)) + .exceptionally((ex) -> { + logger.error("Exception while connecting {} to initial server", player, ex); + return null; + }); + } + }, mcConnection.eventLoop()) + .exceptionally((ex) -> { + logger.error("Exception while completing login initialisation phase for {}", player, ex); + return null; + }); } private CompletableFuture connectToInitialServer(ConnectedPlayer player) { Optional initialFromConfig = player.getNextServerToTry(); PlayerChooseInitialServerEvent event = new PlayerChooseInitialServerEvent(player, - initialFromConfig.orElse(null)); + initialFromConfig.orElse(null)); return server.getEventManager().fire(event) - .thenRunAsync(() -> { - Optional toTry = event.getInitialServer(); - if (!toTry.isPresent()) { - player.disconnect0(Component.translatable("velocity.error.no-available-servers", - NamedTextColor.RED), true); - return; - } - player.createConnectionRequest(toTry.get()).fireAndForget(); - }, mcConnection.eventLoop()); + .thenRunAsync(() -> { + Optional toTry = event.getInitialServer(); + if (!toTry.isPresent()) { + player.disconnect0(Component.translatable("velocity.error.no-available-servers", + NamedTextColor.RED), true); + return; + } + player.createConnectionRequest(toTry.get()).fireAndForget(); + }, mcConnection.eventLoop()); } @Override @@ -237,4 +264,10 @@ public void disconnected() { } this.inbound.cleanup(); } -} + + static enum State { + START, + SUCCESS_SENT, + ACKNOWLEDGED + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java new file mode 100644 index 0000000000..1c9a613bc2 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.connection.client; + +import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.MinecraftConnection; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.KeepAlive; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; +import io.netty.buffer.ByteBuf; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.concurrent.CompletableFuture; + +public class ClientConfigSessionHandler implements MinecraftSessionHandler { + + private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class); + private final VelocityServer server; + private final ConnectedPlayer player; + + private CompletableFuture configSwitchFuture; + + + /** + * Constructs a client config session handler. + * + * @param server the Velocity server instance + * @param player the player + */ + public ClientConfigSessionHandler(VelocityServer server, ConnectedPlayer player) { + this.server = server; + this.player = player; + + } + + @Override + public void activated() { + configSwitchFuture = new CompletableFuture<>(); + } + + @Override + public void deactivated() { + + } + + @Override + public boolean handle(KeepAlive packet) { + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection != null) { + Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId()); + if (sentTime != null) { + MinecraftConnection smc = serverConnection.getConnection(); + if (smc != null) { + player.setPing(System.currentTimeMillis() - sentTime); + smc.write(packet); + } + } + } + return true; + } + + + @Override + public boolean handle(PluginMessage packet) { + + + return true; + } + + @Override + public boolean handle(ResourcePackResponse packet) { + + + return true; + } + + @Override + public boolean handle(FinishedUpdate packet) { + player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, + new ClientPlaySessionHandler(server, player)); + + configSwitchFuture.complete(null); + + return true; + } + + @Override + public void handleGeneric(MinecraftPacket packet) { + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection == null) { + // No server connection yet, probably transitioning. + return; + } + + MinecraftConnection smc = serverConnection.getConnection(); + if (smc != null && serverConnection.getPhase().consideredComplete()) { + if (packet instanceof PluginMessage) { + ((PluginMessage) packet).retain(); + } + smc.write(packet); + } + } + + @Override + public void handleUnknown(ByteBuf buf) { + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection == null) { + // No server connection yet, probably transitioning. + return; + } + + MinecraftConnection smc = serverConnection.getConnection(); + if (smc != null && !smc.isClosed() && serverConnection.getPhase().consideredComplete()) { + smc.write(buf.retain()); + } + } + + @Override + public void disconnected() { + player.teardown(); + } + + @Override + public void exception(Throwable throwable) { + player.disconnect( + Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + } + + public CompletableFuture handleBackendFinishUpdate(VelocityServerConnection serverConn) { + serverConn.getConnection().write(new FinishedUpdate()); + return configSwitchFuture; + } + +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 8993d9b246..fd5a90625e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -17,9 +17,7 @@ package com.velocitypowered.proxy.connection.client; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16; -import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; +import static com.velocitypowered.api.network.ProtocolVersion.*; import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.constructChannelsPacket; import com.google.common.collect.ImmutableList; @@ -67,6 +65,7 @@ import com.velocitypowered.proxy.protocol.packet.chat.session.SessionCommandHandler; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.util.CharacterUtil; @@ -80,6 +79,7 @@ import java.util.List; import java.util.Queue; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentLinkedQueue; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -105,6 +105,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { private final CommandHandler commandHandler; private final ChatTimeKeeper timeKeeper = new ChatTimeKeeper(); + private CompletableFuture configSwitchFuture; + /** * Constructs a client play session handler. * @@ -143,7 +145,7 @@ private boolean updateTimeKeeper(@Nullable Instant instant) { private boolean validateChat(String message) { if (CharacterUtil.containsIllegalCharacters(message)) { player.disconnect( - Component.translatable("velocity.error.illegal-chat-characters", NamedTextColor.RED)); + Component.translatable("velocity.error.illegal-chat-characters", NamedTextColor.RED)); return false; } return true; @@ -151,11 +153,13 @@ private boolean validateChat(String message) { @Override public void activated() { + configSwitchFuture = new CompletableFuture<>(); Collection channels = server.getChannelRegistrar() - .getChannelsForProtocol(player.getProtocolVersion()); + .getChannelsForProtocol(player.getProtocolVersion()); if (!channels.isEmpty()) { PluginMessage register = constructChannelsPacket(player.getProtocolVersion(), channels); player.getConnection().write(register); + player.getKnownChannels().addAll(channels); } } @@ -282,18 +286,19 @@ public boolean handle(PluginMessage packet) { VelocityServerConnection serverConn = (player.getConnectedServer() == null && packet.getChannel().equals( - LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) - ? player.getConnectionInFlight() : player.getConnectedServer(); + LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) + ? player.getConnectionInFlight() : player.getConnectedServer(); MinecraftConnection backendConn = serverConn != null ? serverConn.getConnection() : null; if (serverConn != null && backendConn != null) { if (backendConn.getState() != StateRegistry.PLAY) { logger.warn( - "A plugin message was received while the backend server was not " - + "ready. Channel: {}. Packet discarded.", - packet.getChannel()); + "A plugin message was received while the backend server was not " + + "ready. Channel: {}. Packet discarded.", + packet.getChannel()); } else if (PluginMessageUtil.isRegister(packet)) { List channels = PluginMessageUtil.getChannels(packet); + player.getKnownChannels().addAll(channels); List channelIdentifiers = new ArrayList<>(); for (String channel : channels) { try { @@ -303,18 +308,19 @@ public boolean handle(PluginMessage packet) { } } server.getEventManager() - .fireAndForget( - new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); + .fireAndForget( + new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isUnregister(packet)) { + player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet)); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isMcBrand(packet)) { String brand = PluginMessageUtil.readBrandMessage(packet.content()); server.getEventManager().fireAndForget(new PlayerClientBrandEvent(player, brand)); player.setClientBrand(brand); backendConn.write( - PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), - player.getProtocolVersion())); + PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), + player.getProtocolVersion())); } else if (BungeeCordMessageResponder.isBungeeCordMessage(packet)) { return true; } else { @@ -332,7 +338,7 @@ public boolean handle(PluginMessage packet) { if (id == null) { // We don't have any plugins listening on this channel, process the packet now. if (!player.getPhase().consideredComplete() || !serverConn.getPhase() - .consideredComplete()) { + .consideredComplete()) { // The client is trying to send messages too early. This is primarily caused by mods, // but further aggravated by Velocity. To work around these issues, we will queue any // non-FML handshake messages to be sent once the FML handshake has completed or the @@ -351,9 +357,9 @@ public boolean handle(PluginMessage packet) { server.getEventManager().fire(event).thenAcceptAsync(pme -> { if (pme.getResult().isAllowed()) { PluginMessage message = new PluginMessage(packet.getChannel(), - Unpooled.wrappedBuffer(copy)); + Unpooled.wrappedBuffer(copy)); if (!player.getPhase().consideredComplete() || !serverConn.getPhase() - .consideredComplete()) { + .consideredComplete()) { // We're still processing the connection (see above), enqueue the packet for now. loginPluginMessages.add(message.retain()); } else { @@ -377,6 +383,14 @@ public boolean handle(ResourcePackResponse packet) { return player.onResourcePackResponse(packet.getStatus()); } + @Override + public boolean handle(StartUpdate packet) { + //Complete client switch + player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG); + configSwitchFuture.complete(null); + return true; + } + @Override public void handleGeneric(MinecraftPacket packet) { VelocityServerConnection serverConnection = player.getConnectedServer(); @@ -416,7 +430,7 @@ public void disconnected() { @Override public void exception(Throwable throwable) { player.disconnect( - Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); } @Override @@ -440,6 +454,26 @@ public void writabilityChanged() { } } + public CompletableFuture doSwitch() { + VelocityServerConnection existingConnection = player.getConnectedServer(); + + if (existingConnection != null) { + // Shut down the existing server connection. + player.setConnectedServer(null); + existingConnection.disconnect(); + + // Send keep alive to try to avoid timeouts + player.sendKeepAlive(); + + // Reset Tablist header and footer to prevent desync + player.clearHeaderAndFooter(); + } + + player.getConnection().write(new StartUpdate()); + return configSwitchFuture; + } + + /** * Handles the {@code JoinGame} packet. This function is responsible for handling the client-side * switching servers in Velocity. @@ -482,12 +516,10 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de } serverBossBars.clear(); - // Tell the server about the proxy's plugin message channels. + // Tell the server about this client's plugin message channels. ProtocolVersion serverVersion = serverMc.getProtocolVersion(); - final Collection channels = server.getChannelRegistrar() - .getChannelsForProtocol(serverMc.getProtocolVersion()); - if (!channels.isEmpty()) { - serverMc.delayedWrite(constructChannelsPacket(serverVersion, channels)); + if (!player.getKnownChannels().isEmpty() && serverVersion.compareTo(MINECRAFT_1_20_2) < 0) { + serverMc.delayedWrite(constructChannelsPacket(serverVersion, player.getKnownChannels())); } // If we had plugin messages queued during login/FML handshake, send them now. @@ -499,8 +531,8 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de // Clear any title from the previous server. if (player.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { player.getConnection().delayedWrite( - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET, - player.getProtocolVersion())); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET, + player.getProtocolVersion())); } // Flush everything @@ -571,35 +603,35 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { } server.getCommandManager().offerBrigadierSuggestions(player, command) - .thenAcceptAsync(suggestions -> { - if (suggestions.isEmpty()) { - return; - } + .thenAcceptAsync(suggestions -> { + if (suggestions.isEmpty()) { + return; + } - List offers = new ArrayList<>(); - for (Suggestion suggestion : suggestions.getList()) { - String offer = suggestion.getText(); - Component tooltip = null; - if (suggestion.getTooltip() != null - && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { - tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); - } - offers.add(new Offer(offer, tooltip)); - } - int startPos = packet.getCommand().lastIndexOf(' ') + 1; - if (startPos > 0) { - TabCompleteResponse resp = new TabCompleteResponse(); - resp.setTransactionId(packet.getTransactionId()); - resp.setStart(startPos); - resp.setLength(packet.getCommand().length() - startPos); - resp.getOffers().addAll(offers); - player.getConnection().write(resp); - } - }, player.getConnection().eventLoop()).exceptionally((ex) -> { - logger.error("Exception while handling command tab completion for player {} executing {}", - player, command, ex); - return null; - }); + List offers = new ArrayList<>(); + for (Suggestion suggestion : suggestions.getList()) { + String offer = suggestion.getText(); + Component tooltip = null; + if (suggestion.getTooltip() != null + && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { + tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); + } + offers.add(new Offer(offer, tooltip)); + } + int startPos = packet.getCommand().lastIndexOf(' ') + 1; + if (startPos > 0) { + TabCompleteResponse resp = new TabCompleteResponse(); + resp.setTransactionId(packet.getTransactionId()); + resp.setStart(startPos); + resp.setLength(packet.getCommand().length() - startPos); + resp.getOffers().addAll(offers); + player.getConnection().write(resp); + } + }, player.getConnection().eventLoop()).exceptionally((ex) -> { + logger.error("Exception while handling command tab completion for player {} executing {}", + player, command, ex); + return null; + }); return true; // Sorry, handler; we're just gonna have to lie to you here. } @@ -634,36 +666,36 @@ public void handleTabCompleteResponse(TabCompleteResponse response) { private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteResponse response) { String command = request.getCommand().substring(1); server.getCommandManager().offerBrigadierSuggestions(player, command) - .thenAcceptAsync(offers -> { - boolean legacy = player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0; - try { - for (Suggestion suggestion : offers.getList()) { - String offer = suggestion.getText(); - offer = legacy && !offer.startsWith("/") ? "/" + offer : offer; - if (legacy && offer.startsWith(command)) { - offer = offer.substring(command.length()); - } - Component tooltip = null; - if (suggestion.getTooltip() != null - && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { - tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); + .thenAcceptAsync(offers -> { + boolean legacy = player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0; + try { + for (Suggestion suggestion : offers.getList()) { + String offer = suggestion.getText(); + offer = legacy && !offer.startsWith("/") ? "/" + offer : offer; + if (legacy && offer.startsWith(command)) { + offer = offer.substring(command.length()); + } + Component tooltip = null; + if (suggestion.getTooltip() != null + && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { + tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); + } + response.getOffers().add(new Offer(offer, tooltip)); + } + response.getOffers().sort(null); + player.getConnection().write(response); + } catch (Exception e) { + logger.error("Unable to provide tab list completions for {} for command '{}'", + player.getUsername(), command, + e); } - response.getOffers().add(new Offer(offer, tooltip)); - } - response.getOffers().sort(null); - player.getConnection().write(response); - } catch (Exception e) { - logger.error("Unable to provide tab list completions for {} for command '{}'", - player.getUsername(), command, - e); - } - }, player.getConnection().eventLoop()).exceptionally((ex) -> { - logger.error( - "Exception while finishing command tab completion, with request {} and response {}", - request, - response, ex); - return null; - }); + }, player.getConnection().eventLoop()).exceptionally((ex) -> { + logger.error( + "Exception while finishing command tab completion, with request {} and response {}", + request, + response, ex); + return null; + }); } private void finishRegularTabComplete(TabCompleteRequest request, TabCompleteResponse response) { @@ -672,19 +704,19 @@ private void finishRegularTabComplete(TabCompleteRequest request, TabCompleteRes offers.add(offer.getText()); } server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), offers)) - .thenAcceptAsync(e -> { - response.getOffers().clear(); - for (String s : e.getSuggestions()) { - response.getOffers().add(new Offer(s)); - } - player.getConnection().write(response); - }, player.getConnection().eventLoop()).exceptionally((ex) -> { - logger.error( - "Exception while finishing regular tab completion, with request {} and response{}", - request, - response, ex); - return null; - }); + .thenAcceptAsync(e -> { + response.getOffers().clear(); + for (String s : e.getSuggestions()) { + response.getOffers().add(new Offer(s)); + } + player.getConnection().write(response); + }, player.getConnection().eventLoop()).exceptionally((ex) -> { + logger.error( + "Exception while finishing regular tab completion, with request {} and response{}", + request, + response, ex); + return null; + }); } /** @@ -703,4 +735,4 @@ public void flushQueuedMessages() { } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 90464c9c8d..feecd00463 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -77,10 +77,12 @@ import com.velocitypowered.proxy.tablist.VelocityTabListLegacy; import com.velocitypowered.proxy.util.ClosestLocaleMatcher; import com.velocitypowered.proxy.util.DurationUtils; +import com.velocitypowered.proxy.util.collect.CappedSet; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import java.net.InetSocketAddress; import java.util.ArrayDeque; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -119,16 +121,16 @@ * Represents a player that is connected to the proxy. */ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, KeyIdentifiable, - VelocityInboundConnection { + VelocityInboundConnection { private static final int MAX_PLUGIN_CHANNELS = 1024; private static final PlainTextComponentSerializer PASS_THRU_TRANSLATE = - PlainTextComponentSerializer.builder() - .flattener(ComponentFlattener.basic().toBuilder() - .mapper(KeybindComponent.class, c -> "") - .mapper(TranslatableComponent.class, TranslatableComponent::key) - .build()) - .build(); + PlainTextComponentSerializer.builder() + .flattener(ComponentFlattener.basic().toBuilder() + .mapper(KeybindComponent.class, c -> "") + .mapper(TranslatableComponent.class, TranslatableComponent::key) + .build()) + .build(); static final PermissionProvider DEFAULT_PERMISSIONS = s -> PermissionFunction.ALWAYS_UNDEFINED; private static final Logger logger = LogManager.getLogger(ConnectedPlayer.class); @@ -153,6 +155,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, private final InternalTabList tabList; private final VelocityServer server; private ClientConnectionPhase connectionPhase; + private final Collection knownChannels; private final CompletableFuture teardownFuture = new CompletableFuture<>(); private @MonotonicNonNull List serversToTry = null; private @MonotonicNonNull Boolean previousResourceResponse; @@ -160,13 +163,13 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, private @Nullable ResourcePackInfo pendingResourcePack; private @Nullable ResourcePackInfo appliedResourcePack; private final @NotNull Pointers pointers = Player.super.pointers().toBuilder() - .withDynamic(Identity.UUID, this::getUniqueId) - .withDynamic(Identity.NAME, this::getUsername) - .withDynamic(Identity.DISPLAY_NAME, () -> Component.text(this.getUsername())) - .withDynamic(Identity.LOCALE, this::getEffectiveLocale) - .withStatic(PermissionChecker.POINTER, getPermissionChecker()) - .withStatic(FacetPointers.TYPE, Type.PLAYER) - .build(); + .withDynamic(Identity.UUID, this::getUniqueId) + .withDynamic(Identity.NAME, this::getUsername) + .withDynamic(Identity.DISPLAY_NAME, () -> Component.text(this.getUsername())) + .withDynamic(Identity.LOCALE, this::getEffectiveLocale) + .withStatic(PermissionChecker.POINTER, getPermissionChecker()) + .withStatic(FacetPointers.TYPE, Type.PLAYER) + .build(); private @Nullable String clientBrand; private @Nullable Locale effectiveLocale; private @Nullable IdentifiedKey playerKey; @@ -174,14 +177,15 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, private final ChatBuilderFactory chatBuilderFactory; ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection, - @Nullable InetSocketAddress virtualHost, boolean onlineMode, - @Nullable IdentifiedKey playerKey) { + @Nullable InetSocketAddress virtualHost, boolean onlineMode, + @Nullable IdentifiedKey playerKey) { this.server = server; this.profile = profile; this.connection = connection; this.virtualHost = virtualHost; this.permissionFunction = PermissionFunction.ALWAYS_UNDEFINED; this.connectionPhase = connection.getType().getInitialClientPhase(); + this.knownChannels = CappedSet.create(MAX_PLUGIN_CHANNELS); this.onlineMode = onlineMode; if (connection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { @@ -336,7 +340,7 @@ public ProtocolVersion getProtocolVersion() { */ public Component translateMessage(Component message) { Locale locale = ClosestLocaleMatcher.INSTANCE - .lookupClosest(getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); + .lookupClosest(getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); return GlobalTranslator.render(message, locale); } @@ -345,21 +349,21 @@ public void sendMessage(@NonNull Identity identity, @NonNull Component message) Component translated = translateMessage(message); connection.write(getChatBuilderFactory().builder() - .component(translated).forIdentity(identity).toClient()); + .component(translated).forIdentity(identity).toClient()); } @Override public void sendMessage(@NonNull Identity identity, @NonNull Component message, - @NonNull MessageType type) { + @NonNull MessageType type) { Preconditions.checkNotNull(message, "message"); Preconditions.checkNotNull(type, "type"); Component translated = translateMessage(message); connection.write(getChatBuilderFactory().builder() - .component(translated).forIdentity(identity) - .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM) - .toClient()); + .component(translated).forIdentity(identity) + .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM) + .toClient()); } @Override @@ -370,16 +374,16 @@ public void sendActionBar(net.kyori.adventure.text.@NonNull Component message) { if (playerVersion.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { // Use the title packet instead. GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion); + GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion); pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion) - .serialize(translated)); + .serialize(translated)); connection.write(pkt); } else { // Due to issues with action bar packets, we'll need to convert the text message into a // legacy message and then inject the legacy text into a component... yuck! JsonObject object = new JsonObject(); object.addProperty("text", LegacyComponentSerializer.legacySection() - .serialize(translated)); + .serialize(translated)); LegacyChat legacyChat = new LegacyChat(); legacyChat.setMessage(object.toString()); legacyChat.setType(LegacyChat.GAME_INFO_TYPE); @@ -422,9 +426,9 @@ public void sendPlayerListHeaderAndFooter(final Component header, final Componen public void showTitle(net.kyori.adventure.title.@NonNull Title title) { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this - .getProtocolVersion()); + .getProtocolVersion()); GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); + GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); net.kyori.adventure.title.Title.Times times = title.times(); if (times != null) { timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); @@ -434,12 +438,12 @@ public void showTitle(net.kyori.adventure.title.@NonNull Title title) { connection.delayedWrite(timesPkt); GenericTitlePacket subtitlePkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); + GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); subtitlePkt.setComponent(serializer.serialize(translateMessage(title.subtitle()))); connection.delayedWrite(subtitlePkt); GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); + GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage(title.title()))); connection.delayedWrite(titlePkt); @@ -461,22 +465,22 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { } GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this - .getProtocolVersion()); + .getProtocolVersion()); if (part == TitlePart.TITLE) { GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); + GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.SUBTITLE) { GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); + GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.TIMES) { Times times = (Times) value; GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); + GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); timesPkt.setStay((int) DurationUtils.toTicks(times.stay())); timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut())); @@ -490,7 +494,7 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { public void clearTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { connection.write(GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion())); + GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion())); } } @@ -498,7 +502,7 @@ public void clearTitle() { public void resetTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { connection.write(GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.RESET, this.getProtocolVersion())); + GenericTitlePacket.ActionType.RESET, this.getProtocolVersion())); } } @@ -522,7 +526,7 @@ public ConnectionRequestBuilder createConnectionRequest(RegisteredServer server) } private ConnectionRequestBuilder createConnectionRequest(RegisteredServer server, - @Nullable VelocityServerConnection previousConnection) { + @Nullable VelocityServerConnection previousConnection) { return new ConnectionRequestBuilderImpl(server, previousConnection); } @@ -566,7 +570,7 @@ public void disconnect0(Component reason, boolean duringLogin) { if (server.getConfiguration().isLogPlayerConnections()) { logger.info("{} has disconnected: {}", this, - LegacyComponentSerializer.legacySection().serialize(translated)); + LegacyComponentSerializer.legacySection().serialize(translated)); } connection.closeWith(Disconnect.create(translated, this.getProtocolVersion())); } @@ -591,7 +595,7 @@ public void resetInFlightConnection() { * @param safe whether or not we can safely reconnect to a new server */ public void handleConnectionException(RegisteredServer server, Throwable throwable, - boolean safe) { + boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -612,12 +616,12 @@ public void handleConnectionException(RegisteredServer server, Throwable throwab Component friendlyError; if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { friendlyError = Component.translatable("velocity.error.connected-server-error", - Component.text(server.getServerInfo().getName())); + Component.text(server.getServerInfo().getName())); } else { logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(), - wrapped); + wrapped); friendlyError = Component.translatable("velocity.error.connecting-server-error", - Component.text(server.getServerInfo().getName())); + Component.text(server.getServerInfo().getName())); } handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe); } @@ -630,7 +634,7 @@ public void handleConnectionException(RegisteredServer server, Throwable throwab * @param safe whether or not we can safely reconnect to a new server */ public void handleConnectionException(RegisteredServer server, Disconnect disconnect, - boolean safe) { + boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -640,23 +644,23 @@ public void handleConnectionException(RegisteredServer server, Disconnect discon String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason); if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { logger.info("{}: kicked from server {}: {}", this, server.getServerInfo().getName(), - plainTextReason); + plainTextReason); handleConnectionException(server, disconnectReason, - Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), - disconnectReason), safe); + Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED, + Component.text(server.getServerInfo().getName()), + disconnectReason), safe); } else { logger.error("{}: disconnected while connecting to {}: {}", this, - server.getServerInfo().getName(), plainTextReason); + server.getServerInfo().getName(), plainTextReason); handleConnectionException(server, disconnectReason, - Component.translatable("velocity.error.cant-connect", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), - disconnectReason), safe); + Component.translatable("velocity.error.cant-connect", NamedTextColor.RED, + Component.text(server.getServerInfo().getName()), + disconnectReason), safe); } } private void handleConnectionException(RegisteredServer rs, - @Nullable Component kickReason, Component friendlyReason, boolean safe) { + @Nullable Component kickReason, Component friendlyReason, boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -675,7 +679,7 @@ private void handleConnectionException(RegisteredServer rs, if (kickedFromCurrent) { Optional next = getNextServerToTry(rs); result = next.map(RedirectPlayer::create) - .orElseGet(() -> DisconnectPlayer.create(friendlyReason)); + .orElseGet(() -> DisconnectPlayer.create(friendlyReason)); } else { // If we were kicked by going to another server, the connection should not be in flight if (connectionInFlight != null && connectionInFlight.getServer().equals(rs)) { @@ -684,91 +688,91 @@ private void handleConnectionException(RegisteredServer rs, result = Notify.create(friendlyReason); } KickedFromServerEvent originalEvent = new KickedFromServerEvent(this, rs, kickReason, - !kickedFromCurrent, result); + !kickedFromCurrent, result); handleKickEvent(originalEvent, friendlyReason, kickedFromCurrent); } private void handleKickEvent(KickedFromServerEvent originalEvent, Component friendlyReason, - boolean kickedFromCurrent) { + boolean kickedFromCurrent) { server.getEventManager().fire(originalEvent) - .thenAcceptAsync(event -> { - // There can't be any connection in flight now. - connectionInFlight = null; - - // Make sure we clear the current connected server as the connection is invalid. - VelocityServerConnection previousConnection = connectedServer; - if (kickedFromCurrent) { - connectedServer = null; - } - - if (!isActive()) { - // If the connection is no longer active, it makes no sense to try and recover it. - return; - } + .thenAcceptAsync(event -> { + // There can't be any connection in flight now. + connectionInFlight = null; + + // Make sure we clear the current connected server as the connection is invalid. + VelocityServerConnection previousConnection = connectedServer; + if (kickedFromCurrent) { + connectedServer = null; + } - if (event.getResult() instanceof DisconnectPlayer) { - DisconnectPlayer res = (DisconnectPlayer) event.getResult(); - disconnect(res.getReasonComponent()); - } else if (event.getResult() instanceof RedirectPlayer) { - RedirectPlayer res = (RedirectPlayer) event.getResult(); - createConnectionRequest(res.getServer(), previousConnection) - .connect() - .whenCompleteAsync((status, throwable) -> { - if (throwable != null) { - handleConnectionException(status != null ? status.getAttemptedConnection() - : res.getServer(), throwable, true); - return; - } + if (!isActive()) { + // If the connection is no longer active, it makes no sense to try and recover it. + return; + } - switch (status.getStatus()) { - // Impossible/nonsensical cases - case ALREADY_CONNECTED: - logger.error("{}: already connected to {}", - this, - status.getAttemptedConnection().getServerInfo().getName() - ); - break; - case CONNECTION_IN_PROGRESS: - // Fatal case - case CONNECTION_CANCELLED: - Component fallbackMsg = res.getMessageComponent(); - if (fallbackMsg == null) { - fallbackMsg = friendlyReason; - } - disconnect(status.getReasonComponent().orElse(fallbackMsg)); - break; - case SERVER_DISCONNECTED: - Component reason = status.getReasonComponent() - .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException(res.getServer(), Disconnect.create(reason, - getProtocolVersion()), ((Impl) status).isSafe()); - break; - case SUCCESS: - Component requestedMessage = res.getMessageComponent(); - if (requestedMessage == null) { - requestedMessage = friendlyReason; - } - if (requestedMessage != Component.empty()) { - sendMessage(requestedMessage); - } - break; - default: - // The only remaining value is successful (no need to do anything!) - break; - } - }, connection.eventLoop()); - } else if (event.getResult() instanceof Notify) { - Notify res = (Notify) event.getResult(); - if (event.kickedDuringServerConnect() && previousConnection != null) { - sendMessage(Identity.nil(), res.getMessageComponent()); - } else { - disconnect(res.getMessageComponent()); - } - } else { - // In case someone gets creative, assume we want to disconnect the player. - disconnect(friendlyReason); - } - }, connection.eventLoop()); + if (event.getResult() instanceof DisconnectPlayer) { + DisconnectPlayer res = (DisconnectPlayer) event.getResult(); + disconnect(res.getReasonComponent()); + } else if (event.getResult() instanceof RedirectPlayer) { + RedirectPlayer res = (RedirectPlayer) event.getResult(); + createConnectionRequest(res.getServer(), previousConnection) + .connect() + .whenCompleteAsync((status, throwable) -> { + if (throwable != null) { + handleConnectionException(status != null ? status.getAttemptedConnection() + : res.getServer(), throwable, true); + return; + } + + switch (status.getStatus()) { + // Impossible/nonsensical cases + case ALREADY_CONNECTED: + logger.error("{}: already connected to {}", + this, + status.getAttemptedConnection().getServerInfo().getName() + ); + break; + case CONNECTION_IN_PROGRESS: + // Fatal case + case CONNECTION_CANCELLED: + Component fallbackMsg = res.getMessageComponent(); + if (fallbackMsg == null) { + fallbackMsg = friendlyReason; + } + disconnect(status.getReasonComponent().orElse(fallbackMsg)); + break; + case SERVER_DISCONNECTED: + Component reason = status.getReasonComponent() + .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + handleConnectionException(res.getServer(), Disconnect.create(reason, + getProtocolVersion()), ((Impl) status).isSafe()); + break; + case SUCCESS: + Component requestedMessage = res.getMessageComponent(); + if (requestedMessage == null) { + requestedMessage = friendlyReason; + } + if (requestedMessage != Component.empty()) { + sendMessage(requestedMessage); + } + break; + default: + // The only remaining value is successful (no need to do anything!) + break; + } + }, connection.eventLoop()); + } else if (event.getResult() instanceof Notify) { + Notify res = (Notify) event.getResult(); + if (event.kickedDuringServerConnect() && previousConnection != null) { + sendMessage(Identity.nil(), res.getMessageComponent()); + } else { + disconnect(res.getMessageComponent()); + } + } else { + // In case someone gets creative, assume we want to disconnect the player. + disconnect(friendlyReason); + } + }, connection.eventLoop()); } /** @@ -791,10 +795,10 @@ public Optional getNextServerToTry() { private Optional getNextServerToTry(@Nullable RegisteredServer current) { if (serversToTry == null) { String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString) - .orElse("") - .toLowerCase(Locale.ROOT); + .orElse("") + .toLowerCase(Locale.ROOT); serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr, - Collections.emptyList()); + Collections.emptyList()); } if (serversToTry.isEmpty()) { @@ -809,8 +813,8 @@ private Optional getNextServerToTry(@Nullable RegisteredServer for (int i = tryIndex; i < serversToTry.size(); i++) { String toTryName = serversToTry.get(i); if ((connectedServer != null && hasSameName(connectedServer.getServer(), toTryName)) - || (connectionInFlight != null && hasSameName(connectionInFlight.getServer(), toTryName)) - || (current != null && hasSameName(current, toTryName))) { + || (connectionInFlight != null && hasSameName(connectionInFlight.getServer(), toTryName)) + || (current != null && hasSameName(current, toTryName))) { continue; } @@ -873,11 +877,11 @@ void teardown() { status = LoginStatus.PRE_SERVER_JOIN; } else { status = connectedPlayer.get() == this ? LoginStatus.SUCCESSFUL_LOGIN - : LoginStatus.CONFLICTING_LOGIN; + : LoginStatus.CONFLICTING_LOGIN; } } else { status = connection.isKnownDisconnect() ? LoginStatus.CANCELLED_BY_PROXY : - LoginStatus.CANCELLED_BY_USER; + LoginStatus.CANCELLED_BY_USER; } DisconnectEvent event = new DisconnectEvent(this, status); @@ -897,9 +901,9 @@ public CompletableFuture getTeardownFuture() { @Override public String toString() { boolean isPlayerAddressLoggingEnabled = server.getConfiguration() - .isPlayerAddressLoggingEnabled(); + .isPlayerAddressLoggingEnabled(); String playerIp = - isPlayerAddressLoggingEnabled ? getRemoteAddress().toString() : ""; + isPlayerAddressLoggingEnabled ? getRemoteAddress().toString() : ""; return "[connected player] " + profile.getName() + " (" + playerIp + ")"; } @@ -929,17 +933,17 @@ void setClientBrand(String clientBrand) { @Override public void spoofChatInput(String input) { Preconditions.checkArgument(input.length() <= LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH, - "input cannot be greater than " + LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH - + " characters in length"); + "input cannot be greater than " + LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH + + " characters in length"); if (getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) { this.chatQueue.hijack(getChatBuilderFactory().builder().asPlayer(this).message(input), - (instant, item) -> { - item.setTimestamp(instant); - return item.toServer(); - }); + (instant, item) -> { + item.setTimestamp(instant); + return item.toServer(); + }); } else { ensureBackendConnection().write(getChatBuilderFactory().builder() - .asPlayer(this).message(input).toServer()); + .asPlayer(this).message(input).toServer()); } } @@ -985,7 +989,7 @@ private void tickResourcePackQueue() { while (!outstandingResourcePacks.isEmpty()) { queued = outstandingResourcePacks.peek(); if (queued.getShouldForce() && getProtocolVersion() - .compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { + .compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { break; } onResourcePackResponse(PlayerResourcePackStatusEvent.Status.DECLINED); @@ -1027,19 +1031,19 @@ private void tickResourcePackQueue() { public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status status) { final boolean peek = status == PlayerResourcePackStatusEvent.Status.ACCEPTED; final ResourcePackInfo queued = peek - ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); + ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); server.getEventManager().fire(new PlayerResourcePackStatusEvent(this, status, queued)) - .thenAcceptAsync(event -> { - if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED - && event.getPackInfo() != null && event.getPackInfo().getShouldForce() - && (!event.isOverwriteKick() || event.getPlayer() - .getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) - ) { - event.getPlayer().disconnect(Component - .translatable("multiplayer.requiredTexturePrompt.disconnect")); - } - }); + .thenAcceptAsync(event -> { + if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED + && event.getPackInfo() != null && event.getPackInfo().getShouldForce() + && (!event.isOverwriteKick() || event.getPlayer() + .getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) + ) { + event.getPlayer().disconnect(Component + .translatable("multiplayer.requiredTexturePrompt.disconnect")); + } + }); switch (status) { case ACCEPTED: @@ -1065,7 +1069,14 @@ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status statu } return queued != null - && queued.getOriginalOrigin() != ResourcePackInfo.Origin.DOWNSTREAM_SERVER; + && queued.getOriginalOrigin() != ResourcePackInfo.Origin.DOWNSTREAM_SERVER; + } + + /** + * Gives an indication about the previous resource pack responses. + */ + public @Nullable Boolean getPreviousResourceResponse() { + return previousResourceResponse; } /** @@ -1099,6 +1110,15 @@ public void setPhase(ClientConnectionPhase connectionPhase) { this.connectionPhase = connectionPhase; } + /** + * Return all the plugin message channels "known" to the client. + * + * @return the channels + */ + public Collection getKnownChannels() { + return knownChannels; + } + @Override public @Nullable IdentifiedKey getIdentifiedKey() { return playerKey; @@ -1118,7 +1138,7 @@ private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder { private final @Nullable VelocityRegisteredServer previousServer; ConnectionRequestBuilderImpl(RegisteredServer toConnect, - @Nullable VelocityServerConnection previousConnection) { + @Nullable VelocityServerConnection previousConnection) { this.toConnect = Preconditions.checkNotNull(toConnect, "info"); this.previousServer = previousConnection == null ? null : previousConnection.getServer(); } @@ -1130,13 +1150,13 @@ public RegisteredServer getServer() { private Optional checkServer(RegisteredServer server) { Preconditions.checkArgument(server instanceof VelocityRegisteredServer, - "Not a valid Velocity server."); + "Not a valid Velocity server."); if (connectionInFlight != null || (connectedServer != null - && !connectedServer.hasCompletedJoin())) { + && !connectedServer.hasCompletedJoin())) { return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS); } if (connectedServer != null - && connectedServer.getServer().getServerInfo().equals(server.getServerInfo())) { + && connectedServer.getServer().getServerInfo().equals(server.getServerInfo())) { return Optional.of(ALREADY_CONNECTED); } return Optional.empty(); @@ -1148,36 +1168,36 @@ private CompletableFuture> getInitialStatus() { private CompletableFuture internalConnect() { return this.getInitialStatus() - .thenCompose(initialCheck -> { - if (initialCheck.isPresent()) { - return completedFuture(plainResult(initialCheck.get(), toConnect)); - } - - ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this, - toConnect, previousServer); - return server.getEventManager().fire(event) - .thenComposeAsync(newEvent -> { - Optional newDest = newEvent.getResult().getServer(); - if (!newDest.isPresent()) { - return completedFuture( - plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect) - ); - } - - RegisteredServer realDestination = newDest.get(); - Optional check = checkServer(realDestination); - if (check.isPresent()) { - return completedFuture(plainResult(check.get(), realDestination)); - } - - VelocityRegisteredServer vrs = (VelocityRegisteredServer) realDestination; - VelocityServerConnection con = new VelocityServerConnection(vrs, - previousServer, ConnectedPlayer.this, server); - connectionInFlight = con; - return con.connect().whenCompleteAsync( - (result, exception) -> this.resetIfInFlightIs(con), connection.eventLoop()); - }, connection.eventLoop()); - }); + .thenCompose(initialCheck -> { + if (initialCheck.isPresent()) { + return completedFuture(plainResult(initialCheck.get(), toConnect)); + } + + ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this, + toConnect, previousServer); + return server.getEventManager().fire(event) + .thenComposeAsync(newEvent -> { + Optional newDest = newEvent.getResult().getServer(); + if (!newDest.isPresent()) { + return completedFuture( + plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect) + ); + } + + RegisteredServer realDestination = newDest.get(); + Optional check = checkServer(realDestination); + if (check.isPresent()) { + return completedFuture(plainResult(check.get(), realDestination)); + } + + VelocityRegisteredServer vrs = (VelocityRegisteredServer) realDestination; + VelocityServerConnection con = new VelocityServerConnection(vrs, + previousServer, ConnectedPlayer.this, server); + connectionInFlight = con; + return con.connect().whenCompleteAsync( + (result, exception) -> this.resetIfInFlightIs(con), connection.eventLoop()); + }, connection.eventLoop()); + }); } private void resetIfInFlightIs(VelocityServerConnection establishedConnection) { @@ -1189,49 +1209,49 @@ private void resetIfInFlightIs(VelocityServerConnection establishedConnection) { @Override public CompletableFuture connect() { return this.internalConnect() - .whenCompleteAsync((status, throwable) -> { - if (status != null && !status.isSuccessful()) { - if (!status.isSafe()) { - handleConnectionException(status.getAttemptedConnection(), throwable, false); - } - } - }, connection.eventLoop()) - .thenApply(x -> x); + .whenCompleteAsync((status, throwable) -> { + if (status != null && !status.isSuccessful()) { + if (!status.isSafe()) { + handleConnectionException(status.getAttemptedConnection(), throwable, false); + } + } + }, connection.eventLoop()) + .thenApply(x -> x); } @Override public CompletableFuture connectWithIndication() { return internalConnect() - .whenCompleteAsync((status, throwable) -> { - if (throwable != null) { - // TODO: The exception handling from this is not very good. Find a better way. - handleConnectionException(status != null ? status.getAttemptedConnection() - : toConnect, throwable, true); - return; - } - - switch (status.getStatus()) { - case ALREADY_CONNECTED: - sendMessage(Identity.nil(), ConnectionMessages.ALREADY_CONNECTED); - break; - case CONNECTION_IN_PROGRESS: - sendMessage(Identity.nil(), ConnectionMessages.IN_PROGRESS); - break; - case CONNECTION_CANCELLED: - // Ignored; the plugin probably already handled this. - break; - case SERVER_DISCONNECTED: - Component reason = status.getReasonComponent() - .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException(toConnect, Disconnect.create(reason, - getProtocolVersion()), status.isSafe()); - break; - default: - // The only remaining value is successful (no need to do anything!) - break; - } - }, connection.eventLoop()) - .thenApply(Result::isSuccessful); + .whenCompleteAsync((status, throwable) -> { + if (throwable != null) { + // TODO: The exception handling from this is not very good. Find a better way. + handleConnectionException(status != null ? status.getAttemptedConnection() + : toConnect, throwable, true); + return; + } + + switch (status.getStatus()) { + case ALREADY_CONNECTED: + sendMessage(Identity.nil(), ConnectionMessages.ALREADY_CONNECTED); + break; + case CONNECTION_IN_PROGRESS: + sendMessage(Identity.nil(), ConnectionMessages.IN_PROGRESS); + break; + case CONNECTION_CANCELLED: + // Ignored; the plugin probably already handled this. + break; + case SERVER_DISCONNECTED: + Component reason = status.getReasonComponent() + .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + handleConnectionException(toConnect, Disconnect.create(reason, + getProtocolVersion()), status.isSafe()); + break; + default: + // The only remaining value is successful (no need to do anything!) + break; + } + }, connection.eventLoop()) + .thenApply(Result::isSuccessful); } @Override @@ -1239,4 +1259,4 @@ public void fireAndForget() { connectWithIndication(); } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index e814efaa35..3e181592af 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -66,8 +66,8 @@ public HandshakeSessionHandler(MinecraftConnection connection, VelocityServer se public boolean handle(LegacyPing packet) { connection.setProtocolVersion(ProtocolVersion.LEGACY); StatusSessionHandler handler = new StatusSessionHandler(server, - new LegacyInboundConnection(connection, packet)); - connection.setSessionHandler(handler); + new LegacyInboundConnection(connection, packet)); + connection.setActiveSessionHandler(StateRegistry.STATUS ,handler); handler.handle(packet); return true; } @@ -75,8 +75,8 @@ public boolean handle(LegacyPing packet) { @Override public boolean handle(LegacyHandshake packet) { connection.closeWith(LegacyDisconnect.from(Component.text( - "Your client is extremely old. Please update to a newer version of Minecraft.", - NamedTextColor.RED) + "Your client is extremely old. Please update to a newer version of Minecraft.", + NamedTextColor.RED) )); return true; } @@ -84,19 +84,18 @@ public boolean handle(LegacyHandshake packet) { @Override public boolean handle(Handshake handshake) { InitialInboundConnection ic = new InitialInboundConnection(connection, - cleanVhost(handshake.getServerAddress()), handshake); + cleanVhost(handshake.getServerAddress()), handshake); StateRegistry nextState = getStateForProtocol(handshake.getNextStatus()); if (nextState == null) { LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus()); connection.close(true); } else { - connection.setState(nextState); connection.setProtocolVersion(handshake.getProtocolVersion()); connection.setAssociation(ic); switch (nextState) { case STATUS: - connection.setSessionHandler(new StatusSessionHandler(server, ic)); + connection.setActiveSessionHandler(StateRegistry.STATUS, new StatusSessionHandler(server, ic)); break; case LOGIN: this.handleLogin(handshake, ic); @@ -124,7 +123,7 @@ public boolean handle(Handshake handshake) { private void handleLogin(Handshake handshake, InitialInboundConnection ic) { if (!ProtocolVersion.isSupported(handshake.getProtocolVersion())) { ic.disconnectQuietly(Component.translatable("multiplayer.disconnect.outdated_client") - .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); + .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); return; } @@ -139,21 +138,21 @@ private void handleLogin(Handshake handshake, InitialInboundConnection ic) { // If the proxy is configured for modern forwarding, we must deny connections from 1.12.2 // and lower, otherwise IP information will never get forwarded. if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN - && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { + && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { ic.disconnectQuietly(Component.translatable( - "velocity.error.modern-forwarding-needs-new-client")); + "velocity.error.modern-forwarding-needs-new-client")); return; } LoginInboundConnection lic = new LoginInboundConnection(ic); server.getEventManager().fireAndForget(new ConnectionHandshakeEvent(lic)); - connection.setSessionHandler(new InitialLoginSessionHandler(server, connection, lic)); + connection.setActiveSessionHandler(StateRegistry.LOGIN, new InitialLoginSessionHandler(server, connection, lic)); } private ConnectionType getHandshakeConnectionType(Handshake handshake) { // Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13). if (handshake.getServerAddress().endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN) - && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { + && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { return ConnectionTypes.LEGACY_FORGE; } else if (handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_6) <= 0) { // 1.7 Forge will not notify us during handshake. UNDETERMINED will listen for incoming @@ -208,7 +207,7 @@ private static class LegacyInboundConnection implements VelocityInboundConnectio private final LegacyPing ping; private LegacyInboundConnection(MinecraftConnection connection, - LegacyPing ping) { + LegacyPing ping) { this.connection = connection; this.ping = ping; } @@ -243,4 +242,4 @@ public MinecraftConnection getConnection() { return connection; } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index 01bef5f92c..98d84a476c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -34,6 +34,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.crypto.IdentifiedKeyImpl; +import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; @@ -63,9 +64,9 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(InitialLoginSessionHandler.class); private static final String MOJANG_HASJOINED_URL = - System.getProperty("mojang.sessionserver", - "https://sessionserver.mojang.com/session/minecraft/hasJoined") - .concat("?username=%s&serverId=%s"); + System.getProperty("mojang.sessionserver", + "https://sessionserver.mojang.com/session/minecraft/hasJoined") + .concat("?username=%s&serverId=%s"); private final VelocityServer server; private final MinecraftConnection mcConnection; @@ -76,13 +77,13 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private boolean forceKeyAuthentication; InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection, - LoginInboundConnection inbound) { + LoginInboundConnection inbound) { this.server = Preconditions.checkNotNull(server, "server"); this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.forceKeyAuthentication = System.getProperties().containsKey("auth.forceSecureProfiles") - ? Boolean.getBoolean("auth.forceSecureProfiles") - : server.getConfiguration().isForceKeyAuthentication(); + ? Boolean.getBoolean("auth.forceSecureProfiles") + : server.getConfiguration().isForceKeyAuthentication(); } @Override @@ -93,13 +94,13 @@ public boolean handle(ServerLogin packet) { if (playerKey != null) { if (playerKey.hasExpired()) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key_signature")); + Component.translatable("multiplayer.disconnect.invalid_public_key_signature")); return true; } boolean isKeyValid; if (playerKey.getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 - && playerKey instanceof IdentifiedKeyImpl) { + && playerKey instanceof IdentifiedKeyImpl) { IdentifiedKeyImpl keyImpl = (IdentifiedKeyImpl) playerKey; isKeyValid = keyImpl.internalAddHolder(packet.getHolderUuid()); } else { @@ -111,8 +112,8 @@ public boolean handle(ServerLogin packet) { return true; } } else if (mcConnection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0 - && forceKeyAuthentication - && mcConnection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) < 0) { + && forceKeyAuthentication + && mcConnection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) < 0) { inbound.disconnect(Component.translatable("multiplayer.disconnect.missing_public_key")); return true; } @@ -121,46 +122,46 @@ public boolean handle(ServerLogin packet) { PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername()); server.getEventManager().fire(event) - .thenRunAsync(() -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + .thenRunAsync(() -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - PreLoginComponentResult result = event.getResult(); - Optional disconnectReason = result.getReasonComponent(); - if (disconnectReason.isPresent()) { - // The component is guaranteed to be provided if the connection was denied. - inbound.disconnect(disconnectReason.get()); - return; - } + PreLoginComponentResult result = event.getResult(); + Optional disconnectReason = result.getReasonComponent(); + if (disconnectReason.isPresent()) { + // The component is guaranteed to be provided if the connection was denied. + inbound.disconnect(disconnectReason.get()); + return; + } - inbound.loginEventFired(() -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + inbound.loginEventFired(() -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - mcConnection.eventLoop().execute(() -> { - if (!result.isForceOfflineMode() && (server.getConfiguration().isOnlineMode() - || result.isOnlineModeAllowed())) { - // Request encryption. - EncryptionRequest request = generateEncryptionRequest(); - this.verify = Arrays.copyOf(request.getVerifyToken(), 4); - mcConnection.write(request); - this.currentState = LoginState.ENCRYPTION_REQUEST_SENT; - } else { - mcConnection.setSessionHandler(new AuthSessionHandler( - server, inbound, GameProfile.forOfflinePlayer(login.getUsername()), false - )); - } + mcConnection.eventLoop().execute(() -> { + if (!result.isForceOfflineMode() && (server.getConfiguration().isOnlineMode() + || result.isOnlineModeAllowed())) { + // Request encryption. + EncryptionRequest request = generateEncryptionRequest(); + this.verify = Arrays.copyOf(request.getVerifyToken(), 4); + mcConnection.write(request); + this.currentState = LoginState.ENCRYPTION_REQUEST_SENT; + } else { + mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, new AuthSessionHandler( + server, inbound, GameProfile.forOfflinePlayer(login.getUsername()), false + )); + } + }); + }); + }, mcConnection.eventLoop()) + .exceptionally((ex) -> { + logger.error("Exception in pre-login stage", ex); + return null; }); - }); - }, mcConnection.eventLoop()) - .exceptionally((ex) -> { - logger.error("Exception in pre-login stage", ex); - return null; - }); return true; } @@ -189,7 +190,7 @@ public boolean handle(EncryptionResponse packet) { if (inbound.getIdentifiedKey() != null) { IdentifiedKey playerKey = inbound.getIdentifiedKey(); if (!playerKey.verifyDataSignature(packet.getVerifyToken(), verify, - Longs.toByteArray(packet.getSalt()))) { + Longs.toByteArray(packet.getSalt()))) { throw new IllegalStateException("Invalid client public signature."); } } else { @@ -204,14 +205,14 @@ public boolean handle(EncryptionResponse packet) { String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString(); String url = String.format(MOJANG_HASJOINED_URL, - urlFormParameterEscaper().escape(login.getUsername()), serverId); + urlFormParameterEscaper().escape(login.getUsername()), serverId); if (server.getConfiguration().shouldPreventClientProxyConnections()) { url += "&ip=" + urlFormParameterEscaper().escape(playerIp); } ListenableFuture hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) - .execute(); + .execute(); hasJoinedResponse.addListener(() -> { if (mcConnection.isClosed()) { // The player disconnected after we authenticated them. @@ -234,30 +235,30 @@ public boolean handle(EncryptionResponse packet) { Response profileResponse = hasJoinedResponse.get(); if (profileResponse.getStatusCode() == 200) { final GameProfile profile = GENERAL_GSON.fromJson(profileResponse.getResponseBody(), - GameProfile.class); + GameProfile.class); // Not so fast, now we verify the public key for 1.19.1+ if (inbound.getIdentifiedKey() != null - && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 - && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { + && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 + && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey(); if (!key.internalAddHolder(profile.getId())) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key")); + Component.translatable("multiplayer.disconnect.invalid_public_key")); } } // All went well, initialize the session. - mcConnection.setSessionHandler(new AuthSessionHandler( - server, inbound, profile, true + mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, new AuthSessionHandler( + server, inbound, profile, true )); } else if (profileResponse.getStatusCode() == 204) { // Apparently an offline-mode user logged onto this online-mode proxy. inbound.disconnect(Component.translatable("velocity.error.online-mode-only", - NamedTextColor.RED)); + NamedTextColor.RED)); } else { // Something else went wrong logger.error( - "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", - profileResponse.getStatusCode(), login.getUsername(), playerIp); + "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", + profileResponse.getStatusCode(), login.getUsername(), playerIp); inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); } } catch (ExecutionException e) { @@ -299,8 +300,8 @@ private void assertState(LoginState expectedState) { if (this.currentState != expectedState) { if (MinecraftDecoder.DEBUG) { logger.error("{} Received an unexpected packet requiring state {}, but we are in {}", - inbound, - expectedState, this.currentState); + inbound, + expectedState, this.currentState); } mcConnection.close(true); } @@ -312,4 +313,4 @@ private enum LoginState { ENCRYPTION_REQUEST_SENT, ENCRYPTION_RESPONSE_RECEIVED } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java index 5d75421708..ad26d09b18 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java @@ -56,8 +56,8 @@ public void onFirstJoin(ConnectedPlayer player) { @Override boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { // If we stay in this phase, we do nothing because it means the packet wasn't handled. // Returning false indicates this return false; @@ -88,8 +88,8 @@ LegacyForgeHandshakeClientPhase nextPhase() { @Override boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { // Read the mod list if we haven't already. if (!player.getModInfo().isPresent()) { List mods = LegacyForgeUtil.readModList(message); @@ -158,14 +158,14 @@ public boolean consideredComplete() { @Override boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { super.onHandle(player, message, backendConn); // just in case the timing is awful player.sendKeepAlive(); - MinecraftSessionHandler handler = backendConn.getSessionHandler(); + MinecraftSessionHandler handler = backendConn.getActiveSessionHandler(); if (handler instanceof ClientPlaySessionHandler) { ((ClientPlaySessionHandler) handler).flushQueuedMessages(); } @@ -191,12 +191,12 @@ boolean onHandle(ConnectedPlayer player, @Override public final boolean handle(ConnectedPlayer player, - PluginMessage message, - VelocityServerConnection server) { + PluginMessage message, + VelocityServerConnection server) { if (server != null) { MinecraftConnection backendConn = server.getConnection(); if (backendConn != null - && message.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { + && message.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { // Get the phase and check if we need to start the next phase. LegacyForgeHandshakeClientPhase newPhase = getNewPhase(message); @@ -221,8 +221,8 @@ public final boolean handle(ConnectedPlayer player, * @return true if handled, false otherwise. */ boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { // Send the packet on to the server. backendConn.write(message.retain()); @@ -252,10 +252,10 @@ LegacyForgeHandshakeClientPhase nextPhase() { */ private LegacyForgeHandshakeClientPhase getNewPhase(PluginMessage packet) { if (packetToAdvanceOn != null - && LegacyForgeUtil.getHandshakePacketDiscriminator(packet) == packetToAdvanceOn) { + && LegacyForgeUtil.getHandshakePacketDiscriminator(packet) == packetToAdvanceOn) { return nextPhase(); } return this; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java new file mode 100644 index 0000000000..b0e1a50e30 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2018-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.connection.registry; + +import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo; +import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import net.kyori.adventure.key.Key; +import org.jetbrains.annotations.Nullable; + +public class ClientConfigData { + + private final @Nullable VelocityResourcePackInfo resourcePackInfo; + private final DataTag tag; + private final RegistrySync registry; + private final Key[] features; + private final String brand; + + + private ClientConfigData(@Nullable VelocityResourcePackInfo resourcePackInfo, DataTag tag, + RegistrySync registry, Key[] features, String brand) { + this.resourcePackInfo = resourcePackInfo; + this.tag = tag; + this.registry = registry; + this.features = features; + this.brand = brand; + } + + + public RegistrySync getRegistry() { + return registry; + } + + public DataTag getTag() { + return tag; + } + + public Key[] getFeatures() { + return features; + } + + public @Nullable VelocityResourcePackInfo getResourcePackInfo() { + return resourcePackInfo; + } + + public String getBrand() { + return brand; + } + + public static ClientConfigData.Builder builder(){ + return new Builder(); + } + + + public static class Builder { + + private VelocityResourcePackInfo resourcePackInfo; + private DataTag tag; + private RegistrySync registry; + private Key[] features; + private String brand; + + private Builder(){ + } + + public void clear(){ + this.resourcePackInfo = null; + this.tag = null; + this.registry = null; + this.features = null; + this.brand = null; + } + + public Builder resourcePack(@Nullable VelocityResourcePackInfo resourcePackInfo) { + this.resourcePackInfo = resourcePackInfo; + return this; + } + + public Builder dataTag(DataTag tag) { + this.tag = tag; + return this; + } + + public Builder registry(RegistrySync registry) { + this.registry = registry; + return this; + } + + public Builder features(Key[] features) { + this.features = features; + return this; + } + + public Builder brand(String brand) { + this.brand = brand; + return this; + } + + public ClientConfigData build(){ + return new ClientConfigData(resourcePackInfo, tag, registry, features, brand); + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java new file mode 100644 index 0000000000..1e77ccc9b5 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.connection.registry; + +import com.google.common.collect.ImmutableList; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.Keyed; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class DataTag { + + + private final ImmutableList entrySets; + + public DataTag(ImmutableList entrySets) { + this.entrySets = entrySets; + } + + public List getEntrySets() { + return entrySets; + } + + public static class Set implements Keyed { + + private final Key key; + private final ImmutableList entries; + + public Set(Key key, ImmutableList entries) { + this.key = key; + this.entries = entries; + } + + public List getEntries() { + return entries; + } + + @Override + public @NotNull Key key() { + return key; + } + } + + public static class Entry implements Keyed { + + private final Key key; + private final int[] elements; + + public Entry(Key key, int[] elements) { + this.key = key; + this.elements = elements; + } + + public int[] getElements() { + return elements; + } + + @Override + public @NotNull Key key() { + return key; + } + } +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java index 62f38ebd72..b126649f68 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -29,6 +29,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.netty.LegacyPingDecoder; import com.velocitypowered.proxy.protocol.netty.LegacyPingEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; @@ -56,22 +57,24 @@ public ServerChannelInitializer(final VelocityServer server) { @Override protected void initChannel(final Channel ch) { ch.pipeline() - .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast(READ_TIMEOUT, - new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), - TimeUnit.MILLISECONDS)) - .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) - .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) - .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); + .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(READ_TIMEOUT, + new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), + TimeUnit.MILLISECONDS)) + .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) + .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); final MinecraftConnection connection = new MinecraftConnection(ch, this.server); - connection.setSessionHandler(new HandshakeSessionHandler(connection, this.server)); + connection.setActiveSessionHandler( + StateRegistry.HANDSHAKE, + new HandshakeSessionHandler(connection, this.server)); ch.pipeline().addLast(Connections.HANDLER, connection); if (this.server.getConfiguration().isProxyProtocol()) { ch.pipeline().addFirst(new HAProxyMessageDecoder()); } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 9752eb0620..d69175b2ac 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -41,6 +41,8 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; + +import net.kyori.adventure.key.Key; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -52,19 +54,19 @@ public enum ProtocolUtils { ; private static final GsonComponentSerializer PRE_1_16_SERIALIZER = - GsonComponentSerializer.builder() - .downsampleColors() - .emitLegacyHoverEvent() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) - .build(); + GsonComponentSerializer.builder() + .downsampleColors() + .emitLegacyHoverEvent() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .build(); private static final GsonComponentSerializer MODERN_SERIALIZER = - GsonComponentSerializer.builder() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) - .build(); + GsonComponentSerializer.builder() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .build(); public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB private static final QuietDecoderException BAD_VARINT_CACHED = - new QuietDecoderException("Bad VarInt decoded"); + new QuietDecoderException("Bad VarInt decoded"); private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33]; static { @@ -84,7 +86,7 @@ public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); if (read == Integer.MIN_VALUE) { throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") - : BAD_VARINT_CACHED; + : BAD_VARINT_CACHED; } return read; } @@ -151,11 +153,11 @@ private static void writeVarIntFull(ByteBuf buf, int value) { buf.writeMedium(w); } else if ((value & (0xFFFFFFFF << 28)) == 0) { int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) - | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); + | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); buf.writeInt(w); } else { int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 - | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); + | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); buf.writeInt(w); buf.writeByte(value >>> 28); } @@ -198,12 +200,12 @@ private static String readString(ByteBuf buf, int cap, int length) { // sanity check and then check again to make sure our optimistic guess was good. checkFrame(length <= cap * 3, "Bad string size (got %s, maximum is %s)", length, cap); checkFrame(buf.isReadable(length), - "Trying to read a string that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); + "Trying to read a string that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8); buf.skipBytes(length); checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", - str.length(), cap); + str.length(), cap); return str; } @@ -219,6 +221,52 @@ public static void writeString(ByteBuf buf, CharSequence str) { buf.writeCharSequence(str, StandardCharsets.UTF_8); } + /** + * Reads a standard Mojang Text namespaced:key from the buffer. + * + * @param buf the buffer to read from + * @return the decoded key + */ + public static Key readKey(ByteBuf buf) { + return Key.key(readString(buf), Key.DEFAULT_SEPARATOR); + } + + /** + * Writes a standard Mojang Text namespaced:key to the buffer. + * + * @param buf the buffer to write to + * @param key the key to write + */ + public static void writeKey(ByteBuf buf, Key key) { + writeString(buf, key.asString()); + } + + /** + * Reads a standard Mojang Text namespaced:key array from the buffer. + * + * @param buf the buffer to read from + * @return the decoded key array + */ + public static Key[] readKeyArray(ByteBuf buf) { + Key[] ret = new Key[readVarInt(buf)]; + for (int i = 0; i < ret.length; i++) { + ret[i] = ProtocolUtils.readKey(buf); + } + return ret; + } + + /** + * Writes a standard Mojang Text namespaced:key array to the buffer. + * + * @param buf the buffer to write to + * @param keys the keys to write + */ + public static void writeKeyArray(ByteBuf buf, Key[] keys) { + writeVarInt(buf, keys.length); + for (Key key : keys) { + writeKey(buf, key); + } + } public static byte[] readByteArray(ByteBuf buf) { return readByteArray(buf, DEFAULT_MAX_STRING_SIZE); } @@ -236,8 +284,8 @@ public static byte[] readByteArray(ByteBuf buf, int cap) { checkFrame(length >= 0, "Got a negative-length array (%s)", length); checkFrame(length <= cap, "Bad array size (got %s, maximum is %s)", length, cap); checkFrame(buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); + "Trying to read an array that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); byte[] array = new byte[length]; buf.readBytes(array); return array; @@ -322,7 +370,7 @@ public static CompoundBinaryTag readCompoundTag(ByteBuf buf, BinaryTagIO.Reader return reader.read((DataInput) new ByteBufInputStream(buf)); } catch (IOException thrown) { throw new DecoderException( - "Unable to parse NBT CompoundTag, full error: " + thrown.getMessage()); + "Unable to parse NBT CompoundTag, full error: " + thrown.getMessage()); } } @@ -368,6 +416,34 @@ public static void writeStringArray(ByteBuf buf, String[] stringArray) { } } + /** + * Reads an Integer array from the {@code buf}. + * + * @param buf the buffer to read from + * @return the Integer array from the buffer + */ + public static int[] readVarIntArray(ByteBuf buf) { + int length = readVarInt(buf); + int[] ret = new int[length]; + for (int i = 0; i < length; i++) { + ret[i] = readVarInt(buf); + } + return ret; + } + + /** + * Writes an Integer Array to the {@code buf}. + * + * @param buf the buffer to write to + * @param intArray the array to write + */ + public static void writeVarIntArray(ByteBuf buf, int[] intArray) { + writeVarInt(buf, intArray.length); + for (int i = 0; i < intArray.length; i++) { + writeVarInt(buf, intArray[i]); + } + } + /** * Writes a list of {@link com.velocitypowered.api.util.GameProfile.Property} to the buffer. * @@ -426,7 +502,7 @@ public static byte[] readByteArray17(ByteBuf buf) { int len = readExtendedForgeShort(buf); checkArgument(len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); byte[] ret = new byte[len]; buf.readBytes(ret); @@ -446,7 +522,7 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { int len = readExtendedForgeShort(buf); checkFrame(len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); return buf.readRetainedSlice(len); } @@ -461,11 +537,11 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { checkFrame(b.length <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, - b.length); + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.length); } else { checkFrame(b.length <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -485,11 +561,11 @@ public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { checkFrame(b.readableBytes() <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, - b.readableBytes()); + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.readableBytes()); } else { checkFrame(b.readableBytes() <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.readableBytes()); + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.readableBytes()); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -581,7 +657,7 @@ public static IdentifiedKey readPlayerKey(ProtocolVersion version, ByteBuf buf) byte[] key = ProtocolUtils.readByteArray(buf); byte[] signature = ProtocolUtils.readByteArray(buf, 4096); IdentifiedKey.Revision revision = version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 - ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; + ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; return new IdentifiedKeyImpl(revision, key, expiry, signature); } @@ -592,32 +668,4 @@ public enum Direction { SERVERBOUND, CLIENTBOUND } - - /** - * Reads an Integer array from the {@code buf}. - * - * @param buf the buffer to read from - * @return the Integer array from the buffer - */ - public static int[] readVarIntArray(ByteBuf buf) { - int length = readVarInt(buf); - int[] ret = new int[length]; - for (int i = 0; i < length; i++) { - ret[i] = readVarInt(buf); - } - return ret; - } - - /** - * Writes an Integer Array to the {@code buf}. - * - * @param buf the buffer to write to - * @param intArray the array to write - */ - public static void writeVarIntArray(ByteBuf buf, int[] intArray) { - writeVarInt(buf, intArray.length); - for (int i = 0; i < intArray.length; i++) { - writeVarInt(buf, intArray[i]); - } - } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 6268bffe30..c887a4caba 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -77,16 +77,18 @@ public enum StateRegistry { }, CONFIG { { - serverbound.register(PluginMessage.class, PluginMessage::new, + serverbound.register(ClientSettings.class, ClientSettings::new, map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(FinishedUpdate.class, FinishedUpdate::new, + serverbound.register(PluginMessage.class, PluginMessage::new, map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(KeepAlive.class, KeepAlive::new, + serverbound.register(FinishedUpdate.class, FinishedUpdate::new, map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(PingIdentify.class, PingIdentify::new, + serverbound.register(KeepAlive.class, KeepAlive::new, map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(ResourcePackResponse.class, ResourcePackResponse::new, + serverbound.register(PingIdentify.class, PingIdentify::new, map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register(ResourcePackResponse.class, ResourcePackResponse::new, + map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(PluginMessage.class, PluginMessage::new, map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index 35d6fc888e..6541aedfd1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -42,7 +42,7 @@ public class JoinGame implements MinecraftPacket { private int viewDistance; // 1.14+ private boolean reducedDebugInfo; private boolean showRespawnScreen; - private boolean doLimitedCrafting; + private boolean doLimitedCrafting; // 1.20.2+ private ImmutableSet levelNames; // 1.16+ private CompoundBinaryTag registry; // 1.16+ private DimensionInfo dimensionInfo; // 1.16+ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java index 641407f9f5..1f8d2680ee 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java @@ -17,17 +17,23 @@ package com.velocitypowered.proxy.protocol.packet; +import com.google.common.base.Preconditions; import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.proxy.player.ResourcePackInfo; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import java.util.regex.Pattern; + public class ResourcePackRequest implements MinecraftPacket { private @MonotonicNonNull String url; @@ -35,6 +41,8 @@ public class ResourcePackRequest implements MinecraftPacket { private boolean isRequired; // 1.17+ private @Nullable Component prompt; // 1.17+ + private static final Pattern PLAUSIBLE_SHA1_HASH = Pattern.compile("^[a-z0-9]{40}$"); // 1.20.2+ + public @Nullable String getUrl() { return url; } @@ -99,6 +107,21 @@ public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVer } } + public VelocityResourcePackInfo toServerPromptedPack(){ + ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl( + Preconditions.checkNotNull(url)) + .setPrompt(prompt) + .setShouldForce(isRequired) + .setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + + if (hash != null && !hash.isEmpty()) { + if (PLAUSIBLE_SHA1_HASH.matcher(hash).matches()) { + builder.setHash(ByteBufUtil.decodeHexDump(hash)); + } + } + return (VelocityResourcePackInfo) builder.build(); + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); @@ -107,10 +130,10 @@ public boolean handle(MinecraftSessionHandler handler) { @Override public String toString() { return "ResourcePackRequest{" - + "url='" + url + '\'' - + ", hash='" + hash + '\'' - + ", isRequired=" + isRequired - + ", prompt='" + prompt + '\'' - + '}'; + + "url='" + url + '\'' + + ", hash='" + hash + '\'' + + ", isRequired=" + isRequired + + ", prompt='" + prompt + '\'' + + '}'; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java index cdb15b6012..d688e69b42 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java @@ -22,27 +22,36 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +import net.kyori.adventure.key.Key; public class ActiveFeatures implements MinecraftPacket { - private String[] activeFeatures; + private Key[] activeFeatures; + + public ActiveFeatures(Key[] activeFeatures) { + this.activeFeatures = activeFeatures; + } public ActiveFeatures(){ - this.activeFeatures = new String[0]; + this.activeFeatures = new Key[0]; } - public ActiveFeatures(String[] activeFeatures) { + public void setActiveFeatures(Key[] activeFeatures) { this.activeFeatures = activeFeatures; } + public Key[] getActiveFeatures() { + return activeFeatures; + } + @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - activeFeatures = ProtocolUtils.readStringArray(buf); + activeFeatures = ProtocolUtils.readKeyArray(buf); } @Override public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeStringArray(buf, activeFeatures); + ProtocolUtils.writeKeyArray(buf, activeFeatures); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java index ecc7dedf67..285e98fb10 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java @@ -21,14 +21,19 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; -public class RegistrySync implements MinecraftPacket { +public class RegistrySync extends DeferredByteBufHolder implements MinecraftPacket { private CompoundBinaryTag registryData; + public RegistrySync() { + super(null); + } + @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { registryData = ProtocolUtils.readCompoundTag(buf, BinaryTagIO.reader()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index 7bafc99b7d..9399a02041 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -44,7 +44,7 @@ public class PingSessionHandler implements MinecraftSessionHandler { private boolean completed = false; PingSessionHandler(CompletableFuture result, RegisteredServer server, - MinecraftConnection connection, ProtocolVersion version) { + MinecraftConnection connection, ProtocolVersion version) { this.result = result; this.server = server; this.connection = connection; @@ -60,7 +60,7 @@ public void activated() { handshake.setProtocolVersion(version); connection.delayedWrite(handshake); - connection.setState(StateRegistry.STATUS); + connection.setActiveSessionHandler(StateRegistry.STATUS); connection.delayedWrite(StatusRequest.INSTANCE); connection.flush(); @@ -73,7 +73,7 @@ public boolean handle(StatusResponse packet) { connection.close(true); ServerPing ping = VelocityServer.getPingGsonInstance(version).fromJson(packet.getStatus(), - ServerPing.class); + ServerPing.class); result.complete(ping); return true; } @@ -90,4 +90,4 @@ public void exception(Throwable throwable) { completed = true; result.completeExceptionally(throwable); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index 57780110b0..43fee0e019 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -37,6 +37,7 @@ import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftVarintFrameDecoder; @@ -107,34 +108,41 @@ public CompletableFuture ping(@Nullable EventLoop loop, PingOptions } CompletableFuture pingFuture = new CompletableFuture<>(); server.createBootstrap(loop) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline() - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast(READ_TIMEOUT, - new ReadTimeoutHandler(pingOptions.getTimeout() == 0 - ? server.getConfiguration().getReadTimeout() : pingOptions.getTimeout(), - TimeUnit.MILLISECONDS)) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) - .addLast(MINECRAFT_DECODER, - new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) - .addLast(MINECRAFT_ENCODER, - new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); - - ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); - } - }) - .connect(serverInfo.getAddress()) - .addListener((ChannelFutureListener) future -> { - if (future.isSuccess()) { - MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class); - conn.setSessionHandler(new PingSessionHandler( - pingFuture, VelocityRegisteredServer.this, conn, pingOptions.getProtocolVersion())); - } else { - pingFuture.completeExceptionally(future.cause()); - } - }); + .handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline() + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(READ_TIMEOUT, + new ReadTimeoutHandler(pingOptions.getTimeout() == 0 + ? server.getConfiguration() + .getReadTimeout() : pingOptions.getTimeout(), + TimeUnit.MILLISECONDS)) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(MINECRAFT_DECODER, + new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) + .addLast(MINECRAFT_ENCODER, + new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); + + ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); + } + }) + .connect(serverInfo.getAddress()) + .addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + MinecraftConnection conn = + future.channel().pipeline().get(MinecraftConnection.class); + conn.setActiveSessionHandler(StateRegistry.HANDSHAKE, + new PingSessionHandler( + pingFuture, + VelocityRegisteredServer.this, + conn, + pingOptions.getProtocolVersion() + )); + } else { + pingFuture.completeExceptionally(future.cause()); + } + }); return pingFuture; } @@ -181,4 +189,4 @@ public String toString() { public @NonNull Iterable audiences() { return this.getPlayersConnected(); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java new file mode 100644 index 0000000000..20f71b9644 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019-2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.util.collect; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ForwardingSet; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +/** + * An unsynchronized collection that puts an upper bound on the size of the collection. + */ +public final class CappedSet extends ForwardingSet { + + private final Set delegate; + private final int upperSize; + + private CappedSet(Set delegate, int upperSize) { + this.delegate = delegate; + this.upperSize = upperSize; + } + + /** + * Creates a capped collection backed by a {@link HashSet}. + * + * @param maxSize the maximum size of the collection + * @param the type of elements in the collection + * @return the new collection + */ + public static Set create(int maxSize) { + return new CappedSet<>(new HashSet<>(), maxSize); + } + + @Override + protected Set delegate() { + return delegate; + } + + @Override + public boolean add(T element) { + if (this.delegate.size() >= upperSize) { + Preconditions.checkState(this.delegate.contains(element), + "collection is too large (%s >= %s)", + this.delegate.size(), this.upperSize); + return false; + } + return this.delegate.add(element); + } + + @Override + public boolean addAll(Collection collection) { + return this.standardAddAll(collection); + } +} \ No newline at end of file From e24b8da8b33b278b2997da9d43487e6dacbbb612 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 04:14:57 +0100 Subject: [PATCH 03/41] I *think* I made it better --- .../api/proxy/LoginPhaseConnection.java | 2 +- .../backend/ConfigSessionHandler.java | 32 +++++++++++++++---- .../client/LoginInboundConnection.java | 2 +- .../protocol/packet/config/RegistrySync.java | 9 ++---- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java index 24df0298fe..3b313dff95 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java @@ -26,7 +26,7 @@ public interface LoginPhaseConnection extends InboundConnection, KeyIdentifiable * @param contents the message to send * @param consumer the consumer that will respond to the message */ - void sendLoginPluginMessage(ChannelIdentifier identifier, byte[] contents, + void sendLoginPluginMessage(int messageId, ChannelIdentifier identifier, byte[] contents, MessageConsumer consumer); /** diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index cd0c1238ca..d8aa035591 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -30,13 +30,11 @@ import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.packet.Disconnect; -import com.velocitypowered.proxy.protocol.packet.KeepAlive; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; -import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.*; +import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import jdk.jfr.Experimental; import net.kyori.adventure.text.Component; @@ -93,14 +91,32 @@ public boolean beforeHandle() { return false; } + @Override + public boolean handle(ClientSettings packet) { + System.out.println("ClientSettings packet received"); + return true; + } + + @Override + public boolean handle(ActiveFeatures packet) { + return true; + } + + @Override + public boolean handle(TagsUpdate packet) { + return true; + } + @Override public boolean handle(KeepAlive packet) { + System.out.println("KeepAlive packet received"); serverConn.ensureConnected().write(packet); return true; } @Override public boolean handle(ResourcePackRequest packet) { + System.out.println("ResourcePackRequest packet received"); final MinecraftConnection playerConnection = serverConn.getPlayer().getConnection(); ServerResourcePackSendEvent event = new ServerResourcePackSendEvent( @@ -140,7 +156,7 @@ public boolean handle(ResourcePackRequest packet) { @Override public boolean handle(FinishedUpdate packet) { - + System.out.println("FinishedUpdate packet received"); ClientConfigSessionHandler configHandler = (ClientConfigSessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler(); @@ -180,6 +196,7 @@ private ClientConfigSessionHandler getClientConfigSessionHandler(ConnectedPlayer */ @Override public boolean handle(Disconnect packet) { + System.out.println("Disconnect packet received"); serverConn.disconnect(); resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); return true; @@ -187,6 +204,7 @@ public boolean handle(Disconnect packet) { @Override public boolean handle(PluginMessage packet) { + System.out.println("PluginMessage packet received"); if (PluginMessageUtil.isMcBrand(packet)) { serverConn.getPlayer().getConnection().write( PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), @@ -208,12 +226,14 @@ public void disconnected() { @Override public boolean handle(RegistrySync packet) { + System.out.println("RegistrySync packet received"); serverConn.getPlayer().getConnection().write(packet.retain()); return true; } @Override public void handleGeneric(MinecraftPacket packet) { + System.out.println("MinecraftPacket packet received: " + packet.toString()); serverConn.getPlayer().getConnection().write(packet); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java index 7a90268fa4..6b52d80105 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java @@ -81,7 +81,7 @@ public ProtocolVersion getProtocolVersion() { } @Override - public void sendLoginPluginMessage(ChannelIdentifier identifier, byte[] contents, + public void sendLoginPluginMessage(int messageId, ChannelIdentifier identifier, byte[] contents, MessageConsumer consumer) { if (identifier == null) { throw new NullPointerException("identifier"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java index 285e98fb10..2094c2b6c3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java @@ -23,25 +23,22 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; -import net.kyori.adventure.nbt.BinaryTagIO; -import net.kyori.adventure.nbt.CompoundBinaryTag; public class RegistrySync extends DeferredByteBufHolder implements MinecraftPacket { - private CompoundBinaryTag registryData; - public RegistrySync() { super(null); } + //NBT change in 1.20.2 makes it difficult to parse this packet. @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - registryData = ProtocolUtils.readCompoundTag(buf, BinaryTagIO.reader()); + this.replace(buf.readRetainedSlice(buf.readableBytes())); } @Override public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeCompoundTag(buf, registryData); + buf.writeBytes(content()); } @Override From d2c30fc16991d37ffa4414bb5940963aa8f756d9 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 12:07:40 +0100 Subject: [PATCH 04/41] fix client not agreeing with finish --- .../proxy/connection/client/ClientConfigSessionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index 1c9a613bc2..1ef729734d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -150,7 +150,7 @@ public void exception(Throwable throwable) { } public CompletableFuture handleBackendFinishUpdate(VelocityServerConnection serverConn) { - serverConn.getConnection().write(new FinishedUpdate()); + player.getConnection().write(new FinishedUpdate()); return configSwitchFuture; } From 22ee0c885aa51ea53473446122320e5fffe2010c Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 13:15:54 +0100 Subject: [PATCH 05/41] latest changes --- .../backend/ConfigSessionHandler.java | 1 + .../backend/LoginSessionHandler.java | 3 + .../client/ClientConfigSessionHandler.java | 9 +- .../proxy/protocol/StateRegistry.java | 2 +- .../proxy/protocol/packet/ClientSettings.java | 3 + .../proxy/protocol/packet/JoinGame.java | 83 +++++++++++++++++-- 6 files changed, 91 insertions(+), 10 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index d8aa035591..97ce2df0b1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -94,6 +94,7 @@ public boolean beforeHandle() { @Override public boolean handle(ClientSettings packet) { System.out.println("ClientSettings packet received"); + serverConn.ensureConnected().write(packet); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index e2389f9bed..043956639a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -27,6 +27,7 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.VelocityConstants; +import com.velocitypowered.proxy.connection.client.ClientConfigSessionHandler; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; @@ -166,6 +167,8 @@ public boolean handle(ServerLoginSuccess packet) { smc.write(new LoginAcknowledged()); //Sync backend smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); + serverConn.getPlayer().getConnection().setActiveSessionHandler(StateRegistry.CONFIG, + new ClientConfigSessionHandler(server, serverConn.getPlayer())); }, smc.eventLoop()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index 1ef729734d..9a45abfc6b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -68,6 +68,7 @@ public void deactivated() { @Override public boolean handle(KeepAlive packet) { + System.out.println("CLIENT KEEPALIVE"); VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection != null) { Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId()); @@ -85,20 +86,19 @@ public boolean handle(KeepAlive packet) { @Override public boolean handle(PluginMessage packet) { - - + System.out.println("CLIENT PLUGINMESSAGE"); return true; } @Override public boolean handle(ResourcePackResponse packet) { - - + System.out.println("CLIENT RESOURCEPACK RESPONSE"); return true; } @Override public boolean handle(FinishedUpdate packet) { + System.out.println("CLIENT FINISHUPDATE"); player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, new ClientPlaySessionHandler(server, player)); @@ -109,6 +109,7 @@ public boolean handle(FinishedUpdate packet) { @Override public void handleGeneric(MinecraftPacket packet) { + System.out.println("CLIENT GENERIC: " + packet.toString()); VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection == null) { // No server connection yet, probably transitioning. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index c887a4caba..4239819e03 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -153,7 +153,7 @@ public enum StateRegistry { map(0x08, ProtocolVersion.MINECRAFT_1_19_1, false), map(0x07, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x08, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + map(0x09, ProtocolVersion.MINECRAFT_1_20_2, false)); serverbound.register(PluginMessage.class, PluginMessage::new, map(0x17, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x09, ProtocolVersion.MINECRAFT_1_9, false), diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index 5c267d195a..2384a1623c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -23,6 +23,8 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import java.util.Objects; + +import io.netty.buffer.ByteBufUtil; import org.checkerframework.checker.nullness.qual.Nullable; public class ClientSettings implements MinecraftPacket { @@ -134,6 +136,7 @@ public String toString() { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + System.out.println("BUF: " + ByteBufUtil.prettyHexDump(buf)); this.locale = ProtocolUtils.readString(buf, 16); this.viewDistance = buf.readByte(); this.chatVisibility = ProtocolUtils.readVarInt(buf); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index 6541aedfd1..48c3a67cf4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -212,7 +212,10 @@ public String toString() { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { + if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) { + // haha funny, they made 1.20.2 more complicated + this.decode1202Up(buf, version); + } else if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { // Minecraft 1.16 and above have significantly more complicated logic for reading this packet, // so separate it out. this.decode116Up(buf, version); @@ -290,9 +293,6 @@ private void decode116Up(ByteBuf buf, ProtocolVersion version) { this.reducedDebugInfo = buf.readBoolean(); this.showRespawnScreen = buf.readBoolean(); - if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) { - this.doLimitedCrafting = buf.readBoolean(); - } boolean isDebug = buf.readBoolean(); boolean isFlat = buf.readBoolean(); @@ -308,9 +308,45 @@ private void decode116Up(ByteBuf buf, ProtocolVersion version) { } } + private void decode1202Up(ByteBuf buf, ProtocolVersion version) { + this.entityId = buf.readInt(); + this.isHardcore = buf.readBoolean(); + + this.levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf)); + + this.maxPlayers = ProtocolUtils.readVarInt(buf); + + this.viewDistance = ProtocolUtils.readVarInt(buf); + this.simulationDistance = ProtocolUtils.readVarInt(buf); + + this.reducedDebugInfo = buf.readBoolean(); + this.showRespawnScreen = buf.readBoolean(); + this.doLimitedCrafting = buf.readBoolean(); + + String dimensionIdentifier = ProtocolUtils.readString(buf); + String levelName = ProtocolUtils.readString(buf); + this.partialHashedSeed = buf.readLong(); + + this.gamemode = buf.readByte(); + this.previousGamemode = buf.readByte(); + + boolean isDebug = buf.readBoolean(); + boolean isFlat = buf.readBoolean(); + this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug); + + // optional death location + if (buf.readBoolean()) + this.lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong()); + + this.portalCooldown = ProtocolUtils.readVarInt(buf); + } + @Override public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { + if (version.compareTo(ProtocolVersion.MINECRAFT_1_20_2) >= 0) { + // haha funny, they made 1.20.2 more complicated + this.encode1202Up(buf, version); + } else if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { // Minecraft 1.16 and above have significantly more complicated logic for reading this packet, // so separate it out. this.encode116Up(buf, version); @@ -410,6 +446,43 @@ private void encode116Up(ByteBuf buf, ProtocolVersion version) { } } + private void encode1202Up(ByteBuf buf, ProtocolVersion version) { + buf.writeInt(entityId); + buf.writeBoolean(isHardcore); + + ProtocolUtils.writeStringArray(buf, levelNames.toArray(String[]::new)); + + ProtocolUtils.writeVarInt(buf, maxPlayers); + + ProtocolUtils.writeVarInt(buf, viewDistance); + ProtocolUtils.writeVarInt(buf, simulationDistance); + + buf.writeBoolean(reducedDebugInfo); + buf.writeBoolean(showRespawnScreen); + buf.writeBoolean(doLimitedCrafting); + + ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier()); + ProtocolUtils.writeString(buf, dimensionInfo.getLevelName()); + buf.writeLong(partialHashedSeed); + + buf.writeByte(gamemode); + buf.writeByte(previousGamemode); + + buf.writeBoolean(dimensionInfo.isDebugType()); + buf.writeBoolean(dimensionInfo.isFlat()); + + // optional death location + if (lastDeathPosition != null) { + buf.writeBoolean(true); + ProtocolUtils.writeString(buf, lastDeathPosition.key()); + buf.writeLong(lastDeathPosition.value()); + } else { + buf.writeBoolean(false); + } + + ProtocolUtils.writeVarInt(buf, portalCooldown); + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); From 3e9fb04f4bb4e48e309c6aab0e287a0f2e9d4802 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 14:12:54 +0100 Subject: [PATCH 06/41] possibly fix old support --- .../proxy/connection/backend/LoginSessionHandler.java | 3 --- .../proxy/connection/client/ClientPlaySessionHandler.java | 1 + .../java/com/velocitypowered/proxy/protocol/StateRegistry.java | 2 +- .../com/velocitypowered/proxy/protocol/packet/JoinGame.java | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index 043956639a..e2389f9bed 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -27,7 +27,6 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.VelocityConstants; -import com.velocitypowered.proxy.connection.client.ClientConfigSessionHandler; import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults; @@ -167,8 +166,6 @@ public boolean handle(ServerLoginSuccess packet) { smc.write(new LoginAcknowledged()); //Sync backend smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); - serverConn.getPlayer().getConnection().setActiveSessionHandler(StateRegistry.CONFIG, - new ClientConfigSessionHandler(server, serverConn.getPlayer())); }, smc.eventLoop()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index fd5a90625e..fb4b36da83 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -469,6 +469,7 @@ public CompletableFuture doSwitch() { player.clearHeaderAndFooter(); } + System.out.println("STARTING UPDATE FOR SWITCH"); player.getConnection().write(new StartUpdate()); return configSwitchFuture; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 4239819e03..ac21c38111 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -192,7 +192,7 @@ public enum StateRegistry { map(0x23, ProtocolVersion.MINECRAFT_1_19, false), map(0x24, ProtocolVersion.MINECRAFT_1_19_1, false), map(0x27, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(FinishedUpdate.class, FinishedUpdate::new, + serverbound.register(StartUpdate.class, StartUpdate::new, map(0x0B, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(BossBar.class, BossBar::new, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index 48c3a67cf4..8b0d560604 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -425,7 +425,6 @@ private void encode116Up(ByteBuf buf, ProtocolVersion version) { buf.writeBoolean(reducedDebugInfo); buf.writeBoolean(showRespawnScreen); - buf.writeBoolean(doLimitedCrafting); buf.writeBoolean(dimensionInfo.isDebugType()); buf.writeBoolean(dimensionInfo.isFlat()); From b014087ef9c5d028a30bc59c7bba68de12222d1e Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 Sep 2023 14:43:24 +0100 Subject: [PATCH 07/41] More bugfixes --- .../proxy/connection/backend/TransitionSessionHandler.java | 2 +- .../proxy/connection/client/AuthSessionHandler.java | 2 +- .../proxy/connection/client/ClientPlaySessionHandler.java | 3 ++- .../java/com/velocitypowered/proxy/protocol/StateRegistry.java | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 19edba1476..713b018343 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -122,7 +122,7 @@ public boolean handle(JoinGame packet) { // Change the client to use the ClientPlaySessionHandler if required. ClientPlaySessionHandler playHandler; - if (player.getConnection().setActiveSessionHandler(StateRegistry.PLAY)) { + if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler) { playHandler = (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); } else { playHandler = new ClientPlaySessionHandler(server, player); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index 79ff40c362..d6be623b80 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -215,7 +215,7 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { return; } - if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) > 0) { + if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { mcConnection.setActiveSessionHandler(StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); } else { mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index fb4b36da83..b15c7f7ede 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -65,6 +65,7 @@ import com.velocitypowered.proxy.protocol.packet.chat.session.SessionCommandHandler; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; +import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; @@ -384,7 +385,7 @@ public boolean handle(ResourcePackResponse packet) { } @Override - public boolean handle(StartUpdate packet) { + public boolean handle(FinishedUpdate packet) { //Complete client switch player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG); configSwitchFuture.complete(null); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index ac21c38111..4239819e03 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -192,7 +192,7 @@ public enum StateRegistry { map(0x23, ProtocolVersion.MINECRAFT_1_19, false), map(0x24, ProtocolVersion.MINECRAFT_1_19_1, false), map(0x27, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(StartUpdate.class, StartUpdate::new, + serverbound.register(FinishedUpdate.class, FinishedUpdate::new, map(0x0B, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(BossBar.class, BossBar::new, From d81c78a44b9b858ab8bd678f24cda22d348672f3 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 14:47:43 +0100 Subject: [PATCH 08/41] remove sysouts --- .../proxy/connection/backend/ConfigSessionHandler.java | 8 -------- .../connection/client/ClientConfigSessionHandler.java | 5 ----- .../proxy/connection/client/ClientPlaySessionHandler.java | 1 - .../proxy/protocol/packet/ClientSettings.java | 1 - 4 files changed, 15 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 97ce2df0b1..46fcbc17a6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -93,7 +93,6 @@ public boolean beforeHandle() { @Override public boolean handle(ClientSettings packet) { - System.out.println("ClientSettings packet received"); serverConn.ensureConnected().write(packet); return true; } @@ -110,14 +109,12 @@ public boolean handle(TagsUpdate packet) { @Override public boolean handle(KeepAlive packet) { - System.out.println("KeepAlive packet received"); serverConn.ensureConnected().write(packet); return true; } @Override public boolean handle(ResourcePackRequest packet) { - System.out.println("ResourcePackRequest packet received"); final MinecraftConnection playerConnection = serverConn.getPlayer().getConnection(); ServerResourcePackSendEvent event = new ServerResourcePackSendEvent( @@ -157,7 +154,6 @@ public boolean handle(ResourcePackRequest packet) { @Override public boolean handle(FinishedUpdate packet) { - System.out.println("FinishedUpdate packet received"); ClientConfigSessionHandler configHandler = (ClientConfigSessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler(); @@ -197,7 +193,6 @@ private ClientConfigSessionHandler getClientConfigSessionHandler(ConnectedPlayer */ @Override public boolean handle(Disconnect packet) { - System.out.println("Disconnect packet received"); serverConn.disconnect(); resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); return true; @@ -205,7 +200,6 @@ public boolean handle(Disconnect packet) { @Override public boolean handle(PluginMessage packet) { - System.out.println("PluginMessage packet received"); if (PluginMessageUtil.isMcBrand(packet)) { serverConn.getPlayer().getConnection().write( PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), @@ -227,14 +221,12 @@ public void disconnected() { @Override public boolean handle(RegistrySync packet) { - System.out.println("RegistrySync packet received"); serverConn.getPlayer().getConnection().write(packet.retain()); return true; } @Override public void handleGeneric(MinecraftPacket packet) { - System.out.println("MinecraftPacket packet received: " + packet.toString()); serverConn.getPlayer().getConnection().write(packet); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index 9a45abfc6b..ff167bfe43 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -68,7 +68,6 @@ public void deactivated() { @Override public boolean handle(KeepAlive packet) { - System.out.println("CLIENT KEEPALIVE"); VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection != null) { Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId()); @@ -86,19 +85,16 @@ public boolean handle(KeepAlive packet) { @Override public boolean handle(PluginMessage packet) { - System.out.println("CLIENT PLUGINMESSAGE"); return true; } @Override public boolean handle(ResourcePackResponse packet) { - System.out.println("CLIENT RESOURCEPACK RESPONSE"); return true; } @Override public boolean handle(FinishedUpdate packet) { - System.out.println("CLIENT FINISHUPDATE"); player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, new ClientPlaySessionHandler(server, player)); @@ -109,7 +105,6 @@ public boolean handle(FinishedUpdate packet) { @Override public void handleGeneric(MinecraftPacket packet) { - System.out.println("CLIENT GENERIC: " + packet.toString()); VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection == null) { // No server connection yet, probably transitioning. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index b15c7f7ede..0b1a1bddc4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -470,7 +470,6 @@ public CompletableFuture doSwitch() { player.clearHeaderAndFooter(); } - System.out.println("STARTING UPDATE FOR SWITCH"); player.getConnection().write(new StartUpdate()); return configSwitchFuture; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index 2384a1623c..4eaa33d77e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -136,7 +136,6 @@ public String toString() { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - System.out.println("BUF: " + ByteBufUtil.prettyHexDump(buf)); this.locale = ProtocolUtils.readString(buf, 16); this.viewDistance = buf.readByte(); this.chatVisibility = ProtocolUtils.readVarInt(buf); From 1925195f2838860a588a3f96e9c5ea4fdf6a2202 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 Sep 2023 16:07:02 +0100 Subject: [PATCH 09/41] Add a play packet queue for packets sent during the config state --- .../proxy/connection/MinecraftConnection.java | 10 +++ .../proxy/network/Connections.java | 1 + .../proxy/protocol/StateRegistry.java | 10 +++ .../netty/PlayPacketQueueHandler.java | 84 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 4b1d852e6b..3c35364ea6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -36,6 +36,7 @@ import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; import com.velocitypowered.proxy.connection.client.InitialLoginSessionHandler; import com.velocitypowered.proxy.connection.client.StatusSessionHandler; +import com.velocitypowered.proxy.network.Connections; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.VelocityConnectionEvent; @@ -46,6 +47,7 @@ import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftVarintLengthEncoder; +import com.velocitypowered.proxy.protocol.netty.PlayPacketQueueHandler; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; @@ -354,6 +356,14 @@ private void setState(StateRegistry state) { this.state = state; this.channel.pipeline().get(MinecraftEncoder.class).setState(state); this.channel.pipeline().get(MinecraftDecoder.class).setState(state); + + if (state == StateRegistry.CONFIG) { + // Activate the play packet queue + this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE, new PlayPacketQueueHandler(this.protocolVersion)); + } else if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) != null) { + // Remove the queue + this.channel.pipeline().remove(Connections.PLAY_PACKET_QUEUE); + } } public ProtocolVersion getProtocolVersion() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java index dff8d2236e..27ec4ba8b8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java @@ -35,6 +35,7 @@ public class Connections { public static final String MINECRAFT_DECODER = "minecraft-decoder"; public static final String MINECRAFT_ENCODER = "minecraft-encoder"; public static final String READ_TIMEOUT = "read-timeout"; + public static final String PLAY_PACKET_QUEUE = "play-packet-queue"; private Connections() { throw new AssertionError(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 4239819e03..c3c25306f0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -596,6 +596,16 @@ public int getPacketId(final MinecraftPacket packet) { } return id; } + + /** + * Checks if the registry contains a packet with the specified {@code id}. + * + * @param packet the packet to check + * @return {@code true} if the packet is registered, {@code false} otherwise + */ + public boolean containsPacket(final MinecraftPacket packet) { + return this.packetClassToId.containsKey(packet.getClass()); + } } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java new file mode 100644 index 0000000000..65bcf6ff4f --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -0,0 +1,84 @@ +package com.velocitypowered.proxy.protocol.netty; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.StateRegistry; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.util.ReferenceCountUtil; +import io.netty.util.internal.PlatformDependent; +import org.jetbrains.annotations.NotNull; + +import java.util.Queue; + +/** + * Queues up any pending PLAY packets while the client is in the CONFIG state. + *

+ * Much of the Velocity API (i.e. chat messages) utilize PLAY packets, however + * the client is incapable of receiving these packets during the CONFIG state. + * Certain events such as the ServerPreConnectEvent may be called during this + * time, and we need to ensure that any API that uses these packets will work + * as expected. + *

+ * This handler will queue up any packets that are sent to the client during + * this time, and send them once the client has (re)entered the PLAY state. + */ +public class PlayPacketQueueHandler extends ChannelDuplexHandler { + + private final StateRegistry.PacketRegistry.ProtocolRegistry registry; + private final Queue queue = PlatformDependent.newMpscQueue(); + + public PlayPacketQueueHandler(ProtocolVersion version) { + this.registry = StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version); + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + if (!(msg instanceof MinecraftPacket)) { + ctx.write(msg, promise); + return; + } + + // If the packet exists in the CONFIG state, we want to always + // ensure that it gets sent out to the client + if (this.registry.containsPacket(((MinecraftPacket) msg))) { + ctx.write(msg, promise); + return; + } + + // Otherwise, queue the packet + this.queue.offer((MinecraftPacket) msg); + } + + @Override + public void channelInactive(@NotNull ChannelHandlerContext ctx) { + this.releaseQueue(ctx, false); + } + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) { + this.releaseQueue(ctx, ctx.channel().isActive()); + } + + private void releaseQueue(ChannelHandlerContext ctx, boolean active) { + if (this.queue.isEmpty()) { + return; + } + + // Send out all the queued packets + MinecraftPacket packet; + while ((packet = this.queue.poll()) != null) { + if (active) { + ctx.writeAndFlush(packet); + } else { + ReferenceCountUtil.release(packet); + } + } + + if (active) { + ctx.flush(); + } + } +} From 98013f06589a9571bcc3685a7c397715de0b9902 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sun, 24 Sep 2023 16:30:12 +0100 Subject: [PATCH 10/41] Fix resource pack packet id --- .../java/com/velocitypowered/proxy/protocol/StateRegistry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index c3c25306f0..cdbec66ea2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -319,7 +319,7 @@ public enum StateRegistry { map(0x3D, ProtocolVersion.MINECRAFT_1_19_1, false), map(0x3C, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x40, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x06, ProtocolVersion.MINECRAFT_1_20_2, false)); + map(0x42, ProtocolVersion.MINECRAFT_1_20_2, false)); clientbound.register(HeaderAndFooter.class, HeaderAndFooter::new, map(0x47, ProtocolVersion.MINECRAFT_1_8, true), map(0x48, ProtocolVersion.MINECRAFT_1_9, true), From 252c40a0fc01b52c4337aa11ad6befea8ab00a53 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 17:27:51 +0100 Subject: [PATCH 11/41] reduce amount of reformatting --- .../api/proxy/LoginPhaseConnection.java | 2 +- .../proxy/connection/MinecraftConnection.java | 12 +- .../connection/MinecraftSessionHandler.java | 39 +++++- .../backend/ConfigSessionHandler.java | 17 --- .../backend/LoginSessionHandler.java | 56 ++++----- .../backend/TransitionSessionHandler.java | 14 +-- .../backend/VelocityServerConnection.java | 40 +++---- .../connection/client/AuthSessionHandler.java | 112 +++++++++--------- .../client/HandshakeSessionHandler.java | 18 +-- .../client/InitialLoginSessionHandler.java | 80 ++++++------- .../client/LoginInboundConnection.java | 2 +- .../LegacyForgeHandshakeClientPhase.java | 24 ++-- .../network/ServerChannelInitializer.java | 18 +-- .../proxy/protocol/ProtocolUtils.java | 48 ++++---- .../netty/PlayPacketQueueHandler.java | 17 +++ .../proxy/protocol/packet/ClientSettings.java | 1 - .../protocol/packet/ResourcePackRequest.java | 10 +- .../proxy/server/PingSessionHandler.java | 2 +- 18 files changed, 273 insertions(+), 239 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java index 3b313dff95..24df0298fe 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/LoginPhaseConnection.java @@ -26,7 +26,7 @@ public interface LoginPhaseConnection extends InboundConnection, KeyIdentifiable * @param contents the message to send * @param consumer the consumer that will respond to the message */ - void sendLoginPluginMessage(int messageId, ChannelIdentifier identifier, byte[] contents, + void sendLoginPluginMessage(ChannelIdentifier identifier, byte[] contents, MessageConsumer consumer); /** diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 3c35364ea6..b9d930c328 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -261,7 +261,7 @@ public void flush() { public void closeWith(Object msg) { if (channel.isActive()) { boolean is17 = this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 - && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; + && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; if (is17 && this.getState() != StateRegistry.STATUS) { channel.eventLoop().execute(() -> { // 1.7.x versions have a race condition with switching protocol states, so just explicitly @@ -481,14 +481,14 @@ public void setCompressionThreshold(int threshold) { if (removedDecoder != null && removedEncoder != null) { channel.pipeline().addBefore(MINECRAFT_DECODER, FRAME_ENCODER, - MinecraftVarintLengthEncoder.INSTANCE); + MinecraftVarintLengthEncoder.INSTANCE); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.COMPRESSION_DISABLED); } } else { MinecraftCompressDecoder decoder = (MinecraftCompressDecoder) channel.pipeline() - .get(COMPRESSION_DECODER); + .get(COMPRESSION_DECODER); MinecraftCompressorAndLengthEncoder encoder = - (MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER); + (MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER); if (decoder != null && encoder != null) { decoder.setThreshold(threshold); encoder.setThreshold(threshold); @@ -524,9 +524,9 @@ public void enableEncryption(byte[] secret) throws GeneralSecurityException { VelocityCipher decryptionCipher = factory.forDecryption(key); VelocityCipher encryptionCipher = factory.forEncryption(key); channel.pipeline() - .addBefore(FRAME_DECODER, CIPHER_DECODER, new MinecraftCipherDecoder(decryptionCipher)); + .addBefore(FRAME_DECODER, CIPHER_DECODER, new MinecraftCipherDecoder(decryptionCipher)); channel.pipeline() - .addBefore(FRAME_ENCODER, CIPHER_ENCODER, new MinecraftCipherEncoder(encryptionCipher)); + .addBefore(FRAME_ENCODER, CIPHER_ENCODER, new MinecraftCipherEncoder(encryptionCipher)); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.ENCRYPTION_ENABLED); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java index a6aa30afce..79c9de636b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java @@ -18,7 +18,38 @@ package com.velocitypowered.proxy.connection; import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.packet.*; +import com.velocitypowered.proxy.protocol.packet.AvailableCommands; +import com.velocitypowered.proxy.protocol.packet.BossBar; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; +import com.velocitypowered.proxy.protocol.packet.Disconnect; +import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; +import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; +import com.velocitypowered.proxy.protocol.packet.Handshake; +import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; +import com.velocitypowered.proxy.protocol.packet.JoinGame; +import com.velocitypowered.proxy.protocol.packet.KeepAlive; +import com.velocitypowered.proxy.protocol.packet.LegacyHandshake; +import com.velocitypowered.proxy.protocol.packet.LegacyPing; +import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; +import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; +import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.Respawn; +import com.velocitypowered.proxy.protocol.packet.ServerData; +import com.velocitypowered.proxy.protocol.packet.ServerLogin; +import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; +import com.velocitypowered.proxy.protocol.packet.SetCompression; +import com.velocitypowered.proxy.protocol.packet.StatusPing; +import com.velocitypowered.proxy.protocol.packet.StatusRequest; +import com.velocitypowered.proxy.protocol.packet.StatusResponse; +import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; +import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; +import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.PingIdentify; +import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletion; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChat; @@ -26,7 +57,11 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; -import com.velocitypowered.proxy.protocol.packet.config.*; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; +import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; +import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; +import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 46fcbc17a6..ae5562c01a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -173,24 +173,7 @@ private void switchFailure(Throwable cause) { serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); resultFuture.completeExceptionally(cause); } - /* - private ClientConfigSessionHandler getClientConfigSessionHandler(ConnectedPlayer player) { - ClientPlaySessionHandler playHandler; - if (player.getConnection().getSessionHandler() instanceof ClientPlaySessionHandler) { - playHandler = (ClientPlaySessionHandler) player.getConnection().getSessionHandler(); - } else { - playHandler = new ClientPlaySessionHandler(server, player); - } - ClientConfigSessionHandler configHandler; - if (player.getConnection().getSessionHandler() instanceof ClientConfigSessionHandler) { - configHandler = (ClientConfigSessionHandler) player.getConnection().getSessionHandler(); - } else { - configHandler = new ClientConfigSessionHandler(server, player, playHandler); - } - return configHandler; - } - */ @Override public boolean handle(Disconnect packet) { serverConn.disconnect(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index e2389f9bed..a5fd2785b9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -62,7 +62,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); private static final Component MODERN_IP_FORWARDING_FAILURE = Component - .translatable("velocity.error.modern-forwarding-failed"); + .translatable("velocity.error.modern-forwarding-failed"); private final VelocityServer server; private final VelocityServerConnection serverConn; @@ -70,7 +70,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private boolean informationForwarded; LoginSessionHandler(VelocityServer server, VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -86,7 +86,7 @@ public boolean handle(LoginPluginMessage packet) { MinecraftConnection mc = serverConn.ensureConnected(); VelocityConfiguration configuration = server.getConfiguration(); if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN - && packet.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) { + && packet.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) { int requestedForwardingVersion = VelocityConstants.MODERN_FORWARDING_DEFAULT; // Check version @@ -94,8 +94,8 @@ public boolean handle(LoginPluginMessage packet) { requestedForwardingVersion = packet.content().readByte(); } ByteBuf forwardingData = createForwardingData(configuration.getForwardingSecret(), - serverConn.getPlayerRemoteAddressAsString(), serverConn.getPlayer(), - requestedForwardingVersion); + serverConn.getPlayerRemoteAddressAsString(), serverConn.getPlayer(), + requestedForwardingVersion); LoginPluginResponse response = new LoginPluginResponse(packet.getId(), true, forwardingData); mc.write(response); @@ -109,17 +109,17 @@ public boolean handle(LoginPluginMessage packet) { final byte[] contents = ByteBufUtil.getBytes(packet.content()); final MinecraftChannelIdentifier identifier = MinecraftChannelIdentifier - .from(packet.getChannel()); + .from(packet.getChannel()); this.server.getEventManager().fire(new ServerLoginPluginMessageEvent(serverConn, identifier, - contents, packet.getId())) - .thenAcceptAsync(event -> { - if (event.getResult().isAllowed()) { - mc.write(new LoginPluginResponse(packet.getId(), true, Unpooled - .wrappedBuffer(event.getResult().getResponse()))); - } else { - mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); - } - }, mc.eventLoop()); + contents, packet.getId())) + .thenAcceptAsync(event -> { + if (event.getResult().isAllowed()) { + mc.write(new LoginPluginResponse(packet.getId(), true, Unpooled + .wrappedBuffer(event.getResult().getResponse()))); + } else { + mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); + } + }, mc.eventLoop()); } return true; } @@ -140,9 +140,9 @@ public boolean handle(SetCompression packet) { @Override public boolean handle(ServerLoginSuccess packet) { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN - && !informationForwarded) { + && !informationForwarded) { resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE, - serverConn.getServer())); + serverConn.getServer())); serverConn.disconnect(); return true; } @@ -181,14 +181,14 @@ public void exception(Throwable throwable) { public void disconnected() { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) { resultFuture.completeExceptionally( - new QuietRuntimeException("The connection to the remote server was unexpectedly closed.\n" - + "This is usually because the remote server does not have BungeeCord IP forwarding " - + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " - + "for instructions on how to configure player info forwarding correctly.") + new QuietRuntimeException("The connection to the remote server was unexpectedly closed.\n" + + "This is usually because the remote server does not have BungeeCord IP forwarding " + + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " + + "for instructions on how to configure player info forwarding correctly.") ); } else { resultFuture.completeExceptionally( - new QuietRuntimeException("The connection to the remote server was unexpectedly closed.") + new QuietRuntimeException("The connection to the remote server was unexpectedly closed.") ); } } @@ -199,8 +199,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) if (requested > VelocityConstants.MODERN_FORWARDING_DEFAULT) { if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { return requested >= VelocityConstants.MODERN_LAZY_SESSION - ? VelocityConstants.MODERN_LAZY_SESSION - : VelocityConstants.MODERN_FORWARDING_DEFAULT; + ? VelocityConstants.MODERN_LAZY_SESSION + : VelocityConstants.MODERN_FORWARDING_DEFAULT; } if (player.getIdentifiedKey() != null) { // No enhanced switch on java 11 @@ -210,8 +210,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) // Since V2 is not backwards compatible we have to throw the key if v2 and requested is v1 case LINKED_V2: return requested >= VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 - ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 - : VelocityConstants.MODERN_FORWARDING_DEFAULT; + ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 + : VelocityConstants.MODERN_FORWARDING_DEFAULT; default: return VelocityConstants.MODERN_FORWARDING_DEFAULT; } @@ -223,7 +223,7 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) } private static ByteBuf createForwardingData(byte[] hmacSecret, String address, - ConnectedPlayer player, int requestedVersion) { + ConnectedPlayer player, int requestedVersion) { ByteBuf forwarded = Unpooled.buffer(2048); try { int actualVersion = findForwardingVersion(requestedVersion, player); @@ -237,7 +237,7 @@ private static ByteBuf createForwardingData(byte[] hmacSecret, String address, // This serves as additional redundancy. The key normally is stored in the // login start to the server, but some setups require this. if (actualVersion >= VelocityConstants.MODERN_FORWARDING_WITH_KEY - && actualVersion < VelocityConstants.MODERN_LAZY_SESSION) { + && actualVersion < VelocityConstants.MODERN_LAZY_SESSION) { IdentifiedKey key = player.getIdentifiedKey(); assert key != null; ProtocolUtils.writePlayerKey(forwarded, key); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 713b018343..10e749ab90 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -63,13 +63,13 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { * @param resultFuture the result future */ TransitionSessionHandler(VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; this.bungeecordMessageResponder = new BungeeCordMessageResponder(server, - serverConn.getPlayer()); + serverConn.getPlayer()); } @Override @@ -166,9 +166,9 @@ public boolean handle(Disconnect packet) { // If we were in the middle of the Forge handshake, it is not safe to proceed. We must kick // the client. if (connection.getType() == ConnectionTypes.LEGACY_FORGE - && !serverConn.getPhase().consideredComplete()) { + && !serverConn.getPhase().consideredComplete()) { resultFuture.complete(ConnectionRequestResults.forUnsafeDisconnect(packet, - serverConn.getServer())); + serverConn.getServer())); } else { resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); } @@ -199,7 +199,7 @@ public boolean handle(PluginMessage packet) { // Tell the player that we're leaving and we just aren't coming back. existingConnection.getPhase().onDepartForNewServer(existingConnection, - serverConn.getPlayer()); + serverConn.getPlayer()); } } return true; @@ -212,6 +212,6 @@ public boolean handle(PluginMessage packet) { @Override public void disconnected() { resultFuture - .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); } } \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index edd84eda69..d4213d176e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -81,8 +81,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, * @param server the Velocity proxy instance */ public VelocityServerConnection(VelocityRegisteredServer registeredServer, - @Nullable VelocityRegisteredServer previousServer, - ConnectedPlayer proxyPlayer, VelocityServer server) { + @Nullable VelocityRegisteredServer previousServer, + ConnectedPlayer proxyPlayer, VelocityServer server) { this.registeredServer = registeredServer; this.previousServer = previousServer; this.proxyPlayer = proxyPlayer; @@ -142,16 +142,16 @@ private String createLegacyForwardingAddress(UnaryOperator> prope // separated by \0 (the null byte). In order, you send the original host, the player's IP, their // UUID (undashed), and if you are in online-mode, their login properties (from Mojang). StringBuilder data = new StringBuilder() - .append(proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString()) - .append('\0') - .append(getPlayerRemoteAddressAsString()) - .append('\0') - .append(proxyPlayer.getGameProfile().getUndashedId()) - .append('\0'); + .append(proxyPlayer.getVirtualHost() + .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + .getHostString()) + .append('\0') + .append(getPlayerRemoteAddressAsString()) + .append('\0') + .append(proxyPlayer.getGameProfile().getUndashedId()) + .append('\0'); GENERAL_GSON - .toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); + .toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); return data.toString(); } @@ -162,11 +162,11 @@ private String createLegacyForwardingAddress() { private String createBungeeGuardForwardingAddress(byte[] forwardingSecret) { // Append forwarding secret as a BungeeGuard token. Property property = new Property("bungeeguard-token", - new String(forwardingSecret, StandardCharsets.UTF_8), ""); + new String(forwardingSecret, StandardCharsets.UTF_8), ""); return createLegacyForwardingAddress(properties -> ImmutableList.builder() - .addAll(properties) - .add(property) - .build()); + .addAll(properties) + .add(property) + .build()); } private void startHandshake() { @@ -176,8 +176,8 @@ private void startHandshake() { // Initiate the handshake. ProtocolVersion protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); String playerVhost = proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString(); + .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + .getHostString(); Handshake handshake = new Handshake(); handshake.setNextStatus(StateRegistry.LOGIN_ID); @@ -199,7 +199,7 @@ private void startHandshake() { mc.setProtocolVersion(protocolVersion); mc.setActiveSessionHandler(StateRegistry.LOGIN); if (proxyPlayer.getIdentifiedKey() == null - && proxyPlayer.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { + && proxyPlayer.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { mc.delayedWrite(new ServerLogin(proxyPlayer.getUsername(), proxyPlayer.getUniqueId())); } else { mc.delayedWrite(new ServerLogin(proxyPlayer.getUsername(), proxyPlayer.getIdentifiedKey())); @@ -258,7 +258,7 @@ public void disconnect() { @Override public String toString() { return "[server connection] " + proxyPlayer.getGameProfile().getName() + " -> " - + registeredServer.getServerInfo().getName(); + + registeredServer.getServerInfo().getName(); } @Override @@ -316,7 +316,7 @@ public Map getPendingPings() { */ public boolean isActive() { return connection != null && !connection.isClosed() && !gracefulDisconnect - && proxyPlayer.isActive(); + && proxyPlayer.isActive(); } /** diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index d6be623b80..9518f74ac1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -69,7 +69,7 @@ public class AuthSessionHandler implements MinecraftSessionHandler { private State loginState = State.START; // 1.20.2+ AuthSessionHandler(VelocityServer server, LoginInboundConnection inbound, - GameProfile profile, boolean onlineMode) { + GameProfile profile, boolean onlineMode) { this.server = Preconditions.checkNotNull(server, "server"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.profile = Preconditions.checkNotNull(profile, "profile"); @@ -81,9 +81,9 @@ public class AuthSessionHandler implements MinecraftSessionHandler { public void activated() { // Some connection types may need to alter the game profile. profile = mcConnection.getType().addGameProfileTokensIfRequired(profile, - server.getConfiguration().getPlayerInfoForwardingMode()); + server.getConfiguration().getPlayerInfoForwardingMode()); GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile, - onlineMode); + onlineMode); final GameProfile finalProfile = profile; server.getEventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> { @@ -94,36 +94,36 @@ public void activated() { // Initiate a regular connection and move over to it. ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(), - mcConnection, inbound.getVirtualHost().orElse(null), onlineMode, - inbound.getIdentifiedKey()); + mcConnection, inbound.getVirtualHost().orElse(null), onlineMode, + inbound.getIdentifiedKey()); this.connectedPlayer = player; if (!server.canRegisterConnection(player)) { player.disconnect0(Component.translatable("velocity.error.already-connected-proxy", - NamedTextColor.RED), true); + NamedTextColor.RED), true); return CompletableFuture.completedFuture(null); } logger.info("{} has connected", player); return server.getEventManager() - .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) - .thenAcceptAsync(event -> { - if (!mcConnection.isClosed()) { - // wait for permissions to load, then set the players permission function - final PermissionFunction function = event.createFunction(player); - if (function == null) { - logger.error( + .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) + .thenAcceptAsync(event -> { + if (!mcConnection.isClosed()) { + // wait for permissions to load, then set the players permission function + final PermissionFunction function = event.createFunction(player); + if (function == null) { + logger.error( "A plugin permission provider {} provided an invalid permission function" - + " for player {}. This is a bug in the plugin, not in Velocity. Falling" - + " back to the default permission function.", - event.getProvider().getClass().getName(), - player.getUsername()); - } else { - player.setPermissionFunction(function); - } - startLoginCompletion(player); - } - }, mcConnection.eventLoop()); + + " for player {}. This is a bug in the plugin, not in Velocity. Falling" + + " back to the default permission function.", + event.getProvider().getClass().getName(), + player.getUsername()); + } else { + player.setPermissionFunction(function); + } + startLoginCompletion(player); + } + }, mcConnection.eventLoop()); }, mcConnection.eventLoop()).exceptionally((ex) -> { logger.error("Exception during connection of {}", finalProfile, ex); return null; @@ -151,7 +151,7 @@ private void startLoginCompletion(ConnectedPlayer player) { if (!unlinkedKey.internalAddHolder(player.getUniqueId())) { if (onlineMode) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key")); + Component.translatable("multiplayer.disconnect.invalid_public_key")); return; } else { logger.warn("Key for player " + player.getUsername() + " could not be verified!"); @@ -163,7 +163,7 @@ private void startLoginCompletion(ConnectedPlayer player) { } else { if (!Objects.equals(playerKey.getSignatureHolder(), playerUniqueId)) { logger.warn("UUID for Player " + player.getUsername() + " mismatches! " - + "Chat/Commands signatures will not work correctly for this player!"); + + "Chat/Commands signatures will not work correctly for this player!"); } } } @@ -197,29 +197,29 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { mcConnection.setAssociation(player); server.getEventManager().fire(new LoginEvent(player)) - .thenAcceptAsync(event -> { - if (mcConnection.isClosed()) { - // The player was disconnected - server.getEventManager().fireAndForget(new DisconnectEvent(player, - DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); - return; - } + .thenAcceptAsync(event -> { + if (mcConnection.isClosed()) { + // The player was disconnected + server.getEventManager().fireAndForget(new DisconnectEvent(player, + DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); + return; + } - Optional reason = event.getResult().getReasonComponent(); - if (reason.isPresent()) { - player.disconnect0(reason.get(), true); - } else { - if (!server.registerConnection(player)) { - player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), - true); - return; - } + Optional reason = event.getResult().getReasonComponent(); + if (reason.isPresent()) { + player.disconnect0(reason.get(), true); + } else { + if (!server.registerConnection(player)) { + player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), + true); + return; + } - if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - mcConnection.setActiveSessionHandler(StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); - } else { - mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); - } + if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { + mcConnection.setActiveSessionHandler(StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); + } else { + mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); + } server.getEventManager().fire(new PostLoginEvent(player)) .thenCompose((ignored) -> connectToInitialServer(player)) @@ -238,18 +238,18 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { private CompletableFuture connectToInitialServer(ConnectedPlayer player) { Optional initialFromConfig = player.getNextServerToTry(); PlayerChooseInitialServerEvent event = new PlayerChooseInitialServerEvent(player, - initialFromConfig.orElse(null)); + initialFromConfig.orElse(null)); return server.getEventManager().fire(event) - .thenRunAsync(() -> { - Optional toTry = event.getInitialServer(); - if (!toTry.isPresent()) { - player.disconnect0(Component.translatable("velocity.error.no-available-servers", - NamedTextColor.RED), true); - return; - } - player.createConnectionRequest(toTry.get()).fireAndForget(); - }, mcConnection.eventLoop()); + .thenRunAsync(() -> { + Optional toTry = event.getInitialServer(); + if (!toTry.isPresent()) { + player.disconnect0(Component.translatable("velocity.error.no-available-servers", + NamedTextColor.RED), true); + return; + } + player.createConnectionRequest(toTry.get()).fireAndForget(); + }, mcConnection.eventLoop()); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index 3e181592af..48eb5b8561 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -66,7 +66,7 @@ public HandshakeSessionHandler(MinecraftConnection connection, VelocityServer se public boolean handle(LegacyPing packet) { connection.setProtocolVersion(ProtocolVersion.LEGACY); StatusSessionHandler handler = new StatusSessionHandler(server, - new LegacyInboundConnection(connection, packet)); + new LegacyInboundConnection(connection, packet)); connection.setActiveSessionHandler(StateRegistry.STATUS ,handler); handler.handle(packet); return true; @@ -75,8 +75,8 @@ public boolean handle(LegacyPing packet) { @Override public boolean handle(LegacyHandshake packet) { connection.closeWith(LegacyDisconnect.from(Component.text( - "Your client is extremely old. Please update to a newer version of Minecraft.", - NamedTextColor.RED) + "Your client is extremely old. Please update to a newer version of Minecraft.", + NamedTextColor.RED) )); return true; } @@ -84,7 +84,7 @@ public boolean handle(LegacyHandshake packet) { @Override public boolean handle(Handshake handshake) { InitialInboundConnection ic = new InitialInboundConnection(connection, - cleanVhost(handshake.getServerAddress()), handshake); + cleanVhost(handshake.getServerAddress()), handshake); StateRegistry nextState = getStateForProtocol(handshake.getNextStatus()); if (nextState == null) { LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus()); @@ -123,7 +123,7 @@ public boolean handle(Handshake handshake) { private void handleLogin(Handshake handshake, InitialInboundConnection ic) { if (!ProtocolVersion.isSupported(handshake.getProtocolVersion())) { ic.disconnectQuietly(Component.translatable("multiplayer.disconnect.outdated_client") - .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); + .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); return; } @@ -138,9 +138,9 @@ private void handleLogin(Handshake handshake, InitialInboundConnection ic) { // If the proxy is configured for modern forwarding, we must deny connections from 1.12.2 // and lower, otherwise IP information will never get forwarded. if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN - && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { + && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { ic.disconnectQuietly(Component.translatable( - "velocity.error.modern-forwarding-needs-new-client")); + "velocity.error.modern-forwarding-needs-new-client")); return; } @@ -152,7 +152,7 @@ private void handleLogin(Handshake handshake, InitialInboundConnection ic) { private ConnectionType getHandshakeConnectionType(Handshake handshake) { // Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13). if (handshake.getServerAddress().endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN) - && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { + && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { return ConnectionTypes.LEGACY_FORGE; } else if (handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_6) <= 0) { // 1.7 Forge will not notify us during handshake. UNDETERMINED will listen for incoming @@ -207,7 +207,7 @@ private static class LegacyInboundConnection implements VelocityInboundConnectio private final LegacyPing ping; private LegacyInboundConnection(MinecraftConnection connection, - LegacyPing ping) { + LegacyPing ping) { this.connection = connection; this.ping = ping; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index 98d84a476c..ca313b4076 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -64,9 +64,9 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(InitialLoginSessionHandler.class); private static final String MOJANG_HASJOINED_URL = - System.getProperty("mojang.sessionserver", - "https://sessionserver.mojang.com/session/minecraft/hasJoined") - .concat("?username=%s&serverId=%s"); + System.getProperty("mojang.sessionserver", + "https://sessionserver.mojang.com/session/minecraft/hasJoined") + .concat("?username=%s&serverId=%s"); private final VelocityServer server; private final MinecraftConnection mcConnection; @@ -77,13 +77,13 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private boolean forceKeyAuthentication; InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection, - LoginInboundConnection inbound) { + LoginInboundConnection inbound) { this.server = Preconditions.checkNotNull(server, "server"); this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.forceKeyAuthentication = System.getProperties().containsKey("auth.forceSecureProfiles") - ? Boolean.getBoolean("auth.forceSecureProfiles") - : server.getConfiguration().isForceKeyAuthentication(); + ? Boolean.getBoolean("auth.forceSecureProfiles") + : server.getConfiguration().isForceKeyAuthentication(); } @Override @@ -94,13 +94,13 @@ public boolean handle(ServerLogin packet) { if (playerKey != null) { if (playerKey.hasExpired()) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key_signature")); + Component.translatable("multiplayer.disconnect.invalid_public_key_signature")); return true; } boolean isKeyValid; if (playerKey.getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 - && playerKey instanceof IdentifiedKeyImpl) { + && playerKey instanceof IdentifiedKeyImpl) { IdentifiedKeyImpl keyImpl = (IdentifiedKeyImpl) playerKey; isKeyValid = keyImpl.internalAddHolder(packet.getHolderUuid()); } else { @@ -112,8 +112,8 @@ public boolean handle(ServerLogin packet) { return true; } } else if (mcConnection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0 - && forceKeyAuthentication - && mcConnection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) < 0) { + && forceKeyAuthentication + && mcConnection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) < 0) { inbound.disconnect(Component.translatable("multiplayer.disconnect.missing_public_key")); return true; } @@ -122,25 +122,25 @@ public boolean handle(ServerLogin packet) { PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername()); server.getEventManager().fire(event) - .thenRunAsync(() -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + .thenRunAsync(() -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - PreLoginComponentResult result = event.getResult(); - Optional disconnectReason = result.getReasonComponent(); - if (disconnectReason.isPresent()) { - // The component is guaranteed to be provided if the connection was denied. - inbound.disconnect(disconnectReason.get()); - return; - } + PreLoginComponentResult result = event.getResult(); + Optional disconnectReason = result.getReasonComponent(); + if (disconnectReason.isPresent()) { + // The component is guaranteed to be provided if the connection was denied. + inbound.disconnect(disconnectReason.get()); + return; + } - inbound.loginEventFired(() -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + inbound.loginEventFired(() -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } mcConnection.eventLoop().execute(() -> { if (!result.isForceOfflineMode() && (server.getConfiguration().isOnlineMode() @@ -190,7 +190,7 @@ public boolean handle(EncryptionResponse packet) { if (inbound.getIdentifiedKey() != null) { IdentifiedKey playerKey = inbound.getIdentifiedKey(); if (!playerKey.verifyDataSignature(packet.getVerifyToken(), verify, - Longs.toByteArray(packet.getSalt()))) { + Longs.toByteArray(packet.getSalt()))) { throw new IllegalStateException("Invalid client public signature."); } } else { @@ -205,14 +205,14 @@ public boolean handle(EncryptionResponse packet) { String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString(); String url = String.format(MOJANG_HASJOINED_URL, - urlFormParameterEscaper().escape(login.getUsername()), serverId); + urlFormParameterEscaper().escape(login.getUsername()), serverId); if (server.getConfiguration().shouldPreventClientProxyConnections()) { url += "&ip=" + urlFormParameterEscaper().escape(playerIp); } ListenableFuture hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) - .execute(); + .execute(); hasJoinedResponse.addListener(() -> { if (mcConnection.isClosed()) { // The player disconnected after we authenticated them. @@ -235,30 +235,30 @@ public boolean handle(EncryptionResponse packet) { Response profileResponse = hasJoinedResponse.get(); if (profileResponse.getStatusCode() == 200) { final GameProfile profile = GENERAL_GSON.fromJson(profileResponse.getResponseBody(), - GameProfile.class); + GameProfile.class); // Not so fast, now we verify the public key for 1.19.1+ if (inbound.getIdentifiedKey() != null - && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 - && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { + && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 + && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey(); if (!key.internalAddHolder(profile.getId())) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key")); + Component.translatable("multiplayer.disconnect.invalid_public_key")); } } // All went well, initialize the session. mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, new AuthSessionHandler( - server, inbound, profile, true + server, inbound, profile, true )); } else if (profileResponse.getStatusCode() == 204) { // Apparently an offline-mode user logged onto this online-mode proxy. inbound.disconnect(Component.translatable("velocity.error.online-mode-only", - NamedTextColor.RED)); + NamedTextColor.RED)); } else { // Something else went wrong logger.error( - "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", - profileResponse.getStatusCode(), login.getUsername(), playerIp); + "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", + profileResponse.getStatusCode(), login.getUsername(), playerIp); inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); } } catch (ExecutionException e) { @@ -300,8 +300,8 @@ private void assertState(LoginState expectedState) { if (this.currentState != expectedState) { if (MinecraftDecoder.DEBUG) { logger.error("{} Received an unexpected packet requiring state {}, but we are in {}", - inbound, - expectedState, this.currentState); + inbound, + expectedState, this.currentState); } mcConnection.close(true); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java index 6b52d80105..7a90268fa4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java @@ -81,7 +81,7 @@ public ProtocolVersion getProtocolVersion() { } @Override - public void sendLoginPluginMessage(int messageId, ChannelIdentifier identifier, byte[] contents, + public void sendLoginPluginMessage(ChannelIdentifier identifier, byte[] contents, MessageConsumer consumer) { if (identifier == null) { throw new NullPointerException("identifier"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java index ad26d09b18..71ae60c4fa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java @@ -56,8 +56,8 @@ public void onFirstJoin(ConnectedPlayer player) { @Override boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { // If we stay in this phase, we do nothing because it means the packet wasn't handled. // Returning false indicates this return false; @@ -88,8 +88,8 @@ LegacyForgeHandshakeClientPhase nextPhase() { @Override boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { // Read the mod list if we haven't already. if (!player.getModInfo().isPresent()) { List mods = LegacyForgeUtil.readModList(message); @@ -158,8 +158,8 @@ public boolean consideredComplete() { @Override boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { super.onHandle(player, message, backendConn); // just in case the timing is awful @@ -191,12 +191,12 @@ boolean onHandle(ConnectedPlayer player, @Override public final boolean handle(ConnectedPlayer player, - PluginMessage message, - VelocityServerConnection server) { + PluginMessage message, + VelocityServerConnection server) { if (server != null) { MinecraftConnection backendConn = server.getConnection(); if (backendConn != null - && message.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { + && message.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) { // Get the phase and check if we need to start the next phase. LegacyForgeHandshakeClientPhase newPhase = getNewPhase(message); @@ -221,8 +221,8 @@ public final boolean handle(ConnectedPlayer player, * @return true if handled, false otherwise. */ boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + PluginMessage message, + MinecraftConnection backendConn) { // Send the packet on to the server. backendConn.write(message.retain()); @@ -252,7 +252,7 @@ LegacyForgeHandshakeClientPhase nextPhase() { */ private LegacyForgeHandshakeClientPhase getNewPhase(PluginMessage packet) { if (packetToAdvanceOn != null - && LegacyForgeUtil.getHandshakePacketDiscriminator(packet) == packetToAdvanceOn) { + && LegacyForgeUtil.getHandshakePacketDiscriminator(packet) == packetToAdvanceOn) { return nextPhase(); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java index b126649f68..8ee79e0f1e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -57,15 +57,15 @@ public ServerChannelInitializer(final VelocityServer server) { @Override protected void initChannel(final Channel ch) { ch.pipeline() - .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast(READ_TIMEOUT, - new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), - TimeUnit.MILLISECONDS)) - .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) - .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) - .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); + .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(READ_TIMEOUT, + new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), + TimeUnit.MILLISECONDS)) + .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) + .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); final MinecraftConnection connection = new MinecraftConnection(ch, this.server); connection.setActiveSessionHandler( diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index d69175b2ac..03c342ebe6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -54,19 +54,19 @@ public enum ProtocolUtils { ; private static final GsonComponentSerializer PRE_1_16_SERIALIZER = - GsonComponentSerializer.builder() - .downsampleColors() - .emitLegacyHoverEvent() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) - .build(); + GsonComponentSerializer.builder() + .downsampleColors() + .emitLegacyHoverEvent() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .build(); private static final GsonComponentSerializer MODERN_SERIALIZER = - GsonComponentSerializer.builder() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) - .build(); + GsonComponentSerializer.builder() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .build(); public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB private static final QuietDecoderException BAD_VARINT_CACHED = - new QuietDecoderException("Bad VarInt decoded"); + new QuietDecoderException("Bad VarInt decoded"); private static final int[] VARINT_EXACT_BYTE_LENGTHS = new int[33]; static { @@ -86,7 +86,7 @@ public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); if (read == Integer.MIN_VALUE) { throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") - : BAD_VARINT_CACHED; + : BAD_VARINT_CACHED; } return read; } @@ -153,11 +153,11 @@ private static void writeVarIntFull(ByteBuf buf, int value) { buf.writeMedium(w); } else if ((value & (0xFFFFFFFF << 28)) == 0) { int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) - | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); + | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); buf.writeInt(w); } else { int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 - | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); + | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); buf.writeInt(w); buf.writeByte(value >>> 28); } @@ -200,12 +200,12 @@ private static String readString(ByteBuf buf, int cap, int length) { // sanity check and then check again to make sure our optimistic guess was good. checkFrame(length <= cap * 3, "Bad string size (got %s, maximum is %s)", length, cap); checkFrame(buf.isReadable(length), - "Trying to read a string that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); + "Trying to read a string that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8); buf.skipBytes(length); checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", - str.length(), cap); + str.length(), cap); return str; } @@ -284,8 +284,8 @@ public static byte[] readByteArray(ByteBuf buf, int cap) { checkFrame(length >= 0, "Got a negative-length array (%s)", length); checkFrame(length <= cap, "Bad array size (got %s, maximum is %s)", length, cap); checkFrame(buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); + "Trying to read an array that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); byte[] array = new byte[length]; buf.readBytes(array); return array; @@ -370,7 +370,7 @@ public static CompoundBinaryTag readCompoundTag(ByteBuf buf, BinaryTagIO.Reader return reader.read((DataInput) new ByteBufInputStream(buf)); } catch (IOException thrown) { throw new DecoderException( - "Unable to parse NBT CompoundTag, full error: " + thrown.getMessage()); + "Unable to parse NBT CompoundTag, full error: " + thrown.getMessage()); } } @@ -502,7 +502,7 @@ public static byte[] readByteArray17(ByteBuf buf) { int len = readExtendedForgeShort(buf); checkArgument(len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); byte[] ret = new byte[len]; buf.readBytes(ret); @@ -522,7 +522,7 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { int len = readExtendedForgeShort(buf); checkFrame(len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); return buf.readRetainedSlice(len); } @@ -537,11 +537,11 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { checkFrame(b.length <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, - b.length); + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.length); } else { checkFrame(b.length <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -657,7 +657,7 @@ public static IdentifiedKey readPlayerKey(ProtocolVersion version, ByteBuf buf) byte[] key = ProtocolUtils.readByteArray(buf); byte[] signature = ProtocolUtils.readByteArray(buf, 4096); IdentifiedKey.Revision revision = version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 - ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; + ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; return new IdentifiedKeyImpl(revision, key, expiry, signature); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index 65bcf6ff4f..414b973bb5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -1,3 +1,20 @@ +/* + * Copyright (C) 2023 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.velocitypowered.proxy.protocol.netty; import com.velocitypowered.api.network.ProtocolVersion; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index 4eaa33d77e..930bfa094a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -24,7 +24,6 @@ import io.netty.buffer.ByteBuf; import java.util.Objects; -import io.netty.buffer.ByteBufUtil; import org.checkerframework.checker.nullness.qual.Nullable; public class ClientSettings implements MinecraftPacket { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java index 1f8d2680ee..1a7f198f5b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java @@ -130,10 +130,10 @@ public boolean handle(MinecraftSessionHandler handler) { @Override public String toString() { return "ResourcePackRequest{" - + "url='" + url + '\'' - + ", hash='" + hash + '\'' - + ", isRequired=" + isRequired - + ", prompt='" + prompt + '\'' - + '}'; + + "url='" + url + '\'' + + ", hash='" + hash + '\'' + + ", isRequired=" + isRequired + + ", prompt='" + prompt + '\'' + + '}'; } } \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index 9399a02041..ce6a4075c4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -44,7 +44,7 @@ public class PingSessionHandler implements MinecraftSessionHandler { private boolean completed = false; PingSessionHandler(CompletableFuture result, RegisteredServer server, - MinecraftConnection connection, ProtocolVersion version) { + MinecraftConnection connection, ProtocolVersion version) { this.result = result; this.server = server; this.connection = connection; From 2e5f7fb18dc94b65737cdd78dc5e04bce03855d9 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 17:35:10 +0100 Subject: [PATCH 12/41] fix random spaces --- .../proxy/connection/backend/ConfigSessionHandler.java | 2 +- .../connection/client/ClientConfigSessionHandler.java | 6 +----- .../proxy/connection/registry/ClientConfigData.java | 8 ++------ .../proxy/connection/registry/DataTag.java | 2 -- .../proxy/protocol/packet/ClientSettings.java | 1 - 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index ae5562c01a..e9494b3842 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -213,7 +213,7 @@ public void handleGeneric(MinecraftPacket packet) { serverConn.getPlayer().getConnection().write(packet); } - public static enum State{ + public static enum State { START, NEGOTIATING, PLUGIN_MESSAGE_INTERRUPT, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index ff167bfe43..9086b9106c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -43,7 +43,6 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler { private CompletableFuture configSwitchFuture; - /** * Constructs a client config session handler. * @@ -53,7 +52,6 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler { public ClientConfigSessionHandler(VelocityServer server, ConnectedPlayer player) { this.server = server; this.player = player; - } @Override @@ -62,9 +60,7 @@ public void activated() { } @Override - public void deactivated() { - - } + public void deactivated() {} @Override public boolean handle(KeepAlive packet) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java index b0e1a50e30..6dbadf03f0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java @@ -40,7 +40,6 @@ private ClientConfigData(@Nullable VelocityResourcePackInfo resourcePackInfo, Da this.brand = brand; } - public RegistrySync getRegistry() { return registry; } @@ -65,19 +64,16 @@ public static ClientConfigData.Builder builder(){ return new Builder(); } - public static class Builder { - private VelocityResourcePackInfo resourcePackInfo; private DataTag tag; private RegistrySync registry; private Key[] features; private String brand; - private Builder(){ - } + private Builder() {} - public void clear(){ + public void clear() { this.resourcePackInfo = null; this.tag = null; this.registry = null; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java index 1e77ccc9b5..af1144d2b4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java @@ -25,8 +25,6 @@ import java.util.List; public class DataTag { - - private final ImmutableList entrySets; public DataTag(ImmutableList entrySets) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index 930bfa094a..c013929e4b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -27,7 +27,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class ClientSettings implements MinecraftPacket { - private @Nullable String locale; private byte viewDistance; private int chatVisibility; From 09a41c2e23a437d89cdeb1a4c2b9d5d662d33fb1 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 17:44:21 +0100 Subject: [PATCH 13/41] remove wildcards --- .../proxy/protocol/StateRegistry.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index cdbec66ea2..b1273486fb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -23,7 +23,36 @@ import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.SERVERBOUND; import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.proxy.protocol.packet.*; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; +import com.velocitypowered.proxy.protocol.packet.StatusRequest; +import com.velocitypowered.proxy.protocol.packet.Handshake; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; +import com.velocitypowered.proxy.protocol.packet.StatusPing; +import com.velocitypowered.proxy.protocol.packet.BossBar; +import com.velocitypowered.proxy.protocol.packet.StatusResponse; +import com.velocitypowered.proxy.protocol.packet.KeepAlive; +import com.velocitypowered.proxy.protocol.packet.PingIdentify; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.Disconnect; +import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; +import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; +import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; +import com.velocitypowered.proxy.protocol.packet.AvailableCommands; +import com.velocitypowered.proxy.protocol.packet.JoinGame; +import com.velocitypowered.proxy.protocol.packet.Respawn; +import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; +import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; +import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; +import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.ServerData; +import com.velocitypowered.proxy.protocol.packet.ServerLogin; +import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; +import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; +import com.velocitypowered.proxy.protocol.packet.SetCompression; +import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletion; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChat; @@ -31,7 +60,11 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; -import com.velocitypowered.proxy.protocol.packet.config.*; +import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; +import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; +import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; From f5b7fa8ef55f67bd43172d442a6f2f488ee62e6b Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 23:37:13 +0100 Subject: [PATCH 14/41] make requested changes --- proxy/build.gradle.kts | 3 +- .../proxy/connection/MinecraftConnection.java | 111 +++++++----- .../client/ClientPlaySessionHandler.java | 168 +++++++++++------- .../proxy/protocol/ProtocolUtils.java | 12 +- .../netty/PlayPacketQueueHandler.java | 2 +- 5 files changed, 182 insertions(+), 114 deletions(-) diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 3a3029fc59..8d6ed59453 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -12,8 +12,7 @@ application { tasks { withType { - exclude("**/com/velocitypowered/proxy/protocol/**") - exclude("**/com/velocitypowered/proxy/connection/**") + exclude("**/com/velocitypowered/proxy/protocol/packet/**") } jar { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index b9d930c328..cb26738318 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -95,7 +95,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { * Initializes a new {@link MinecraftConnection} instance. * * @param channel the channel on the connection - * @param server the Velocity instance + * @param server the Velocity instance */ public MinecraftConnection(Channel channel, VelocityServer server) { this.channel = channel; @@ -123,9 +123,10 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { activeSessionHandler.disconnected(); } - if (association != null && !knownDisconnect - && !(activeSessionHandler instanceof StatusSessionHandler) - && server.getConfiguration().isLogPlayerConnections()) { + if (association != null + && !knownDisconnect + && !(activeSessionHandler instanceof StatusSessionHandler) + && server.getConfiguration().isLogPlayerConnections()) { logger.info("{} has disconnected", association); } } @@ -153,8 +154,8 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } } else if (msg instanceof HAProxyMessage) { HAProxyMessage proxyMessage = (HAProxyMessage) msg; - this.remoteAddress = new InetSocketAddress(proxyMessage.sourceAddress(), - proxyMessage.sourcePort()); + this.remoteAddress = + new InetSocketAddress(proxyMessage.sourceAddress(), proxyMessage.sourcePort()); } else if (msg instanceof ByteBuf) { activeSessionHandler.handleUnknown((ByteBuf) msg); } @@ -177,8 +178,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E try { activeSessionHandler.exception(cause); } catch (Exception ex) { - logger.error("{}: exception handling exception in {}", - (association != null ? association : channel.remoteAddress()), activeSessionHandler, cause); + logger.error( + "{}: exception handling exception in {}", + (association != null ? association : channel.remoteAddress()), + activeSessionHandler, + cause); } } @@ -186,13 +190,15 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E if (cause instanceof ReadTimeoutException) { logger.error("{}: read timed out", association); } else { - boolean frontlineHandler = activeSessionHandler instanceof InitialLoginSessionHandler + boolean frontlineHandler = + activeSessionHandler instanceof InitialLoginSessionHandler || activeSessionHandler instanceof HandshakeSessionHandler || activeSessionHandler instanceof StatusSessionHandler; boolean isQuietDecoderException = cause instanceof QuietDecoderException; boolean willLog = !isQuietDecoderException && !frontlineHandler; if (willLog) { - logger.error("{}: exception encountered in {}", association, activeSessionHandler, cause); + logger.error( + "{}: exception encountered in {}", association, activeSessionHandler, cause); } else { knownDisconnect = true; } @@ -244,9 +250,7 @@ public void delayedWrite(Object msg) { } } - /** - * Flushes the connection. - */ + /** Flushes the connection. */ public void flush() { if (channel.isActive()) { channel.flush(); @@ -260,18 +264,28 @@ public void flush() { */ public void closeWith(Object msg) { if (channel.isActive()) { - boolean is17 = this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 - && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; + boolean is17 = + this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 + && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; if (is17 && this.getState() != StateRegistry.STATUS) { - channel.eventLoop().execute(() -> { - // 1.7.x versions have a race condition with switching protocol states, so just explicitly - // close the connection after a short while. - this.setAutoReading(false); - channel.eventLoop().schedule(() -> { - knownDisconnect = true; - channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); - }, 250, TimeUnit.MILLISECONDS); - }); + channel + .eventLoop() + .execute( + () -> { + // 1.7.x versions have a race condition with switching protocol states, so just + // explicitly + // close the connection after a short while. + this.setAutoReading(false); + channel + .eventLoop() + .schedule( + () -> { + knownDisconnect = true; + channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); + }, + 250, + TimeUnit.MILLISECONDS); + }); } else { knownDisconnect = true; channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); @@ -296,12 +310,15 @@ public void close(boolean markKnown) { } channel.close(); } else { - channel.eventLoop().execute(() -> { - if (markKnown) { - knownDisconnect = true; - } - channel.close(); - }); + channel + .eventLoop() + .execute( + () -> { + if (markKnown) { + knownDisconnect = true; + } + channel.close(); + }); } } } @@ -359,7 +376,12 @@ private void setState(StateRegistry state) { if (state == StateRegistry.CONFIG) { // Activate the play packet queue - this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE, new PlayPacketQueueHandler(this.protocolVersion)); + this.channel + .pipeline() + .addAfter( + Connections.MINECRAFT_ENCODER, + Connections.PLAY_PACKET_QUEUE, + new PlayPacketQueueHandler(this.protocolVersion)); } else if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) != null) { // Remove the queue this.channel.pipeline().remove(Connections.PLAY_PACKET_QUEUE); @@ -408,7 +430,8 @@ public void setProtocolVersion(ProtocolVersion protocolVersion) { * @param registry the registry of the handler * @param sessionHandler the handler to use */ - public void setActiveSessionHandler(StateRegistry registry, MinecraftSessionHandler sessionHandler) { + public void setActiveSessionHandler( + StateRegistry registry, MinecraftSessionHandler sessionHandler) { Preconditions.checkNotNull(registry); ensureInEventLoop(); @@ -435,7 +458,7 @@ public boolean setActiveSessionHandler(StateRegistry registry) { if (handler != null) { boolean flag = true; if (this.activeSessionHandler != null - && (flag = !Objects.equals(handler, this.activeSessionHandler))) { + && (flag = !Objects.equals(handler, this.activeSessionHandler))) { this.activeSessionHandler.deactivated(); } this.activeSessionHandler = handler; @@ -466,8 +489,8 @@ private void ensureOpen() { } /** - * Sets the compression threshold on the connection. You are responsible for sending - * {@link com.velocitypowered.proxy.protocol.packet.SetCompression} beforehand. + * Sets the compression threshold on the connection. You are responsible for sending {@link + * com.velocitypowered.proxy.protocol.packet.SetCompression} beforehand. * * @param threshold the compression threshold to use */ @@ -480,13 +503,14 @@ public void setCompressionThreshold(int threshold) { final ChannelHandler removedEncoder = channel.pipeline().remove(COMPRESSION_ENCODER); if (removedDecoder != null && removedEncoder != null) { - channel.pipeline().addBefore(MINECRAFT_DECODER, FRAME_ENCODER, - MinecraftVarintLengthEncoder.INSTANCE); + channel + .pipeline() + .addBefore(MINECRAFT_DECODER, FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.COMPRESSION_DISABLED); } } else { - MinecraftCompressDecoder decoder = (MinecraftCompressDecoder) channel.pipeline() - .get(COMPRESSION_DECODER); + MinecraftCompressDecoder decoder = + (MinecraftCompressDecoder) channel.pipeline().get(COMPRESSION_DECODER); MinecraftCompressorAndLengthEncoder encoder = (MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER); if (decoder != null && encoder != null) { @@ -523,9 +547,11 @@ public void enableEncryption(byte[] secret) throws GeneralSecurityException { VelocityCipherFactory factory = Natives.cipher.get(); VelocityCipher decryptionCipher = factory.forDecryption(key); VelocityCipher encryptionCipher = factory.forEncryption(key); - channel.pipeline() + channel + .pipeline() .addBefore(FRAME_DECODER, CIPHER_DECODER, new MinecraftCipherDecoder(decryptionCipher)); - channel.pipeline() + channel + .pipeline() .addBefore(FRAME_ENCODER, CIPHER_ENCODER, new MinecraftCipherEncoder(encryptionCipher)); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.ENCRYPTION_ENABLED); @@ -557,5 +583,4 @@ public ConnectionType getType() { public void setType(ConnectionType connectionType) { this.connectionType = connectionType; } - -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 0b1a1bddc4..8ff96ed828 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -146,7 +146,7 @@ private boolean updateTimeKeeper(@Nullable Instant instant) { private boolean validateChat(String message) { if (CharacterUtil.containsIllegalCharacters(message)) { player.disconnect( - Component.translatable("velocity.error.illegal-chat-characters", NamedTextColor.RED)); + Component.translatable("velocity.error.illegal-chat-characters", NamedTextColor.RED)); return false; } return true; @@ -155,8 +155,8 @@ private boolean validateChat(String message) { @Override public void activated() { configSwitchFuture = new CompletableFuture<>(); - Collection channels = server.getChannelRegistrar() - .getChannelsForProtocol(player.getProtocolVersion()); + Collection channels = + server.getChannelRegistrar().getChannelsForProtocol(player.getProtocolVersion()); if (!channels.isEmpty()) { PluginMessage register = constructChannelsPacket(player.getProtocolVersion(), channels); player.getConnection().write(register); @@ -285,18 +285,18 @@ public boolean handle(PluginMessage packet) { // Handling edge case when packet with FML client handshake (state COMPLETE) // arrives after JoinGame packet from destination server VelocityServerConnection serverConn = - (player.getConnectedServer() == null - && packet.getChannel().equals( - LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) - ? player.getConnectionInFlight() : player.getConnectedServer(); + (player.getConnectedServer() == null + && packet.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) + ? player.getConnectionInFlight() + : player.getConnectedServer(); MinecraftConnection backendConn = serverConn != null ? serverConn.getConnection() : null; if (serverConn != null && backendConn != null) { if (backendConn.getState() != StateRegistry.PLAY) { logger.warn( - "A plugin message was received while the backend server was not " - + "ready. Channel: {}. Packet discarded.", - packet.getChannel()); + "A plugin message was received while the backend server was not " + + "ready. Channel: {}. Packet discarded.", + packet.getChannel()); } else if (PluginMessageUtil.isRegister(packet)) { List channels = PluginMessageUtil.getChannels(packet); player.getKnownChannels().addAll(channels); @@ -308,9 +308,10 @@ public boolean handle(PluginMessage packet) { channelIdentifiers.add(new LegacyChannelIdentifier(channel)); } } - server.getEventManager() - .fireAndForget( - new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); + server + .getEventManager() + .fireAndForget( + new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isUnregister(packet)) { player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet)); @@ -320,8 +321,8 @@ public boolean handle(PluginMessage packet) { server.getEventManager().fireAndForget(new PlayerClientBrandEvent(player, brand)); player.setClientBrand(brand); backendConn.write( - PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), - player.getProtocolVersion())); + PluginMessageUtil.rewriteMinecraftBrand( + packet, server.getVersion(), player.getProtocolVersion())); } else if (BungeeCordMessageResponder.isBungeeCordMessage(packet)) { return true; } else { @@ -338,8 +339,8 @@ public boolean handle(PluginMessage packet) { ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel()); if (id == null) { // We don't have any plugins listening on this channel, process the packet now. - if (!player.getPhase().consideredComplete() || !serverConn.getPhase() - .consideredComplete()) { + if (!player.getPhase().consideredComplete() + || !serverConn.getPhase().consideredComplete()) { // The client is trying to send messages too early. This is primarily caused by mods, // but further aggravated by Velocity. To work around these issues, we will queue any // non-FML handshake messages to be sent once the FML handshake has completed or the @@ -355,22 +356,31 @@ public boolean handle(PluginMessage packet) { } else { byte[] copy = ByteBufUtil.getBytes(packet.content()); PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy); - server.getEventManager().fire(event).thenAcceptAsync(pme -> { - if (pme.getResult().isAllowed()) { - PluginMessage message = new PluginMessage(packet.getChannel(), - Unpooled.wrappedBuffer(copy)); - if (!player.getPhase().consideredComplete() || !serverConn.getPhase() - .consideredComplete()) { - // We're still processing the connection (see above), enqueue the packet for now. - loginPluginMessages.add(message.retain()); - } else { - backendConn.write(message); - } - } - }, backendConn.eventLoop()).exceptionally((ex) -> { - logger.error("Exception while handling plugin message packet for {}", player, ex); - return null; - }); + server + .getEventManager() + .fire(event) + .thenAcceptAsync( + pme -> { + if (pme.getResult().isAllowed()) { + PluginMessage message = + new PluginMessage(packet.getChannel(), Unpooled.wrappedBuffer(copy)); + if (!player.getPhase().consideredComplete() + || !serverConn.getPhase().consideredComplete()) { + // We're still processing the connection (see above), enqueue the packet + // for now. + loginPluginMessages.add(message.retain()); + } else { + backendConn.write(message); + } + } + }, + backendConn.eventLoop()) + .exceptionally( + (ex) -> { + logger.error( + "Exception while handling plugin message packet for {}", player, ex); + return null; + }); } } } @@ -386,7 +396,7 @@ public boolean handle(ResourcePackResponse packet) { @Override public boolean handle(FinishedUpdate packet) { - //Complete client switch + // Complete client switch player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG); configSwitchFuture.complete(null); return true; @@ -431,7 +441,7 @@ public void disconnected() { @Override public void exception(Throwable throwable) { player.disconnect( - Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); } @Override @@ -471,15 +481,15 @@ public CompletableFuture doSwitch() { } player.getConnection().write(new StartUpdate()); + return configSwitchFuture; } - /** * Handles the {@code JoinGame} packet. This function is responsible for handling the client-side * switching servers in Velocity. * - * @param joinGame the join game packet + * @param joinGame the join game packet * @param destination the new server we are connecting to */ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection destination) { @@ -531,9 +541,11 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de // Clear any title from the previous server. if (player.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { - player.getConnection().delayedWrite( - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET, - player.getProtocolVersion())); + player + .getConnection() + .delayedWrite( + GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.RESET, player.getProtocolVersion())); } // Flush everything @@ -603,8 +615,11 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { return false; } - server.getCommandManager().offerBrigadierSuggestions(player, command) - .thenAcceptAsync(suggestions -> { + server + .getCommandManager() + .offerBrigadierSuggestions(player, command) + .thenAcceptAsync( + suggestions -> { if (suggestions.isEmpty()) { return; } @@ -614,7 +629,7 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { String offer = suggestion.getText(); Component tooltip = null; if (suggestion.getTooltip() != null - && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { + && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); } offers.add(new Offer(offer, tooltip)); @@ -628,9 +643,15 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { resp.getOffers().addAll(offers); player.getConnection().write(resp); } - }, player.getConnection().eventLoop()).exceptionally((ex) -> { - logger.error("Exception while handling command tab completion for player {} executing {}", - player, command, ex); + }, + player.getConnection().eventLoop()) + .exceptionally( + (ex) -> { + logger.error( + "Exception while handling command tab completion for player {} executing {}", + player, + command, + ex); return null; }); return true; // Sorry, handler; we're just gonna have to lie to you here. @@ -666,8 +687,11 @@ public void handleTabCompleteResponse(TabCompleteResponse response) { private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteResponse response) { String command = request.getCommand().substring(1); - server.getCommandManager().offerBrigadierSuggestions(player, command) - .thenAcceptAsync(offers -> { + server + .getCommandManager() + .offerBrigadierSuggestions(player, command) + .thenAcceptAsync( + offers -> { boolean legacy = player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0; try { for (Suggestion suggestion : offers.getList()) { @@ -678,7 +702,7 @@ private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteRes } Component tooltip = null; if (suggestion.getTooltip() != null - && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { + && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); } response.getOffers().add(new Offer(offer, tooltip)); @@ -686,15 +710,21 @@ private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteRes response.getOffers().sort(null); player.getConnection().write(response); } catch (Exception e) { - logger.error("Unable to provide tab list completions for {} for command '{}'", - player.getUsername(), command, - e); + logger.error( + "Unable to provide tab list completions for {} for command '{}'", + player.getUsername(), + command, + e); } - }, player.getConnection().eventLoop()).exceptionally((ex) -> { + }, + player.getConnection().eventLoop()) + .exceptionally( + (ex) -> { logger.error( - "Exception while finishing command tab completion, with request {} and response {}", - request, - response, ex); + "Exception while finishing command tab completion, with request {} and response {}", + request, + response, + ex); return null; }); } @@ -704,25 +734,30 @@ private void finishRegularTabComplete(TabCompleteRequest request, TabCompleteRes for (Offer offer : response.getOffers()) { offers.add(offer.getText()); } - server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), offers)) - .thenAcceptAsync(e -> { + server + .getEventManager() + .fire(new TabCompleteEvent(player, request.getCommand(), offers)) + .thenAcceptAsync( + e -> { response.getOffers().clear(); for (String s : e.getSuggestions()) { response.getOffers().add(new Offer(s)); } player.getConnection().write(response); - }, player.getConnection().eventLoop()).exceptionally((ex) -> { + }, + player.getConnection().eventLoop()) + .exceptionally( + (ex) -> { logger.error( - "Exception while finishing regular tab completion, with request {} and response{}", - request, - response, ex); + "Exception while finishing regular tab completion, with request {} and response{}", + request, + response, + ex); return null; }); } - /** - * Immediately send any queued messages to the server. - */ + /** Immediately send any queued messages to the server. */ public void flushQueuedMessages() { VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection != null) { @@ -735,5 +770,4 @@ public void flushQueuedMessages() { } } } - -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 03c342ebe6..93edc2d265 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -248,7 +248,13 @@ public static void writeKey(ByteBuf buf, Key key) { * @return the decoded key array */ public static Key[] readKeyArray(ByteBuf buf) { - Key[] ret = new Key[readVarInt(buf)]; + int length = readVarInt(buf); + checkFrame(length >= 0, "Got a negative-length array (%s)", length); + checkFrame(buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); + Key[] ret = new Key[length]; + for (int i = 0; i < ret.length; i++) { ret[i] = ProtocolUtils.readKey(buf); } @@ -424,6 +430,10 @@ public static void writeStringArray(ByteBuf buf, String[] stringArray) { */ public static int[] readVarIntArray(ByteBuf buf) { int length = readVarInt(buf); + checkFrame(length >= 0, "Got a negative-length array (%s)", length); + checkFrame(buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); int[] ret = new int[length]; for (int i = 0; i < length; i++) { ret[i] = readVarInt(buf); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index 414b973bb5..62dd4d3036 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -88,7 +88,7 @@ private void releaseQueue(ChannelHandlerContext ctx, boolean active) { MinecraftPacket packet; while ((packet = this.queue.poll()) != null) { if (active) { - ctx.writeAndFlush(packet); + ctx.write(packet, ctx.voidPromise()); } else { ReferenceCountUtil.release(packet); } From 87cd1109f54927ddffabc7dc11b7d019c4cb5839 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Sun, 24 Sep 2023 23:46:22 +0100 Subject: [PATCH 15/41] reformat using google style format --- .../backend/BackendConfigSessionHandler.java | 14 +- .../backend/ConfigSessionHandler.java | 144 +++--- .../backend/LoginSessionHandler.java | 102 ++-- .../backend/TransitionSessionHandler.java | 66 +-- .../backend/VelocityServerConnection.java | 137 +++--- .../connection/client/AuthSessionHandler.java | 232 ++++++---- .../client/ClientConfigSessionHandler.java | 15 +- .../connection/client/ConnectedPlayer.java | 435 +++++++++++------- .../client/HandshakeSessionHandler.java | 44 +- .../client/InitialLoginSessionHandler.java | 232 +++++----- .../LegacyForgeHandshakeClientPhase.java | 57 +-- .../connection/registry/ClientConfigData.java | 15 +- .../proxy/connection/registry/DataTag.java | 2 +- .../proxy/network/Connections.java | 4 +- .../network/ServerChannelInitializer.java | 16 +- .../proxy/protocol/ProtocolUtils.java | 133 +++--- .../proxy/protocol/StateRegistry.java | 379 +++++++++------ .../netty/PlayPacketQueueHandler.java | 23 +- .../proxy/protocol/packet/ClientSettings.java | 41 +- .../proxy/protocol/packet/JoinGame.java | 65 ++- .../protocol/packet/LoginAcknowledged.java | 38 +- .../proxy/protocol/packet/PingIdentify.java | 46 +- .../protocol/packet/ResourcePackRequest.java | 23 +- .../proxy/protocol/packet/ServerLogin.java | 12 +- .../packet/config/ActiveFeatures.java | 68 +-- .../packet/config/FinishedUpdate.java | 31 +- .../protocol/packet/config/RegistrySync.java | 36 +- .../protocol/packet/config/StartUpdate.java | 31 +- .../protocol/packet/config/TagsUpdate.java | 84 ++-- .../proxy/server/PingSessionHandler.java | 17 +- .../server/VelocityRegisteredServer.java | 81 ++-- .../proxy/util/collect/CappedSet.java | 16 +- 32 files changed, 1523 insertions(+), 1116 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java index 6b18e449f7..48d3308d54 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java @@ -25,9 +25,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** - * Handles the initial server configuration setup. - */ +/** Handles the initial server configuration setup. */ public class BackendConfigSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(BackendConfigSessionHandler.class); @@ -37,18 +35,18 @@ public class BackendConfigSessionHandler implements MinecraftSessionHandler { private final CompletableFuture resultFuture; private boolean informationForwarded; - BackendConfigSessionHandler(VelocityServer server, VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + BackendConfigSessionHandler( + VelocityServer server, + VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; } - @Override public boolean handle(StartUpdate packet) { return true; } - -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index e9494b3842..fdb0aba7fa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -45,9 +45,8 @@ import java.util.concurrent.CompletableFuture; /** - * A special session handler that catches "last minute" disconnects. - * This version is to accommodate 1.20.2+ switching. - * Yes, some of this is exceptionally stupid. + * A special session handler that catches "last minute" disconnects. This version is to accommodate + * 1.20.2+ switching. Yes, some of this is exceptionally stupid. */ @Experimental public class ConfigSessionHandler implements MinecraftSessionHandler { @@ -58,19 +57,19 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { private final VelocityServerConnection serverConn; private final CompletableFuture resultFuture; - private State state; /** * Creates the new transition handler. * - * @param server the Velocity server instance - * @param serverConn the server connection + * @param server the Velocity server instance + * @param serverConn the server connection * @param resultFuture the result future */ - ConfigSessionHandler(VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + ConfigSessionHandler( + VelocityServer server, + VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -78,8 +77,7 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { } @Override - public void deactivated() { - } + public void deactivated() {} @Override public boolean beforeHandle() { @@ -117,37 +115,47 @@ public boolean handle(KeepAlive packet) { public boolean handle(ResourcePackRequest packet) { final MinecraftConnection playerConnection = serverConn.getPlayer().getConnection(); - ServerResourcePackSendEvent event = new ServerResourcePackSendEvent( - packet.toServerPromptedPack(), this.serverConn); - - server.getEventManager().fire(event).thenAcceptAsync(serverResourcePackSendEvent -> { - if (playerConnection.isClosed()) { - return; - } - if (serverResourcePackSendEvent.getResult().isAllowed()) { - ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); - if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { - ((VelocityResourcePackInfo) toSend) - .setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); - } - - serverConn.getPlayer().queueResourcePack(toSend); - } else if (serverConn.getConnection() != null) { - serverConn.getConnection().write(new ResourcePackResponse( - packet.getHash(), - PlayerResourcePackStatusEvent.Status.DECLINED - )); - } - }, playerConnection.eventLoop()).exceptionally((ex) -> { - if (serverConn.getConnection() != null) { - serverConn.getConnection().write(new ResourcePackResponse( - packet.getHash(), - PlayerResourcePackStatusEvent.Status.DECLINED - )); - } - logger.error("Exception while handling resource pack send for {}", playerConnection, ex); - return null; - }); + ServerResourcePackSendEvent event = + new ServerResourcePackSendEvent(packet.toServerPromptedPack(), this.serverConn); + + server + .getEventManager() + .fire(event) + .thenAcceptAsync( + serverResourcePackSendEvent -> { + if (playerConnection.isClosed()) { + return; + } + if (serverResourcePackSendEvent.getResult().isAllowed()) { + ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); + if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { + ((VelocityResourcePackInfo) toSend) + .setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + } + + serverConn.getPlayer().queueResourcePack(toSend); + } else if (serverConn.getConnection() != null) { + serverConn + .getConnection() + .write( + new ResourcePackResponse( + packet.getHash(), PlayerResourcePackStatusEvent.Status.DECLINED)); + } + }, + playerConnection.eventLoop()) + .exceptionally( + (ex) -> { + if (serverConn.getConnection() != null) { + serverConn + .getConnection() + .write( + new ResourcePackResponse( + packet.getHash(), PlayerResourcePackStatusEvent.Status.DECLINED)); + } + logger.error( + "Exception while handling resource pack send for {}", playerConnection, ex); + return null; + }); return true; } @@ -155,21 +163,30 @@ public boolean handle(ResourcePackRequest packet) { @Override public boolean handle(FinishedUpdate packet) { ClientConfigSessionHandler configHandler = - (ClientConfigSessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler(); - - configHandler.handleBackendFinishUpdate(serverConn).thenAcceptAsync((unused) -> { - serverConn.ensureConnected().write(new FinishedUpdate()); - serverConn.ensureConnected().setActiveSessionHandler(StateRegistry.PLAY, - new TransitionSessionHandler(server, serverConn, resultFuture)); - }, serverConn.ensureConnected().eventLoop()); + (ClientConfigSessionHandler) + serverConn.getPlayer().getConnection().getActiveSessionHandler(); + + configHandler + .handleBackendFinishUpdate(serverConn) + .thenAcceptAsync( + (unused) -> { + serverConn.ensureConnected().write(new FinishedUpdate()); + serverConn + .ensureConnected() + .setActiveSessionHandler( + StateRegistry.PLAY, + new TransitionSessionHandler(server, serverConn, resultFuture)); + }, + serverConn.ensureConnected().eventLoop()); return true; } - private void switchFailure(Throwable cause) { - logger.error("Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - serverConn.getPlayer().getUsername(), cause); + logger.error( + "Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + serverConn.getPlayer().getUsername(), + cause); serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); resultFuture.completeExceptionally(cause); } @@ -184,22 +201,27 @@ public boolean handle(Disconnect packet) { @Override public boolean handle(PluginMessage packet) { if (PluginMessageUtil.isMcBrand(packet)) { - serverConn.getPlayer().getConnection().write( - PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), - serverConn.getPlayer().getProtocolVersion())); + serverConn + .getPlayer() + .getConnection() + .write( + PluginMessageUtil.rewriteMinecraftBrand( + packet, server.getVersion(), serverConn.getPlayer().getProtocolVersion())); } else { // TODO: Change this so its usable for mod loaders serverConn.disconnect(); - resultFuture.complete(ConnectionRequestResults.forDisconnect( - Component.translatable("multiplayer.disconnect.missing_tags"), serverConn.getServer())); + resultFuture.complete( + ConnectionRequestResults.forDisconnect( + Component.translatable("multiplayer.disconnect.missing_tags"), + serverConn.getServer())); } return true; } @Override public void disconnected() { - resultFuture - .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + resultFuture.completeExceptionally( + new IOException("Unexpectedly disconnected from remote server")); } @Override @@ -220,4 +242,4 @@ public static enum State { RESOURCE_PACK_INTERRUPT, COMPLETE } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index a5fd2785b9..5ac6076f71 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -54,22 +54,22 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** - * Handles a player trying to log into the proxy. - */ +/** Handles a player trying to log into the proxy. */ public class LoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); - private static final Component MODERN_IP_FORWARDING_FAILURE = Component - .translatable("velocity.error.modern-forwarding-failed"); + private static final Component MODERN_IP_FORWARDING_FAILURE = + Component.translatable("velocity.error.modern-forwarding-failed"); private final VelocityServer server; private final VelocityServerConnection serverConn; private final CompletableFuture resultFuture; private boolean informationForwarded; - LoginSessionHandler(VelocityServer server, VelocityServerConnection serverConn, + LoginSessionHandler( + VelocityServer server, + VelocityServerConnection serverConn, CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; @@ -93,9 +93,12 @@ public boolean handle(LoginPluginMessage packet) { if (packet.content().readableBytes() == 1) { requestedForwardingVersion = packet.content().readByte(); } - ByteBuf forwardingData = createForwardingData(configuration.getForwardingSecret(), - serverConn.getPlayerRemoteAddressAsString(), serverConn.getPlayer(), - requestedForwardingVersion); + ByteBuf forwardingData = + createForwardingData( + configuration.getForwardingSecret(), + serverConn.getPlayerRemoteAddressAsString(), + serverConn.getPlayer(), + requestedForwardingVersion); LoginPluginResponse response = new LoginPluginResponse(packet.getId(), true, forwardingData); mc.write(response); @@ -108,18 +111,24 @@ public boolean handle(LoginPluginMessage packet) { } final byte[] contents = ByteBufUtil.getBytes(packet.content()); - final MinecraftChannelIdentifier identifier = MinecraftChannelIdentifier - .from(packet.getChannel()); - this.server.getEventManager().fire(new ServerLoginPluginMessageEvent(serverConn, identifier, - contents, packet.getId())) - .thenAcceptAsync(event -> { - if (event.getResult().isAllowed()) { - mc.write(new LoginPluginResponse(packet.getId(), true, Unpooled - .wrappedBuffer(event.getResult().getResponse()))); - } else { - mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); - } - }, mc.eventLoop()); + final MinecraftChannelIdentifier identifier = + MinecraftChannelIdentifier.from(packet.getChannel()); + this.server + .getEventManager() + .fire(new ServerLoginPluginMessageEvent(serverConn, identifier, contents, packet.getId())) + .thenAcceptAsync( + event -> { + if (event.getResult().isAllowed()) { + mc.write( + new LoginPluginResponse( + packet.getId(), + true, + Unpooled.wrappedBuffer(event.getResult().getResponse()))); + } else { + mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); + } + }, + mc.eventLoop()); } return true; } @@ -141,8 +150,9 @@ public boolean handle(SetCompression packet) { public boolean handle(ServerLoginSuccess packet) { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) { - resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE, - serverConn.getServer())); + resultFuture.complete( + ConnectionRequestResults.forDisconnect( + MODERN_IP_FORWARDING_FAILURE, serverConn.getServer())); serverConn.disconnect(); return true; } @@ -153,20 +163,27 @@ public boolean handle(ServerLoginSuccess packet) { // Move into the PLAY phase. MinecraftConnection smc = serverConn.ensureConnected(); if (smc.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture)); + smc.setActiveSessionHandler( + StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture)); } else { CompletableFuture switchFuture; - if (serverConn.getPlayer().getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler) { - switchFuture = ((ClientPlaySessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler()) + if (serverConn.getPlayer().getConnection().getActiveSessionHandler() + instanceof ClientPlaySessionHandler) { + switchFuture = + ((ClientPlaySessionHandler) + serverConn.getPlayer().getConnection().getActiveSessionHandler()) .doSwitch(); } else { switchFuture = CompletableFuture.completedFuture(null); } - switchFuture.thenAcceptAsync((unused) -> { - smc.write(new LoginAcknowledged()); - //Sync backend - smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); - }, smc.eventLoop()); + switchFuture.thenAcceptAsync( + (unused) -> { + smc.write(new LoginAcknowledged()); + // Sync backend + smc.setActiveSessionHandler( + StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); + }, + smc.eventLoop()); } return true; @@ -181,15 +198,15 @@ public void exception(Throwable throwable) { public void disconnected() { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) { resultFuture.completeExceptionally( - new QuietRuntimeException("The connection to the remote server was unexpectedly closed.\n" - + "This is usually because the remote server does not have BungeeCord IP forwarding " - + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " - + "for instructions on how to configure player info forwarding correctly.") - ); + new QuietRuntimeException( + "The connection to the remote server was unexpectedly closed.\n" + + "This is usually because the remote server does not have BungeeCord IP forwarding " + + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " + + "for instructions on how to configure player info forwarding correctly.")); } else { resultFuture.completeExceptionally( - new QuietRuntimeException("The connection to the remote server was unexpectedly closed.") - ); + new QuietRuntimeException( + "The connection to the remote server was unexpectedly closed.")); } } @@ -207,7 +224,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) switch (player.getIdentifiedKey().getKeyRevision()) { case GENERIC_V1: return VelocityConstants.MODERN_FORWARDING_WITH_KEY; - // Since V2 is not backwards compatible we have to throw the key if v2 and requested is v1 + // Since V2 is not backwards compatible we have to throw the key if v2 and requested is + // v1 case LINKED_V2: return requested >= VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 @@ -222,8 +240,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) return VelocityConstants.MODERN_FORWARDING_DEFAULT; } - private static ByteBuf createForwardingData(byte[] hmacSecret, String address, - ConnectedPlayer player, int requestedVersion) { + private static ByteBuf createForwardingData( + byte[] hmacSecret, String address, ConnectedPlayer player, int requestedVersion) { ByteBuf forwarded = Unpooled.buffer(2048); try { int actualVersion = findForwardingVersion(requestedVersion, player); @@ -273,4 +291,4 @@ private static ByteBuf createForwardingData(byte[] hmacSecret, String address, throw new AssertionError(e); } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 10e749ab90..1042ecd1f6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -43,9 +43,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** - * A special session handler that catches "last minute" disconnects. - */ +/** A special session handler that catches "last minute" disconnects. */ public class TransitionSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(TransitionSessionHandler.class); @@ -58,18 +56,19 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { /** * Creates the new transition handler. * - * @param server the Velocity server instance - * @param serverConn the server connection + * @param server the Velocity server instance + * @param serverConn the server connection * @param resultFuture the result future */ - TransitionSessionHandler(VelocityServer server, + TransitionSessionHandler( + VelocityServer server, VelocityServerConnection serverConn, CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; - this.bungeecordMessageResponder = new BungeeCordMessageResponder(server, - serverConn.getPlayer()); + this.bungeecordMessageResponder = + new BungeeCordMessageResponder(server, serverConn.getPlayer()); } @Override @@ -110,9 +109,11 @@ public boolean handle(JoinGame packet) { // The goods are in hand! We got JoinGame. Let's transition completely to the new state. smc.setAutoReading(false); - server.getEventManager() - .fire(new ServerConnectedEvent(player, serverConn.getServer(), previousServer)) - .thenRunAsync(() -> { + server + .getEventManager() + .fire(new ServerConnectedEvent(player, serverConn.getServer(), previousServer)) + .thenRunAsync( + () -> { // Make sure we can still transition (player might have disconnected here). if (!serverConn.isActive()) { // Connection is obsolete. @@ -122,8 +123,10 @@ public boolean handle(JoinGame packet) { // Change the client to use the ClientPlaySessionHandler if required. ClientPlaySessionHandler playHandler; - if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler) { - playHandler = (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); + if (player.getConnection().getActiveSessionHandler() + instanceof ClientPlaySessionHandler) { + playHandler = + (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); } else { playHandler = new ClientPlaySessionHandler(server, player); player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, playHandler); @@ -133,7 +136,8 @@ public boolean handle(JoinGame packet) { // Set the new play session handler for the server. We will have nothing more to do // with this connection once this task finishes up. - smc.setActiveSessionHandler(StateRegistry.PLAY, new BackendPlaySessionHandler(server, serverConn)); + smc.setActiveSessionHandler( + StateRegistry.PLAY, new BackendPlaySessionHandler(server, serverConn)); // Clean up disabling auto-read while the connected event was being processed. smc.setAutoReading(true); @@ -142,14 +146,19 @@ public boolean handle(JoinGame packet) { serverConn.getPlayer().setConnectedServer(serverConn); // We're done! :) - server.getEventManager().fireAndForget(new ServerPostConnectEvent(player, - previousServer)); + server + .getEventManager() + .fireAndForget(new ServerPostConnectEvent(player, previousServer)); resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer())); - }, smc.eventLoop()) - .exceptionally(exc -> { - logger.error("Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - player.getUsername(), exc); + }, + smc.eventLoop()) + .exceptionally( + exc -> { + logger.error( + "Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + player.getUsername(), + exc); player.disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); resultFuture.completeExceptionally(exc); return null; @@ -167,8 +176,8 @@ public boolean handle(Disconnect packet) { // the client. if (connection.getType() == ConnectionTypes.LEGACY_FORGE && !serverConn.getPhase().consideredComplete()) { - resultFuture.complete(ConnectionRequestResults.forUnsafeDisconnect(packet, - serverConn.getServer())); + resultFuture.complete( + ConnectionRequestResults.forUnsafeDisconnect(packet, serverConn.getServer())); } else { resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); } @@ -198,8 +207,9 @@ public boolean handle(PluginMessage packet) { existingConnection.setConnectionPhase(IN_TRANSITION); // Tell the player that we're leaving and we just aren't coming back. - existingConnection.getPhase().onDepartForNewServer(existingConnection, - serverConn.getPlayer()); + existingConnection + .getPhase() + .onDepartForNewServer(existingConnection, serverConn.getPlayer()); } } return true; @@ -211,7 +221,7 @@ public boolean handle(PluginMessage packet) { @Override public void disconnected() { - resultFuture - .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + resultFuture.completeExceptionally( + new IOException("Unexpectedly disconnected from remote server")); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index d4213d176e..61dba9efdf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -56,9 +56,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Handles a connection from the proxy to some backend server. - */ +/** Handles a connection from the proxy to some backend server. */ public class VelocityServerConnection implements MinecraftConnectionAssociation, ServerConnection { private final VelocityRegisteredServer registeredServer; @@ -76,13 +74,15 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, * Initializes a new server connection. * * @param registeredServer the server to connect to - * @param previousServer the server the player is coming from - * @param proxyPlayer the player connecting to the server - * @param server the Velocity proxy instance + * @param previousServer the server the player is coming from + * @param proxyPlayer the player connecting to the server + * @param server the Velocity proxy instance */ - public VelocityServerConnection(VelocityRegisteredServer registeredServer, + public VelocityServerConnection( + VelocityRegisteredServer registeredServer, @Nullable VelocityRegisteredServer previousServer, - ConnectedPlayer proxyPlayer, VelocityServer server) { + ConnectedPlayer proxyPlayer, + VelocityServer server) { this.registeredServer = registeredServer; this.previousServer = previousServer; this.proxyPlayer = proxyPlayer; @@ -93,37 +93,43 @@ public VelocityServerConnection(VelocityRegisteredServer registeredServer, * Connects to the server. * * @return a {@link com.velocitypowered.api.proxy.ConnectionRequestBuilder.Result} representing - * whether or not the connect succeeded + * whether or not the connect succeeded */ public CompletableFuture connect() { CompletableFuture result = new CompletableFuture<>(); // Note: we use the event loop for the connection the player is on. This reduces context // switches. - server.createBootstrap(proxyPlayer.getConnection().eventLoop()) - .handler(server.getBackendChannelInitializer()) - .connect(registeredServer.getServerInfo().getAddress()) - .addListener((ChannelFutureListener) future -> { - if (future.isSuccess()) { - connection = new MinecraftConnection(future.channel(), server); - connection.setAssociation(VelocityServerConnection.this); - future.channel().pipeline().addLast(HANDLER, connection); - - // Kick off the connection process - if (!connection.setActiveSessionHandler(StateRegistry.HANDSHAKE)) { - MinecraftSessionHandler handler = new LoginSessionHandler(server, VelocityServerConnection.this, result); - connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, handler); - connection.addSessionHandler(StateRegistry.LOGIN, handler); - } - - // Set the connection phase, which may, for future forge (or whatever), be determined - // at this point already - connectionPhase = connection.getType().getInitialBackendPhase(); - startHandshake(); - } else { - // Complete the result immediately. ConnectedPlayer will reset the in-flight connection. - result.completeExceptionally(future.cause()); - } - }); + server + .createBootstrap(proxyPlayer.getConnection().eventLoop()) + .handler(server.getBackendChannelInitializer()) + .connect(registeredServer.getServerInfo().getAddress()) + .addListener( + (ChannelFutureListener) + future -> { + if (future.isSuccess()) { + connection = new MinecraftConnection(future.channel(), server); + connection.setAssociation(VelocityServerConnection.this); + future.channel().pipeline().addLast(HANDLER, connection); + + // Kick off the connection process + if (!connection.setActiveSessionHandler(StateRegistry.HANDSHAKE)) { + MinecraftSessionHandler handler = + new LoginSessionHandler(server, VelocityServerConnection.this, result); + connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, handler); + connection.addSessionHandler(StateRegistry.LOGIN, handler); + } + + // Set the connection phase, which may, for future forge (or whatever), be + // determined + // at this point already + connectionPhase = connection.getType().getInitialBackendPhase(); + startHandshake(); + } else { + // Complete the result immediately. ConnectedPlayer will reset the in-flight + // connection. + result.completeExceptionally(future.cause()); + } + }); return result; } @@ -141,17 +147,20 @@ private String createLegacyForwardingAddress(UnaryOperator> prope // BungeeCord IP forwarding is simply a special injection after the "address" in the handshake, // separated by \0 (the null byte). In order, you send the original host, the player's IP, their // UUID (undashed), and if you are in online-mode, their login properties (from Mojang). - StringBuilder data = new StringBuilder() - .append(proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString()) - .append('\0') - .append(getPlayerRemoteAddressAsString()) - .append('\0') - .append(proxyPlayer.getGameProfile().getUndashedId()) - .append('\0'); - GENERAL_GSON - .toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); + StringBuilder data = + new StringBuilder() + .append( + proxyPlayer + .getVirtualHost() + .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + .getHostString()) + .append('\0') + .append(getPlayerRemoteAddressAsString()) + .append('\0') + .append(proxyPlayer.getGameProfile().getUndashedId()) + .append('\0'); + GENERAL_GSON.toJson( + propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); return data.toString(); } @@ -161,12 +170,10 @@ private String createLegacyForwardingAddress() { private String createBungeeGuardForwardingAddress(byte[] forwardingSecret) { // Append forwarding secret as a BungeeGuard token. - Property property = new Property("bungeeguard-token", - new String(forwardingSecret, StandardCharsets.UTF_8), ""); - return createLegacyForwardingAddress(properties -> ImmutableList.builder() - .addAll(properties) - .add(property) - .build()); + Property property = + new Property("bungeeguard-token", new String(forwardingSecret, StandardCharsets.UTF_8), ""); + return createLegacyForwardingAddress( + properties -> ImmutableList.builder().addAll(properties).add(property).build()); } private void startHandshake() { @@ -175,9 +182,11 @@ private void startHandshake() { // Initiate the handshake. ProtocolVersion protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); - String playerVhost = proxyPlayer.getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString(); + String playerVhost = + proxyPlayer + .getVirtualHost() + .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + .getHostString(); Handshake handshake = new Handshake(); handshake.setNextStatus(StateRegistry.LOGIN_ID); @@ -244,9 +253,7 @@ public ConnectedPlayer getPlayer() { return proxyPlayer; } - /** - * Disconnects from the server. - */ + /** Disconnects from the server. */ public void disconnect() { if (connection != null) { gracefulDisconnect = true; @@ -257,7 +264,9 @@ public void disconnect() { @Override public String toString() { - return "[server connection] " + proxyPlayer.getGameProfile().getName() + " -> " + return "[server connection] " + + proxyPlayer.getGameProfile().getName() + + " -> " + registeredServer.getServerInfo().getName(); } @@ -270,7 +279,7 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { * Sends a plugin message to the server through this connection. * * @param identifier the channel ID to use - * @param data the data + * @param data the data * @return whether or not the message was sent */ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { @@ -284,9 +293,7 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { return true; } - /** - * Indicates that we have completed the plugin process. - */ + /** Indicates that we have completed the plugin process. */ public void completeJoin() { if (!hasCompletedJoin) { hasCompletedJoin = true; @@ -315,7 +322,9 @@ public Map getPendingPings() { * @return whether or not the player is online */ public boolean isActive() { - return connection != null && !connection.isClosed() && !gracefulDisconnect + return connection != null + && !connection.isClosed() + && !gracefulDisconnect && proxyPlayer.isActive(); } @@ -355,4 +364,4 @@ public CompoundBinaryTag getActiveDimensionRegistry() { public void setActiveDimensionRegistry(CompoundBinaryTag activeDimensionRegistry) { this.activeDimensionRegistry = activeDimensionRegistry; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index 9518f74ac1..0f185548c5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -53,9 +53,7 @@ import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** - * A session handler that is activated to complete the login phase. - */ +/** A session handler that is activated to complete the login phase. */ public class AuthSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(AuthSessionHandler.class); @@ -68,8 +66,11 @@ public class AuthSessionHandler implements MinecraftSessionHandler { private final boolean onlineMode; private State loginState = State.START; // 1.20.2+ - AuthSessionHandler(VelocityServer server, LoginInboundConnection inbound, - GameProfile profile, boolean onlineMode) { + AuthSessionHandler( + VelocityServer server, + LoginInboundConnection inbound, + GameProfile profile, + boolean onlineMode) { this.server = Preconditions.checkNotNull(server, "server"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.profile = Preconditions.checkNotNull(profile, "profile"); @@ -80,54 +81,74 @@ public class AuthSessionHandler implements MinecraftSessionHandler { @Override public void activated() { // Some connection types may need to alter the game profile. - profile = mcConnection.getType().addGameProfileTokensIfRequired(profile, - server.getConfiguration().getPlayerInfoForwardingMode()); - GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile, - onlineMode); + profile = + mcConnection + .getType() + .addGameProfileTokensIfRequired( + profile, server.getConfiguration().getPlayerInfoForwardingMode()); + GameProfileRequestEvent profileRequestEvent = + new GameProfileRequestEvent(inbound, profile, onlineMode); final GameProfile finalProfile = profile; - server.getEventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> { - if (mcConnection.isClosed()) { - // The player disconnected after we authenticated them. - return CompletableFuture.completedFuture(null); - } + server + .getEventManager() + .fire(profileRequestEvent) + .thenComposeAsync( + profileEvent -> { + if (mcConnection.isClosed()) { + // The player disconnected after we authenticated them. + return CompletableFuture.completedFuture(null); + } - // Initiate a regular connection and move over to it. - ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(), - mcConnection, inbound.getVirtualHost().orElse(null), onlineMode, - inbound.getIdentifiedKey()); - this.connectedPlayer = player; - if (!server.canRegisterConnection(player)) { - player.disconnect0(Component.translatable("velocity.error.already-connected-proxy", - NamedTextColor.RED), true); - return CompletableFuture.completedFuture(null); - } + // Initiate a regular connection and move over to it. + ConnectedPlayer player = + new ConnectedPlayer( + server, + profileEvent.getGameProfile(), + mcConnection, + inbound.getVirtualHost().orElse(null), + onlineMode, + inbound.getIdentifiedKey()); + this.connectedPlayer = player; + if (!server.canRegisterConnection(player)) { + player.disconnect0( + Component.translatable( + "velocity.error.already-connected-proxy", NamedTextColor.RED), + true); + return CompletableFuture.completedFuture(null); + } - logger.info("{} has connected", player); + logger.info("{} has connected", player); - return server.getEventManager() - .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) - .thenAcceptAsync(event -> { - if (!mcConnection.isClosed()) { - // wait for permissions to load, then set the players permission function - final PermissionFunction function = event.createFunction(player); - if (function == null) { - logger.error( - "A plugin permission provider {} provided an invalid permission function" - + " for player {}. This is a bug in the plugin, not in Velocity. Falling" - + " back to the default permission function.", - event.getProvider().getClass().getName(), - player.getUsername()); - } else { - player.setPermissionFunction(function); - } - startLoginCompletion(player); - } - }, mcConnection.eventLoop()); - }, mcConnection.eventLoop()).exceptionally((ex) -> { - logger.error("Exception during connection of {}", finalProfile, ex); - return null; - }); + return server + .getEventManager() + .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) + .thenAcceptAsync( + event -> { + if (!mcConnection.isClosed()) { + // wait for permissions to load, then set the players permission function + final PermissionFunction function = event.createFunction(player); + if (function == null) { + logger.error( + "A plugin permission provider {} provided an invalid permission function" + + " for player {}. This is a bug in the plugin, not in Velocity. Falling" + + " back to the default permission function.", + event.getProvider().getClass().getName(), + player.getUsername()); + } else { + player.setPermissionFunction(function); + } + startLoginCompletion(player); + } + }, + mcConnection.eventLoop()); + }, + mcConnection.eventLoop()) + .exceptionally( + (ex) -> { + logger.error("Exception during connection of {}", finalProfile, ex); + return null; + }); } private void startLoginCompletion(ConnectedPlayer player) { @@ -162,8 +183,11 @@ private void startLoginCompletion(ConnectedPlayer player) { } } else { if (!Objects.equals(playerKey.getSignatureHolder(), playerUniqueId)) { - logger.warn("UUID for Player " + player.getUsername() + " mismatches! " - + "Chat/Commands signatures will not work correctly for this player!"); + logger.warn( + "UUID for Player " + + player.getUsername() + + " mismatches! " + + "Chat/Commands signatures will not work correctly for this player!"); } } } @@ -184,8 +208,7 @@ private void startLoginCompletion(ConnectedPlayer player) { @Override public boolean handle(LoginAcknowledged packet) { if (loginState != State.SUCCESS_SENT) { - inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_player_data")); + inbound.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_data")); } else { loginState = State.ACKNOWLEDGED; completeLoginProtocolPhaseAndInitialize(connectedPlayer); @@ -196,60 +219,81 @@ public boolean handle(LoginAcknowledged packet) { private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { mcConnection.setAssociation(player); - server.getEventManager().fire(new LoginEvent(player)) - .thenAcceptAsync(event -> { - if (mcConnection.isClosed()) { - // The player was disconnected - server.getEventManager().fireAndForget(new DisconnectEvent(player, - DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); - return; - } + server + .getEventManager() + .fire(new LoginEvent(player)) + .thenAcceptAsync( + event -> { + if (mcConnection.isClosed()) { + // The player was disconnected + server + .getEventManager() + .fireAndForget( + new DisconnectEvent( + player, DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); + return; + } - Optional reason = event.getResult().getReasonComponent(); - if (reason.isPresent()) { - player.disconnect0(reason.get(), true); - } else { - if (!server.registerConnection(player)) { - player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), - true); - return; - } + Optional reason = event.getResult().getReasonComponent(); + if (reason.isPresent()) { + player.disconnect0(reason.get(), true); + } else { + if (!server.registerConnection(player)) { + player.disconnect0( + Component.translatable("velocity.error.already-connected-proxy"), true); + return; + } - if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - mcConnection.setActiveSessionHandler(StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); - } else { - mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); - } + if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { + mcConnection.setActiveSessionHandler( + StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); + } else { + mcConnection.setActiveSessionHandler( + StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); + } - server.getEventManager().fire(new PostLoginEvent(player)) - .thenCompose((ignored) -> connectToInitialServer(player)) - .exceptionally((ex) -> { - logger.error("Exception while connecting {} to initial server", player, ex); + server + .getEventManager() + .fire(new PostLoginEvent(player)) + .thenCompose((ignored) -> connectToInitialServer(player)) + .exceptionally( + (ex) -> { + logger.error( + "Exception while connecting {} to initial server", player, ex); return null; }); } - }, mcConnection.eventLoop()) - .exceptionally((ex) -> { - logger.error("Exception while completing login initialisation phase for {}", player, ex); + }, + mcConnection.eventLoop()) + .exceptionally( + (ex) -> { + logger.error( + "Exception while completing login initialisation phase for {}", player, ex); return null; }); } private CompletableFuture connectToInitialServer(ConnectedPlayer player) { Optional initialFromConfig = player.getNextServerToTry(); - PlayerChooseInitialServerEvent event = new PlayerChooseInitialServerEvent(player, - initialFromConfig.orElse(null)); + PlayerChooseInitialServerEvent event = + new PlayerChooseInitialServerEvent(player, initialFromConfig.orElse(null)); - return server.getEventManager().fire(event) - .thenRunAsync(() -> { - Optional toTry = event.getInitialServer(); - if (!toTry.isPresent()) { - player.disconnect0(Component.translatable("velocity.error.no-available-servers", - NamedTextColor.RED), true); - return; - } - player.createConnectionRequest(toTry.get()).fireAndForget(); - }, mcConnection.eventLoop()); + return server + .getEventManager() + .fire(event) + .thenRunAsync( + () -> { + Optional toTry = event.getInitialServer(); + if (!toTry.isPresent()) { + player.disconnect0( + Component.translatable( + "velocity.error.no-available-servers", NamedTextColor.RED), + true); + return; + } + player.createConnectionRequest(toTry.get()).fireAndForget(); + }, + mcConnection.eventLoop()); } @Override @@ -270,4 +314,4 @@ static enum State { SUCCESS_SENT, ACKNOWLEDGED } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index 9086b9106c..94f422f3a4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -46,8 +46,8 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler { /** * Constructs a client config session handler. * - * @param server the Velocity server instance - * @param player the player + * @param server the Velocity server instance + * @param player the player */ public ClientConfigSessionHandler(VelocityServer server, ConnectedPlayer player) { this.server = server; @@ -78,7 +78,6 @@ public boolean handle(KeepAlive packet) { return true; } - @Override public boolean handle(PluginMessage packet) { return true; @@ -91,8 +90,9 @@ public boolean handle(ResourcePackResponse packet) { @Override public boolean handle(FinishedUpdate packet) { - player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, - new ClientPlaySessionHandler(server, player)); + player + .getConnection() + .setActiveSessionHandler(StateRegistry.PLAY, new ClientPlaySessionHandler(server, player)); configSwitchFuture.complete(null); @@ -138,12 +138,11 @@ public void disconnected() { @Override public void exception(Throwable throwable) { player.disconnect( - Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); } public CompletableFuture handleBackendFinishUpdate(VelocityServerConnection serverConn) { player.getConnection().write(new FinishedUpdate()); return configSwitchFuture; } - -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index feecd00463..a30d058820 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -117,29 +117,30 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.NotNull; -/** - * Represents a player that is connected to the proxy. - */ -public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, KeyIdentifiable, - VelocityInboundConnection { +/** Represents a player that is connected to the proxy. */ +public class ConnectedPlayer + implements MinecraftConnectionAssociation, Player, KeyIdentifiable, VelocityInboundConnection { private static final int MAX_PLUGIN_CHANNELS = 1024; private static final PlainTextComponentSerializer PASS_THRU_TRANSLATE = - PlainTextComponentSerializer.builder() - .flattener(ComponentFlattener.basic().toBuilder() - .mapper(KeybindComponent.class, c -> "") - .mapper(TranslatableComponent.class, TranslatableComponent::key) - .build()) - .build(); + PlainTextComponentSerializer.builder() + .flattener( + ComponentFlattener.basic().toBuilder() + .mapper(KeybindComponent.class, c -> "") + .mapper(TranslatableComponent.class, TranslatableComponent::key) + .build()) + .build(); static final PermissionProvider DEFAULT_PERMISSIONS = s -> PermissionFunction.ALWAYS_UNDEFINED; private static final Logger logger = LogManager.getLogger(ConnectedPlayer.class); private final Identity identity = new IdentityImpl(); + /** * The actual Minecraft connection. This is actually a wrapper object around the Netty channel. */ private final MinecraftConnection connection; + private final @Nullable InetSocketAddress virtualHost; private GameProfile profile; private PermissionFunction permissionFunction; @@ -162,7 +163,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, private final Queue outstandingResourcePacks = new ArrayDeque<>(); private @Nullable ResourcePackInfo pendingResourcePack; private @Nullable ResourcePackInfo appliedResourcePack; - private final @NotNull Pointers pointers = Player.super.pointers().toBuilder() + private final @NotNull Pointers pointers = + Player.super.pointers().toBuilder() .withDynamic(Identity.UUID, this::getUniqueId) .withDynamic(Identity.NAME, this::getUsername) .withDynamic(Identity.DISPLAY_NAME, () -> Component.text(this.getUsername())) @@ -176,9 +178,13 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, private final ChatQueue chatQueue; private final ChatBuilderFactory chatBuilderFactory; - ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection, - @Nullable InetSocketAddress virtualHost, boolean onlineMode, - @Nullable IdentifiedKey playerKey) { + ConnectedPlayer( + VelocityServer server, + GameProfile profile, + MinecraftConnection connection, + @Nullable InetSocketAddress virtualHost, + boolean onlineMode, + @Nullable IdentifiedKey playerKey) { this.server = server; this.profile = profile; this.connection = connection; @@ -339,8 +345,9 @@ public ProtocolVersion getProtocolVersion() { * @return the translated message */ public Component translateMessage(Component message) { - Locale locale = ClosestLocaleMatcher.INSTANCE - .lookupClosest(getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); + Locale locale = + ClosestLocaleMatcher.INSTANCE.lookupClosest( + getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); return GlobalTranslator.render(message, locale); } @@ -348,20 +355,23 @@ public Component translateMessage(Component message) { public void sendMessage(@NonNull Identity identity, @NonNull Component message) { Component translated = translateMessage(message); - connection.write(getChatBuilderFactory().builder() - .component(translated).forIdentity(identity).toClient()); + connection.write( + getChatBuilderFactory().builder().component(translated).forIdentity(identity).toClient()); } @Override - public void sendMessage(@NonNull Identity identity, @NonNull Component message, - @NonNull MessageType type) { + public void sendMessage( + @NonNull Identity identity, @NonNull Component message, @NonNull MessageType type) { Preconditions.checkNotNull(message, "message"); Preconditions.checkNotNull(type, "type"); Component translated = translateMessage(message); - connection.write(getChatBuilderFactory().builder() - .component(translated).forIdentity(identity) + connection.write( + getChatBuilderFactory() + .builder() + .component(translated) + .forIdentity(identity) .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM) .toClient()); } @@ -373,17 +383,16 @@ public void sendActionBar(net.kyori.adventure.text.@NonNull Component message) { ProtocolVersion playerVersion = getProtocolVersion(); if (playerVersion.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { // Use the title packet instead. - GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket pkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion); - pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion) - .serialize(translated)); + pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion).serialize(translated)); connection.write(pkt); } else { // Due to issues with action bar packets, we'll need to convert the text message into a // legacy message and then inject the legacy text into a component... yuck! JsonObject object = new JsonObject(); - object.addProperty("text", LegacyComponentSerializer.legacySection() - .serialize(translated)); + object.addProperty("text", LegacyComponentSerializer.legacySection().serialize(translated)); LegacyChat legacyChat = new LegacyChat(); legacyChat.setMessage(object.toString()); legacyChat.setType(LegacyChat.GAME_INFO_TYPE); @@ -425,9 +434,10 @@ public void sendPlayerListHeaderAndFooter(final Component header, final Componen @Override public void showTitle(net.kyori.adventure.title.@NonNull Title title) { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this - .getProtocolVersion()); - GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( + GsonComponentSerializer serializer = + ProtocolUtils.getJsonChatSerializer(this.getProtocolVersion()); + GenericTitlePacket timesPkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); net.kyori.adventure.title.Title.Times times = title.times(); if (times != null) { @@ -437,12 +447,14 @@ public void showTitle(net.kyori.adventure.title.@NonNull Title title) { } connection.delayedWrite(timesPkt); - GenericTitlePacket subtitlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket subtitlePkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); subtitlePkt.setComponent(serializer.serialize(translateMessage(title.subtitle()))); connection.delayedWrite(subtitlePkt); - GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket titlePkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage(title.title()))); connection.delayedWrite(titlePkt); @@ -464,22 +476,25 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { return; } - GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this - .getProtocolVersion()); + GsonComponentSerializer serializer = + ProtocolUtils.getJsonChatSerializer(this.getProtocolVersion()); if (part == TitlePart.TITLE) { - GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket titlePkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.SUBTITLE) { - GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket titlePkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.TIMES) { Times times = (Times) value; - GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket timesPkt = + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); timesPkt.setStay((int) DurationUtils.toTicks(times.stay())); @@ -493,7 +508,8 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { @Override public void clearTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write(GenericTitlePacket.constructTitlePacket( + connection.write( + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion())); } } @@ -501,7 +517,8 @@ public void clearTitle() { @Override public void resetTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write(GenericTitlePacket.constructTitlePacket( + connection.write( + GenericTitlePacket.constructTitlePacket( GenericTitlePacket.ActionType.RESET, this.getProtocolVersion())); } } @@ -525,8 +542,8 @@ public ConnectionRequestBuilder createConnectionRequest(RegisteredServer server) return new ConnectionRequestBuilderImpl(server, this.connectedServer); } - private ConnectionRequestBuilder createConnectionRequest(RegisteredServer server, - @Nullable VelocityServerConnection previousConnection) { + private ConnectionRequestBuilder createConnectionRequest( + RegisteredServer server, @Nullable VelocityServerConnection previousConnection) { return new ConnectionRequestBuilderImpl(server, previousConnection); } @@ -562,15 +579,17 @@ public void disconnect(Component reason) { /** * Disconnects the player from the proxy. * - * @param reason the reason for disconnecting the player + * @param reason the reason for disconnecting the player * @param duringLogin whether the disconnect happened during login */ public void disconnect0(Component reason, boolean duringLogin) { Component translated = this.translateMessage(reason); if (server.getConfiguration().isLogPlayerConnections()) { - logger.info("{} has disconnected: {}", this, - LegacyComponentSerializer.legacySection().serialize(translated)); + logger.info( + "{} has disconnected: {}", + this, + LegacyComponentSerializer.legacySection().serialize(translated)); } connection.closeWith(Disconnect.create(translated, this.getProtocolVersion())); } @@ -590,12 +609,12 @@ public void resetInFlightConnection() { /** * Handles unexpected disconnects. * - * @param server the server we disconnected from + * @param server the server we disconnected from * @param throwable the exception - * @param safe whether or not we can safely reconnect to a new server + * @param safe whether or not we can safely reconnect to a new server */ - public void handleConnectionException(RegisteredServer server, Throwable throwable, - boolean safe) { + public void handleConnectionException( + RegisteredServer server, Throwable throwable, boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -615,12 +634,16 @@ public void handleConnectionException(RegisteredServer server, Throwable throwab Component friendlyError; if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { - friendlyError = Component.translatable("velocity.error.connected-server-error", + friendlyError = + Component.translatable( + "velocity.error.connected-server-error", Component.text(server.getServerInfo().getName())); } else { - logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(), - wrapped); - friendlyError = Component.translatable("velocity.error.connecting-server-error", + logger.error( + "{}: unable to connect to server {}", this, server.getServerInfo().getName(), wrapped); + friendlyError = + Component.translatable( + "velocity.error.connecting-server-error", Component.text(server.getServerInfo().getName())); } handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe); @@ -629,12 +652,12 @@ public void handleConnectionException(RegisteredServer server, Throwable throwab /** * Handles unexpected disconnects. * - * @param server the server we disconnected from + * @param server the server we disconnected from * @param disconnect the disconnect packet - * @param safe whether or not we can safely reconnect to a new server + * @param safe whether or not we can safely reconnect to a new server */ - public void handleConnectionException(RegisteredServer server, Disconnect disconnect, - boolean safe) { + public void handleConnectionException( + RegisteredServer server, Disconnect disconnect, boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -643,24 +666,37 @@ public void handleConnectionException(RegisteredServer server, Disconnect discon Component disconnectReason = GsonComponentSerializer.gson().deserialize(disconnect.getReason()); String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason); if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { - logger.info("{}: kicked from server {}: {}", this, server.getServerInfo().getName(), - plainTextReason); - handleConnectionException(server, disconnectReason, - Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), - disconnectReason), safe); + logger.info( + "{}: kicked from server {}: {}", this, server.getServerInfo().getName(), plainTextReason); + handleConnectionException( + server, + disconnectReason, + Component.translatable( + "velocity.error.moved-to-new-server", + NamedTextColor.RED, + Component.text(server.getServerInfo().getName()), + disconnectReason), + safe); } else { - logger.error("{}: disconnected while connecting to {}: {}", this, - server.getServerInfo().getName(), plainTextReason); - handleConnectionException(server, disconnectReason, - Component.translatable("velocity.error.cant-connect", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), - disconnectReason), safe); + logger.error( + "{}: disconnected while connecting to {}: {}", + this, + server.getServerInfo().getName(), + plainTextReason); + handleConnectionException( + server, + disconnectReason, + Component.translatable( + "velocity.error.cant-connect", + NamedTextColor.RED, + Component.text(server.getServerInfo().getName()), + disconnectReason), + safe); } } - private void handleConnectionException(RegisteredServer rs, - @Nullable Component kickReason, Component friendlyReason, boolean safe) { + private void handleConnectionException( + RegisteredServer rs, @Nullable Component kickReason, Component friendlyReason, boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -678,8 +714,8 @@ private void handleConnectionException(RegisteredServer rs, ServerKickResult result; if (kickedFromCurrent) { Optional next = getNextServerToTry(rs); - result = next.map(RedirectPlayer::create) - .orElseGet(() -> DisconnectPlayer.create(friendlyReason)); + result = + next.map(RedirectPlayer::create).orElseGet(() -> DisconnectPlayer.create(friendlyReason)); } else { // If we were kicked by going to another server, the connection should not be in flight if (connectionInFlight != null && connectionInFlight.getServer().equals(rs)) { @@ -687,15 +723,18 @@ private void handleConnectionException(RegisteredServer rs, } result = Notify.create(friendlyReason); } - KickedFromServerEvent originalEvent = new KickedFromServerEvent(this, rs, kickReason, - !kickedFromCurrent, result); + KickedFromServerEvent originalEvent = + new KickedFromServerEvent(this, rs, kickReason, !kickedFromCurrent, result); handleKickEvent(originalEvent, friendlyReason, kickedFromCurrent); } - private void handleKickEvent(KickedFromServerEvent originalEvent, Component friendlyReason, - boolean kickedFromCurrent) { - server.getEventManager().fire(originalEvent) - .thenAcceptAsync(event -> { + private void handleKickEvent( + KickedFromServerEvent originalEvent, Component friendlyReason, boolean kickedFromCurrent) { + server + .getEventManager() + .fire(originalEvent) + .thenAcceptAsync( + event -> { // There can't be any connection in flight now. connectionInFlight = null; @@ -716,21 +755,24 @@ private void handleKickEvent(KickedFromServerEvent originalEvent, Component frie } else if (event.getResult() instanceof RedirectPlayer) { RedirectPlayer res = (RedirectPlayer) event.getResult(); createConnectionRequest(res.getServer(), previousConnection) - .connect() - .whenCompleteAsync((status, throwable) -> { + .connect() + .whenCompleteAsync( + (status, throwable) -> { if (throwable != null) { - handleConnectionException(status != null ? status.getAttemptedConnection() - : res.getServer(), throwable, true); + handleConnectionException( + status != null ? status.getAttemptedConnection() : res.getServer(), + throwable, + true); return; } switch (status.getStatus()) { - // Impossible/nonsensical cases + // Impossible/nonsensical cases case ALREADY_CONNECTED: - logger.error("{}: already connected to {}", - this, - status.getAttemptedConnection().getServerInfo().getName() - ); + logger.error( + "{}: already connected to {}", + this, + status.getAttemptedConnection().getServerInfo().getName()); break; case CONNECTION_IN_PROGRESS: // Fatal case @@ -742,10 +784,14 @@ private void handleKickEvent(KickedFromServerEvent originalEvent, Component frie disconnect(status.getReasonComponent().orElse(fallbackMsg)); break; case SERVER_DISCONNECTED: - Component reason = status.getReasonComponent() + Component reason = + status + .getReasonComponent() .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException(res.getServer(), Disconnect.create(reason, - getProtocolVersion()), ((Impl) status).isSafe()); + handleConnectionException( + res.getServer(), + Disconnect.create(reason, getProtocolVersion()), + ((Impl) status).isSafe()); break; case SUCCESS: Component requestedMessage = res.getMessageComponent(); @@ -760,7 +806,8 @@ private void handleKickEvent(KickedFromServerEvent originalEvent, Component frie // The only remaining value is successful (no need to do anything!) break; } - }, connection.eventLoop()); + }, + connection.eventLoop()); } else if (event.getResult() instanceof Notify) { Notify res = (Notify) event.getResult(); if (event.kickedDuringServerConnect() && previousConnection != null) { @@ -772,7 +819,8 @@ private void handleKickEvent(KickedFromServerEvent originalEvent, Component frie // In case someone gets creative, assume we want to disconnect the player. disconnect(friendlyReason); } - }, connection.eventLoop()); + }, + connection.eventLoop()); } /** @@ -794,11 +842,16 @@ public Optional getNextServerToTry() { */ private Optional getNextServerToTry(@Nullable RegisteredServer current) { if (serversToTry == null) { - String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString) + String virtualHostStr = + getVirtualHost() + .map(InetSocketAddress::getHostString) .orElse("") .toLowerCase(Locale.ROOT); - serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr, - Collections.emptyList()); + serversToTry = + server + .getConfiguration() + .getForcedHosts() + .getOrDefault(virtualHostStr, Collections.emptyList()); } if (serversToTry.isEmpty()) { @@ -813,8 +866,8 @@ private Optional getNextServerToTry(@Nullable RegisteredServer for (int i = tryIndex; i < serversToTry.size(); i++) { String toTryName = serversToTry.get(i); if ((connectedServer != null && hasSameName(connectedServer.getServer(), toTryName)) - || (connectionInFlight != null && hasSameName(connectionInFlight.getServer(), toTryName)) - || (current != null && hasSameName(current, toTryName))) { + || (connectionInFlight != null && hasSameName(connectionInFlight.getServer(), toTryName)) + || (current != null && hasSameName(current, toTryName))) { continue; } @@ -876,22 +929,30 @@ void teardown() { if (!connectedPlayer.get().getCurrentServer().isPresent()) { status = LoginStatus.PRE_SERVER_JOIN; } else { - status = connectedPlayer.get() == this ? LoginStatus.SUCCESSFUL_LOGIN + status = + connectedPlayer.get() == this + ? LoginStatus.SUCCESSFUL_LOGIN : LoginStatus.CONFLICTING_LOGIN; } } else { - status = connection.isKnownDisconnect() ? LoginStatus.CANCELLED_BY_PROXY : - LoginStatus.CANCELLED_BY_USER; + status = + connection.isKnownDisconnect() + ? LoginStatus.CANCELLED_BY_PROXY + : LoginStatus.CANCELLED_BY_USER; } DisconnectEvent event = new DisconnectEvent(this, status); - server.getEventManager().fire(event).whenComplete((val, ex) -> { - if (ex == null) { - this.teardownFuture.complete(null); - } else { - this.teardownFuture.completeExceptionally(ex); - } - }); + server + .getEventManager() + .fire(event) + .whenComplete( + (val, ex) -> { + if (ex == null) { + this.teardownFuture.complete(null); + } else { + this.teardownFuture.completeExceptionally(ex); + } + }); } public CompletableFuture getTeardownFuture() { @@ -900,10 +961,10 @@ public CompletableFuture getTeardownFuture() { @Override public String toString() { - boolean isPlayerAddressLoggingEnabled = server.getConfiguration() - .isPlayerAddressLoggingEnabled(); + boolean isPlayerAddressLoggingEnabled = + server.getConfiguration().isPlayerAddressLoggingEnabled(); String playerIp = - isPlayerAddressLoggingEnabled ? getRemoteAddress().toString() : ""; + isPlayerAddressLoggingEnabled ? getRemoteAddress().toString() : ""; return "[connected player] " + profile.getName() + " (" + playerIp + ")"; } @@ -932,18 +993,21 @@ void setClientBrand(String clientBrand) { @Override public void spoofChatInput(String input) { - Preconditions.checkArgument(input.length() <= LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH, - "input cannot be greater than " + LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH - + " characters in length"); + Preconditions.checkArgument( + input.length() <= LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH, + "input cannot be greater than " + + LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH + + " characters in length"); if (getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) { - this.chatQueue.hijack(getChatBuilderFactory().builder().asPlayer(this).message(input), - (instant, item) -> { - item.setTimestamp(instant); - return item.toServer(); - }); + this.chatQueue.hijack( + getChatBuilderFactory().builder().asPlayer(this).message(input), + (instant, item) -> { + item.setTimestamp(instant); + return item.toServer(); + }); } else { - ensureBackendConnection().write(getChatBuilderFactory().builder() - .asPlayer(this).message(input).toServer()); + ensureBackendConnection() + .write(getChatBuilderFactory().builder().asPlayer(this).message(input).toServer()); } } @@ -988,8 +1052,8 @@ private void tickResourcePackQueue() { // Unless its 1.17+ and forced it will come back denied anyway while (!outstandingResourcePacks.isEmpty()) { queued = outstandingResourcePacks.peek(); - if (queued.getShouldForce() && getProtocolVersion() - .compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { + if (queued.getShouldForce() + && getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { break; } onResourcePackResponse(PlayerResourcePackStatusEvent.Status.DECLINED); @@ -1025,23 +1089,30 @@ private void tickResourcePackQueue() { return pendingResourcePack; } - /** - * Processes a client response to a sent resource-pack. - */ + /** Processes a client response to a sent resource-pack. */ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status status) { final boolean peek = status == PlayerResourcePackStatusEvent.Status.ACCEPTED; - final ResourcePackInfo queued = peek - ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); - - server.getEventManager().fire(new PlayerResourcePackStatusEvent(this, status, queued)) - .thenAcceptAsync(event -> { + final ResourcePackInfo queued = + peek ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); + + server + .getEventManager() + .fire(new PlayerResourcePackStatusEvent(this, status, queued)) + .thenAcceptAsync( + event -> { if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED - && event.getPackInfo() != null && event.getPackInfo().getShouldForce() - && (!event.isOverwriteKick() || event.getPlayer() - .getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) - ) { - event.getPlayer().disconnect(Component - .translatable("multiplayer.requiredTexturePrompt.disconnect")); + && event.getPackInfo() != null + && event.getPackInfo().getShouldForce() + && (!event.isOverwriteKick() + || event + .getPlayer() + .getProtocolVersion() + .compareTo(ProtocolVersion.MINECRAFT_1_17) + >= 0)) { + event + .getPlayer() + .disconnect( + Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); } }); @@ -1069,12 +1140,10 @@ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status statu } return queued != null - && queued.getOriginalOrigin() != ResourcePackInfo.Origin.DOWNSTREAM_SERVER; + && queued.getOriginalOrigin() != ResourcePackInfo.Origin.DOWNSTREAM_SERVER; } - /** - * Gives an indication about the previous resource pack responses. - */ + /** Gives an indication about the previous resource pack responses. */ public @Nullable Boolean getPreviousResourceResponse() { return previousResourceResponse; } @@ -1137,8 +1206,8 @@ private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder { private final RegisteredServer toConnect; private final @Nullable VelocityRegisteredServer previousServer; - ConnectionRequestBuilderImpl(RegisteredServer toConnect, - @Nullable VelocityServerConnection previousConnection) { + ConnectionRequestBuilderImpl( + RegisteredServer toConnect, @Nullable VelocityServerConnection previousConnection) { this.toConnect = Preconditions.checkNotNull(toConnect, "info"); this.previousServer = previousConnection == null ? null : previousConnection.getServer(); } @@ -1149,14 +1218,14 @@ public RegisteredServer getServer() { } private Optional checkServer(RegisteredServer server) { - Preconditions.checkArgument(server instanceof VelocityRegisteredServer, - "Not a valid Velocity server."); - if (connectionInFlight != null || (connectedServer != null - && !connectedServer.hasCompletedJoin())) { + Preconditions.checkArgument( + server instanceof VelocityRegisteredServer, "Not a valid Velocity server."); + if (connectionInFlight != null + || (connectedServer != null && !connectedServer.hasCompletedJoin())) { return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS); } if (connectedServer != null - && connectedServer.getServer().getServerInfo().equals(server.getServerInfo())) { + && connectedServer.getServer().getServerInfo().equals(server.getServerInfo())) { return Optional.of(ALREADY_CONNECTED); } return Optional.empty(); @@ -1168,35 +1237,45 @@ private CompletableFuture> getInitialStatus() { private CompletableFuture internalConnect() { return this.getInitialStatus() - .thenCompose(initialCheck -> { + .thenCompose( + initialCheck -> { if (initialCheck.isPresent()) { return completedFuture(plainResult(initialCheck.get(), toConnect)); } - ServerPreConnectEvent event = new ServerPreConnectEvent(ConnectedPlayer.this, - toConnect, previousServer); - return server.getEventManager().fire(event) - .thenComposeAsync(newEvent -> { + ServerPreConnectEvent event = + new ServerPreConnectEvent(ConnectedPlayer.this, toConnect, previousServer); + return server + .getEventManager() + .fire(event) + .thenComposeAsync( + newEvent -> { Optional newDest = newEvent.getResult().getServer(); if (!newDest.isPresent()) { return completedFuture( - plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect) - ); + plainResult( + ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, + toConnect)); } RegisteredServer realDestination = newDest.get(); - Optional check = checkServer(realDestination); + Optional check = + checkServer(realDestination); if (check.isPresent()) { return completedFuture(plainResult(check.get(), realDestination)); } VelocityRegisteredServer vrs = (VelocityRegisteredServer) realDestination; - VelocityServerConnection con = new VelocityServerConnection(vrs, - previousServer, ConnectedPlayer.this, server); + VelocityServerConnection con = + new VelocityServerConnection( + vrs, previousServer, ConnectedPlayer.this, server); connectionInFlight = con; - return con.connect().whenCompleteAsync( - (result, exception) -> this.resetIfInFlightIs(con), connection.eventLoop()); - }, connection.eventLoop()); + return con.connect() + .whenCompleteAsync( + (result, exception) -> this.resetIfInFlightIs(con), + connection.eventLoop()); + }, + connection.eventLoop()); }); } @@ -1209,24 +1288,29 @@ private void resetIfInFlightIs(VelocityServerConnection establishedConnection) { @Override public CompletableFuture connect() { return this.internalConnect() - .whenCompleteAsync((status, throwable) -> { + .whenCompleteAsync( + (status, throwable) -> { if (status != null && !status.isSuccessful()) { if (!status.isSafe()) { handleConnectionException(status.getAttemptedConnection(), throwable, false); } } - }, connection.eventLoop()) - .thenApply(x -> x); + }, + connection.eventLoop()) + .thenApply(x -> x); } @Override public CompletableFuture connectWithIndication() { return internalConnect() - .whenCompleteAsync((status, throwable) -> { + .whenCompleteAsync( + (status, throwable) -> { if (throwable != null) { // TODO: The exception handling from this is not very good. Find a better way. - handleConnectionException(status != null ? status.getAttemptedConnection() - : toConnect, throwable, true); + handleConnectionException( + status != null ? status.getAttemptedConnection() : toConnect, + throwable, + true); return; } @@ -1241,17 +1325,22 @@ public CompletableFuture connectWithIndication() { // Ignored; the plugin probably already handled this. break; case SERVER_DISCONNECTED: - Component reason = status.getReasonComponent() + Component reason = + status + .getReasonComponent() .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException(toConnect, Disconnect.create(reason, - getProtocolVersion()), status.isSafe()); + handleConnectionException( + toConnect, + Disconnect.create(reason, getProtocolVersion()), + status.isSafe()); break; default: // The only remaining value is successful (no need to do anything!) break; } - }, connection.eventLoop()) - .thenApply(Result::isSuccessful); + }, + connection.eventLoop()) + .thenApply(Result::isSuccessful); } @Override @@ -1259,4 +1348,4 @@ public void fireAndForget() { connectWithIndication(); } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index 48eb5b8561..f7ec0d8977 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -47,8 +47,8 @@ /** * The initial handler used when a connection is established to the proxy. This will either - * transition to {@link StatusSessionHandler} or {@link InitialLoginSessionHandler} as soon - * as the handshake packet is received. + * transition to {@link StatusSessionHandler} or {@link InitialLoginSessionHandler} as soon as the + * handshake packet is received. */ public class HandshakeSessionHandler implements MinecraftSessionHandler { @@ -65,26 +65,28 @@ public HandshakeSessionHandler(MinecraftConnection connection, VelocityServer se @Override public boolean handle(LegacyPing packet) { connection.setProtocolVersion(ProtocolVersion.LEGACY); - StatusSessionHandler handler = new StatusSessionHandler(server, - new LegacyInboundConnection(connection, packet)); - connection.setActiveSessionHandler(StateRegistry.STATUS ,handler); + StatusSessionHandler handler = + new StatusSessionHandler(server, new LegacyInboundConnection(connection, packet)); + connection.setActiveSessionHandler(StateRegistry.STATUS, handler); handler.handle(packet); return true; } @Override public boolean handle(LegacyHandshake packet) { - connection.closeWith(LegacyDisconnect.from(Component.text( - "Your client is extremely old. Please update to a newer version of Minecraft.", - NamedTextColor.RED) - )); + connection.closeWith( + LegacyDisconnect.from( + Component.text( + "Your client is extremely old. Please update to a newer version of Minecraft.", + NamedTextColor.RED))); return true; } @Override public boolean handle(Handshake handshake) { - InitialInboundConnection ic = new InitialInboundConnection(connection, - cleanVhost(handshake.getServerAddress()), handshake); + InitialInboundConnection ic = + new InitialInboundConnection( + connection, cleanVhost(handshake.getServerAddress()), handshake); StateRegistry nextState = getStateForProtocol(handshake.getNextStatus()); if (nextState == null) { LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus()); @@ -95,7 +97,8 @@ public boolean handle(Handshake handshake) { switch (nextState) { case STATUS: - connection.setActiveSessionHandler(StateRegistry.STATUS, new StatusSessionHandler(server, ic)); + connection.setActiveSessionHandler( + StateRegistry.STATUS, new StatusSessionHandler(server, ic)); break; case LOGIN: this.handleLogin(handshake, ic); @@ -122,8 +125,9 @@ public boolean handle(Handshake handshake) { private void handleLogin(Handshake handshake, InitialInboundConnection ic) { if (!ProtocolVersion.isSupported(handshake.getProtocolVersion())) { - ic.disconnectQuietly(Component.translatable("multiplayer.disconnect.outdated_client") - .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); + ic.disconnectQuietly( + Component.translatable("multiplayer.disconnect.outdated_client") + .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); return; } @@ -139,14 +143,15 @@ private void handleLogin(Handshake handshake, InitialInboundConnection ic) { // and lower, otherwise IP information will never get forwarded. if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && handshake.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { - ic.disconnectQuietly(Component.translatable( - "velocity.error.modern-forwarding-needs-new-client")); + ic.disconnectQuietly( + Component.translatable("velocity.error.modern-forwarding-needs-new-client")); return; } LoginInboundConnection lic = new LoginInboundConnection(ic); server.getEventManager().fireAndForget(new ConnectionHandshakeEvent(lic)); - connection.setActiveSessionHandler(StateRegistry.LOGIN, new InitialLoginSessionHandler(server, connection, lic)); + connection.setActiveSessionHandler( + StateRegistry.LOGIN, new InitialLoginSessionHandler(server, connection, lic)); } private ConnectionType getHandshakeConnectionType(Handshake handshake) { @@ -206,8 +211,7 @@ private static class LegacyInboundConnection implements VelocityInboundConnectio private final MinecraftConnection connection; private final LegacyPing ping; - private LegacyInboundConnection(MinecraftConnection connection, - LegacyPing ping) { + private LegacyInboundConnection(MinecraftConnection connection, LegacyPing ping) { this.connection = connection; this.ping = ping; } @@ -242,4 +246,4 @@ public MinecraftConnection getConnection() { return connection; } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index ca313b4076..c2d72e00b0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -57,14 +57,13 @@ import org.asynchttpclient.Response; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** - * Handles authenticating the player to Mojang's servers. - */ +/** Handles authenticating the player to Mojang's servers. */ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(InitialLoginSessionHandler.class); private static final String MOJANG_HASJOINED_URL = - System.getProperty("mojang.sessionserver", + System.getProperty( + "mojang.sessionserver", "https://sessionserver.mojang.com/session/minecraft/hasJoined") .concat("?username=%s&serverId=%s"); @@ -76,14 +75,15 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private LoginState currentState = LoginState.LOGIN_PACKET_EXPECTED; private boolean forceKeyAuthentication; - InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection, - LoginInboundConnection inbound) { + InitialLoginSessionHandler( + VelocityServer server, MinecraftConnection mcConnection, LoginInboundConnection inbound) { this.server = Preconditions.checkNotNull(server, "server"); this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); - this.forceKeyAuthentication = System.getProperties().containsKey("auth.forceSecureProfiles") - ? Boolean.getBoolean("auth.forceSecureProfiles") - : server.getConfiguration().isForceKeyAuthentication(); + this.forceKeyAuthentication = + System.getProperties().containsKey("auth.forceSecureProfiles") + ? Boolean.getBoolean("auth.forceSecureProfiles") + : server.getConfiguration().isForceKeyAuthentication(); } @Override @@ -121,44 +121,58 @@ public boolean handle(ServerLogin packet) { this.login = packet; PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername()); - server.getEventManager().fire(event) - .thenRunAsync(() -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + server + .getEventManager() + .fire(event) + .thenRunAsync( + () -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - PreLoginComponentResult result = event.getResult(); - Optional disconnectReason = result.getReasonComponent(); - if (disconnectReason.isPresent()) { - // The component is guaranteed to be provided if the connection was denied. - inbound.disconnect(disconnectReason.get()); - return; - } + PreLoginComponentResult result = event.getResult(); + Optional disconnectReason = result.getReasonComponent(); + if (disconnectReason.isPresent()) { + // The component is guaranteed to be provided if the connection was denied. + inbound.disconnect(disconnectReason.get()); + return; + } - inbound.loginEventFired(() -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + inbound.loginEventFired( + () -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - mcConnection.eventLoop().execute(() -> { - if (!result.isForceOfflineMode() && (server.getConfiguration().isOnlineMode() - || result.isOnlineModeAllowed())) { - // Request encryption. - EncryptionRequest request = generateEncryptionRequest(); - this.verify = Arrays.copyOf(request.getVerifyToken(), 4); - mcConnection.write(request); - this.currentState = LoginState.ENCRYPTION_REQUEST_SENT; - } else { - mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, new AuthSessionHandler( - server, inbound, GameProfile.forOfflinePlayer(login.getUsername()), false - )); - } - }); - }); - }, mcConnection.eventLoop()) - .exceptionally((ex) -> { + mcConnection + .eventLoop() + .execute( + () -> { + if (!result.isForceOfflineMode() + && (server.getConfiguration().isOnlineMode() + || result.isOnlineModeAllowed())) { + // Request encryption. + EncryptionRequest request = generateEncryptionRequest(); + this.verify = Arrays.copyOf(request.getVerifyToken(), 4); + mcConnection.write(request); + this.currentState = LoginState.ENCRYPTION_REQUEST_SENT; + } else { + mcConnection.setActiveSessionHandler( + StateRegistry.LOGIN, + new AuthSessionHandler( + server, + inbound, + GameProfile.forOfflinePlayer(login.getUsername()), + false)); + } + }); + }); + }, + mcConnection.eventLoop()) + .exceptionally( + (ex) -> { logger.error("Exception in pre-login stage", ex); return null; }); @@ -189,8 +203,8 @@ public boolean handle(EncryptionResponse packet) { KeyPair serverKeyPair = server.getServerKeyPair(); if (inbound.getIdentifiedKey() != null) { IdentifiedKey playerKey = inbound.getIdentifiedKey(); - if (!playerKey.verifyDataSignature(packet.getVerifyToken(), verify, - Longs.toByteArray(packet.getSalt()))) { + if (!playerKey.verifyDataSignature( + packet.getVerifyToken(), verify, Longs.toByteArray(packet.getSalt()))) { throw new IllegalStateException("Invalid client public signature."); } } else { @@ -204,71 +218,79 @@ public boolean handle(EncryptionResponse packet) { String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic()); String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString(); - String url = String.format(MOJANG_HASJOINED_URL, - urlFormParameterEscaper().escape(login.getUsername()), serverId); + String url = + String.format( + MOJANG_HASJOINED_URL, + urlFormParameterEscaper().escape(login.getUsername()), + serverId); if (server.getConfiguration().shouldPreventClientProxyConnections()) { url += "&ip=" + urlFormParameterEscaper().escape(playerIp); } - ListenableFuture hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) - .execute(); - hasJoinedResponse.addListener(() -> { - if (mcConnection.isClosed()) { - // The player disconnected after we authenticated them. - return; - } + ListenableFuture hasJoinedResponse = + server.getAsyncHttpClient().prepareGet(url).execute(); + hasJoinedResponse.addListener( + () -> { + if (mcConnection.isClosed()) { + // The player disconnected after we authenticated them. + return; + } - // Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption - // is enabled. - try { - mcConnection.enableEncryption(decryptedSharedSecret); - } catch (GeneralSecurityException e) { - logger.error("Unable to enable encryption for connection", e); - // At this point, the connection is encrypted, but something's wrong on our side and - // we can't do anything about it. - mcConnection.close(true); - return; - } + // Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption + // is enabled. + try { + mcConnection.enableEncryption(decryptedSharedSecret); + } catch (GeneralSecurityException e) { + logger.error("Unable to enable encryption for connection", e); + // At this point, the connection is encrypted, but something's wrong on our side and + // we can't do anything about it. + mcConnection.close(true); + return; + } - try { - Response profileResponse = hasJoinedResponse.get(); - if (profileResponse.getStatusCode() == 200) { - final GameProfile profile = GENERAL_GSON.fromJson(profileResponse.getResponseBody(), - GameProfile.class); - // Not so fast, now we verify the public key for 1.19.1+ - if (inbound.getIdentifiedKey() != null - && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 - && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { - IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey(); - if (!key.internalAddHolder(profile.getId())) { + try { + Response profileResponse = hasJoinedResponse.get(); + if (profileResponse.getStatusCode() == 200) { + final GameProfile profile = + GENERAL_GSON.fromJson(profileResponse.getResponseBody(), GameProfile.class); + // Not so fast, now we verify the public key for 1.19.1+ + if (inbound.getIdentifiedKey() != null + && inbound.getIdentifiedKey().getKeyRevision() + == IdentifiedKey.Revision.LINKED_V2 + && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { + IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey(); + if (!key.internalAddHolder(profile.getId())) { + inbound.disconnect( + Component.translatable("multiplayer.disconnect.invalid_public_key")); + } + } + // All went well, initialize the session. + mcConnection.setActiveSessionHandler( + StateRegistry.LOGIN, new AuthSessionHandler(server, inbound, profile, true)); + } else if (profileResponse.getStatusCode() == 204) { + // Apparently an offline-mode user logged onto this online-mode proxy. inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key")); + Component.translatable("velocity.error.online-mode-only", NamedTextColor.RED)); + } else { + // Something else went wrong + logger.error( + "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", + profileResponse.getStatusCode(), + login.getUsername(), + playerIp); + inbound.disconnect( + Component.translatable("multiplayer.disconnect.authservers_down")); } + } catch (ExecutionException e) { + logger.error("Unable to authenticate with Mojang", e); + inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); + } catch (InterruptedException e) { + // not much we can do usefully + Thread.currentThread().interrupt(); } - // All went well, initialize the session. - mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, new AuthSessionHandler( - server, inbound, profile, true - )); - } else if (profileResponse.getStatusCode() == 204) { - // Apparently an offline-mode user logged onto this online-mode proxy. - inbound.disconnect(Component.translatable("velocity.error.online-mode-only", - NamedTextColor.RED)); - } else { - // Something else went wrong - logger.error( - "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", - profileResponse.getStatusCode(), login.getUsername(), playerIp); - inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); - } - } catch (ExecutionException e) { - logger.error("Unable to authenticate with Mojang", e); - inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); - } catch (InterruptedException e) { - // not much we can do usefully - Thread.currentThread().interrupt(); - } - }, mcConnection.eventLoop()); + }, + mcConnection.eventLoop()); } catch (GeneralSecurityException e) { logger.error("Unable to enable encryption", e); mcConnection.close(true); @@ -299,9 +321,11 @@ public void disconnected() { private void assertState(LoginState expectedState) { if (this.currentState != expectedState) { if (MinecraftDecoder.DEBUG) { - logger.error("{} Received an unexpected packet requiring state {}, but we are in {}", + logger.error( + "{} Received an unexpected packet requiring state {}, but we are in {}", inbound, - expectedState, this.currentState); + expectedState, + this.currentState); } mcConnection.close(true); } @@ -313,4 +337,4 @@ private enum LoginState { ENCRYPTION_REQUEST_SENT, ENCRYPTION_RESPONSE_RECEIVED } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java index 71ae60c4fa..aedd0adbb5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java @@ -28,9 +28,7 @@ import java.util.List; import javax.annotation.Nullable; -/** - * Allows for simple tracking of the phase that the Legacy Forge handshake is in. - */ +/** Allows for simple tracking of the phase that the Legacy Forge handshake is in. */ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase { /** @@ -55,9 +53,8 @@ public void onFirstJoin(ConnectedPlayer player) { } @Override - boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle( + ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { // If we stay in this phase, we do nothing because it means the packet wasn't handled. // Returning false indicates this return false; @@ -76,9 +73,9 @@ LegacyForgeHandshakeClientPhase nextPhase() { }, /** - * The Mod list is sent to the server, captured by Velocity. Transition to - * {@link #WAITING_SERVER_DATA} when an ACK is sent, which indicates to the server to start - * sending state data. + * The Mod list is sent to the server, captured by Velocity. Transition to {@link + * #WAITING_SERVER_DATA} when an ACK is sent, which indicates to the server to start sending state + * data. */ MOD_LIST(LegacyForgeConstants.ACK_DISCRIMINATOR) { @Override @@ -87,9 +84,8 @@ LegacyForgeHandshakeClientPhase nextPhase() { } @Override - boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle( + ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { // Read the mod list if we haven't already. if (!player.getModInfo().isPresent()) { List mods = LegacyForgeUtil.readModList(message); @@ -138,11 +134,10 @@ LegacyForgeHandshakeClientPhase nextPhase() { /** * The handshake is complete. The handshake can be reset. * - *

Note that a successful connection to a server does not mean that - * we will be in this state. After a handshake reset, if the next server is vanilla we will still - * be in the {@link #NOT_STARTED} phase, which means we must NOT send a reset packet. This is - * handled by overriding the {@link #resetConnectionPhase(ConnectedPlayer)} in this element (it is - * usually a no-op).

+ *

Note that a successful connection to a server does not mean that we will be in this state. + * After a handshake reset, if the next server is vanilla we will still be in the {@link + * #NOT_STARTED} phase, which means we must NOT send a reset packet. This is handled by overriding + * the {@link #resetConnectionPhase(ConnectedPlayer)} in this element (it is usually a no-op). */ COMPLETE(null) { @Override @@ -157,9 +152,8 @@ public boolean consideredComplete() { } @Override - boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle( + ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { super.onHandle(player, message, backendConn); // just in case the timing is awful @@ -174,25 +168,22 @@ boolean onHandle(ConnectedPlayer player, } }; - @Nullable - private final Integer packetToAdvanceOn; + @Nullable private final Integer packetToAdvanceOn; /** * Creates an instance of the {@link LegacyForgeHandshakeClientPhase}. * * @param packetToAdvanceOn The ID of the packet discriminator that indicates that the client has - * moved onto a new phase, and as such, Velocity should do so too - * (inspecting {@link #nextPhase()}. A null indicates there is no further - * phase to transition to. + * moved onto a new phase, and as such, Velocity should do so too (inspecting {@link + * #nextPhase()}. A null indicates there is no further phase to transition to. */ LegacyForgeHandshakeClientPhase(Integer packetToAdvanceOn) { this.packetToAdvanceOn = packetToAdvanceOn; } @Override - public final boolean handle(ConnectedPlayer player, - PluginMessage message, - VelocityServerConnection server) { + public final boolean handle( + ConnectedPlayer player, PluginMessage message, VelocityServerConnection server) { if (server != null) { MinecraftConnection backendConn = server.getConnection(); if (backendConn != null @@ -215,14 +206,12 @@ public final boolean handle(ConnectedPlayer player, /** * Handles the phase tasks. * - * @param player The player - * @param message The message to handle + * @param player The player + * @param message The message to handle * @param backendConn The backend connection to write to, if required. * @return true if handled, false otherwise. */ - boolean onHandle(ConnectedPlayer player, - PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { // Send the packet on to the server. backendConn.write(message.retain()); @@ -258,4 +247,4 @@ private LegacyForgeHandshakeClientPhase getNewPhase(PluginMessage packet) { return this; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java index 6dbadf03f0..b91e903dc9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java @@ -30,9 +30,12 @@ public class ClientConfigData { private final Key[] features; private final String brand; - - private ClientConfigData(@Nullable VelocityResourcePackInfo resourcePackInfo, DataTag tag, - RegistrySync registry, Key[] features, String brand) { + private ClientConfigData( + @Nullable VelocityResourcePackInfo resourcePackInfo, + DataTag tag, + RegistrySync registry, + Key[] features, + String brand) { this.resourcePackInfo = resourcePackInfo; this.tag = tag; this.registry = registry; @@ -60,7 +63,7 @@ public String getBrand() { return brand; } - public static ClientConfigData.Builder builder(){ + public static ClientConfigData.Builder builder() { return new Builder(); } @@ -106,8 +109,8 @@ public Builder brand(String brand) { return this; } - public ClientConfigData build(){ + public ClientConfigData build() { return new ClientConfigData(resourcePackInfo, tag, registry, features, brand); } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java index af1144d2b4..54201f0c04 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java @@ -74,4 +74,4 @@ public int[] getElements() { return key; } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java index 27ec4ba8b8..6e55242384 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java @@ -17,9 +17,7 @@ package com.velocitypowered.proxy.network; -/** - * Constants used for the pipeline. - */ +/** Constants used for the pipeline. */ public class Connections { public static final String CIPHER_DECODER = "cipher-decoder"; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java index 8ee79e0f1e..4d7d97c3b8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -42,9 +42,7 @@ import io.netty.handler.timeout.ReadTimeoutHandler; import java.util.concurrent.TimeUnit; -/** - * Server channel initializer. - */ +/** Server channel initializer. */ @SuppressWarnings("WeakerAccess") public class ServerChannelInitializer extends ChannelInitializer { @@ -59,9 +57,10 @@ protected void initChannel(final Channel ch) { ch.pipeline() .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast(READ_TIMEOUT, - new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), - TimeUnit.MILLISECONDS)) + .addLast( + READ_TIMEOUT, + new ReadTimeoutHandler( + this.server.getConfiguration().getReadTimeout(), TimeUnit.MILLISECONDS)) .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) @@ -69,12 +68,11 @@ protected void initChannel(final Channel ch) { final MinecraftConnection connection = new MinecraftConnection(ch, this.server); connection.setActiveSessionHandler( - StateRegistry.HANDSHAKE, - new HandshakeSessionHandler(connection, this.server)); + StateRegistry.HANDSHAKE, new HandshakeSessionHandler(connection, this.server)); ch.pipeline().addLast(Connections.HANDLER, connection); if (this.server.getConfiguration().isProxyProtocol()) { ch.pipeline().addFirst(new HAProxyMessageDecoder()); } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 93edc2d265..34a6e171e3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -47,9 +47,7 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -/** - * Utilities for writing and reading data in the Minecraft protocol. - */ +/** Utilities for writing and reading data in the Minecraft protocol. */ public enum ProtocolUtils { ; @@ -85,7 +83,8 @@ public enum ProtocolUtils { public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); if (read == Integer.MIN_VALUE) { - throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") + throw MinecraftDecoder.DEBUG + ? new CorruptedFrameException("Bad VarInt decoded") : BAD_VARINT_CACHED; } return read; @@ -125,7 +124,7 @@ public static int varIntBytes(int value) { /** * Writes a Minecraft-style VarInt to the specified {@code buf}. * - * @param buf the buffer to read from + * @param buf the buffer to read from * @param value the integer to write */ public static void writeVarInt(ByteBuf buf, int value) { @@ -152,12 +151,18 @@ private static void writeVarIntFull(ByteBuf buf, int value) { int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14); buf.writeMedium(w); } else if ((value & (0xFFFFFFFF << 28)) == 0) { - int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) - | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); + int w = + (value & 0x7F | 0x80) << 24 + | (((value >>> 7) & 0x7F | 0x80) << 16) + | ((value >>> 14) & 0x7F | 0x80) << 8 + | (value >>> 21); buf.writeInt(w); } else { - int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 - | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); + int w = + (value & 0x7F | 0x80) << 24 + | ((value >>> 7) & 0x7F | 0x80) << 16 + | ((value >>> 14) & 0x7F | 0x80) << 8 + | ((value >>> 21) & 0x7F | 0x80); buf.writeInt(w); buf.writeByte(value >>> 28); } @@ -167,7 +172,7 @@ private static void writeVarIntFull(ByteBuf buf, int value) { * Writes the specified {@code value} as a 21-bit Minecraft VarInt to the specified {@code buf}. * The upper 11 bits will be discarded. * - * @param buf the buffer to read from + * @param buf the buffer to read from * @param value the integer to write */ public static void write21BitVarInt(ByteBuf buf, int value) { @@ -199,13 +204,14 @@ private static String readString(ByteBuf buf, int cap, int length) { // consider the length of a UTF-8 character, which can be up to 3 bytes. We do an initial // sanity check and then check again to make sure our optimistic guess was good. checkFrame(length <= cap * 3, "Bad string size (got %s, maximum is %s)", length, cap); - checkFrame(buf.isReadable(length), - "Trying to read a string that is too long (wanted %s, only have %s)", length, + checkFrame( + buf.isReadable(length), + "Trying to read a string that is too long (wanted %s, only have %s)", + length, buf.readableBytes()); String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8); buf.skipBytes(length); - checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", - str.length(), cap); + checkFrame(str.length() <= cap, "Got a too-long string (got %s, max %s)", str.length(), cap); return str; } @@ -250,9 +256,11 @@ public static void writeKey(ByteBuf buf, Key key) { public static Key[] readKeyArray(ByteBuf buf) { int length = readVarInt(buf); checkFrame(length >= 0, "Got a negative-length array (%s)", length); - checkFrame(buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); + checkFrame( + buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", + length, + buf.readableBytes()); Key[] ret = new Key[length]; for (int i = 0; i < ret.length; i++) { @@ -273,6 +281,7 @@ public static void writeKeyArray(ByteBuf buf, Key[] keys) { writeKey(buf, key); } } + public static byte[] readByteArray(ByteBuf buf) { return readByteArray(buf, DEFAULT_MAX_STRING_SIZE); } @@ -289,8 +298,10 @@ public static byte[] readByteArray(ByteBuf buf, int cap) { int length = readVarInt(buf); checkFrame(length >= 0, "Got a negative-length array (%s)", length); checkFrame(length <= cap, "Bad array size (got %s, maximum is %s)", length, cap); - checkFrame(buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", length, + checkFrame( + buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", + length, buf.readableBytes()); byte[] array = new byte[length]; buf.readBytes(array); @@ -354,7 +365,7 @@ public static UUID readUuidIntArray(ByteBuf buf) { /** * Writes an UUID as an Integer Array to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param uuid the UUID to write */ public static void writeUuidIntArray(ByteBuf buf, UUID uuid) { @@ -367,7 +378,7 @@ public static void writeUuidIntArray(ByteBuf buf, UUID uuid) { /** * Reads a {@link net.kyori.adventure.nbt.CompoundBinaryTag} from the {@code buf}. * - * @param buf the buffer to read from + * @param buf the buffer to read from * @param reader the NBT reader to use * @return {@link net.kyori.adventure.nbt.CompoundBinaryTag} the CompoundTag from the buffer */ @@ -383,7 +394,7 @@ public static CompoundBinaryTag readCompoundTag(ByteBuf buf, BinaryTagIO.Reader /** * Writes a CompoundTag to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param compoundTag the CompoundTag to write */ public static void writeCompoundTag(ByteBuf buf, CompoundBinaryTag compoundTag) { @@ -412,7 +423,7 @@ public static String[] readStringArray(ByteBuf buf) { /** * Writes a String Array to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param stringArray the array to write */ public static void writeStringArray(ByteBuf buf, String[] stringArray) { @@ -431,9 +442,11 @@ public static void writeStringArray(ByteBuf buf, String[] stringArray) { public static int[] readVarIntArray(ByteBuf buf) { int length = readVarInt(buf); checkFrame(length >= 0, "Got a negative-length array (%s)", length); - checkFrame(buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", length, - buf.readableBytes()); + checkFrame( + buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", + length, + buf.readableBytes()); int[] ret = new int[length]; for (int i = 0; i < length; i++) { ret[i] = readVarInt(buf); @@ -444,7 +457,7 @@ public static int[] readVarIntArray(ByteBuf buf) { /** * Writes an Integer Array to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param intArray the array to write */ public static void writeVarIntArray(ByteBuf buf, int[] intArray) { @@ -457,7 +470,7 @@ public static void writeVarIntArray(ByteBuf buf, int[] intArray) { /** * Writes a list of {@link com.velocitypowered.api.util.GameProfile.Property} to the buffer. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param properties the properties to serialize */ public static void writeProperties(ByteBuf buf, List properties) { @@ -511,8 +524,11 @@ public static byte[] readByteArray17(ByteBuf buf) { // No vanilla packet should give a 3 byte packet int len = readExtendedForgeShort(buf); - checkArgument(len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + checkArgument( + len <= FORGE_MAX_ARRAY_LENGTH, + "Cannot receive array longer than %s (got %s bytes)", + FORGE_MAX_ARRAY_LENGTH, + len); byte[] ret = new byte[len]; buf.readBytes(ret); @@ -531,8 +547,11 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { // No vanilla packet should give a 3 byte packet int len = readExtendedForgeShort(buf); - checkFrame(len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + checkFrame( + len <= FORGE_MAX_ARRAY_LENGTH, + "Cannot receive array longer than %s (got %s bytes)", + FORGE_MAX_ARRAY_LENGTH, + len); return buf.readRetainedSlice(len); } @@ -540,18 +559,22 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { /** * Writes an byte array for legacy version 1.7 to the specified {@code buf} * - * @param b array - * @param buf buf + * @param b array + * @param buf buf * @param allowExtended forge */ public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { - checkFrame(b.length <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + checkFrame( + b.length <= FORGE_MAX_ARRAY_LENGTH, + "Cannot send array longer than %s (got %s bytes)", + FORGE_MAX_ARRAY_LENGTH, b.length); } else { - checkFrame(b.length <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); + checkFrame( + b.length <= Short.MAX_VALUE, + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", + b.length); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -564,18 +587,22 @@ public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended /** * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf} * - * @param b array - * @param buf buf + * @param b array + * @param buf buf * @param allowExtended forge */ public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { - checkFrame(b.readableBytes() <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, - b.readableBytes()); + checkFrame( + b.readableBytes() <= FORGE_MAX_ARRAY_LENGTH, + "Cannot send array longer than %s (got %s bytes)", + FORGE_MAX_ARRAY_LENGTH, + b.readableBytes()); } else { - checkFrame(b.readableBytes() <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.readableBytes()); + checkFrame( + b.readableBytes() <= Short.MAX_VALUE, + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", + b.readableBytes()); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -604,7 +631,7 @@ public static int readExtendedForgeShort(ByteBuf buf) { /** * Writes a Minecraft-style extended short to the specified {@code buf}. * - * @param buf buf to write + * @param buf buf to write * @param toWrite the extended short to write */ public static void writeExtendedForgeShort(ByteBuf buf, int toWrite) { @@ -647,7 +674,7 @@ public static GsonComponentSerializer getJsonChatSerializer(ProtocolVersion vers /** * Writes a players {@link IdentifiedKey} to the buffer. * - * @param buf the buffer + * @param buf the buffer * @param playerKey the key to write */ public static void writePlayerKey(ByteBuf buf, IdentifiedKey playerKey) { @@ -666,16 +693,16 @@ public static IdentifiedKey readPlayerKey(ProtocolVersion version, ByteBuf buf) long expiry = buf.readLong(); byte[] key = ProtocolUtils.readByteArray(buf); byte[] signature = ProtocolUtils.readByteArray(buf, 4096); - IdentifiedKey.Revision revision = version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 - ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; + IdentifiedKey.Revision revision = + version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 + ? IdentifiedKey.Revision.GENERIC_V1 + : IdentifiedKey.Revision.LINKED_V2; return new IdentifiedKeyImpl(revision, key, expiry, signature); } - /** - * Represents the direction in which a packet flows. - */ + /** Represents the direction in which a packet flows. */ public enum Direction { SERVERBOUND, CLIENTBOUND } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index b1273486fb..786e7f3a28 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -84,63 +84,86 @@ import java.util.function.Supplier; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Registry of all Minecraft protocol states and the packets for each state. - */ +/** Registry of all Minecraft protocol states and the packets for each state. */ public enum StateRegistry { - HANDSHAKE { { - serverbound.register(Handshake.class, Handshake::new, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + serverbound.register( + Handshake.class, Handshake::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); } }, STATUS { { - serverbound.register(StatusRequest.class, () -> StatusRequest.INSTANCE, + serverbound.register( + StatusRequest.class, + () -> StatusRequest.INSTANCE, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); - serverbound.register(StatusPing.class, StatusPing::new, - map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + serverbound.register( + StatusPing.class, StatusPing::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); - clientbound.register(StatusResponse.class, StatusResponse::new, + clientbound.register( + StatusResponse.class, + StatusResponse::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); - clientbound.register(StatusPing.class, StatusPing::new, - map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + clientbound.register( + StatusPing.class, StatusPing::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); } }, CONFIG { { - serverbound.register(ClientSettings.class, ClientSettings::new, - map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(PluginMessage.class, PluginMessage::new, - map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(FinishedUpdate.class, FinishedUpdate::new, - map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(KeepAlive.class, KeepAlive::new, - map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(PingIdentify.class, PingIdentify::new, - map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(ResourcePackResponse.class, ResourcePackResponse::new, - map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); - - clientbound.register(PluginMessage.class, PluginMessage::new, - map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(Disconnect.class, Disconnect::new, - map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(FinishedUpdate.class, FinishedUpdate::new, - map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(KeepAlive.class, KeepAlive::new, - map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(PingIdentify.class, PingIdentify::new, - map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(RegistrySync.class, RegistrySync::new, - map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new, - map(0x06, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(ActiveFeatures.class, ActiveFeatures::new, - map(0x07, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(TagsUpdate.class, TagsUpdate::new, - map(0x08, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register( + ClientSettings.class, + ClientSettings::new, + map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register( + PluginMessage.class, + PluginMessage::new, + map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register( + FinishedUpdate.class, + FinishedUpdate::new, + map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register( + KeepAlive.class, KeepAlive::new, map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register( + PingIdentify.class, + PingIdentify::new, + map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + serverbound.register( + ResourcePackResponse.class, + ResourcePackResponse::new, + map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); + + clientbound.register( + PluginMessage.class, + PluginMessage::new, + map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + Disconnect.class, Disconnect::new, map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + FinishedUpdate.class, + FinishedUpdate::new, + map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + KeepAlive.class, KeepAlive::new, map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + PingIdentify.class, + PingIdentify::new, + map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + RegistrySync.class, + RegistrySync::new, + map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + ResourcePackRequest.class, + ResourcePackRequest::new, + map(0x06, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + ActiveFeatures.class, + ActiveFeatures::new, + map(0x07, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + TagsUpdate.class, TagsUpdate::new, map(0x08, ProtocolVersion.MINECRAFT_1_20_2, false)); } }, PLAY { @@ -148,7 +171,9 @@ public enum StateRegistry { serverbound.fallback = false; clientbound.fallback = false; - serverbound.register(TabCompleteRequest.class, TabCompleteRequest::new, + serverbound.register( + TabCompleteRequest.class, + TabCompleteRequest::new, map(0x14, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x01, ProtocolVersion.MINECRAFT_1_9, false), map(0x02, ProtocolVersion.MINECRAFT_1_12, false), @@ -160,23 +185,35 @@ public enum StateRegistry { map(0x08, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x09, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x0A, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(LegacyChat.class, LegacyChat::new, + serverbound.register( + LegacyChat.class, + LegacyChat::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x02, ProtocolVersion.MINECRAFT_1_9, false), map(0x03, ProtocolVersion.MINECRAFT_1_12, false), map(0x02, ProtocolVersion.MINECRAFT_1_12_1, false), map(0x03, ProtocolVersion.MINECRAFT_1_14, ProtocolVersion.MINECRAFT_1_18_2, false)); - serverbound.register(KeyedPlayerCommand.class, KeyedPlayerCommand::new, + serverbound.register( + KeyedPlayerCommand.class, + KeyedPlayerCommand::new, map(0x03, ProtocolVersion.MINECRAFT_1_19, false), map(0x04, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); - serverbound.register(KeyedPlayerChat.class, KeyedPlayerChat::new, + serverbound.register( + KeyedPlayerChat.class, + KeyedPlayerChat::new, map(0x04, ProtocolVersion.MINECRAFT_1_19, false), map(0x05, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); - serverbound.register(SessionPlayerCommand.class, SessionPlayerCommand::new, + serverbound.register( + SessionPlayerCommand.class, + SessionPlayerCommand::new, map(0x04, ProtocolVersion.MINECRAFT_1_19_3, false)); - serverbound.register(SessionPlayerChat.class, SessionPlayerChat::new, + serverbound.register( + SessionPlayerChat.class, + SessionPlayerChat::new, map(0x05, ProtocolVersion.MINECRAFT_1_19_3, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(ClientSettings.class, ClientSettings::new, + serverbound.register( + ClientSettings.class, + ClientSettings::new, map(0x15, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x04, ProtocolVersion.MINECRAFT_1_9, false), map(0x05, ProtocolVersion.MINECRAFT_1_12, false), @@ -187,7 +224,9 @@ public enum StateRegistry { map(0x07, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x08, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x09, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(PluginMessage.class, PluginMessage::new, + serverbound.register( + PluginMessage.class, + PluginMessage::new, map(0x17, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x09, ProtocolVersion.MINECRAFT_1_9, false), map(0x0A, ProtocolVersion.MINECRAFT_1_12, false), @@ -200,7 +239,9 @@ public enum StateRegistry { map(0x0C, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x0D, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x0F, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(KeepAlive.class, KeepAlive::new, + serverbound.register( + KeepAlive.class, + KeepAlive::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x0B, ProtocolVersion.MINECRAFT_1_9, false), map(0x0C, ProtocolVersion.MINECRAFT_1_12, false), @@ -214,7 +255,9 @@ public enum StateRegistry { map(0x11, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x12, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x14, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(ResourcePackResponse.class, ResourcePackResponse::new, + serverbound.register( + ResourcePackResponse.class, + ResourcePackResponse::new, map(0x19, ProtocolVersion.MINECRAFT_1_8, false), map(0x16, ProtocolVersion.MINECRAFT_1_9, false), map(0x18, ProtocolVersion.MINECRAFT_1_12, false), @@ -225,10 +268,14 @@ public enum StateRegistry { map(0x23, ProtocolVersion.MINECRAFT_1_19, false), map(0x24, ProtocolVersion.MINECRAFT_1_19_1, false), map(0x27, ProtocolVersion.MINECRAFT_1_20_2, false)); - serverbound.register(FinishedUpdate.class, FinishedUpdate::new, + serverbound.register( + FinishedUpdate.class, + FinishedUpdate::new, map(0x0B, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(BossBar.class, BossBar::new, + clientbound.register( + BossBar.class, + BossBar::new, map(0x0C, ProtocolVersion.MINECRAFT_1_9, false), map(0x0D, ProtocolVersion.MINECRAFT_1_15, false), map(0x0C, ProtocolVersion.MINECRAFT_1_16, false), @@ -236,14 +283,18 @@ public enum StateRegistry { map(0x0A, ProtocolVersion.MINECRAFT_1_19, false), map(0x0B, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x0A, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(LegacyChat.class, LegacyChat::new, + clientbound.register( + LegacyChat.class, + LegacyChat::new, map(0x02, ProtocolVersion.MINECRAFT_1_7_2, true), map(0x0F, ProtocolVersion.MINECRAFT_1_9, true), map(0x0E, ProtocolVersion.MINECRAFT_1_13, true), map(0x0F, ProtocolVersion.MINECRAFT_1_15, true), map(0x0E, ProtocolVersion.MINECRAFT_1_16, true), map(0x0F, ProtocolVersion.MINECRAFT_1_17, ProtocolVersion.MINECRAFT_1_18_2, true)); - clientbound.register(TabCompleteResponse.class, TabCompleteResponse::new, + clientbound.register( + TabCompleteResponse.class, + TabCompleteResponse::new, map(0x3A, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x0E, ProtocolVersion.MINECRAFT_1_9, false), map(0x10, ProtocolVersion.MINECRAFT_1_13, false), @@ -255,7 +306,9 @@ public enum StateRegistry { map(0x0D, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x0F, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x10, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(AvailableCommands.class, AvailableCommands::new, + clientbound.register( + AvailableCommands.class, + AvailableCommands::new, map(0x11, ProtocolVersion.MINECRAFT_1_13, false), map(0x12, ProtocolVersion.MINECRAFT_1_15, false), map(0x11, ProtocolVersion.MINECRAFT_1_16, false), @@ -265,7 +318,9 @@ public enum StateRegistry { map(0x0E, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x10, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x11, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(PluginMessage.class, PluginMessage::new, + clientbound.register( + PluginMessage.class, + PluginMessage::new, map(0x3F, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x18, ProtocolVersion.MINECRAFT_1_9, false), map(0x19, ProtocolVersion.MINECRAFT_1_13, false), @@ -279,7 +334,9 @@ public enum StateRegistry { map(0x15, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x17, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x18, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(Disconnect.class, Disconnect::new, + clientbound.register( + Disconnect.class, + Disconnect::new, map(0x40, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x1A, ProtocolVersion.MINECRAFT_1_9, false), map(0x1B, ProtocolVersion.MINECRAFT_1_13, false), @@ -293,7 +350,9 @@ public enum StateRegistry { map(0x17, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x1A, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x1B, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(KeepAlive.class, KeepAlive::new, + clientbound.register( + KeepAlive.class, + KeepAlive::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x1F, ProtocolVersion.MINECRAFT_1_9, false), map(0x21, ProtocolVersion.MINECRAFT_1_13, false), @@ -307,7 +366,9 @@ public enum StateRegistry { map(0x1F, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x23, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x24, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(JoinGame.class, JoinGame::new, + clientbound.register( + JoinGame.class, + JoinGame::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x23, ProtocolVersion.MINECRAFT_1_9, false), map(0x25, ProtocolVersion.MINECRAFT_1_13, false), @@ -321,7 +382,9 @@ public enum StateRegistry { map(0x24, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x28, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x29, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(Respawn.class, Respawn::new, + clientbound.register( + Respawn.class, + Respawn::new, map(0x07, ProtocolVersion.MINECRAFT_1_7_2, true), map(0x33, ProtocolVersion.MINECRAFT_1_9, true), map(0x34, ProtocolVersion.MINECRAFT_1_12, true), @@ -337,7 +400,9 @@ public enum StateRegistry { map(0x3D, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x41, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x43, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new, + clientbound.register( + ResourcePackRequest.class, + ResourcePackRequest::new, map(0x48, ProtocolVersion.MINECRAFT_1_8, false), map(0x32, ProtocolVersion.MINECRAFT_1_9, false), map(0x33, ProtocolVersion.MINECRAFT_1_12, false), @@ -353,7 +418,9 @@ public enum StateRegistry { map(0x3C, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x40, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x42, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(HeaderAndFooter.class, HeaderAndFooter::new, + clientbound.register( + HeaderAndFooter.class, + HeaderAndFooter::new, map(0x47, ProtocolVersion.MINECRAFT_1_8, true), map(0x48, ProtocolVersion.MINECRAFT_1_9, true), map(0x47, ProtocolVersion.MINECRAFT_1_9_4, true), @@ -370,7 +437,9 @@ public enum StateRegistry { map(0x61, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x65, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x68, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(LegacyTitlePacket.class, LegacyTitlePacket::new, + clientbound.register( + LegacyTitlePacket.class, + LegacyTitlePacket::new, map(0x45, ProtocolVersion.MINECRAFT_1_8, true), map(0x45, ProtocolVersion.MINECRAFT_1_9, true), map(0x47, ProtocolVersion.MINECRAFT_1_12, true), @@ -379,41 +448,53 @@ public enum StateRegistry { map(0x4F, ProtocolVersion.MINECRAFT_1_14, true), map(0x50, ProtocolVersion.MINECRAFT_1_15, true), map(0x4F, ProtocolVersion.MINECRAFT_1_16, ProtocolVersion.MINECRAFT_1_16_4, true)); - clientbound.register(TitleSubtitlePacket.class, TitleSubtitlePacket::new, + clientbound.register( + TitleSubtitlePacket.class, + TitleSubtitlePacket::new, map(0x57, ProtocolVersion.MINECRAFT_1_17, true), map(0x58, ProtocolVersion.MINECRAFT_1_18, true), map(0x5B, ProtocolVersion.MINECRAFT_1_19_1, true), map(0x59, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x5D, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x5F, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(TitleTextPacket.class, TitleTextPacket::new, + clientbound.register( + TitleTextPacket.class, + TitleTextPacket::new, map(0x59, ProtocolVersion.MINECRAFT_1_17, true), map(0x5A, ProtocolVersion.MINECRAFT_1_18, true), map(0x5D, ProtocolVersion.MINECRAFT_1_19_1, true), map(0x5B, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x5F, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x61, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(TitleActionbarPacket.class, TitleActionbarPacket::new, + clientbound.register( + TitleActionbarPacket.class, + TitleActionbarPacket::new, map(0x41, ProtocolVersion.MINECRAFT_1_17, true), map(0x40, ProtocolVersion.MINECRAFT_1_19, true), map(0x43, ProtocolVersion.MINECRAFT_1_19_1, true), map(0x42, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x46, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x48, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(TitleTimesPacket.class, TitleTimesPacket::new, + clientbound.register( + TitleTimesPacket.class, + TitleTimesPacket::new, map(0x5A, ProtocolVersion.MINECRAFT_1_17, true), map(0x5B, ProtocolVersion.MINECRAFT_1_18, true), map(0x5E, ProtocolVersion.MINECRAFT_1_19_1, true), map(0x5C, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x60, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x62, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(TitleClearPacket.class, TitleClearPacket::new, + clientbound.register( + TitleClearPacket.class, + TitleClearPacket::new, map(0x10, ProtocolVersion.MINECRAFT_1_17, true), map(0x0D, ProtocolVersion.MINECRAFT_1_19, true), map(0x0C, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x0E, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x0F, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(LegacyPlayerListItem.class, LegacyPlayerListItem::new, + clientbound.register( + LegacyPlayerListItem.class, + LegacyPlayerListItem::new, map(0x38, ProtocolVersion.MINECRAFT_1_7_2, false), map(0x2D, ProtocolVersion.MINECRAFT_1_9, false), map(0x2E, ProtocolVersion.MINECRAFT_1_12_1, false), @@ -425,55 +506,79 @@ public enum StateRegistry { map(0x36, ProtocolVersion.MINECRAFT_1_17, false), map(0x34, ProtocolVersion.MINECRAFT_1_19, false), map(0x37, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); - clientbound.register(RemovePlayerInfo.class, RemovePlayerInfo::new, + clientbound.register( + RemovePlayerInfo.class, + RemovePlayerInfo::new, map(0x35, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x39, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x3B, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(UpsertPlayerInfo.class, UpsertPlayerInfo::new, + clientbound.register( + UpsertPlayerInfo.class, + UpsertPlayerInfo::new, map(0x36, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x3A, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x3C, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(SystemChat.class, SystemChat::new, + clientbound.register( + SystemChat.class, + SystemChat::new, map(0x5F, ProtocolVersion.MINECRAFT_1_19, true), map(0x62, ProtocolVersion.MINECRAFT_1_19_1, true), map(0x60, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x64, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x67, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(PlayerChatCompletion.class, PlayerChatCompletion::new, + clientbound.register( + PlayerChatCompletion.class, + PlayerChatCompletion::new, map(0x15, ProtocolVersion.MINECRAFT_1_19_1, true), map(0x14, ProtocolVersion.MINECRAFT_1_19_3, true), map(0x16, ProtocolVersion.MINECRAFT_1_19_4, true), map(0x17, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register(ServerData.class, ServerData::new, + clientbound.register( + ServerData.class, + ServerData::new, map(0x3F, ProtocolVersion.MINECRAFT_1_19, false), map(0x42, ProtocolVersion.MINECRAFT_1_19_1, false), map(0x41, ProtocolVersion.MINECRAFT_1_19_3, false), map(0x45, ProtocolVersion.MINECRAFT_1_19_4, false), map(0x47, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(StartUpdate.class, StartUpdate::new, - map(0x65, ProtocolVersion.MINECRAFT_1_20_2, false)); + clientbound.register( + StartUpdate.class, StartUpdate::new, map(0x65, ProtocolVersion.MINECRAFT_1_20_2, false)); } }, LOGIN { { - serverbound.register(ServerLogin.class, ServerLogin::new, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); - serverbound.register(EncryptionResponse.class, EncryptionResponse::new, + serverbound.register( + ServerLogin.class, ServerLogin::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + serverbound.register( + EncryptionResponse.class, + EncryptionResponse::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); - serverbound.register(LoginPluginResponse.class, LoginPluginResponse::new, + serverbound.register( + LoginPluginResponse.class, + LoginPluginResponse::new, map(0x02, ProtocolVersion.MINECRAFT_1_13, false)); - serverbound.register(LoginAcknowledged.class, LoginAcknowledged::new, + serverbound.register( + LoginAcknowledged.class, + LoginAcknowledged::new, map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register(Disconnect.class, Disconnect::new, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); - clientbound.register(EncryptionRequest.class, EncryptionRequest::new, + clientbound.register( + Disconnect.class, Disconnect::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + clientbound.register( + EncryptionRequest.class, + EncryptionRequest::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); - clientbound.register(ServerLoginSuccess.class, ServerLoginSuccess::new, + clientbound.register( + ServerLoginSuccess.class, + ServerLoginSuccess::new, map(0x02, ProtocolVersion.MINECRAFT_1_7_2, false)); - clientbound.register(SetCompression.class, SetCompression::new, + clientbound.register( + SetCompression.class, + SetCompression::new, map(0x03, ProtocolVersion.MINECRAFT_1_8, false)); - clientbound.register(LoginPluginMessage.class, LoginPluginMessage::new, + clientbound.register( + LoginPluginMessage.class, + LoginPluginMessage::new, map(0x04, ProtocolVersion.MINECRAFT_1_13, false)); } }; @@ -483,14 +588,12 @@ public enum StateRegistry { protected final PacketRegistry clientbound = new PacketRegistry(CLIENTBOUND); protected final PacketRegistry serverbound = new PacketRegistry(SERVERBOUND); - public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry(Direction direction, - ProtocolVersion version) { + public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry( + Direction direction, ProtocolVersion version) { return (direction == SERVERBOUND ? serverbound : clientbound).getProtocolRegistry(version); } - /** - * Packet registry. - */ + /** Packet registry. */ public static class PacketRegistry { private final Direction direction; @@ -521,8 +624,8 @@ ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) { return registry; } -

void register(Class

clazz, Supplier

packetSupplier, - PacketMapping... mappings) { +

void register( + Class

clazz, Supplier

packetSupplier, PacketMapping... mappings) { if (mappings.length == 0) { throw new IllegalArgumentException("At least one mapping must be provided."); } @@ -542,15 +645,18 @@

void register(Class

clazz, Supplier

packetSupp "Last mapping version cannot be higher than highest mapping version"); } } - ProtocolVersion to = current == next ? lastValid != null - ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS) : next.protocolVersion; + ProtocolVersion to = + current == next + ? lastValid != null ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS) + : next.protocolVersion; ProtocolVersion lastInList = - lastValid != null ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS); + lastValid != null ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS); if (from.compareTo(to) >= 0 && from != lastInList) { - throw new IllegalArgumentException(String.format( - "Next mapping version (%s) should be lower then current (%s)", to, from)); + throw new IllegalArgumentException( + String.format( + "Next mapping version (%s) should be lower then current (%s)", to, from)); } for (ProtocolVersion protocol : EnumSet.range(from, to)) { @@ -559,19 +665,24 @@

void register(Class

clazz, Supplier

packetSupp } ProtocolRegistry registry = this.versions.get(protocol); if (registry == null) { - throw new IllegalArgumentException("Unknown protocol version " - + current.protocolVersion); + throw new IllegalArgumentException( + "Unknown protocol version " + current.protocolVersion); } if (registry.packetIdToSupplier.containsKey(current.id)) { - throw new IllegalArgumentException("Can not register class " + clazz.getSimpleName() - + " with id " + current.id + " for " + registry.version - + " because another packet is already registered"); + throw new IllegalArgumentException( + "Can not register class " + + clazz.getSimpleName() + + " with id " + + current.id + + " for " + + registry.version + + " because another packet is already registered"); } if (registry.packetClassToId.containsKey(clazz)) { - throw new IllegalArgumentException(clazz.getSimpleName() - + " is already registered for version " + registry.version); + throw new IllegalArgumentException( + clazz.getSimpleName() + " is already registered for version " + registry.version); } if (!current.encodeOnly) { @@ -582,9 +693,7 @@

void register(Class

clazz, Supplier

packetSupp } } - /** - * Protocol registry. - */ + /** Protocol registry. */ public class ProtocolRegistry { public final ProtocolVersion version; @@ -622,10 +731,10 @@ public class ProtocolRegistry { public int getPacketId(final MinecraftPacket packet) { final int id = this.packetClassToId.getInt(packet.getClass()); if (id == Integer.MIN_VALUE) { - throw new IllegalArgumentException(String.format( - "Unable to find id for packet of type %s in %s protocol %s", - packet.getClass().getName(), PacketRegistry.this.direction, this.version - )); + throw new IllegalArgumentException( + String.format( + "Unable to find id for packet of type %s in %s protocol %s", + packet.getClass().getName(), PacketRegistry.this.direction, this.version)); } return id; } @@ -642,9 +751,7 @@ public boolean containsPacket(final MinecraftPacket packet) { } } - /** - * Packet mapping. - */ + /** Packet mapping. */ public static final class PacketMapping { private final int id; @@ -652,8 +759,11 @@ public static final class PacketMapping { private final boolean encodeOnly; private final @Nullable ProtocolVersion lastValidProtocolVersion; - PacketMapping(int id, ProtocolVersion protocolVersion, - ProtocolVersion lastValidProtocolVersion, boolean packetDecoding) { + PacketMapping( + int id, + ProtocolVersion protocolVersion, + ProtocolVersion lastValidProtocolVersion, + boolean packetDecoding) { this.id = id; this.protocolVersion = protocolVersion; this.lastValidProtocolVersion = lastValidProtocolVersion; @@ -663,9 +773,12 @@ public static final class PacketMapping { @Override public String toString() { return "PacketMapping{" - + "id=" + id - + ", protocolVersion=" + protocolVersion - + ", encodeOnly=" + encodeOnly + + "id=" + + id + + ", protocolVersion=" + + protocolVersion + + ", encodeOnly=" + + encodeOnly + '}'; } @@ -692,8 +805,8 @@ public int hashCode() { /** * Creates a PacketMapping using the provided arguments. * - * @param id Packet Id - * @param version Protocol version + * @param id Packet Id + * @param version Protocol version * @param encodeOnly When true packet decoding will be disabled * @return PacketMapping with the provided arguments */ @@ -705,15 +818,17 @@ private static PacketMapping map(int id, ProtocolVersion version, boolean encode /** * Creates a PacketMapping using the provided arguments. * - * @param id Packet Id - * @param version Protocol version - * @param encodeOnly When true packet decoding will be disabled + * @param id Packet Id + * @param version Protocol version + * @param encodeOnly When true packet decoding will be disabled * @param lastValidProtocolVersion Last version this Mapping is valid at * @return PacketMapping with the provided arguments */ - private static PacketMapping map(int id, ProtocolVersion version, - ProtocolVersion lastValidProtocolVersion, boolean encodeOnly) { + private static PacketMapping map( + int id, + ProtocolVersion version, + ProtocolVersion lastValidProtocolVersion, + boolean encodeOnly) { return new PacketMapping(id, version, lastValidProtocolVersion, encodeOnly); } - } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index 62dd4d3036..724b58931f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -32,15 +32,14 @@ /** * Queues up any pending PLAY packets while the client is in the CONFIG state. - *

- * Much of the Velocity API (i.e. chat messages) utilize PLAY packets, however - * the client is incapable of receiving these packets during the CONFIG state. - * Certain events such as the ServerPreConnectEvent may be called during this - * time, and we need to ensure that any API that uses these packets will work - * as expected. - *

- * This handler will queue up any packets that are sent to the client during - * this time, and send them once the client has (re)entered the PLAY state. + * + *

Much of the Velocity API (i.e. chat messages) utilize PLAY packets, however the client is + * incapable of receiving these packets during the CONFIG state. Certain events such as the + * ServerPreConnectEvent may be called during this time, and we need to ensure that any API that + * uses these packets will work as expected. + * + *

This handler will queue up any packets that are sent to the client during this time, and send + * them once the client has (re)entered the PLAY state. */ public class PlayPacketQueueHandler extends ChannelDuplexHandler { @@ -48,11 +47,13 @@ public class PlayPacketQueueHandler extends ChannelDuplexHandler { private final Queue queue = PlatformDependent.newMpscQueue(); public PlayPacketQueueHandler(ProtocolVersion version) { - this.registry = StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version); + this.registry = + StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version); } @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) + throws Exception { if (!(msg instanceof MinecraftPacket)) { ctx.write(msg, promise); return; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index c013929e4b..34e8d73325 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -37,11 +37,17 @@ public class ClientSettings implements MinecraftPacket { private boolean chatFilteringEnabled; // Added in 1.17 private boolean clientListingAllowed; // Added in 1.18, overwrites server-list "anonymous" mode - public ClientSettings() { - } - - public ClientSettings(String locale, byte viewDistance, int chatVisibility, boolean chatColors, - short skinParts, int mainHand, boolean chatFilteringEnabled, boolean clientListingAllowed) { + public ClientSettings() {} + + public ClientSettings( + String locale, + byte viewDistance, + int chatVisibility, + boolean chatColors, + short skinParts, + int mainHand, + boolean chatFilteringEnabled, + boolean clientListingAllowed) { this.locale = locale; this.viewDistance = viewDistance; this.chatVisibility = chatVisibility; @@ -121,14 +127,23 @@ public void setClientListingAllowed(boolean clientListingAllowed) { @Override public String toString() { return "ClientSettings{" - + "locale='" + locale + '\'' - + ", viewDistance=" + viewDistance - + ", chatVisibility=" + chatVisibility - + ", chatColors=" + chatColors - + ", skinParts=" + skinParts - + ", mainHand=" + mainHand - + ", chatFilteringEnabled=" + chatFilteringEnabled - + ", clientListingAllowed=" + clientListingAllowed + + "locale='" + + locale + + '\'' + + ", viewDistance=" + + viewDistance + + ", chatVisibility=" + + chatVisibility + + ", chatColors=" + + chatColors + + ", skinParts=" + + skinParts + + ", mainHand=" + + mainHand + + ", chatFilteringEnabled=" + + chatFilteringEnabled + + ", clientListingAllowed=" + + clientListingAllowed + '}'; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index 8b0d560604..fdbfbb65bb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -187,26 +187,51 @@ public CompoundBinaryTag getRegistry() { @Override public String toString() { return "JoinGame{" - + "entityId=" + entityId - + ", gamemode=" + gamemode - + ", dimension=" + dimension - + ", partialHashedSeed=" + partialHashedSeed - + ", difficulty=" + difficulty - + ", isHardcore=" + isHardcore - + ", maxPlayers=" + maxPlayers - + ", levelType='" + levelType + '\'' - + ", viewDistance=" + viewDistance - + ", reducedDebugInfo=" + reducedDebugInfo - + ", showRespawnScreen=" + showRespawnScreen - + ", doLimitedCrafting=" + doLimitedCrafting - + ", levelNames=" + levelNames - + ", registry='" + registry + '\'' - + ", dimensionInfo='" + dimensionInfo + '\'' - + ", currentDimensionData='" + currentDimensionData + '\'' - + ", previousGamemode=" + previousGamemode - + ", simulationDistance=" + simulationDistance - + ", lastDeathPosition='" + lastDeathPosition + '\'' - + ", portalCooldown=" + portalCooldown + + "entityId=" + + entityId + + ", gamemode=" + + gamemode + + ", dimension=" + + dimension + + ", partialHashedSeed=" + + partialHashedSeed + + ", difficulty=" + + difficulty + + ", isHardcore=" + + isHardcore + + ", maxPlayers=" + + maxPlayers + + ", levelType='" + + levelType + + '\'' + + ", viewDistance=" + + viewDistance + + ", reducedDebugInfo=" + + reducedDebugInfo + + ", showRespawnScreen=" + + showRespawnScreen + + ", doLimitedCrafting=" + + doLimitedCrafting + + ", levelNames=" + + levelNames + + ", registry='" + + registry + + '\'' + + ", dimensionInfo='" + + dimensionInfo + + '\'' + + ", currentDimensionData='" + + currentDimensionData + + '\'' + + ", previousGamemode=" + + previousGamemode + + ", simulationDistance=" + + simulationDistance + + ", lastDeathPosition='" + + lastDeathPosition + + '\'' + + ", portalCooldown=" + + portalCooldown + '}'; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java index 257901b3bd..7b9a26ed2b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java @@ -25,22 +25,22 @@ public class LoginAcknowledged implements MinecraftPacket { - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - } - - - @Override - public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - return 0; - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + @Override + public void decode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + + @Override + public void encode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + + @Override + public int expectedMaxLength( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 0; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java index 62da66e0e7..2d3d9b5da8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentify.java @@ -25,27 +25,25 @@ public class PingIdentify implements MinecraftPacket { - private int id; - - @Override - public String toString() { - return "Ping{" - + "id=" + id - + '}'; - } - - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - id = buf.readInt(); - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - buf.writeInt(id); - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + private int id; + + @Override + public String toString() { + return "Ping{" + "id=" + id + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + id = buf.readInt(); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + buf.writeInt(id); + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java index 1a7f198f5b..e63c979234 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java @@ -107,9 +107,9 @@ public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVer } } - public VelocityResourcePackInfo toServerPromptedPack(){ - ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl( - Preconditions.checkNotNull(url)) + public VelocityResourcePackInfo toServerPromptedPack() { + ResourcePackInfo.Builder builder = + new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url)) .setPrompt(prompt) .setShouldForce(isRequired) .setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); @@ -130,10 +130,17 @@ public boolean handle(MinecraftSessionHandler handler) { @Override public String toString() { return "ResourcePackRequest{" - + "url='" + url + '\'' - + ", hash='" + hash + '\'' - + ", isRequired=" + isRequired - + ", prompt='" + prompt + '\'' + + "url='" + + url + + '\'' + + ", hash='" + + hash + + '\'' + + ", isRequired=" + + isRequired + + ", prompt='" + + prompt + + '\'' + '}'; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java index 1aafc67cef..2ad44eed72 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java @@ -32,15 +32,14 @@ public class ServerLogin implements MinecraftPacket { - private static final QuietDecoderException EMPTY_USERNAME = new QuietDecoderException( - "Empty username!"); + private static final QuietDecoderException EMPTY_USERNAME = + new QuietDecoderException("Empty username!"); private @Nullable String username; private @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3 private @Nullable UUID holderUuid; // Used for key revision 2 - public ServerLogin() { - } + public ServerLogin() {} public ServerLogin(String username, @Nullable IdentifiedKey playerKey) { this.username = Preconditions.checkNotNull(username, "username"); @@ -74,10 +73,7 @@ public void setPlayerKey(IdentifiedKey playerKey) { @Override public String toString() { - return "ServerLogin{" - + "username='" + username + '\'' - + "playerKey='" + playerKey + '\'' - + '}'; + return "ServerLogin{" + "username='" + username + '\'' + "playerKey='" + playerKey + '\'' + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java index d688e69b42..0773540b41 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java @@ -26,36 +26,38 @@ public class ActiveFeatures implements MinecraftPacket { - private Key[] activeFeatures; - - public ActiveFeatures(Key[] activeFeatures) { - this.activeFeatures = activeFeatures; - } - - public ActiveFeatures(){ - this.activeFeatures = new Key[0]; - } - - public void setActiveFeatures(Key[] activeFeatures) { - this.activeFeatures = activeFeatures; - } - - public Key[] getActiveFeatures() { - return activeFeatures; - } - - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - activeFeatures = ProtocolUtils.readKeyArray(buf); - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeKeyArray(buf, activeFeatures); - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + private Key[] activeFeatures; + + public ActiveFeatures(Key[] activeFeatures) { + this.activeFeatures = activeFeatures; + } + + public ActiveFeatures() { + this.activeFeatures = new Key[0]; + } + + public void setActiveFeatures(Key[] activeFeatures) { + this.activeFeatures = activeFeatures; + } + + public Key[] getActiveFeatures() { + return activeFeatures; + } + + @Override + public void decode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + activeFeatures = ProtocolUtils.readKeyArray(buf); + } + + @Override + public void encode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeKeyArray(buf, activeFeatures); + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java index 5d7b183d73..59aed0c139 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java @@ -25,21 +25,22 @@ public class FinishedUpdate implements MinecraftPacket { - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - } + @Override + public void decode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - } + @Override + public void encode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} - @Override - public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - return 0; - } + @Override + public int expectedMaxLength( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 0; + } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java index 2094c2b6c3..9ae5d1fb9e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java @@ -26,23 +26,25 @@ public class RegistrySync extends DeferredByteBufHolder implements MinecraftPacket { - public RegistrySync() { - super(null); - } + public RegistrySync() { + super(null); + } - //NBT change in 1.20.2 makes it difficult to parse this packet. - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - this.replace(buf.readRetainedSlice(buf.readableBytes())); - } + // NBT change in 1.20.2 makes it difficult to parse this packet. + @Override + public void decode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + this.replace(buf.readRetainedSlice(buf.readableBytes())); + } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - buf.writeBytes(content()); - } + @Override + public void encode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + buf.writeBytes(content()); + } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java index 015d4c64e8..aff9f87a9a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java @@ -25,21 +25,22 @@ public class StartUpdate implements MinecraftPacket { - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - } + @Override + public void decode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - } + @Override + public void encode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} - @Override - public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - return 0; - } + @Override + public int expectedMaxLength( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 0; + } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java index 1c57156671..90061b4797 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java @@ -28,53 +28,55 @@ public class TagsUpdate implements MinecraftPacket { - private Map> tags; + private Map> tags; - public TagsUpdate(Map> tags) { - this.tags = tags; - } + public TagsUpdate(Map> tags) { + this.tags = tags; + } - public TagsUpdate() { - this.tags = Map.of(); - } + public TagsUpdate() { + this.tags = Map.of(); + } - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ImmutableMap.Builder> builder = ImmutableMap.builder(); - int size = ProtocolUtils.readVarInt(buf); - for (int i = 0; i < size; i++) { - String key = ProtocolUtils.readString(buf); + @Override + public void decode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ImmutableMap.Builder> builder = ImmutableMap.builder(); + int size = ProtocolUtils.readVarInt(buf); + for (int i = 0; i < size; i++) { + String key = ProtocolUtils.readString(buf); - int innerSize = ProtocolUtils.readVarInt(buf); - ImmutableMap.Builder innerBuilder = ImmutableMap.builder(); - for (int j = 0; j < innerSize; j++) { - String innerKey = ProtocolUtils.readString(buf); - int[] innerValue = ProtocolUtils.readVarIntArray(buf); - innerBuilder.put(innerKey, innerValue); - } + int innerSize = ProtocolUtils.readVarInt(buf); + ImmutableMap.Builder innerBuilder = ImmutableMap.builder(); + for (int j = 0; j < innerSize; j++) { + String innerKey = ProtocolUtils.readString(buf); + int[] innerValue = ProtocolUtils.readVarIntArray(buf); + innerBuilder.put(innerKey, innerValue); + } - builder.put(key, innerBuilder.build()); - } - tags = builder.build(); + builder.put(key, innerBuilder.build()); } + tags = builder.build(); + } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, tags.size()); - for (Map.Entry> entry : tags.entrySet()) { - ProtocolUtils.writeString(buf, entry.getKey()); - // Oh, joy - ProtocolUtils.writeVarInt(buf, entry.getValue().size()); - for (Map.Entry innerEntry : entry.getValue().entrySet()) { - // Yea, object oriented programming be damned - ProtocolUtils.writeString(buf, innerEntry.getKey()); - ProtocolUtils.writeVarIntArray(buf, innerEntry.getValue()); - } - } + @Override + public void encode( + ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, tags.size()); + for (Map.Entry> entry : tags.entrySet()) { + ProtocolUtils.writeString(buf, entry.getKey()); + // Oh, joy + ProtocolUtils.writeVarInt(buf, entry.getValue().size()); + for (Map.Entry innerEntry : entry.getValue().entrySet()) { + // Yea, object oriented programming be damned + ProtocolUtils.writeString(buf, innerEntry.getKey()); + ProtocolUtils.writeVarIntArray(buf, innerEntry.getValue()); + } } + } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} \ No newline at end of file + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index ce6a4075c4..c264484f91 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -32,8 +32,8 @@ import java.util.concurrent.CompletableFuture; /** - * Session handler used to implement - * {@link VelocityRegisteredServer#ping(EventLoop, ProtocolVersion)}. + * Session handler used to implement {@link VelocityRegisteredServer#ping(EventLoop, + * ProtocolVersion)}. */ public class PingSessionHandler implements MinecraftSessionHandler { @@ -43,8 +43,11 @@ public class PingSessionHandler implements MinecraftSessionHandler { private final ProtocolVersion version; private boolean completed = false; - PingSessionHandler(CompletableFuture result, RegisteredServer server, - MinecraftConnection connection, ProtocolVersion version) { + PingSessionHandler( + CompletableFuture result, + RegisteredServer server, + MinecraftConnection connection, + ProtocolVersion version) { this.result = result; this.server = server; this.connection = connection; @@ -72,8 +75,8 @@ public boolean handle(StatusResponse packet) { completed = true; connection.close(true); - ServerPing ping = VelocityServer.getPingGsonInstance(version).fromJson(packet.getStatus(), - ServerPing.class); + ServerPing ping = + VelocityServer.getPingGsonInstance(version).fromJson(packet.getStatus(), ServerPing.class); result.complete(ping); return true; } @@ -90,4 +93,4 @@ public void exception(Throwable throwable) { completed = true; result.completeExceptionally(throwable); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index 43fee0e019..22bc33f203 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -60,9 +60,7 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a server registered on the proxy. - */ +/** Represents a server registered on the proxy. */ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAudience { private final @Nullable VelocityServer server; @@ -95,10 +93,10 @@ public CompletableFuture ping() { } /** - * Pings the specified server using the specified event {@code loop}, claiming to be - * {@code version}. + * Pings the specified server using the specified event {@code loop}, claiming to be {@code + * version}. * - * @param loop the event loop to use + * @param loop the event loop to use * @param pingOptions the options to apply to this ping * @return the server list ping response */ @@ -107,42 +105,50 @@ public CompletableFuture ping(@Nullable EventLoop loop, PingOptions throw new IllegalStateException("No Velocity proxy instance available"); } CompletableFuture pingFuture = new CompletableFuture<>(); - server.createBootstrap(loop) - .handler(new ChannelInitializer() { + server + .createBootstrap(loop) + .handler( + new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline() - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast(READ_TIMEOUT, - new ReadTimeoutHandler(pingOptions.getTimeout() == 0 - ? server.getConfiguration() - .getReadTimeout() : pingOptions.getTimeout(), - TimeUnit.MILLISECONDS)) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) - .addLast(MINECRAFT_DECODER, - new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) - .addLast(MINECRAFT_ENCODER, - new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast( + READ_TIMEOUT, + new ReadTimeoutHandler( + pingOptions.getTimeout() == 0 + ? server.getConfiguration().getReadTimeout() + : pingOptions.getTimeout(), + TimeUnit.MILLISECONDS)) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast( + MINECRAFT_DECODER, + new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) + .addLast( + MINECRAFT_ENCODER, + new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); } }) - .connect(serverInfo.getAddress()) - .addListener((ChannelFutureListener) future -> { - if (future.isSuccess()) { - MinecraftConnection conn = + .connect(serverInfo.getAddress()) + .addListener( + (ChannelFutureListener) + future -> { + if (future.isSuccess()) { + MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class); - conn.setActiveSessionHandler(StateRegistry.HANDSHAKE, + conn.setActiveSessionHandler( + StateRegistry.HANDSHAKE, new PingSessionHandler( - pingFuture, - VelocityRegisteredServer.this, - conn, - pingOptions.getProtocolVersion() - )); - } else { - pingFuture.completeExceptionally(future.cause()); - } - }); + pingFuture, + VelocityRegisteredServer.this, + conn, + pingOptions.getProtocolVersion())); + } else { + pingFuture.completeExceptionally(future.cause()); + } + }); return pingFuture; } @@ -164,14 +170,15 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { * afterwards. * * @param identifier the channel ID to use - * @param data the data + * @param data the data * @return whether or not the message was sent */ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { for (ConnectedPlayer player : players.values()) { VelocityServerConnection serverConnection = player.getConnectedServer(); - if (serverConnection != null && serverConnection.getConnection() != null - && serverConnection.getServer() == this) { + if (serverConnection != null + && serverConnection.getConnection() != null + && serverConnection.getServer() == this) { return serverConnection.sendPluginMessage(identifier, data); } } @@ -189,4 +196,4 @@ public String toString() { public @NonNull Iterable audiences() { return this.getPlayersConnected(); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java index 20f71b9644..faf67c9c17 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java @@ -23,9 +23,7 @@ import java.util.HashSet; import java.util.Set; -/** - * An unsynchronized collection that puts an upper bound on the size of the collection. - */ +/** An unsynchronized collection that puts an upper bound on the size of the collection. */ public final class CappedSet extends ForwardingSet { private final Set delegate; @@ -40,7 +38,7 @@ private CappedSet(Set delegate, int upperSize) { * Creates a capped collection backed by a {@link HashSet}. * * @param maxSize the maximum size of the collection - * @param the type of elements in the collection + * @param the type of elements in the collection * @return the new collection */ public static Set create(int maxSize) { @@ -55,9 +53,11 @@ protected Set delegate() { @Override public boolean add(T element) { if (this.delegate.size() >= upperSize) { - Preconditions.checkState(this.delegate.contains(element), - "collection is too large (%s >= %s)", - this.delegate.size(), this.upperSize); + Preconditions.checkState( + this.delegate.contains(element), + "collection is too large (%s >= %s)", + this.delegate.size(), + this.upperSize); return false; } return this.delegate.add(element); @@ -67,4 +67,4 @@ public boolean add(T element) { public boolean addAll(Collection collection) { return this.standardAddAll(collection); } -} \ No newline at end of file +} From bea6c30eb542356407a7d65e5bf9c8450e626e02 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Mon, 25 Sep 2023 00:51:42 +0100 Subject: [PATCH 16/41] fix style violations --- .../connection/MinecraftSessionHandler.java | 10 ++-- .../backend/ConfigSessionHandler.java | 47 ++++++++++-------- .../backend/LoginSessionHandler.java | 3 +- .../connection/client/AuthSessionHandler.java | 6 +-- .../client/ClientConfigSessionHandler.java | 6 ++- .../client/ClientPlaySessionHandler.java | 26 ++++++---- .../connection/client/ConnectedPlayer.java | 2 +- .../connection/registry/ClientConfigData.java | 15 ++++++ .../proxy/connection/registry/DataTag.java | 22 ++++++++- .../proxy/protocol/ProtocolUtils.java | 1 - .../proxy/protocol/StateRegistry.java | 48 +++++++++---------- .../netty/PlayPacketQueueHandler.java | 3 +- 12 files changed, 119 insertions(+), 70 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java index 79c9de636b..ea01eb0082 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java @@ -31,8 +31,10 @@ import com.velocitypowered.proxy.protocol.packet.LegacyHandshake; import com.velocitypowered.proxy.protocol.packet.LegacyPing; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; +import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import com.velocitypowered.proxy.protocol.packet.PingIdentify; import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; @@ -48,8 +50,6 @@ import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; -import com.velocitypowered.proxy.protocol.packet.PingIdentify; -import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletion; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChat; @@ -57,11 +57,11 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; -import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; -import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; -import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; +import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; +import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index fdb0aba7fa..0b692aaef6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -30,20 +30,24 @@ import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.packet.*; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; +import com.velocitypowered.proxy.protocol.packet.Disconnect; +import com.velocitypowered.proxy.protocol.packet.KeepAlive; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; +import java.io.IOException; +import java.util.concurrent.CompletableFuture; import jdk.jfr.Experimental; import net.kyori.adventure.text.Component; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.IOException; -import java.util.concurrent.CompletableFuture; - /** * A special session handler that catches "last minute" disconnects. This version is to accommodate * 1.20.2+ switching. Yes, some of this is exceptionally stupid. @@ -181,16 +185,6 @@ public boolean handle(FinishedUpdate packet) { return true; } - private void switchFailure(Throwable cause) { - logger.error( - "Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - serverConn.getPlayer().getUsername(), - cause); - serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - resultFuture.completeExceptionally(cause); - } - @Override public boolean handle(Disconnect packet) { serverConn.disconnect(); @@ -218,23 +212,36 @@ public boolean handle(PluginMessage packet) { return true; } - @Override - public void disconnected() { - resultFuture.completeExceptionally( - new IOException("Unexpectedly disconnected from remote server")); - } - @Override public boolean handle(RegistrySync packet) { serverConn.getPlayer().getConnection().write(packet.retain()); return true; } + @Override + public void disconnected() { + resultFuture.completeExceptionally( + new IOException("Unexpectedly disconnected from remote server")); + } + @Override public void handleGeneric(MinecraftPacket packet) { serverConn.getPlayer().getConnection().write(packet); } + private void switchFailure(Throwable cause) { + logger.error( + "Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + serverConn.getPlayer().getUsername(), + cause); + serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + resultFuture.completeExceptionally(cause); + } + + /** + * Represents the state of the configuration stage. + */ public static enum State { START, NEGOTIATING, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index 5ac6076f71..f3bf2eedb4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -200,7 +200,8 @@ public void disconnected() { resultFuture.completeExceptionally( new QuietRuntimeException( "The connection to the remote server was unexpectedly closed.\n" - + "This is usually because the remote server does not have BungeeCord IP forwarding " + + "This is usually because the remote server " + + "does not have BungeeCord IP forwarding " + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " + "for instructions on how to configure player info forwarding correctly.")); } else { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index 0f185548c5..ce8d1a65b9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -130,9 +130,9 @@ public void activated() { final PermissionFunction function = event.createFunction(player); if (function == null) { logger.error( - "A plugin permission provider {} provided an invalid permission function" - + " for player {}. This is a bug in the plugin, not in Velocity. Falling" - + " back to the default permission function.", + "A plugin permission provider {} provided an invalid permission " + + "function for player {}. This is a bug in the plugin, not in " + + "Velocity. Falling back to the default permission function.", event.getProvider().getClass().getName(), player.getUsername()); } else { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index 94f422f3a4..d9e155f7ce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -28,13 +28,15 @@ import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import io.netty.buffer.ByteBuf; +import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.concurrent.CompletableFuture; - +/** + * Handles the client config stage. + */ public class ClientConfigSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 8ff96ed828..acc94940dc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -17,7 +17,6 @@ package com.velocitypowered.proxy.connection.client; -import static com.velocitypowered.api.network.ProtocolVersion.*; import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.constructChannelsPacket; import com.google.common.collect.ImmutableList; @@ -465,6 +464,11 @@ public void writabilityChanged() { } } + /** + * Handles switching stages for swapping between servers. + * + * @return a future that completes when the switch is complete + */ public CompletableFuture doSwitch() { VelocityServerConnection existingConnection = player.getConnectedServer(); @@ -529,7 +533,8 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de // Tell the server about this client's plugin message channels. ProtocolVersion serverVersion = serverMc.getProtocolVersion(); - if (!player.getKnownChannels().isEmpty() && serverVersion.compareTo(MINECRAFT_1_20_2) < 0) { + if (!player.getKnownChannels().isEmpty() + && serverVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { serverMc.delayedWrite(constructChannelsPacket(serverVersion, player.getKnownChannels())); } @@ -540,7 +545,7 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de } // Clear any title from the previous server. - if (player.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { + if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { player .getConnection() .delayedWrite( @@ -565,7 +570,7 @@ private void doFastClientServerSwitch(JoinGame joinGame) { // improving compatibility with mods. final Respawn respawn = Respawn.fromJoinGame(joinGame); - if (player.getProtocolVersion().compareTo(MINECRAFT_1_16) < 0) { + if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_16) < 0) { // Before Minecraft 1.16, we could not switch to the same dimension without sending an // additional respawn. On older versions of Minecraft this forces the client to perform // garbage collection which adds additional latency. @@ -607,7 +612,7 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { String commandLabel = command.substring(0, commandEndPosition); if (!server.getCommandManager().hasCommand(commandLabel)) { - if (player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0) { + if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { // Outstanding tab completes are recorded for use with 1.12 clients and below to provide // additional tab completion support. outstandingTabComplete = packet; @@ -658,7 +663,7 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { } private boolean handleRegularTabComplete(TabCompleteRequest packet) { - if (player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0) { + if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0) { // Outstanding tab completes are recorded for use with 1.12 clients and below to provide // additional tab completion support. outstandingTabComplete = packet; @@ -692,7 +697,8 @@ private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteRes .offerBrigadierSuggestions(player, command) .thenAcceptAsync( offers -> { - boolean legacy = player.getProtocolVersion().compareTo(MINECRAFT_1_13) < 0; + boolean legacy = + player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0; try { for (Suggestion suggestion : offers.getList()) { String offer = suggestion.getText(); @@ -721,7 +727,8 @@ private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteRes .exceptionally( (ex) -> { logger.error( - "Exception while finishing command tab completion, with request {} and response {}", + "Exception while finishing command tab completion," + + " with request {} and response {}", request, response, ex); @@ -749,7 +756,8 @@ private void finishRegularTabComplete(TabCompleteRequest request, TabCompleteRes .exceptionally( (ex) -> { logger.error( - "Exception while finishing regular tab completion, with request {} and response{}", + "Exception while finishing regular tab completion," + + " with request {} and response{}", request, response, ex); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index a30d058820..86cfe1eef8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -767,7 +767,7 @@ private void handleKickEvent( } switch (status.getStatus()) { - // Impossible/nonsensical cases + // Impossible/nonsensical cases case ALREADY_CONNECTED: logger.error( "{}: already connected to {}", diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java index b91e903dc9..9d0aa6496f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java @@ -22,6 +22,10 @@ import net.kyori.adventure.key.Key; import org.jetbrains.annotations.Nullable; +/** + * Holds the registry data that is sent + * to the client during the config stage. + */ public class ClientConfigData { private final @Nullable VelocityResourcePackInfo resourcePackInfo; @@ -63,10 +67,18 @@ public String getBrand() { return brand; } + /** + * Creates a new builder. + * + * @return ClientConfigData.Builder + */ public static ClientConfigData.Builder builder() { return new Builder(); } + /** + * Builder for ClientConfigData. + */ public static class Builder { private VelocityResourcePackInfo resourcePackInfo; private DataTag tag; @@ -76,6 +88,9 @@ public static class Builder { private Builder() {} + /** + * Clears the builder. + */ public void clear() { this.resourcePackInfo = null; this.tag = null; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java index 54201f0c04..9a7d0de737 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DataTag.java @@ -18,12 +18,14 @@ package com.velocitypowered.proxy.connection.registry; import com.google.common.collect.ImmutableList; +import java.util.List; import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Keyed; import org.jetbrains.annotations.NotNull; -import java.util.List; - +/** + * Represents a data tag. + */ public class DataTag { private final ImmutableList entrySets; @@ -31,10 +33,18 @@ public DataTag(ImmutableList entrySets) { this.entrySets = entrySets; } + /** + * Returns the entry sets. + * + * @return List of entry sets + */ public List getEntrySets() { return entrySets; } + /** + * Represents a data tag set. + */ public static class Set implements Keyed { private final Key key; @@ -45,6 +55,11 @@ public Set(Key key, ImmutableList entries) { this.entries = entries; } + /** + * Returns the entries. + * + * @return List of entries + */ public List getEntries() { return entries; } @@ -55,6 +70,9 @@ public List getEntries() { } } + /** + * Represents a data tag entry. + */ public static class Entry implements Keyed { private final Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 34a6e171e3..d6a6479582 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -41,7 +41,6 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; - import net.kyori.adventure.key.Key; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 786e7f3a28..4144a4ac50 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -23,36 +23,36 @@ import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.SERVERBOUND; import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; -import com.velocitypowered.proxy.protocol.packet.StatusRequest; -import com.velocitypowered.proxy.protocol.packet.Handshake; -import com.velocitypowered.proxy.protocol.packet.ClientSettings; -import com.velocitypowered.proxy.protocol.packet.StatusPing; +import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.BossBar; -import com.velocitypowered.proxy.protocol.packet.StatusResponse; -import com.velocitypowered.proxy.protocol.packet.KeepAlive; -import com.velocitypowered.proxy.protocol.packet.PingIdentify; -import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.Disconnect; -import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; -import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; -import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; -import com.velocitypowered.proxy.protocol.packet.AvailableCommands; -import com.velocitypowered.proxy.protocol.packet.JoinGame; -import com.velocitypowered.proxy.protocol.packet.Respawn; +import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; +import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; +import com.velocitypowered.proxy.protocol.packet.Handshake; import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; +import com.velocitypowered.proxy.protocol.packet.JoinGame; +import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; +import com.velocitypowered.proxy.protocol.packet.LoginAcknowledged; +import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; +import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; +import com.velocitypowered.proxy.protocol.packet.PingIdentify; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfo; -import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; +import com.velocitypowered.proxy.protocol.packet.Respawn; import com.velocitypowered.proxy.protocol.packet.ServerData; import com.velocitypowered.proxy.protocol.packet.ServerLogin; -import com.velocitypowered.proxy.protocol.packet.EncryptionResponse; -import com.velocitypowered.proxy.protocol.packet.EncryptionRequest; -import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse; -import com.velocitypowered.proxy.protocol.packet.LoginPluginMessage; -import com.velocitypowered.proxy.protocol.packet.SetCompression; import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; +import com.velocitypowered.proxy.protocol.packet.SetCompression; +import com.velocitypowered.proxy.protocol.packet.StatusPing; +import com.velocitypowered.proxy.protocol.packet.StatusRequest; +import com.velocitypowered.proxy.protocol.packet.StatusResponse; +import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; +import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; +import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletion; import com.velocitypowered.proxy.protocol.packet.chat.SystemChat; import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChat; @@ -60,11 +60,11 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; -import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; -import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; +import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; +import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index 724b58931f..ec7453d404 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -26,9 +26,8 @@ import io.netty.channel.ChannelPromise; import io.netty.util.ReferenceCountUtil; import io.netty.util.internal.PlatformDependent; -import org.jetbrains.annotations.NotNull; - import java.util.Queue; +import org.jetbrains.annotations.NotNull; /** * Queues up any pending PLAY packets while the client is in the CONFIG state. From 0a6e9136d931769b3e61c7fff11c2b69dd79c786 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Mon, 25 Sep 2023 00:54:12 +0100 Subject: [PATCH 17/41] remove redundent code --- .../proxy/connection/client/ConnectedPlayer.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 86cfe1eef8..2b69837a12 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -77,12 +77,10 @@ import com.velocitypowered.proxy.tablist.VelocityTabListLegacy; import com.velocitypowered.proxy.util.ClosestLocaleMatcher; import com.velocitypowered.proxy.util.DurationUtils; -import com.velocitypowered.proxy.util.collect.CappedSet; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import java.net.InetSocketAddress; import java.util.ArrayDeque; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -156,7 +154,6 @@ public class ConnectedPlayer private final InternalTabList tabList; private final VelocityServer server; private ClientConnectionPhase connectionPhase; - private final Collection knownChannels; private final CompletableFuture teardownFuture = new CompletableFuture<>(); private @MonotonicNonNull List serversToTry = null; private @MonotonicNonNull Boolean previousResourceResponse; @@ -191,7 +188,6 @@ public class ConnectedPlayer this.virtualHost = virtualHost; this.permissionFunction = PermissionFunction.ALWAYS_UNDEFINED; this.connectionPhase = connection.getType().getInitialClientPhase(); - this.knownChannels = CappedSet.create(MAX_PLUGIN_CHANNELS); this.onlineMode = onlineMode; if (connection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { @@ -1179,15 +1175,6 @@ public void setPhase(ClientConnectionPhase connectionPhase) { this.connectionPhase = connectionPhase; } - /** - * Return all the plugin message channels "known" to the client. - * - * @return the channels - */ - public Collection getKnownChannels() { - return knownChannels; - } - @Override public @Nullable IdentifiedKey getIdentifiedKey() { return playerKey; From 490850199e9d1310161c6150ace0643f7fbf84e3 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Mon, 25 Sep 2023 00:56:48 +0100 Subject: [PATCH 18/41] remove missed references --- .../connection/backend/TransitionSessionHandler.java | 7 ------- .../connection/client/ClientPlaySessionHandler.java | 10 ---------- 2 files changed, 17 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 1042ecd1f6..d0d89898f9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -37,7 +37,6 @@ import com.velocitypowered.proxy.protocol.packet.JoinGame; import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import java.io.IOException; import java.util.concurrent.CompletableFuture; import org.apache.logging.log4j.LogManager; @@ -191,12 +190,6 @@ public boolean handle(PluginMessage packet) { return true; } - if (PluginMessageUtil.isRegister(packet)) { - serverConn.getPlayer().getKnownChannels().addAll(PluginMessageUtil.getChannels(packet)); - } else if (PluginMessageUtil.isUnregister(packet)) { - serverConn.getPlayer().getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet)); - } - // We always need to handle plugin messages, for Forge compatibility. if (serverConn.getPhase().handle(serverConn, serverConn.getPlayer(), packet)) { // Handled, but check the server connection phase. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index acc94940dc..dcb1de13a5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -159,7 +159,6 @@ public void activated() { if (!channels.isEmpty()) { PluginMessage register = constructChannelsPacket(player.getProtocolVersion(), channels); player.getConnection().write(register); - player.getKnownChannels().addAll(channels); } } @@ -298,7 +297,6 @@ public boolean handle(PluginMessage packet) { packet.getChannel()); } else if (PluginMessageUtil.isRegister(packet)) { List channels = PluginMessageUtil.getChannels(packet); - player.getKnownChannels().addAll(channels); List channelIdentifiers = new ArrayList<>(); for (String channel : channels) { try { @@ -313,7 +311,6 @@ public boolean handle(PluginMessage packet) { new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isUnregister(packet)) { - player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet)); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isMcBrand(packet)) { String brand = PluginMessageUtil.readBrandMessage(packet.content()); @@ -531,13 +528,6 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de } serverBossBars.clear(); - // Tell the server about this client's plugin message channels. - ProtocolVersion serverVersion = serverMc.getProtocolVersion(); - if (!player.getKnownChannels().isEmpty() - && serverVersion.compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - serverMc.delayedWrite(constructChannelsPacket(serverVersion, player.getKnownChannels())); - } - // If we had plugin messages queued during login/FML handshake, send them now. PluginMessage pm; while ((pm = loginPluginMessages.poll()) != null) { From 034953e1a33912c57cf02f2bc304d57f438820e4 Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Mon, 25 Sep 2023 13:02:24 +0100 Subject: [PATCH 19/41] Ensure super.channelInactive is called in PlayPacketQueueHandler --- .../proxy/protocol/netty/PlayPacketQueueHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index ec7453d404..f8ccb3596b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -70,12 +70,14 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) } @Override - public void channelInactive(@NotNull ChannelHandlerContext ctx) { + public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception { this.releaseQueue(ctx, false); + + super.channelInactive(ctx); } @Override - public void handlerRemoved(ChannelHandlerContext ctx) { + public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { this.releaseQueue(ctx, ctx.channel().isActive()); } From 75411ce5a1cdc043dbbb354f490bfa23553ef253 Mon Sep 17 00:00:00 2001 From: pkt77 Date: Sun, 24 Sep 2023 20:26:16 +0100 Subject: [PATCH 20/41] Fix login race case --- .../connection/client/AuthSessionHandler.java | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index ce8d1a65b9..cccc498cb1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -192,17 +192,7 @@ private void startLoginCompletion(ConnectedPlayer player) { } } - ServerLoginSuccess success = new ServerLoginSuccess(); - success.setUsername(player.getUsername()); - success.setProperties(player.getGameProfileProperties()); - success.setUuid(playerUniqueId); - mcConnection.write(success); - - if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - completeLoginProtocolPhaseAndInitialize(player); - } else { - loginState = State.SUCCESS_SENT; - } + completeLoginProtocolPhaseAndInitialize(player); } @Override @@ -211,7 +201,19 @@ public boolean handle(LoginAcknowledged packet) { inbound.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_data")); } else { loginState = State.ACKNOWLEDGED; - completeLoginProtocolPhaseAndInitialize(connectedPlayer); + mcConnection.setActiveSessionHandler( + StateRegistry.CONFIG, new ClientConfigSessionHandler(server, connectedPlayer)); + + server + .getEventManager() + .fire(new PostLoginEvent(connectedPlayer)) + .thenCompose((ignored) -> connectToInitialServer(connectedPlayer)) + .exceptionally( + (ex) -> { + logger.error( + "Exception while connecting {} to initial server", connectedPlayer, ex); + return null; + }); } return true; } @@ -244,26 +246,29 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { return; } + ServerLoginSuccess success = new ServerLoginSuccess(); + success.setUsername(player.getUsername()); + success.setProperties(player.getGameProfileProperties()); + success.setUuid(player.getUniqueId()); + mcConnection.write(success); + + loginState = State.SUCCESS_SENT; if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { + loginState = State.ACKNOWLEDGED; mcConnection.setActiveSessionHandler( - StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); - } else { - mcConnection.setActiveSessionHandler( - StateRegistry.CONFIG, new ClientConfigSessionHandler(server, player)); + StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); + server + .getEventManager() + .fire(new PostLoginEvent(player)) + .thenCompose((ignored) -> connectToInitialServer(player)) + .exceptionally( + (ex) -> { + logger.error( + "Exception while connecting {} to initial server", player, ex); + return null; + }); } - - server - .getEventManager() - .fire(new PostLoginEvent(player)) - .thenCompose((ignored) -> connectToInitialServer(player)) - .exceptionally( - (ex) -> { - logger.error( - "Exception while connecting {} to initial server", player, ex); - return null; - }); - } - }, + }}, mcConnection.eventLoop()) .exceptionally( (ex) -> { From 0bc584ec0bcac92bb39eccebd2d78295ad6ed3dc Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Mon, 25 Sep 2023 19:07:29 +0100 Subject: [PATCH 21/41] sigh --- .../proxy/connection/client/AuthSessionHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index cccc498cb1..0a09293d88 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -202,7 +202,7 @@ public boolean handle(LoginAcknowledged packet) { } else { loginState = State.ACKNOWLEDGED; mcConnection.setActiveSessionHandler( - StateRegistry.CONFIG, new ClientConfigSessionHandler(server, connectedPlayer)); + StateRegistry.CONFIG, new ClientConfigSessionHandler(server, connectedPlayer)); server .getEventManager() @@ -256,7 +256,7 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { loginState = State.ACKNOWLEDGED; mcConnection.setActiveSessionHandler( - StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); + StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); server .getEventManager() .fire(new PostLoginEvent(player)) From 53dc57e5cf26354c779db2b2a29d89193142df0d Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Mon, 25 Sep 2023 19:56:54 +0100 Subject: [PATCH 22/41] fix style violations --- .../proxy/connection/client/AuthSessionHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index 0a09293d88..b2519f295c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -268,7 +268,8 @@ private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { return null; }); } - }}, + } + }, mcConnection.eventLoop()) .exceptionally( (ex) -> { From 2520dfdbd57415a4c4adff1d94f0154917eec256 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Mon, 25 Sep 2023 20:23:42 +0100 Subject: [PATCH 23/41] fix climbables --- .../proxy/connection/backend/ConfigSessionHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 0b692aaef6..f98c8587bc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -106,6 +106,7 @@ public boolean handle(ActiveFeatures packet) { @Override public boolean handle(TagsUpdate packet) { + serverConn.getPlayer().getConnection().write(packet); return true; } From f8a55947a0c7dca74c199ae0c321dc0ce56c744c Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 26 Sep 2023 19:47:24 +0100 Subject: [PATCH 24/41] fix support for skin layers not loading --- .../backend/BackendPlaySessionHandler.java | 7 ++++++ .../backend/ConfigSessionHandler.java | 25 ++++--------------- .../backend/TransitionSessionHandler.java | 3 +++ .../client/ClientConfigSessionHandler.java | 12 ++++++--- .../client/ClientPlaySessionHandler.java | 8 +++++- .../connection/client/ConnectedPlayer.java | 7 ++++++ 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index f931348178..063683fa90 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -41,6 +41,7 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.BossBar; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItem; @@ -125,6 +126,12 @@ public boolean handle(KeepAlive packet) { return false; // forwards on } + @Override + public boolean handle(ClientSettings packet) { + serverConn.ensureConnected().write(packet); + return true; + } + @Override public boolean handle(Disconnect packet) { serverConn.disconnect(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index f98c8587bc..bd7b1b3ba7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -30,13 +30,11 @@ import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.ResourcePackRequest; import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; -import com.velocitypowered.proxy.protocol.packet.config.ActiveFeatures; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; @@ -93,17 +91,6 @@ public boolean beforeHandle() { return false; } - @Override - public boolean handle(ClientSettings packet) { - serverConn.ensureConnected().write(packet); - return true; - } - - @Override - public boolean handle(ActiveFeatures packet) { - return true; - } - @Override public boolean handle(TagsUpdate packet) { serverConn.getPlayer().getConnection().write(packet); @@ -232,17 +219,15 @@ public void handleGeneric(MinecraftPacket packet) { private void switchFailure(Throwable cause) { logger.error( - "Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - serverConn.getPlayer().getUsername(), - cause); + "Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + serverConn.getPlayer().getUsername(), + cause); serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); resultFuture.completeExceptionally(cause); } - /** - * Represents the state of the configuration stage. - */ + /** Represents the state of the configuration stage. */ public static enum State { START, NEGOTIATING, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index d0d89898f9..28d907faa7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -143,6 +143,9 @@ public boolean handle(JoinGame packet) { // Now set the connected server. serverConn.getPlayer().setConnectedServer(serverConn); + for (int i = 0; i < player.getClientSettingsPacketQueue().size(); i++) { + serverConn.ensureConnected().write(player.getClientSettingsPacketQueue().remove(i)); + } // We're done! :) server diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index d9e155f7ce..c04cb09994 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -23,6 +23,7 @@ import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.PluginMessage; import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; @@ -34,9 +35,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** - * Handles the client config stage. - */ +/** Handles the client config stage. */ public class ClientConfigSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class); @@ -85,8 +84,15 @@ public boolean handle(PluginMessage packet) { return true; } + @Override + public boolean handle(ClientSettings packet) { + player.getClientSettingsPacketQueue().add(packet); + return true; + } + @Override public boolean handle(ResourcePackResponse packet) { + player.getConnection().write(packet); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index dcb1de13a5..69a552c54d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -188,7 +188,13 @@ public boolean handle(KeepAlive packet) { @Override public boolean handle(ClientSettings packet) { player.setPlayerSettings(packet); - return false; // will forward onto the server + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection == null) { + // No server connection yet, probably transitioning. + return true; + } + player.getConnectedServer().ensureConnected().write(packet); + return true; // will forward onto the server } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 2b69837a12..210b669457 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -81,6 +81,7 @@ import io.netty.buffer.Unpooled; import java.net.InetSocketAddress; import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -174,6 +175,7 @@ public class ConnectedPlayer private @Nullable IdentifiedKey playerKey; private final ChatQueue chatQueue; private final ChatBuilderFactory chatBuilderFactory; + private final List clientSettingsPacketQueue; ConnectedPlayer( VelocityServer server, @@ -200,6 +202,7 @@ public class ConnectedPlayer this.playerKey = playerKey; this.chatQueue = new ChatQueue(this); this.chatBuilderFactory = new ChatBuilderFactory(this.getProtocolVersion()); + this.clientSettingsPacketQueue = new ArrayList<>(); } public ChatBuilderFactory getChatBuilderFactory() { @@ -284,6 +287,10 @@ public PlayerSettings getPlayerSettings() { return settings == null ? ClientSettingsWrapper.DEFAULT : this.settings; } + public List getClientSettingsPacketQueue() { + return clientSettingsPacketQueue; + } + @Override public boolean hasSentPlayerSettings() { return settings != null; From 0b12a2b7b323733e9c6c9f16046dd2b8ef7e44d2 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 26 Sep 2023 21:07:53 +0100 Subject: [PATCH 25/41] fix servers pinging servers --- .../proxy/connection/MinecraftConnection.java | 8 +++++++- .../velocitypowered/proxy/server/PingSessionHandler.java | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index cb26738318..393d806780 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -367,7 +367,13 @@ public void setAutoReading(boolean autoReading) { } // Ideally only used by the state switch - private void setState(StateRegistry state) { + + /** + * Sets the new state for the connection. + * + * @param state the state to use + */ + public void setState(StateRegistry state) { ensureInEventLoop(); this.state = state; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index c264484f91..f9a64359f7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -64,6 +64,7 @@ public void activated() { connection.delayedWrite(handshake); connection.setActiveSessionHandler(StateRegistry.STATUS); + connection.setState(StateRegistry.STATUS); connection.delayedWrite(StatusRequest.INSTANCE); connection.flush(); From 45f6167a2dec00bf5fe23508ae98503de21173a9 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 26 Sep 2023 22:25:53 +0100 Subject: [PATCH 26/41] fix client settings not forwarding between servers --- .../proxy/connection/backend/TransitionSessionHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 28d907faa7..667cdd4c50 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -144,7 +144,7 @@ public boolean handle(JoinGame packet) { // Now set the connected server. serverConn.getPlayer().setConnectedServer(serverConn); for (int i = 0; i < player.getClientSettingsPacketQueue().size(); i++) { - serverConn.ensureConnected().write(player.getClientSettingsPacketQueue().remove(i)); + serverConn.ensureConnected().write(player.getClientSettingsPacketQueue().get(i)); } // We're done! :) From 1474c7e1481fdd036275a867b079b9f559c9b608 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 26 Sep 2023 22:29:55 +0100 Subject: [PATCH 27/41] change to a single value instead of a list --- .../connection/backend/TransitionSessionHandler.java | 4 +--- .../client/ClientConfigSessionHandler.java | 2 +- .../proxy/connection/client/ConnectedPlayer.java | 12 +++++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 667cdd4c50..0f38aa76a6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -143,9 +143,7 @@ public boolean handle(JoinGame packet) { // Now set the connected server. serverConn.getPlayer().setConnectedServer(serverConn); - for (int i = 0; i < player.getClientSettingsPacketQueue().size(); i++) { - serverConn.ensureConnected().write(player.getClientSettingsPacketQueue().get(i)); - } + serverConn.ensureConnected().write(player.getClientSettingsPacket()); // We're done! :) server diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index c04cb09994..f8bd36c39a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -86,7 +86,7 @@ public boolean handle(PluginMessage packet) { @Override public boolean handle(ClientSettings packet) { - player.getClientSettingsPacketQueue().add(packet); + player.setClientSettingsPacket(packet); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 210b669457..d182aaa0ec 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -81,7 +81,6 @@ import io.netty.buffer.Unpooled; import java.net.InetSocketAddress; import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -173,9 +172,9 @@ public class ConnectedPlayer private @Nullable String clientBrand; private @Nullable Locale effectiveLocale; private @Nullable IdentifiedKey playerKey; + private @Nullable ClientSettings clientSettingsPacket; private final ChatQueue chatQueue; private final ChatBuilderFactory chatBuilderFactory; - private final List clientSettingsPacketQueue; ConnectedPlayer( VelocityServer server, @@ -202,7 +201,6 @@ public class ConnectedPlayer this.playerKey = playerKey; this.chatQueue = new ChatQueue(this); this.chatBuilderFactory = new ChatBuilderFactory(this.getProtocolVersion()); - this.clientSettingsPacketQueue = new ArrayList<>(); } public ChatBuilderFactory getChatBuilderFactory() { @@ -287,8 +285,8 @@ public PlayerSettings getPlayerSettings() { return settings == null ? ClientSettingsWrapper.DEFAULT : this.settings; } - public List getClientSettingsPacketQueue() { - return clientSettingsPacketQueue; + public ClientSettings getClientSettingsPacket() { + return clientSettingsPacket; } @Override @@ -296,6 +294,10 @@ public boolean hasSentPlayerSettings() { return settings != null; } + public void setClientSettingsPacket(ClientSettings clientSettingsPacket) { + this.clientSettingsPacket = clientSettingsPacket; + } + void setPlayerSettings(ClientSettings settings) { ClientSettingsWrapper cs = new ClientSettingsWrapper(settings); this.settings = cs; From cb21a2c9963310a5b8e8fcf3848d0fb420616ec9 Mon Sep 17 00:00:00 2001 From: Gero Date: Wed, 27 Sep 2023 11:46:55 +0200 Subject: [PATCH 28/41] disable auto reading during state switch --- .../proxy/connection/MinecraftConnection.java | 2 +- .../connection/backend/ConfigSessionHandler.java | 15 ++++++++------- .../connection/backend/LoginSessionHandler.java | 2 ++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 393d806780..551d6ebeed 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -348,7 +348,7 @@ public boolean isKnownDisconnect() { } /** - * Determines whether or not the channel should continue reading data automaticaly. + * Determines whether or not the channel should continue reading data automatically. * * @param autoReading whether or not we should read data automatically */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index bd7b1b3ba7..58135b8da2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -154,22 +154,23 @@ public boolean handle(ResourcePackRequest packet) { @Override public boolean handle(FinishedUpdate packet) { + MinecraftConnection smc = serverConn.ensureConnected(); ClientConfigSessionHandler configHandler = (ClientConfigSessionHandler) serverConn.getPlayer().getConnection().getActiveSessionHandler(); + smc.setAutoReading(false); configHandler .handleBackendFinishUpdate(serverConn) .thenAcceptAsync( (unused) -> { - serverConn.ensureConnected().write(new FinishedUpdate()); - serverConn - .ensureConnected() - .setActiveSessionHandler( - StateRegistry.PLAY, - new TransitionSessionHandler(server, serverConn, resultFuture)); + smc.write(new FinishedUpdate()); + smc.setActiveSessionHandler( + StateRegistry.PLAY, + new TransitionSessionHandler(server, serverConn, resultFuture)); + smc.setAutoReading(true); }, - serverConn.ensureConnected().eventLoop()); + smc.eventLoop()); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index f3bf2eedb4..71de19f56e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -166,6 +166,7 @@ public boolean handle(ServerLoginSuccess packet) { smc.setActiveSessionHandler( StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture)); } else { + smc.setAutoReading(false); CompletableFuture switchFuture; if (serverConn.getPlayer().getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler) { @@ -182,6 +183,7 @@ public boolean handle(ServerLoginSuccess packet) { // Sync backend smc.setActiveSessionHandler( StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); + smc.setAutoReading(true); }, smc.eventLoop()); } From a097e34d6a692eae1bd2040f0a7f0b89f83d1912 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Wed, 27 Sep 2023 13:10:28 +0100 Subject: [PATCH 29/41] ensure client settings packet is not null --- .../proxy/connection/backend/TransitionSessionHandler.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 0f38aa76a6..6384033231 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -143,7 +143,9 @@ public boolean handle(JoinGame packet) { // Now set the connected server. serverConn.getPlayer().setConnectedServer(serverConn); - serverConn.ensureConnected().write(player.getClientSettingsPacket()); + if (player.getClientSettingsPacket() != null) { + serverConn.ensureConnected().write(player.getClientSettingsPacket()); + } // We're done! :) server From c1c1b9b00b5172ccc45a0988291f54e78c8d4645 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Wed, 27 Sep 2023 13:12:08 +0100 Subject: [PATCH 30/41] remove cappedset --- .../proxy/util/collect/CappedSet.java | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java b/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java deleted file mode 100644 index faf67c9c17..0000000000 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/collect/CappedSet.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2019-2023 Velocity Contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.velocitypowered.proxy.util.collect; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ForwardingSet; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -/** An unsynchronized collection that puts an upper bound on the size of the collection. */ -public final class CappedSet extends ForwardingSet { - - private final Set delegate; - private final int upperSize; - - private CappedSet(Set delegate, int upperSize) { - this.delegate = delegate; - this.upperSize = upperSize; - } - - /** - * Creates a capped collection backed by a {@link HashSet}. - * - * @param maxSize the maximum size of the collection - * @param the type of elements in the collection - * @return the new collection - */ - public static Set create(int maxSize) { - return new CappedSet<>(new HashSet<>(), maxSize); - } - - @Override - protected Set delegate() { - return delegate; - } - - @Override - public boolean add(T element) { - if (this.delegate.size() >= upperSize) { - Preconditions.checkState( - this.delegate.contains(element), - "collection is too large (%s >= %s)", - this.delegate.size(), - this.upperSize); - return false; - } - return this.delegate.add(element); - } - - @Override - public boolean addAll(Collection collection) { - return this.standardAddAll(collection); - } -} From 6b7afbc2e04d5c7ba2849ce14965c23d4e527ca7 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Wed, 27 Sep 2023 13:21:06 +0100 Subject: [PATCH 31/41] bring back static imports --- .../proxy/protocol/StateRegistry.java | 964 +++++++++--------- 1 file changed, 493 insertions(+), 471 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 4144a4ac50..54744dc5af 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -18,6 +18,28 @@ package com.velocitypowered.proxy.protocol; import static com.google.common.collect.Iterables.getLast; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12_1; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_15; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_2; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_4; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_17; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18_2; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_1; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_3; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_4; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_2; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9_4; +import static com.velocitypowered.api.network.ProtocolVersion.MINIMUM_VERSION; +import static com.velocitypowered.api.network.ProtocolVersion.SUPPORTED_VERSIONS; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.CLIENTBOUND; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction.SERVERBOUND; @@ -89,81 +111,81 @@ public enum StateRegistry { HANDSHAKE { { serverbound.register( - Handshake.class, Handshake::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + Handshake.class, Handshake::new, map(0x00, MINECRAFT_1_7_2, false)); } }, STATUS { { serverbound.register( - StatusRequest.class, - () -> StatusRequest.INSTANCE, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + StatusRequest.class, + () -> StatusRequest.INSTANCE, + map(0x00, MINECRAFT_1_7_2, false)); serverbound.register( - StatusPing.class, StatusPing::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + StatusPing.class, StatusPing::new, map(0x01, MINECRAFT_1_7_2, false)); clientbound.register( - StatusResponse.class, - StatusResponse::new, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + StatusResponse.class, + StatusResponse::new, + map(0x00, MINECRAFT_1_7_2, false)); clientbound.register( - StatusPing.class, StatusPing::new, map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + StatusPing.class, StatusPing::new, map(0x01, MINECRAFT_1_7_2, false)); } }, CONFIG { { serverbound.register( - ClientSettings.class, - ClientSettings::new, - map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + ClientSettings.class, + ClientSettings::new, + map(0x00, MINECRAFT_1_20_2, false)); serverbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); + PluginMessage.class, + PluginMessage::new, + map(0x01, MINECRAFT_1_20_2, false)); serverbound.register( - FinishedUpdate.class, - FinishedUpdate::new, - map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); + FinishedUpdate.class, + FinishedUpdate::new, + map(0x02, MINECRAFT_1_20_2, false)); serverbound.register( - KeepAlive.class, KeepAlive::new, map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + KeepAlive.class, KeepAlive::new, map(0x03, MINECRAFT_1_20_2, false)); serverbound.register( - PingIdentify.class, - PingIdentify::new, - map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + PingIdentify.class, + PingIdentify::new, + map(0x04, MINECRAFT_1_20_2, false)); serverbound.register( - ResourcePackResponse.class, - ResourcePackResponse::new, - map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); + ResourcePackResponse.class, + ResourcePackResponse::new, + map(0x05, MINECRAFT_1_20_2, false)); clientbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x00, ProtocolVersion.MINECRAFT_1_20_2, false)); + PluginMessage.class, + PluginMessage::new, + map(0x00, MINECRAFT_1_20_2, false)); clientbound.register( - Disconnect.class, Disconnect::new, map(0x01, ProtocolVersion.MINECRAFT_1_20_2, false)); + Disconnect.class, Disconnect::new, map(0x01, MINECRAFT_1_20_2, false)); clientbound.register( - FinishedUpdate.class, - FinishedUpdate::new, - map(0x02, ProtocolVersion.MINECRAFT_1_20_2, false)); + FinishedUpdate.class, + FinishedUpdate::new, + map(0x02, MINECRAFT_1_20_2, false)); clientbound.register( - KeepAlive.class, KeepAlive::new, map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + KeepAlive.class, KeepAlive::new, map(0x03, MINECRAFT_1_20_2, false)); clientbound.register( - PingIdentify.class, - PingIdentify::new, - map(0x04, ProtocolVersion.MINECRAFT_1_20_2, false)); + PingIdentify.class, + PingIdentify::new, + map(0x04, MINECRAFT_1_20_2, false)); clientbound.register( - RegistrySync.class, - RegistrySync::new, - map(0x05, ProtocolVersion.MINECRAFT_1_20_2, false)); + RegistrySync.class, + RegistrySync::new, + map(0x05, MINECRAFT_1_20_2, false)); clientbound.register( - ResourcePackRequest.class, - ResourcePackRequest::new, - map(0x06, ProtocolVersion.MINECRAFT_1_20_2, false)); + ResourcePackRequest.class, + ResourcePackRequest::new, + map(0x06, MINECRAFT_1_20_2, false)); clientbound.register( - ActiveFeatures.class, - ActiveFeatures::new, - map(0x07, ProtocolVersion.MINECRAFT_1_20_2, false)); + ActiveFeatures.class, + ActiveFeatures::new, + map(0x07, MINECRAFT_1_20_2, false)); clientbound.register( - TagsUpdate.class, TagsUpdate::new, map(0x08, ProtocolVersion.MINECRAFT_1_20_2, false)); + TagsUpdate.class, TagsUpdate::new, map(0x08, MINECRAFT_1_20_2, false)); } }, PLAY { @@ -172,414 +194,414 @@ public enum StateRegistry { clientbound.fallback = false; serverbound.register( - TabCompleteRequest.class, - TabCompleteRequest::new, - map(0x14, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x01, ProtocolVersion.MINECRAFT_1_9, false), - map(0x02, ProtocolVersion.MINECRAFT_1_12, false), - map(0x01, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x05, ProtocolVersion.MINECRAFT_1_13, false), - map(0x06, ProtocolVersion.MINECRAFT_1_14, false), - map(0x08, ProtocolVersion.MINECRAFT_1_19, false), - map(0x09, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x08, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x09, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x0A, ProtocolVersion.MINECRAFT_1_20_2, false)); + TabCompleteRequest.class, + TabCompleteRequest::new, + map(0x14, MINECRAFT_1_7_2, false), + map(0x01, MINECRAFT_1_9, false), + map(0x02, MINECRAFT_1_12, false), + map(0x01, MINECRAFT_1_12_1, false), + map(0x05, MINECRAFT_1_13, false), + map(0x06, MINECRAFT_1_14, false), + map(0x08, MINECRAFT_1_19, false), + map(0x09, MINECRAFT_1_19_1, false), + map(0x08, MINECRAFT_1_19_3, false), + map(0x09, MINECRAFT_1_19_4, false), + map(0x0A, MINECRAFT_1_20_2, false)); serverbound.register( - LegacyChat.class, - LegacyChat::new, - map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x02, ProtocolVersion.MINECRAFT_1_9, false), - map(0x03, ProtocolVersion.MINECRAFT_1_12, false), - map(0x02, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x03, ProtocolVersion.MINECRAFT_1_14, ProtocolVersion.MINECRAFT_1_18_2, false)); + LegacyChat.class, + LegacyChat::new, + map(0x01, MINECRAFT_1_7_2, false), + map(0x02, MINECRAFT_1_9, false), + map(0x03, MINECRAFT_1_12, false), + map(0x02, MINECRAFT_1_12_1, false), + map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false)); serverbound.register( - KeyedPlayerCommand.class, - KeyedPlayerCommand::new, - map(0x03, ProtocolVersion.MINECRAFT_1_19, false), - map(0x04, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); + KeyedPlayerCommand.class, + KeyedPlayerCommand::new, + map(0x03, MINECRAFT_1_19, false), + map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); serverbound.register( - KeyedPlayerChat.class, - KeyedPlayerChat::new, - map(0x04, ProtocolVersion.MINECRAFT_1_19, false), - map(0x05, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); + KeyedPlayerChat.class, + KeyedPlayerChat::new, + map(0x04, MINECRAFT_1_19, false), + map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); serverbound.register( - SessionPlayerCommand.class, - SessionPlayerCommand::new, - map(0x04, ProtocolVersion.MINECRAFT_1_19_3, false)); + SessionPlayerCommand.class, + SessionPlayerCommand::new, + map(0x04, MINECRAFT_1_19_3, false)); serverbound.register( - SessionPlayerChat.class, - SessionPlayerChat::new, - map(0x05, ProtocolVersion.MINECRAFT_1_19_3, ProtocolVersion.MINECRAFT_1_20_2, false)); + SessionPlayerChat.class, + SessionPlayerChat::new, + map(0x05, MINECRAFT_1_19_3, MINECRAFT_1_20_2, false)); serverbound.register( - ClientSettings.class, - ClientSettings::new, - map(0x15, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x04, ProtocolVersion.MINECRAFT_1_9, false), - map(0x05, ProtocolVersion.MINECRAFT_1_12, false), - map(0x04, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x05, ProtocolVersion.MINECRAFT_1_14, false), - map(0x07, ProtocolVersion.MINECRAFT_1_19, false), - map(0x08, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x07, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x08, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x09, ProtocolVersion.MINECRAFT_1_20_2, false)); + ClientSettings.class, + ClientSettings::new, + map(0x15, MINECRAFT_1_7_2, false), + map(0x04, MINECRAFT_1_9, false), + map(0x05, MINECRAFT_1_12, false), + map(0x04, MINECRAFT_1_12_1, false), + map(0x05, MINECRAFT_1_14, false), + map(0x07, MINECRAFT_1_19, false), + map(0x08, MINECRAFT_1_19_1, false), + map(0x07, MINECRAFT_1_19_3, false), + map(0x08, MINECRAFT_1_19_4, false), + map(0x09, MINECRAFT_1_20_2, false)); serverbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x17, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x09, ProtocolVersion.MINECRAFT_1_9, false), - map(0x0A, ProtocolVersion.MINECRAFT_1_12, false), - map(0x09, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x0A, ProtocolVersion.MINECRAFT_1_13, false), - map(0x0B, ProtocolVersion.MINECRAFT_1_14, false), - map(0x0A, ProtocolVersion.MINECRAFT_1_17, false), - map(0x0C, ProtocolVersion.MINECRAFT_1_19, false), - map(0x0D, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x0C, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x0D, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x0F, ProtocolVersion.MINECRAFT_1_20_2, false)); + PluginMessage.class, + PluginMessage::new, + map(0x17, MINECRAFT_1_7_2, false), + map(0x09, MINECRAFT_1_9, false), + map(0x0A, MINECRAFT_1_12, false), + map(0x09, MINECRAFT_1_12_1, false), + map(0x0A, MINECRAFT_1_13, false), + map(0x0B, MINECRAFT_1_14, false), + map(0x0A, MINECRAFT_1_17, false), + map(0x0C, MINECRAFT_1_19, false), + map(0x0D, MINECRAFT_1_19_1, false), + map(0x0C, MINECRAFT_1_19_3, false), + map(0x0D, MINECRAFT_1_19_4, false), + map(0x0F, MINECRAFT_1_20_2, false)); serverbound.register( - KeepAlive.class, - KeepAlive::new, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x0B, ProtocolVersion.MINECRAFT_1_9, false), - map(0x0C, ProtocolVersion.MINECRAFT_1_12, false), - map(0x0B, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x0E, ProtocolVersion.MINECRAFT_1_13, false), - map(0x0F, ProtocolVersion.MINECRAFT_1_14, false), - map(0x10, ProtocolVersion.MINECRAFT_1_16, false), - map(0x0F, ProtocolVersion.MINECRAFT_1_17, false), - map(0x11, ProtocolVersion.MINECRAFT_1_19, false), - map(0x12, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x11, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x12, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x14, ProtocolVersion.MINECRAFT_1_20_2, false)); + KeepAlive.class, + KeepAlive::new, + map(0x00, MINECRAFT_1_7_2, false), + map(0x0B, MINECRAFT_1_9, false), + map(0x0C, MINECRAFT_1_12, false), + map(0x0B, MINECRAFT_1_12_1, false), + map(0x0E, MINECRAFT_1_13, false), + map(0x0F, MINECRAFT_1_14, false), + map(0x10, MINECRAFT_1_16, false), + map(0x0F, MINECRAFT_1_17, false), + map(0x11, MINECRAFT_1_19, false), + map(0x12, MINECRAFT_1_19_1, false), + map(0x11, MINECRAFT_1_19_3, false), + map(0x12, MINECRAFT_1_19_4, false), + map(0x14, MINECRAFT_1_20_2, false)); serverbound.register( - ResourcePackResponse.class, - ResourcePackResponse::new, - map(0x19, ProtocolVersion.MINECRAFT_1_8, false), - map(0x16, ProtocolVersion.MINECRAFT_1_9, false), - map(0x18, ProtocolVersion.MINECRAFT_1_12, false), - map(0x1D, ProtocolVersion.MINECRAFT_1_13, false), - map(0x1F, ProtocolVersion.MINECRAFT_1_14, false), - map(0x20, ProtocolVersion.MINECRAFT_1_16, false), - map(0x21, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x23, ProtocolVersion.MINECRAFT_1_19, false), - map(0x24, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x27, ProtocolVersion.MINECRAFT_1_20_2, false)); + ResourcePackResponse.class, + ResourcePackResponse::new, + map(0x19, MINECRAFT_1_8, false), + map(0x16, MINECRAFT_1_9, false), + map(0x18, MINECRAFT_1_12, false), + map(0x1D, MINECRAFT_1_13, false), + map(0x1F, MINECRAFT_1_14, false), + map(0x20, MINECRAFT_1_16, false), + map(0x21, MINECRAFT_1_16_2, false), + map(0x23, MINECRAFT_1_19, false), + map(0x24, MINECRAFT_1_19_1, false), + map(0x27, MINECRAFT_1_20_2, false)); serverbound.register( - FinishedUpdate.class, - FinishedUpdate::new, - map(0x0B, ProtocolVersion.MINECRAFT_1_20_2, false)); - - clientbound.register( - BossBar.class, - BossBar::new, - map(0x0C, ProtocolVersion.MINECRAFT_1_9, false), - map(0x0D, ProtocolVersion.MINECRAFT_1_15, false), - map(0x0C, ProtocolVersion.MINECRAFT_1_16, false), - map(0x0D, ProtocolVersion.MINECRAFT_1_17, false), - map(0x0A, ProtocolVersion.MINECRAFT_1_19, false), - map(0x0B, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x0A, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - LegacyChat.class, - LegacyChat::new, - map(0x02, ProtocolVersion.MINECRAFT_1_7_2, true), - map(0x0F, ProtocolVersion.MINECRAFT_1_9, true), - map(0x0E, ProtocolVersion.MINECRAFT_1_13, true), - map(0x0F, ProtocolVersion.MINECRAFT_1_15, true), - map(0x0E, ProtocolVersion.MINECRAFT_1_16, true), - map(0x0F, ProtocolVersion.MINECRAFT_1_17, ProtocolVersion.MINECRAFT_1_18_2, true)); - clientbound.register( - TabCompleteResponse.class, - TabCompleteResponse::new, - map(0x3A, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x0E, ProtocolVersion.MINECRAFT_1_9, false), - map(0x10, ProtocolVersion.MINECRAFT_1_13, false), - map(0x11, ProtocolVersion.MINECRAFT_1_15, false), - map(0x10, ProtocolVersion.MINECRAFT_1_16, false), - map(0x0F, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x11, ProtocolVersion.MINECRAFT_1_17, false), - map(0x0E, ProtocolVersion.MINECRAFT_1_19, false), - map(0x0D, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x0F, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x10, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - AvailableCommands.class, - AvailableCommands::new, - map(0x11, ProtocolVersion.MINECRAFT_1_13, false), - map(0x12, ProtocolVersion.MINECRAFT_1_15, false), - map(0x11, ProtocolVersion.MINECRAFT_1_16, false), - map(0x10, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x12, ProtocolVersion.MINECRAFT_1_17, false), - map(0x0F, ProtocolVersion.MINECRAFT_1_19, false), - map(0x0E, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x10, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x11, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x3F, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x18, ProtocolVersion.MINECRAFT_1_9, false), - map(0x19, ProtocolVersion.MINECRAFT_1_13, false), - map(0x18, ProtocolVersion.MINECRAFT_1_14, false), - map(0x19, ProtocolVersion.MINECRAFT_1_15, false), - map(0x18, ProtocolVersion.MINECRAFT_1_16, false), - map(0x17, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x18, ProtocolVersion.MINECRAFT_1_17, false), - map(0x15, ProtocolVersion.MINECRAFT_1_19, false), - map(0x16, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x15, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x17, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x18, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - Disconnect.class, - Disconnect::new, - map(0x40, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x1A, ProtocolVersion.MINECRAFT_1_9, false), - map(0x1B, ProtocolVersion.MINECRAFT_1_13, false), - map(0x1A, ProtocolVersion.MINECRAFT_1_14, false), - map(0x1B, ProtocolVersion.MINECRAFT_1_15, false), - map(0x1A, ProtocolVersion.MINECRAFT_1_16, false), - map(0x19, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x1A, ProtocolVersion.MINECRAFT_1_17, false), - map(0x17, ProtocolVersion.MINECRAFT_1_19, false), - map(0x19, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x17, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x1A, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x1B, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - KeepAlive.class, - KeepAlive::new, - map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x1F, ProtocolVersion.MINECRAFT_1_9, false), - map(0x21, ProtocolVersion.MINECRAFT_1_13, false), - map(0x20, ProtocolVersion.MINECRAFT_1_14, false), - map(0x21, ProtocolVersion.MINECRAFT_1_15, false), - map(0x20, ProtocolVersion.MINECRAFT_1_16, false), - map(0x1F, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x21, ProtocolVersion.MINECRAFT_1_17, false), - map(0x1E, ProtocolVersion.MINECRAFT_1_19, false), - map(0x20, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x1F, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x23, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x24, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - JoinGame.class, - JoinGame::new, - map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x23, ProtocolVersion.MINECRAFT_1_9, false), - map(0x25, ProtocolVersion.MINECRAFT_1_13, false), - map(0x25, ProtocolVersion.MINECRAFT_1_14, false), - map(0x26, ProtocolVersion.MINECRAFT_1_15, false), - map(0x25, ProtocolVersion.MINECRAFT_1_16, false), - map(0x24, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x26, ProtocolVersion.MINECRAFT_1_17, false), - map(0x23, ProtocolVersion.MINECRAFT_1_19, false), - map(0x25, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x24, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x28, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x29, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - Respawn.class, - Respawn::new, - map(0x07, ProtocolVersion.MINECRAFT_1_7_2, true), - map(0x33, ProtocolVersion.MINECRAFT_1_9, true), - map(0x34, ProtocolVersion.MINECRAFT_1_12, true), - map(0x35, ProtocolVersion.MINECRAFT_1_12_1, true), - map(0x38, ProtocolVersion.MINECRAFT_1_13, true), - map(0x3A, ProtocolVersion.MINECRAFT_1_14, true), - map(0x3B, ProtocolVersion.MINECRAFT_1_15, true), - map(0x3A, ProtocolVersion.MINECRAFT_1_16, true), - map(0x39, ProtocolVersion.MINECRAFT_1_16_2, true), - map(0x3D, ProtocolVersion.MINECRAFT_1_17, true), - map(0x3B, ProtocolVersion.MINECRAFT_1_19, true), - map(0x3E, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x3D, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x41, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x43, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - ResourcePackRequest.class, - ResourcePackRequest::new, - map(0x48, ProtocolVersion.MINECRAFT_1_8, false), - map(0x32, ProtocolVersion.MINECRAFT_1_9, false), - map(0x33, ProtocolVersion.MINECRAFT_1_12, false), - map(0x34, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x37, ProtocolVersion.MINECRAFT_1_13, false), - map(0x39, ProtocolVersion.MINECRAFT_1_14, false), - map(0x3A, ProtocolVersion.MINECRAFT_1_15, false), - map(0x39, ProtocolVersion.MINECRAFT_1_16, false), - map(0x38, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x3C, ProtocolVersion.MINECRAFT_1_17, false), - map(0x3A, ProtocolVersion.MINECRAFT_1_19, false), - map(0x3D, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x3C, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x40, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x42, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - HeaderAndFooter.class, - HeaderAndFooter::new, - map(0x47, ProtocolVersion.MINECRAFT_1_8, true), - map(0x48, ProtocolVersion.MINECRAFT_1_9, true), - map(0x47, ProtocolVersion.MINECRAFT_1_9_4, true), - map(0x49, ProtocolVersion.MINECRAFT_1_12, true), - map(0x4A, ProtocolVersion.MINECRAFT_1_12_1, true), - map(0x4E, ProtocolVersion.MINECRAFT_1_13, true), - map(0x53, ProtocolVersion.MINECRAFT_1_14, true), - map(0x54, ProtocolVersion.MINECRAFT_1_15, true), - map(0x53, ProtocolVersion.MINECRAFT_1_16, true), - map(0x5E, ProtocolVersion.MINECRAFT_1_17, true), - map(0x5F, ProtocolVersion.MINECRAFT_1_18, true), - map(0x60, ProtocolVersion.MINECRAFT_1_19, true), - map(0x63, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x61, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x65, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x68, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - LegacyTitlePacket.class, - LegacyTitlePacket::new, - map(0x45, ProtocolVersion.MINECRAFT_1_8, true), - map(0x45, ProtocolVersion.MINECRAFT_1_9, true), - map(0x47, ProtocolVersion.MINECRAFT_1_12, true), - map(0x48, ProtocolVersion.MINECRAFT_1_12_1, true), - map(0x4B, ProtocolVersion.MINECRAFT_1_13, true), - map(0x4F, ProtocolVersion.MINECRAFT_1_14, true), - map(0x50, ProtocolVersion.MINECRAFT_1_15, true), - map(0x4F, ProtocolVersion.MINECRAFT_1_16, ProtocolVersion.MINECRAFT_1_16_4, true)); - clientbound.register( - TitleSubtitlePacket.class, - TitleSubtitlePacket::new, - map(0x57, ProtocolVersion.MINECRAFT_1_17, true), - map(0x58, ProtocolVersion.MINECRAFT_1_18, true), - map(0x5B, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x59, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x5D, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x5F, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - TitleTextPacket.class, - TitleTextPacket::new, - map(0x59, ProtocolVersion.MINECRAFT_1_17, true), - map(0x5A, ProtocolVersion.MINECRAFT_1_18, true), - map(0x5D, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x5B, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x5F, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x61, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - TitleActionbarPacket.class, - TitleActionbarPacket::new, - map(0x41, ProtocolVersion.MINECRAFT_1_17, true), - map(0x40, ProtocolVersion.MINECRAFT_1_19, true), - map(0x43, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x42, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x46, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x48, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - TitleTimesPacket.class, - TitleTimesPacket::new, - map(0x5A, ProtocolVersion.MINECRAFT_1_17, true), - map(0x5B, ProtocolVersion.MINECRAFT_1_18, true), - map(0x5E, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x5C, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x60, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x62, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - TitleClearPacket.class, - TitleClearPacket::new, - map(0x10, ProtocolVersion.MINECRAFT_1_17, true), - map(0x0D, ProtocolVersion.MINECRAFT_1_19, true), - map(0x0C, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x0E, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x0F, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - LegacyPlayerListItem.class, - LegacyPlayerListItem::new, - map(0x38, ProtocolVersion.MINECRAFT_1_7_2, false), - map(0x2D, ProtocolVersion.MINECRAFT_1_9, false), - map(0x2E, ProtocolVersion.MINECRAFT_1_12_1, false), - map(0x30, ProtocolVersion.MINECRAFT_1_13, false), - map(0x33, ProtocolVersion.MINECRAFT_1_14, false), - map(0x34, ProtocolVersion.MINECRAFT_1_15, false), - map(0x33, ProtocolVersion.MINECRAFT_1_16, false), - map(0x32, ProtocolVersion.MINECRAFT_1_16_2, false), - map(0x36, ProtocolVersion.MINECRAFT_1_17, false), - map(0x34, ProtocolVersion.MINECRAFT_1_19, false), - map(0x37, ProtocolVersion.MINECRAFT_1_19_1, ProtocolVersion.MINECRAFT_1_19_1, false)); - clientbound.register( - RemovePlayerInfo.class, - RemovePlayerInfo::new, - map(0x35, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x39, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x3B, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - UpsertPlayerInfo.class, - UpsertPlayerInfo::new, - map(0x36, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x3A, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x3C, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - SystemChat.class, - SystemChat::new, - map(0x5F, ProtocolVersion.MINECRAFT_1_19, true), - map(0x62, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x60, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x64, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x67, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - PlayerChatCompletion.class, - PlayerChatCompletion::new, - map(0x15, ProtocolVersion.MINECRAFT_1_19_1, true), - map(0x14, ProtocolVersion.MINECRAFT_1_19_3, true), - map(0x16, ProtocolVersion.MINECRAFT_1_19_4, true), - map(0x17, ProtocolVersion.MINECRAFT_1_20_2, true)); - clientbound.register( - ServerData.class, - ServerData::new, - map(0x3F, ProtocolVersion.MINECRAFT_1_19, false), - map(0x42, ProtocolVersion.MINECRAFT_1_19_1, false), - map(0x41, ProtocolVersion.MINECRAFT_1_19_3, false), - map(0x45, ProtocolVersion.MINECRAFT_1_19_4, false), - map(0x47, ProtocolVersion.MINECRAFT_1_20_2, false)); - clientbound.register( - StartUpdate.class, StartUpdate::new, map(0x65, ProtocolVersion.MINECRAFT_1_20_2, false)); + FinishedUpdate.class, + FinishedUpdate::new, + map(0x0B, MINECRAFT_1_20_2, false)); + + clientbound.register( + BossBar.class, + BossBar::new, + map(0x0C, MINECRAFT_1_9, false), + map(0x0D, MINECRAFT_1_15, false), + map(0x0C, MINECRAFT_1_16, false), + map(0x0D, MINECRAFT_1_17, false), + map(0x0A, MINECRAFT_1_19, false), + map(0x0B, MINECRAFT_1_19_4, false), + map(0x0A, MINECRAFT_1_20_2, false)); + clientbound.register( + LegacyChat.class, + LegacyChat::new, + map(0x02, MINECRAFT_1_7_2, true), + map(0x0F, MINECRAFT_1_9, true), + map(0x0E, MINECRAFT_1_13, true), + map(0x0F, MINECRAFT_1_15, true), + map(0x0E, MINECRAFT_1_16, true), + map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, true)); + clientbound.register( + TabCompleteResponse.class, + TabCompleteResponse::new, + map(0x3A, MINECRAFT_1_7_2, false), + map(0x0E, MINECRAFT_1_9, false), + map(0x10, MINECRAFT_1_13, false), + map(0x11, MINECRAFT_1_15, false), + map(0x10, MINECRAFT_1_16, false), + map(0x0F, MINECRAFT_1_16_2, false), + map(0x11, MINECRAFT_1_17, false), + map(0x0E, MINECRAFT_1_19, false), + map(0x0D, MINECRAFT_1_19_3, false), + map(0x0F, MINECRAFT_1_19_4, false), + map(0x10, MINECRAFT_1_20_2, false)); + clientbound.register( + AvailableCommands.class, + AvailableCommands::new, + map(0x11, MINECRAFT_1_13, false), + map(0x12, MINECRAFT_1_15, false), + map(0x11, MINECRAFT_1_16, false), + map(0x10, MINECRAFT_1_16_2, false), + map(0x12, MINECRAFT_1_17, false), + map(0x0F, MINECRAFT_1_19, false), + map(0x0E, MINECRAFT_1_19_3, false), + map(0x10, MINECRAFT_1_19_4, false), + map(0x11, MINECRAFT_1_20_2, false)); + clientbound.register( + PluginMessage.class, + PluginMessage::new, + map(0x3F, MINECRAFT_1_7_2, false), + map(0x18, MINECRAFT_1_9, false), + map(0x19, MINECRAFT_1_13, false), + map(0x18, MINECRAFT_1_14, false), + map(0x19, MINECRAFT_1_15, false), + map(0x18, MINECRAFT_1_16, false), + map(0x17, MINECRAFT_1_16_2, false), + map(0x18, MINECRAFT_1_17, false), + map(0x15, MINECRAFT_1_19, false), + map(0x16, MINECRAFT_1_19_1, false), + map(0x15, MINECRAFT_1_19_3, false), + map(0x17, MINECRAFT_1_19_4, false), + map(0x18, MINECRAFT_1_20_2, false)); + clientbound.register( + Disconnect.class, + Disconnect::new, + map(0x40, MINECRAFT_1_7_2, false), + map(0x1A, MINECRAFT_1_9, false), + map(0x1B, MINECRAFT_1_13, false), + map(0x1A, MINECRAFT_1_14, false), + map(0x1B, MINECRAFT_1_15, false), + map(0x1A, MINECRAFT_1_16, false), + map(0x19, MINECRAFT_1_16_2, false), + map(0x1A, MINECRAFT_1_17, false), + map(0x17, MINECRAFT_1_19, false), + map(0x19, MINECRAFT_1_19_1, false), + map(0x17, MINECRAFT_1_19_3, false), + map(0x1A, MINECRAFT_1_19_4, false), + map(0x1B, MINECRAFT_1_20_2, false)); + clientbound.register( + KeepAlive.class, + KeepAlive::new, + map(0x00, MINECRAFT_1_7_2, false), + map(0x1F, MINECRAFT_1_9, false), + map(0x21, MINECRAFT_1_13, false), + map(0x20, MINECRAFT_1_14, false), + map(0x21, MINECRAFT_1_15, false), + map(0x20, MINECRAFT_1_16, false), + map(0x1F, MINECRAFT_1_16_2, false), + map(0x21, MINECRAFT_1_17, false), + map(0x1E, MINECRAFT_1_19, false), + map(0x20, MINECRAFT_1_19_1, false), + map(0x1F, MINECRAFT_1_19_3, false), + map(0x23, MINECRAFT_1_19_4, false), + map(0x24, MINECRAFT_1_20_2, false)); + clientbound.register( + JoinGame.class, + JoinGame::new, + map(0x01, MINECRAFT_1_7_2, false), + map(0x23, MINECRAFT_1_9, false), + map(0x25, MINECRAFT_1_13, false), + map(0x25, MINECRAFT_1_14, false), + map(0x26, MINECRAFT_1_15, false), + map(0x25, MINECRAFT_1_16, false), + map(0x24, MINECRAFT_1_16_2, false), + map(0x26, MINECRAFT_1_17, false), + map(0x23, MINECRAFT_1_19, false), + map(0x25, MINECRAFT_1_19_1, false), + map(0x24, MINECRAFT_1_19_3, false), + map(0x28, MINECRAFT_1_19_4, false), + map(0x29, MINECRAFT_1_20_2, false)); + clientbound.register( + Respawn.class, + Respawn::new, + map(0x07, MINECRAFT_1_7_2, true), + map(0x33, MINECRAFT_1_9, true), + map(0x34, MINECRAFT_1_12, true), + map(0x35, MINECRAFT_1_12_1, true), + map(0x38, MINECRAFT_1_13, true), + map(0x3A, MINECRAFT_1_14, true), + map(0x3B, MINECRAFT_1_15, true), + map(0x3A, MINECRAFT_1_16, true), + map(0x39, MINECRAFT_1_16_2, true), + map(0x3D, MINECRAFT_1_17, true), + map(0x3B, MINECRAFT_1_19, true), + map(0x3E, MINECRAFT_1_19_1, true), + map(0x3D, MINECRAFT_1_19_3, true), + map(0x41, MINECRAFT_1_19_4, true), + map(0x43, MINECRAFT_1_20_2, true)); + clientbound.register( + ResourcePackRequest.class, + ResourcePackRequest::new, + map(0x48, MINECRAFT_1_8, false), + map(0x32, MINECRAFT_1_9, false), + map(0x33, MINECRAFT_1_12, false), + map(0x34, MINECRAFT_1_12_1, false), + map(0x37, MINECRAFT_1_13, false), + map(0x39, MINECRAFT_1_14, false), + map(0x3A, MINECRAFT_1_15, false), + map(0x39, MINECRAFT_1_16, false), + map(0x38, MINECRAFT_1_16_2, false), + map(0x3C, MINECRAFT_1_17, false), + map(0x3A, MINECRAFT_1_19, false), + map(0x3D, MINECRAFT_1_19_1, false), + map(0x3C, MINECRAFT_1_19_3, false), + map(0x40, MINECRAFT_1_19_4, false), + map(0x42, MINECRAFT_1_20_2, false)); + clientbound.register( + HeaderAndFooter.class, + HeaderAndFooter::new, + map(0x47, MINECRAFT_1_8, true), + map(0x48, MINECRAFT_1_9, true), + map(0x47, MINECRAFT_1_9_4, true), + map(0x49, MINECRAFT_1_12, true), + map(0x4A, MINECRAFT_1_12_1, true), + map(0x4E, MINECRAFT_1_13, true), + map(0x53, MINECRAFT_1_14, true), + map(0x54, MINECRAFT_1_15, true), + map(0x53, MINECRAFT_1_16, true), + map(0x5E, MINECRAFT_1_17, true), + map(0x5F, MINECRAFT_1_18, true), + map(0x60, MINECRAFT_1_19, true), + map(0x63, MINECRAFT_1_19_1, true), + map(0x61, MINECRAFT_1_19_3, true), + map(0x65, MINECRAFT_1_19_4, true), + map(0x68, MINECRAFT_1_20_2, true)); + clientbound.register( + LegacyTitlePacket.class, + LegacyTitlePacket::new, + map(0x45, MINECRAFT_1_8, true), + map(0x45, MINECRAFT_1_9, true), + map(0x47, MINECRAFT_1_12, true), + map(0x48, MINECRAFT_1_12_1, true), + map(0x4B, MINECRAFT_1_13, true), + map(0x4F, MINECRAFT_1_14, true), + map(0x50, MINECRAFT_1_15, true), + map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true)); + clientbound.register( + TitleSubtitlePacket.class, + TitleSubtitlePacket::new, + map(0x57, MINECRAFT_1_17, true), + map(0x58, MINECRAFT_1_18, true), + map(0x5B, MINECRAFT_1_19_1, true), + map(0x59, MINECRAFT_1_19_3, true), + map(0x5D, MINECRAFT_1_19_4, true), + map(0x5F, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleTextPacket.class, + TitleTextPacket::new, + map(0x59, MINECRAFT_1_17, true), + map(0x5A, MINECRAFT_1_18, true), + map(0x5D, MINECRAFT_1_19_1, true), + map(0x5B, MINECRAFT_1_19_3, true), + map(0x5F, MINECRAFT_1_19_4, true), + map(0x61, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleActionbarPacket.class, + TitleActionbarPacket::new, + map(0x41, MINECRAFT_1_17, true), + map(0x40, MINECRAFT_1_19, true), + map(0x43, MINECRAFT_1_19_1, true), + map(0x42, MINECRAFT_1_19_3, true), + map(0x46, MINECRAFT_1_19_4, true), + map(0x48, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleTimesPacket.class, + TitleTimesPacket::new, + map(0x5A, MINECRAFT_1_17, true), + map(0x5B, MINECRAFT_1_18, true), + map(0x5E, MINECRAFT_1_19_1, true), + map(0x5C, MINECRAFT_1_19_3, true), + map(0x60, MINECRAFT_1_19_4, true), + map(0x62, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleClearPacket.class, + TitleClearPacket::new, + map(0x10, MINECRAFT_1_17, true), + map(0x0D, MINECRAFT_1_19, true), + map(0x0C, MINECRAFT_1_19_3, true), + map(0x0E, MINECRAFT_1_19_4, true), + map(0x0F, MINECRAFT_1_20_2, true)); + clientbound.register( + LegacyPlayerListItem.class, + LegacyPlayerListItem::new, + map(0x38, MINECRAFT_1_7_2, false), + map(0x2D, MINECRAFT_1_9, false), + map(0x2E, MINECRAFT_1_12_1, false), + map(0x30, MINECRAFT_1_13, false), + map(0x33, MINECRAFT_1_14, false), + map(0x34, MINECRAFT_1_15, false), + map(0x33, MINECRAFT_1_16, false), + map(0x32, MINECRAFT_1_16_2, false), + map(0x36, MINECRAFT_1_17, false), + map(0x34, MINECRAFT_1_19, false), + map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + clientbound.register( + RemovePlayerInfo.class, + RemovePlayerInfo::new, + map(0x35, MINECRAFT_1_19_3, false), + map(0x39, MINECRAFT_1_19_4, false), + map(0x3B, MINECRAFT_1_20_2, false)); + clientbound.register( + UpsertPlayerInfo.class, + UpsertPlayerInfo::new, + map(0x36, MINECRAFT_1_19_3, false), + map(0x3A, MINECRAFT_1_19_4, false), + map(0x3C, MINECRAFT_1_20_2, false)); + clientbound.register( + SystemChat.class, + SystemChat::new, + map(0x5F, MINECRAFT_1_19, true), + map(0x62, MINECRAFT_1_19_1, true), + map(0x60, MINECRAFT_1_19_3, true), + map(0x64, MINECRAFT_1_19_4, true), + map(0x67, MINECRAFT_1_20_2, true)); + clientbound.register( + PlayerChatCompletion.class, + PlayerChatCompletion::new, + map(0x15, MINECRAFT_1_19_1, true), + map(0x14, MINECRAFT_1_19_3, true), + map(0x16, MINECRAFT_1_19_4, true), + map(0x17, MINECRAFT_1_20_2, true)); + clientbound.register( + ServerData.class, + ServerData::new, + map(0x3F, MINECRAFT_1_19, false), + map(0x42, MINECRAFT_1_19_1, false), + map(0x41, MINECRAFT_1_19_3, false), + map(0x45, MINECRAFT_1_19_4, false), + map(0x47, MINECRAFT_1_20_2, false)); + clientbound.register( + StartUpdate.class, StartUpdate::new, map(0x65, MINECRAFT_1_20_2, false)); } }, LOGIN { { serverbound.register( - ServerLogin.class, ServerLogin::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + ServerLogin.class, ServerLogin::new, map(0x00, MINECRAFT_1_7_2, false)); serverbound.register( - EncryptionResponse.class, - EncryptionResponse::new, - map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + EncryptionResponse.class, + EncryptionResponse::new, + map(0x01, MINECRAFT_1_7_2, false)); serverbound.register( - LoginPluginResponse.class, - LoginPluginResponse::new, - map(0x02, ProtocolVersion.MINECRAFT_1_13, false)); + LoginPluginResponse.class, + LoginPluginResponse::new, + map(0x02, MINECRAFT_1_13, false)); serverbound.register( - LoginAcknowledged.class, - LoginAcknowledged::new, - map(0x03, ProtocolVersion.MINECRAFT_1_20_2, false)); + LoginAcknowledged.class, + LoginAcknowledged::new, + map(0x03, MINECRAFT_1_20_2, false)); clientbound.register( - Disconnect.class, Disconnect::new, map(0x00, ProtocolVersion.MINECRAFT_1_7_2, false)); + Disconnect.class, Disconnect::new, map(0x00, MINECRAFT_1_7_2, false)); clientbound.register( - EncryptionRequest.class, - EncryptionRequest::new, - map(0x01, ProtocolVersion.MINECRAFT_1_7_2, false)); + EncryptionRequest.class, + EncryptionRequest::new, + map(0x01, MINECRAFT_1_7_2, false)); clientbound.register( - ServerLoginSuccess.class, - ServerLoginSuccess::new, - map(0x02, ProtocolVersion.MINECRAFT_1_7_2, false)); + ServerLoginSuccess.class, + ServerLoginSuccess::new, + map(0x02, MINECRAFT_1_7_2, false)); clientbound.register( - SetCompression.class, - SetCompression::new, - map(0x03, ProtocolVersion.MINECRAFT_1_8, false)); + SetCompression.class, + SetCompression::new, + map(0x03, MINECRAFT_1_8, false)); clientbound.register( - LoginPluginMessage.class, - LoginPluginMessage::new, - map(0x04, ProtocolVersion.MINECRAFT_1_13, false)); + LoginPluginMessage.class, + LoginPluginMessage::new, + map(0x04, MINECRAFT_1_13, false)); } }; @@ -589,7 +611,7 @@ public enum StateRegistry { protected final PacketRegistry serverbound = new PacketRegistry(SERVERBOUND); public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry( - Direction direction, ProtocolVersion version) { + Direction direction, ProtocolVersion version) { return (direction == SERVERBOUND ? serverbound : clientbound).getProtocolRegistry(version); } @@ -617,7 +639,7 @@ ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) { ProtocolRegistry registry = versions.get(version); if (registry == null) { if (fallback) { - return getProtocolRegistry(ProtocolVersion.MINIMUM_VERSION); + return getProtocolRegistry(MINIMUM_VERSION); } throw new IllegalArgumentException("Could not find data for protocol version " + version); } @@ -625,7 +647,7 @@ ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) { }

void register( - Class

clazz, Supplier

packetSupplier, PacketMapping... mappings) { + Class

clazz, Supplier

packetSupplier, PacketMapping... mappings) { if (mappings.length == 0) { throw new IllegalArgumentException("At least one mapping must be provided."); } @@ -642,21 +664,21 @@

void register( } if (from.compareTo(lastValid) > 0) { throw new IllegalArgumentException( - "Last mapping version cannot be higher than highest mapping version"); + "Last mapping version cannot be higher than highest mapping version"); } } ProtocolVersion to = - current == next - ? lastValid != null ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS) - : next.protocolVersion; + current == next + ? lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS) + : next.protocolVersion; ProtocolVersion lastInList = - lastValid != null ? lastValid : getLast(ProtocolVersion.SUPPORTED_VERSIONS); + lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS); if (from.compareTo(to) >= 0 && from != lastInList) { throw new IllegalArgumentException( - String.format( - "Next mapping version (%s) should be lower then current (%s)", to, from)); + String.format( + "Next mapping version (%s) should be lower then current (%s)", to, from)); } for (ProtocolVersion protocol : EnumSet.range(from, to)) { @@ -666,23 +688,23 @@

void register( ProtocolRegistry registry = this.versions.get(protocol); if (registry == null) { throw new IllegalArgumentException( - "Unknown protocol version " + current.protocolVersion); + "Unknown protocol version " + current.protocolVersion); } if (registry.packetIdToSupplier.containsKey(current.id)) { throw new IllegalArgumentException( - "Can not register class " - + clazz.getSimpleName() - + " with id " - + current.id - + " for " - + registry.version - + " because another packet is already registered"); + "Can not register class " + + clazz.getSimpleName() + + " with id " + + current.id + + " for " + + registry.version + + " because another packet is already registered"); } if (registry.packetClassToId.containsKey(clazz)) { throw new IllegalArgumentException( - clazz.getSimpleName() + " is already registered for version " + registry.version); + clazz.getSimpleName() + " is already registered for version " + registry.version); } if (!current.encodeOnly) { @@ -698,9 +720,9 @@ public class ProtocolRegistry { public final ProtocolVersion version; final IntObjectMap> packetIdToSupplier = - new IntObjectHashMap<>(16, 0.5f); + new IntObjectHashMap<>(16, 0.5f); final Object2IntMap> packetClassToId = - new Object2IntOpenHashMap<>(16, 0.5f); + new Object2IntOpenHashMap<>(16, 0.5f); ProtocolRegistry(final ProtocolVersion version) { this.version = version; @@ -732,9 +754,9 @@ public int getPacketId(final MinecraftPacket packet) { final int id = this.packetClassToId.getInt(packet.getClass()); if (id == Integer.MIN_VALUE) { throw new IllegalArgumentException( - String.format( - "Unable to find id for packet of type %s in %s protocol %s", - packet.getClass().getName(), PacketRegistry.this.direction, this.version)); + String.format( + "Unable to find id for packet of type %s in %s protocol %s", + packet.getClass().getName(), PacketRegistry.this.direction, this.version)); } return id; } @@ -760,10 +782,10 @@ public static final class PacketMapping { private final @Nullable ProtocolVersion lastValidProtocolVersion; PacketMapping( - int id, - ProtocolVersion protocolVersion, - ProtocolVersion lastValidProtocolVersion, - boolean packetDecoding) { + int id, + ProtocolVersion protocolVersion, + ProtocolVersion lastValidProtocolVersion, + boolean packetDecoding) { this.id = id; this.protocolVersion = protocolVersion; this.lastValidProtocolVersion = lastValidProtocolVersion; @@ -773,13 +795,13 @@ public static final class PacketMapping { @Override public String toString() { return "PacketMapping{" - + "id=" - + id - + ", protocolVersion=" - + protocolVersion - + ", encodeOnly=" - + encodeOnly - + '}'; + + "id=" + + id + + ", protocolVersion=" + + protocolVersion + + ", encodeOnly=" + + encodeOnly + + '}'; } @Override @@ -792,8 +814,8 @@ public boolean equals(@Nullable Object o) { } PacketMapping that = (PacketMapping) o; return id == that.id - && protocolVersion == that.protocolVersion - && encodeOnly == that.encodeOnly; + && protocolVersion == that.protocolVersion + && encodeOnly == that.encodeOnly; } @Override @@ -825,10 +847,10 @@ private static PacketMapping map(int id, ProtocolVersion version, boolean encode * @return PacketMapping with the provided arguments */ private static PacketMapping map( - int id, - ProtocolVersion version, - ProtocolVersion lastValidProtocolVersion, - boolean encodeOnly) { + int id, + ProtocolVersion version, + ProtocolVersion lastValidProtocolVersion, + boolean encodeOnly) { return new PacketMapping(id, version, lastValidProtocolVersion, encodeOnly); } } From cd1d2dc4ea4d8605efe0ed7912cdb2d11aedd238 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Wed, 27 Sep 2023 21:17:58 +0100 Subject: [PATCH 32/41] remove experimental --- .../backend/ConfigSessionHandler.java | 2 - .../proxy/protocol/StateRegistry.java | 909 +++++++++--------- 2 files changed, 429 insertions(+), 482 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 58135b8da2..9e398f5ba1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -41,7 +41,6 @@ import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import java.io.IOException; import java.util.concurrent.CompletableFuture; -import jdk.jfr.Experimental; import net.kyori.adventure.text.Component; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -50,7 +49,6 @@ * A special session handler that catches "last minute" disconnects. This version is to accommodate * 1.20.2+ switching. Yes, some of this is exceptionally stupid. */ -@Experimental public class ConfigSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(ConfigSessionHandler.class); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 54744dc5af..90dc1acb82 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -110,82 +110,51 @@ public enum StateRegistry { HANDSHAKE { { - serverbound.register( - Handshake.class, Handshake::new, map(0x00, MINECRAFT_1_7_2, false)); + serverbound.register(Handshake.class, Handshake::new, map(0x00, MINECRAFT_1_7_2, false)); } }, STATUS { { serverbound.register( - StatusRequest.class, - () -> StatusRequest.INSTANCE, - map(0x00, MINECRAFT_1_7_2, false)); - serverbound.register( - StatusPing.class, StatusPing::new, map(0x01, MINECRAFT_1_7_2, false)); + StatusRequest.class, () -> StatusRequest.INSTANCE, map(0x00, MINECRAFT_1_7_2, false)); + serverbound.register(StatusPing.class, StatusPing::new, map(0x01, MINECRAFT_1_7_2, false)); clientbound.register( - StatusResponse.class, - StatusResponse::new, - map(0x00, MINECRAFT_1_7_2, false)); - clientbound.register( - StatusPing.class, StatusPing::new, map(0x01, MINECRAFT_1_7_2, false)); + StatusResponse.class, StatusResponse::new, map(0x00, MINECRAFT_1_7_2, false)); + clientbound.register(StatusPing.class, StatusPing::new, map(0x01, MINECRAFT_1_7_2, false)); } }, CONFIG { { serverbound.register( - ClientSettings.class, - ClientSettings::new, - map(0x00, MINECRAFT_1_20_2, false)); + ClientSettings.class, ClientSettings::new, map(0x00, MINECRAFT_1_20_2, false)); serverbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x01, MINECRAFT_1_20_2, false)); + PluginMessage.class, PluginMessage::new, map(0x01, MINECRAFT_1_20_2, false)); serverbound.register( - FinishedUpdate.class, - FinishedUpdate::new, - map(0x02, MINECRAFT_1_20_2, false)); + FinishedUpdate.class, FinishedUpdate::new, map(0x02, MINECRAFT_1_20_2, false)); + serverbound.register(KeepAlive.class, KeepAlive::new, map(0x03, MINECRAFT_1_20_2, false)); serverbound.register( - KeepAlive.class, KeepAlive::new, map(0x03, MINECRAFT_1_20_2, false)); + PingIdentify.class, PingIdentify::new, map(0x04, MINECRAFT_1_20_2, false)); serverbound.register( - PingIdentify.class, - PingIdentify::new, - map(0x04, MINECRAFT_1_20_2, false)); - serverbound.register( - ResourcePackResponse.class, - ResourcePackResponse::new, - map(0x05, MINECRAFT_1_20_2, false)); + ResourcePackResponse.class, + ResourcePackResponse::new, + map(0x05, MINECRAFT_1_20_2, false)); clientbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x00, MINECRAFT_1_20_2, false)); - clientbound.register( - Disconnect.class, Disconnect::new, map(0x01, MINECRAFT_1_20_2, false)); + PluginMessage.class, PluginMessage::new, map(0x00, MINECRAFT_1_20_2, false)); + clientbound.register(Disconnect.class, Disconnect::new, map(0x01, MINECRAFT_1_20_2, false)); clientbound.register( - FinishedUpdate.class, - FinishedUpdate::new, - map(0x02, MINECRAFT_1_20_2, false)); + FinishedUpdate.class, FinishedUpdate::new, map(0x02, MINECRAFT_1_20_2, false)); + clientbound.register(KeepAlive.class, KeepAlive::new, map(0x03, MINECRAFT_1_20_2, false)); clientbound.register( - KeepAlive.class, KeepAlive::new, map(0x03, MINECRAFT_1_20_2, false)); + PingIdentify.class, PingIdentify::new, map(0x04, MINECRAFT_1_20_2, false)); clientbound.register( - PingIdentify.class, - PingIdentify::new, - map(0x04, MINECRAFT_1_20_2, false)); + RegistrySync.class, RegistrySync::new, map(0x05, MINECRAFT_1_20_2, false)); clientbound.register( - RegistrySync.class, - RegistrySync::new, - map(0x05, MINECRAFT_1_20_2, false)); + ResourcePackRequest.class, ResourcePackRequest::new, map(0x06, MINECRAFT_1_20_2, false)); clientbound.register( - ResourcePackRequest.class, - ResourcePackRequest::new, - map(0x06, MINECRAFT_1_20_2, false)); - clientbound.register( - ActiveFeatures.class, - ActiveFeatures::new, - map(0x07, MINECRAFT_1_20_2, false)); - clientbound.register( - TagsUpdate.class, TagsUpdate::new, map(0x08, MINECRAFT_1_20_2, false)); + ActiveFeatures.class, ActiveFeatures::new, map(0x07, MINECRAFT_1_20_2, false)); + clientbound.register(TagsUpdate.class, TagsUpdate::new, map(0x08, MINECRAFT_1_20_2, false)); } }, PLAY { @@ -194,414 +163,395 @@ public enum StateRegistry { clientbound.fallback = false; serverbound.register( - TabCompleteRequest.class, - TabCompleteRequest::new, - map(0x14, MINECRAFT_1_7_2, false), - map(0x01, MINECRAFT_1_9, false), - map(0x02, MINECRAFT_1_12, false), - map(0x01, MINECRAFT_1_12_1, false), - map(0x05, MINECRAFT_1_13, false), - map(0x06, MINECRAFT_1_14, false), - map(0x08, MINECRAFT_1_19, false), - map(0x09, MINECRAFT_1_19_1, false), - map(0x08, MINECRAFT_1_19_3, false), - map(0x09, MINECRAFT_1_19_4, false), - map(0x0A, MINECRAFT_1_20_2, false)); + TabCompleteRequest.class, + TabCompleteRequest::new, + map(0x14, MINECRAFT_1_7_2, false), + map(0x01, MINECRAFT_1_9, false), + map(0x02, MINECRAFT_1_12, false), + map(0x01, MINECRAFT_1_12_1, false), + map(0x05, MINECRAFT_1_13, false), + map(0x06, MINECRAFT_1_14, false), + map(0x08, MINECRAFT_1_19, false), + map(0x09, MINECRAFT_1_19_1, false), + map(0x08, MINECRAFT_1_19_3, false), + map(0x09, MINECRAFT_1_19_4, false), + map(0x0A, MINECRAFT_1_20_2, false)); serverbound.register( - LegacyChat.class, - LegacyChat::new, - map(0x01, MINECRAFT_1_7_2, false), - map(0x02, MINECRAFT_1_9, false), - map(0x03, MINECRAFT_1_12, false), - map(0x02, MINECRAFT_1_12_1, false), - map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false)); + LegacyChat.class, + LegacyChat::new, + map(0x01, MINECRAFT_1_7_2, false), + map(0x02, MINECRAFT_1_9, false), + map(0x03, MINECRAFT_1_12, false), + map(0x02, MINECRAFT_1_12_1, false), + map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false)); serverbound.register( - KeyedPlayerCommand.class, - KeyedPlayerCommand::new, - map(0x03, MINECRAFT_1_19, false), - map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + KeyedPlayerCommand.class, + KeyedPlayerCommand::new, + map(0x03, MINECRAFT_1_19, false), + map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); serverbound.register( - KeyedPlayerChat.class, - KeyedPlayerChat::new, - map(0x04, MINECRAFT_1_19, false), - map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + KeyedPlayerChat.class, + KeyedPlayerChat::new, + map(0x04, MINECRAFT_1_19, false), + map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); serverbound.register( - SessionPlayerCommand.class, - SessionPlayerCommand::new, - map(0x04, MINECRAFT_1_19_3, false)); + SessionPlayerCommand.class, + SessionPlayerCommand::new, + map(0x04, MINECRAFT_1_19_3, false)); serverbound.register( - SessionPlayerChat.class, - SessionPlayerChat::new, - map(0x05, MINECRAFT_1_19_3, MINECRAFT_1_20_2, false)); + SessionPlayerChat.class, + SessionPlayerChat::new, + map(0x05, MINECRAFT_1_19_3, MINECRAFT_1_20_2, false)); serverbound.register( - ClientSettings.class, - ClientSettings::new, - map(0x15, MINECRAFT_1_7_2, false), - map(0x04, MINECRAFT_1_9, false), - map(0x05, MINECRAFT_1_12, false), - map(0x04, MINECRAFT_1_12_1, false), - map(0x05, MINECRAFT_1_14, false), - map(0x07, MINECRAFT_1_19, false), - map(0x08, MINECRAFT_1_19_1, false), - map(0x07, MINECRAFT_1_19_3, false), - map(0x08, MINECRAFT_1_19_4, false), - map(0x09, MINECRAFT_1_20_2, false)); + ClientSettings.class, + ClientSettings::new, + map(0x15, MINECRAFT_1_7_2, false), + map(0x04, MINECRAFT_1_9, false), + map(0x05, MINECRAFT_1_12, false), + map(0x04, MINECRAFT_1_12_1, false), + map(0x05, MINECRAFT_1_14, false), + map(0x07, MINECRAFT_1_19, false), + map(0x08, MINECRAFT_1_19_1, false), + map(0x07, MINECRAFT_1_19_3, false), + map(0x08, MINECRAFT_1_19_4, false), + map(0x09, MINECRAFT_1_20_2, false)); serverbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x17, MINECRAFT_1_7_2, false), - map(0x09, MINECRAFT_1_9, false), - map(0x0A, MINECRAFT_1_12, false), - map(0x09, MINECRAFT_1_12_1, false), - map(0x0A, MINECRAFT_1_13, false), - map(0x0B, MINECRAFT_1_14, false), - map(0x0A, MINECRAFT_1_17, false), - map(0x0C, MINECRAFT_1_19, false), - map(0x0D, MINECRAFT_1_19_1, false), - map(0x0C, MINECRAFT_1_19_3, false), - map(0x0D, MINECRAFT_1_19_4, false), - map(0x0F, MINECRAFT_1_20_2, false)); + PluginMessage.class, + PluginMessage::new, + map(0x17, MINECRAFT_1_7_2, false), + map(0x09, MINECRAFT_1_9, false), + map(0x0A, MINECRAFT_1_12, false), + map(0x09, MINECRAFT_1_12_1, false), + map(0x0A, MINECRAFT_1_13, false), + map(0x0B, MINECRAFT_1_14, false), + map(0x0A, MINECRAFT_1_17, false), + map(0x0C, MINECRAFT_1_19, false), + map(0x0D, MINECRAFT_1_19_1, false), + map(0x0C, MINECRAFT_1_19_3, false), + map(0x0D, MINECRAFT_1_19_4, false), + map(0x0F, MINECRAFT_1_20_2, false)); serverbound.register( - KeepAlive.class, - KeepAlive::new, - map(0x00, MINECRAFT_1_7_2, false), - map(0x0B, MINECRAFT_1_9, false), - map(0x0C, MINECRAFT_1_12, false), - map(0x0B, MINECRAFT_1_12_1, false), - map(0x0E, MINECRAFT_1_13, false), - map(0x0F, MINECRAFT_1_14, false), - map(0x10, MINECRAFT_1_16, false), - map(0x0F, MINECRAFT_1_17, false), - map(0x11, MINECRAFT_1_19, false), - map(0x12, MINECRAFT_1_19_1, false), - map(0x11, MINECRAFT_1_19_3, false), - map(0x12, MINECRAFT_1_19_4, false), - map(0x14, MINECRAFT_1_20_2, false)); + KeepAlive.class, + KeepAlive::new, + map(0x00, MINECRAFT_1_7_2, false), + map(0x0B, MINECRAFT_1_9, false), + map(0x0C, MINECRAFT_1_12, false), + map(0x0B, MINECRAFT_1_12_1, false), + map(0x0E, MINECRAFT_1_13, false), + map(0x0F, MINECRAFT_1_14, false), + map(0x10, MINECRAFT_1_16, false), + map(0x0F, MINECRAFT_1_17, false), + map(0x11, MINECRAFT_1_19, false), + map(0x12, MINECRAFT_1_19_1, false), + map(0x11, MINECRAFT_1_19_3, false), + map(0x12, MINECRAFT_1_19_4, false), + map(0x14, MINECRAFT_1_20_2, false)); serverbound.register( - ResourcePackResponse.class, - ResourcePackResponse::new, - map(0x19, MINECRAFT_1_8, false), - map(0x16, MINECRAFT_1_9, false), - map(0x18, MINECRAFT_1_12, false), - map(0x1D, MINECRAFT_1_13, false), - map(0x1F, MINECRAFT_1_14, false), - map(0x20, MINECRAFT_1_16, false), - map(0x21, MINECRAFT_1_16_2, false), - map(0x23, MINECRAFT_1_19, false), - map(0x24, MINECRAFT_1_19_1, false), - map(0x27, MINECRAFT_1_20_2, false)); + ResourcePackResponse.class, + ResourcePackResponse::new, + map(0x19, MINECRAFT_1_8, false), + map(0x16, MINECRAFT_1_9, false), + map(0x18, MINECRAFT_1_12, false), + map(0x1D, MINECRAFT_1_13, false), + map(0x1F, MINECRAFT_1_14, false), + map(0x20, MINECRAFT_1_16, false), + map(0x21, MINECRAFT_1_16_2, false), + map(0x23, MINECRAFT_1_19, false), + map(0x24, MINECRAFT_1_19_1, false), + map(0x27, MINECRAFT_1_20_2, false)); serverbound.register( - FinishedUpdate.class, - FinishedUpdate::new, - map(0x0B, MINECRAFT_1_20_2, false)); - - clientbound.register( - BossBar.class, - BossBar::new, - map(0x0C, MINECRAFT_1_9, false), - map(0x0D, MINECRAFT_1_15, false), - map(0x0C, MINECRAFT_1_16, false), - map(0x0D, MINECRAFT_1_17, false), - map(0x0A, MINECRAFT_1_19, false), - map(0x0B, MINECRAFT_1_19_4, false), - map(0x0A, MINECRAFT_1_20_2, false)); - clientbound.register( - LegacyChat.class, - LegacyChat::new, - map(0x02, MINECRAFT_1_7_2, true), - map(0x0F, MINECRAFT_1_9, true), - map(0x0E, MINECRAFT_1_13, true), - map(0x0F, MINECRAFT_1_15, true), - map(0x0E, MINECRAFT_1_16, true), - map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, true)); - clientbound.register( - TabCompleteResponse.class, - TabCompleteResponse::new, - map(0x3A, MINECRAFT_1_7_2, false), - map(0x0E, MINECRAFT_1_9, false), - map(0x10, MINECRAFT_1_13, false), - map(0x11, MINECRAFT_1_15, false), - map(0x10, MINECRAFT_1_16, false), - map(0x0F, MINECRAFT_1_16_2, false), - map(0x11, MINECRAFT_1_17, false), - map(0x0E, MINECRAFT_1_19, false), - map(0x0D, MINECRAFT_1_19_3, false), - map(0x0F, MINECRAFT_1_19_4, false), - map(0x10, MINECRAFT_1_20_2, false)); - clientbound.register( - AvailableCommands.class, - AvailableCommands::new, - map(0x11, MINECRAFT_1_13, false), - map(0x12, MINECRAFT_1_15, false), - map(0x11, MINECRAFT_1_16, false), - map(0x10, MINECRAFT_1_16_2, false), - map(0x12, MINECRAFT_1_17, false), - map(0x0F, MINECRAFT_1_19, false), - map(0x0E, MINECRAFT_1_19_3, false), - map(0x10, MINECRAFT_1_19_4, false), - map(0x11, MINECRAFT_1_20_2, false)); - clientbound.register( - PluginMessage.class, - PluginMessage::new, - map(0x3F, MINECRAFT_1_7_2, false), - map(0x18, MINECRAFT_1_9, false), - map(0x19, MINECRAFT_1_13, false), - map(0x18, MINECRAFT_1_14, false), - map(0x19, MINECRAFT_1_15, false), - map(0x18, MINECRAFT_1_16, false), - map(0x17, MINECRAFT_1_16_2, false), - map(0x18, MINECRAFT_1_17, false), - map(0x15, MINECRAFT_1_19, false), - map(0x16, MINECRAFT_1_19_1, false), - map(0x15, MINECRAFT_1_19_3, false), - map(0x17, MINECRAFT_1_19_4, false), - map(0x18, MINECRAFT_1_20_2, false)); - clientbound.register( - Disconnect.class, - Disconnect::new, - map(0x40, MINECRAFT_1_7_2, false), - map(0x1A, MINECRAFT_1_9, false), - map(0x1B, MINECRAFT_1_13, false), - map(0x1A, MINECRAFT_1_14, false), - map(0x1B, MINECRAFT_1_15, false), - map(0x1A, MINECRAFT_1_16, false), - map(0x19, MINECRAFT_1_16_2, false), - map(0x1A, MINECRAFT_1_17, false), - map(0x17, MINECRAFT_1_19, false), - map(0x19, MINECRAFT_1_19_1, false), - map(0x17, MINECRAFT_1_19_3, false), - map(0x1A, MINECRAFT_1_19_4, false), - map(0x1B, MINECRAFT_1_20_2, false)); - clientbound.register( - KeepAlive.class, - KeepAlive::new, - map(0x00, MINECRAFT_1_7_2, false), - map(0x1F, MINECRAFT_1_9, false), - map(0x21, MINECRAFT_1_13, false), - map(0x20, MINECRAFT_1_14, false), - map(0x21, MINECRAFT_1_15, false), - map(0x20, MINECRAFT_1_16, false), - map(0x1F, MINECRAFT_1_16_2, false), - map(0x21, MINECRAFT_1_17, false), - map(0x1E, MINECRAFT_1_19, false), - map(0x20, MINECRAFT_1_19_1, false), - map(0x1F, MINECRAFT_1_19_3, false), - map(0x23, MINECRAFT_1_19_4, false), - map(0x24, MINECRAFT_1_20_2, false)); - clientbound.register( - JoinGame.class, - JoinGame::new, - map(0x01, MINECRAFT_1_7_2, false), - map(0x23, MINECRAFT_1_9, false), - map(0x25, MINECRAFT_1_13, false), - map(0x25, MINECRAFT_1_14, false), - map(0x26, MINECRAFT_1_15, false), - map(0x25, MINECRAFT_1_16, false), - map(0x24, MINECRAFT_1_16_2, false), - map(0x26, MINECRAFT_1_17, false), - map(0x23, MINECRAFT_1_19, false), - map(0x25, MINECRAFT_1_19_1, false), - map(0x24, MINECRAFT_1_19_3, false), - map(0x28, MINECRAFT_1_19_4, false), - map(0x29, MINECRAFT_1_20_2, false)); - clientbound.register( - Respawn.class, - Respawn::new, - map(0x07, MINECRAFT_1_7_2, true), - map(0x33, MINECRAFT_1_9, true), - map(0x34, MINECRAFT_1_12, true), - map(0x35, MINECRAFT_1_12_1, true), - map(0x38, MINECRAFT_1_13, true), - map(0x3A, MINECRAFT_1_14, true), - map(0x3B, MINECRAFT_1_15, true), - map(0x3A, MINECRAFT_1_16, true), - map(0x39, MINECRAFT_1_16_2, true), - map(0x3D, MINECRAFT_1_17, true), - map(0x3B, MINECRAFT_1_19, true), - map(0x3E, MINECRAFT_1_19_1, true), - map(0x3D, MINECRAFT_1_19_3, true), - map(0x41, MINECRAFT_1_19_4, true), - map(0x43, MINECRAFT_1_20_2, true)); - clientbound.register( - ResourcePackRequest.class, - ResourcePackRequest::new, - map(0x48, MINECRAFT_1_8, false), - map(0x32, MINECRAFT_1_9, false), - map(0x33, MINECRAFT_1_12, false), - map(0x34, MINECRAFT_1_12_1, false), - map(0x37, MINECRAFT_1_13, false), - map(0x39, MINECRAFT_1_14, false), - map(0x3A, MINECRAFT_1_15, false), - map(0x39, MINECRAFT_1_16, false), - map(0x38, MINECRAFT_1_16_2, false), - map(0x3C, MINECRAFT_1_17, false), - map(0x3A, MINECRAFT_1_19, false), - map(0x3D, MINECRAFT_1_19_1, false), - map(0x3C, MINECRAFT_1_19_3, false), - map(0x40, MINECRAFT_1_19_4, false), - map(0x42, MINECRAFT_1_20_2, false)); - clientbound.register( - HeaderAndFooter.class, - HeaderAndFooter::new, - map(0x47, MINECRAFT_1_8, true), - map(0x48, MINECRAFT_1_9, true), - map(0x47, MINECRAFT_1_9_4, true), - map(0x49, MINECRAFT_1_12, true), - map(0x4A, MINECRAFT_1_12_1, true), - map(0x4E, MINECRAFT_1_13, true), - map(0x53, MINECRAFT_1_14, true), - map(0x54, MINECRAFT_1_15, true), - map(0x53, MINECRAFT_1_16, true), - map(0x5E, MINECRAFT_1_17, true), - map(0x5F, MINECRAFT_1_18, true), - map(0x60, MINECRAFT_1_19, true), - map(0x63, MINECRAFT_1_19_1, true), - map(0x61, MINECRAFT_1_19_3, true), - map(0x65, MINECRAFT_1_19_4, true), - map(0x68, MINECRAFT_1_20_2, true)); - clientbound.register( - LegacyTitlePacket.class, - LegacyTitlePacket::new, - map(0x45, MINECRAFT_1_8, true), - map(0x45, MINECRAFT_1_9, true), - map(0x47, MINECRAFT_1_12, true), - map(0x48, MINECRAFT_1_12_1, true), - map(0x4B, MINECRAFT_1_13, true), - map(0x4F, MINECRAFT_1_14, true), - map(0x50, MINECRAFT_1_15, true), - map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true)); - clientbound.register( - TitleSubtitlePacket.class, - TitleSubtitlePacket::new, - map(0x57, MINECRAFT_1_17, true), - map(0x58, MINECRAFT_1_18, true), - map(0x5B, MINECRAFT_1_19_1, true), - map(0x59, MINECRAFT_1_19_3, true), - map(0x5D, MINECRAFT_1_19_4, true), - map(0x5F, MINECRAFT_1_20_2, true)); - clientbound.register( - TitleTextPacket.class, - TitleTextPacket::new, - map(0x59, MINECRAFT_1_17, true), - map(0x5A, MINECRAFT_1_18, true), - map(0x5D, MINECRAFT_1_19_1, true), - map(0x5B, MINECRAFT_1_19_3, true), - map(0x5F, MINECRAFT_1_19_4, true), - map(0x61, MINECRAFT_1_20_2, true)); - clientbound.register( - TitleActionbarPacket.class, - TitleActionbarPacket::new, - map(0x41, MINECRAFT_1_17, true), - map(0x40, MINECRAFT_1_19, true), - map(0x43, MINECRAFT_1_19_1, true), - map(0x42, MINECRAFT_1_19_3, true), - map(0x46, MINECRAFT_1_19_4, true), - map(0x48, MINECRAFT_1_20_2, true)); - clientbound.register( - TitleTimesPacket.class, - TitleTimesPacket::new, - map(0x5A, MINECRAFT_1_17, true), - map(0x5B, MINECRAFT_1_18, true), - map(0x5E, MINECRAFT_1_19_1, true), - map(0x5C, MINECRAFT_1_19_3, true), - map(0x60, MINECRAFT_1_19_4, true), - map(0x62, MINECRAFT_1_20_2, true)); - clientbound.register( - TitleClearPacket.class, - TitleClearPacket::new, - map(0x10, MINECRAFT_1_17, true), - map(0x0D, MINECRAFT_1_19, true), - map(0x0C, MINECRAFT_1_19_3, true), - map(0x0E, MINECRAFT_1_19_4, true), - map(0x0F, MINECRAFT_1_20_2, true)); - clientbound.register( - LegacyPlayerListItem.class, - LegacyPlayerListItem::new, - map(0x38, MINECRAFT_1_7_2, false), - map(0x2D, MINECRAFT_1_9, false), - map(0x2E, MINECRAFT_1_12_1, false), - map(0x30, MINECRAFT_1_13, false), - map(0x33, MINECRAFT_1_14, false), - map(0x34, MINECRAFT_1_15, false), - map(0x33, MINECRAFT_1_16, false), - map(0x32, MINECRAFT_1_16_2, false), - map(0x36, MINECRAFT_1_17, false), - map(0x34, MINECRAFT_1_19, false), - map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); - clientbound.register( - RemovePlayerInfo.class, - RemovePlayerInfo::new, - map(0x35, MINECRAFT_1_19_3, false), - map(0x39, MINECRAFT_1_19_4, false), - map(0x3B, MINECRAFT_1_20_2, false)); - clientbound.register( - UpsertPlayerInfo.class, - UpsertPlayerInfo::new, - map(0x36, MINECRAFT_1_19_3, false), - map(0x3A, MINECRAFT_1_19_4, false), - map(0x3C, MINECRAFT_1_20_2, false)); - clientbound.register( - SystemChat.class, - SystemChat::new, - map(0x5F, MINECRAFT_1_19, true), - map(0x62, MINECRAFT_1_19_1, true), - map(0x60, MINECRAFT_1_19_3, true), - map(0x64, MINECRAFT_1_19_4, true), - map(0x67, MINECRAFT_1_20_2, true)); - clientbound.register( - PlayerChatCompletion.class, - PlayerChatCompletion::new, - map(0x15, MINECRAFT_1_19_1, true), - map(0x14, MINECRAFT_1_19_3, true), - map(0x16, MINECRAFT_1_19_4, true), - map(0x17, MINECRAFT_1_20_2, true)); - clientbound.register( - ServerData.class, - ServerData::new, - map(0x3F, MINECRAFT_1_19, false), - map(0x42, MINECRAFT_1_19_1, false), - map(0x41, MINECRAFT_1_19_3, false), - map(0x45, MINECRAFT_1_19_4, false), - map(0x47, MINECRAFT_1_20_2, false)); - clientbound.register( - StartUpdate.class, StartUpdate::new, map(0x65, MINECRAFT_1_20_2, false)); + FinishedUpdate.class, FinishedUpdate::new, map(0x0B, MINECRAFT_1_20_2, false)); + + clientbound.register( + BossBar.class, + BossBar::new, + map(0x0C, MINECRAFT_1_9, false), + map(0x0D, MINECRAFT_1_15, false), + map(0x0C, MINECRAFT_1_16, false), + map(0x0D, MINECRAFT_1_17, false), + map(0x0A, MINECRAFT_1_19, false), + map(0x0B, MINECRAFT_1_19_4, false), + map(0x0A, MINECRAFT_1_20_2, false)); + clientbound.register( + LegacyChat.class, + LegacyChat::new, + map(0x02, MINECRAFT_1_7_2, true), + map(0x0F, MINECRAFT_1_9, true), + map(0x0E, MINECRAFT_1_13, true), + map(0x0F, MINECRAFT_1_15, true), + map(0x0E, MINECRAFT_1_16, true), + map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, true)); + clientbound.register( + TabCompleteResponse.class, + TabCompleteResponse::new, + map(0x3A, MINECRAFT_1_7_2, false), + map(0x0E, MINECRAFT_1_9, false), + map(0x10, MINECRAFT_1_13, false), + map(0x11, MINECRAFT_1_15, false), + map(0x10, MINECRAFT_1_16, false), + map(0x0F, MINECRAFT_1_16_2, false), + map(0x11, MINECRAFT_1_17, false), + map(0x0E, MINECRAFT_1_19, false), + map(0x0D, MINECRAFT_1_19_3, false), + map(0x0F, MINECRAFT_1_19_4, false), + map(0x10, MINECRAFT_1_20_2, false)); + clientbound.register( + AvailableCommands.class, + AvailableCommands::new, + map(0x11, MINECRAFT_1_13, false), + map(0x12, MINECRAFT_1_15, false), + map(0x11, MINECRAFT_1_16, false), + map(0x10, MINECRAFT_1_16_2, false), + map(0x12, MINECRAFT_1_17, false), + map(0x0F, MINECRAFT_1_19, false), + map(0x0E, MINECRAFT_1_19_3, false), + map(0x10, MINECRAFT_1_19_4, false), + map(0x11, MINECRAFT_1_20_2, false)); + clientbound.register( + PluginMessage.class, + PluginMessage::new, + map(0x3F, MINECRAFT_1_7_2, false), + map(0x18, MINECRAFT_1_9, false), + map(0x19, MINECRAFT_1_13, false), + map(0x18, MINECRAFT_1_14, false), + map(0x19, MINECRAFT_1_15, false), + map(0x18, MINECRAFT_1_16, false), + map(0x17, MINECRAFT_1_16_2, false), + map(0x18, MINECRAFT_1_17, false), + map(0x15, MINECRAFT_1_19, false), + map(0x16, MINECRAFT_1_19_1, false), + map(0x15, MINECRAFT_1_19_3, false), + map(0x17, MINECRAFT_1_19_4, false), + map(0x18, MINECRAFT_1_20_2, false)); + clientbound.register( + Disconnect.class, + Disconnect::new, + map(0x40, MINECRAFT_1_7_2, false), + map(0x1A, MINECRAFT_1_9, false), + map(0x1B, MINECRAFT_1_13, false), + map(0x1A, MINECRAFT_1_14, false), + map(0x1B, MINECRAFT_1_15, false), + map(0x1A, MINECRAFT_1_16, false), + map(0x19, MINECRAFT_1_16_2, false), + map(0x1A, MINECRAFT_1_17, false), + map(0x17, MINECRAFT_1_19, false), + map(0x19, MINECRAFT_1_19_1, false), + map(0x17, MINECRAFT_1_19_3, false), + map(0x1A, MINECRAFT_1_19_4, false), + map(0x1B, MINECRAFT_1_20_2, false)); + clientbound.register( + KeepAlive.class, + KeepAlive::new, + map(0x00, MINECRAFT_1_7_2, false), + map(0x1F, MINECRAFT_1_9, false), + map(0x21, MINECRAFT_1_13, false), + map(0x20, MINECRAFT_1_14, false), + map(0x21, MINECRAFT_1_15, false), + map(0x20, MINECRAFT_1_16, false), + map(0x1F, MINECRAFT_1_16_2, false), + map(0x21, MINECRAFT_1_17, false), + map(0x1E, MINECRAFT_1_19, false), + map(0x20, MINECRAFT_1_19_1, false), + map(0x1F, MINECRAFT_1_19_3, false), + map(0x23, MINECRAFT_1_19_4, false), + map(0x24, MINECRAFT_1_20_2, false)); + clientbound.register( + JoinGame.class, + JoinGame::new, + map(0x01, MINECRAFT_1_7_2, false), + map(0x23, MINECRAFT_1_9, false), + map(0x25, MINECRAFT_1_13, false), + map(0x25, MINECRAFT_1_14, false), + map(0x26, MINECRAFT_1_15, false), + map(0x25, MINECRAFT_1_16, false), + map(0x24, MINECRAFT_1_16_2, false), + map(0x26, MINECRAFT_1_17, false), + map(0x23, MINECRAFT_1_19, false), + map(0x25, MINECRAFT_1_19_1, false), + map(0x24, MINECRAFT_1_19_3, false), + map(0x28, MINECRAFT_1_19_4, false), + map(0x29, MINECRAFT_1_20_2, false)); + clientbound.register( + Respawn.class, + Respawn::new, + map(0x07, MINECRAFT_1_7_2, true), + map(0x33, MINECRAFT_1_9, true), + map(0x34, MINECRAFT_1_12, true), + map(0x35, MINECRAFT_1_12_1, true), + map(0x38, MINECRAFT_1_13, true), + map(0x3A, MINECRAFT_1_14, true), + map(0x3B, MINECRAFT_1_15, true), + map(0x3A, MINECRAFT_1_16, true), + map(0x39, MINECRAFT_1_16_2, true), + map(0x3D, MINECRAFT_1_17, true), + map(0x3B, MINECRAFT_1_19, true), + map(0x3E, MINECRAFT_1_19_1, true), + map(0x3D, MINECRAFT_1_19_3, true), + map(0x41, MINECRAFT_1_19_4, true), + map(0x43, MINECRAFT_1_20_2, true)); + clientbound.register( + ResourcePackRequest.class, + ResourcePackRequest::new, + map(0x48, MINECRAFT_1_8, false), + map(0x32, MINECRAFT_1_9, false), + map(0x33, MINECRAFT_1_12, false), + map(0x34, MINECRAFT_1_12_1, false), + map(0x37, MINECRAFT_1_13, false), + map(0x39, MINECRAFT_1_14, false), + map(0x3A, MINECRAFT_1_15, false), + map(0x39, MINECRAFT_1_16, false), + map(0x38, MINECRAFT_1_16_2, false), + map(0x3C, MINECRAFT_1_17, false), + map(0x3A, MINECRAFT_1_19, false), + map(0x3D, MINECRAFT_1_19_1, false), + map(0x3C, MINECRAFT_1_19_3, false), + map(0x40, MINECRAFT_1_19_4, false), + map(0x42, MINECRAFT_1_20_2, false)); + clientbound.register( + HeaderAndFooter.class, + HeaderAndFooter::new, + map(0x47, MINECRAFT_1_8, true), + map(0x48, MINECRAFT_1_9, true), + map(0x47, MINECRAFT_1_9_4, true), + map(0x49, MINECRAFT_1_12, true), + map(0x4A, MINECRAFT_1_12_1, true), + map(0x4E, MINECRAFT_1_13, true), + map(0x53, MINECRAFT_1_14, true), + map(0x54, MINECRAFT_1_15, true), + map(0x53, MINECRAFT_1_16, true), + map(0x5E, MINECRAFT_1_17, true), + map(0x5F, MINECRAFT_1_18, true), + map(0x60, MINECRAFT_1_19, true), + map(0x63, MINECRAFT_1_19_1, true), + map(0x61, MINECRAFT_1_19_3, true), + map(0x65, MINECRAFT_1_19_4, true), + map(0x68, MINECRAFT_1_20_2, true)); + clientbound.register( + LegacyTitlePacket.class, + LegacyTitlePacket::new, + map(0x45, MINECRAFT_1_8, true), + map(0x45, MINECRAFT_1_9, true), + map(0x47, MINECRAFT_1_12, true), + map(0x48, MINECRAFT_1_12_1, true), + map(0x4B, MINECRAFT_1_13, true), + map(0x4F, MINECRAFT_1_14, true), + map(0x50, MINECRAFT_1_15, true), + map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true)); + clientbound.register( + TitleSubtitlePacket.class, + TitleSubtitlePacket::new, + map(0x57, MINECRAFT_1_17, true), + map(0x58, MINECRAFT_1_18, true), + map(0x5B, MINECRAFT_1_19_1, true), + map(0x59, MINECRAFT_1_19_3, true), + map(0x5D, MINECRAFT_1_19_4, true), + map(0x5F, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleTextPacket.class, + TitleTextPacket::new, + map(0x59, MINECRAFT_1_17, true), + map(0x5A, MINECRAFT_1_18, true), + map(0x5D, MINECRAFT_1_19_1, true), + map(0x5B, MINECRAFT_1_19_3, true), + map(0x5F, MINECRAFT_1_19_4, true), + map(0x61, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleActionbarPacket.class, + TitleActionbarPacket::new, + map(0x41, MINECRAFT_1_17, true), + map(0x40, MINECRAFT_1_19, true), + map(0x43, MINECRAFT_1_19_1, true), + map(0x42, MINECRAFT_1_19_3, true), + map(0x46, MINECRAFT_1_19_4, true), + map(0x48, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleTimesPacket.class, + TitleTimesPacket::new, + map(0x5A, MINECRAFT_1_17, true), + map(0x5B, MINECRAFT_1_18, true), + map(0x5E, MINECRAFT_1_19_1, true), + map(0x5C, MINECRAFT_1_19_3, true), + map(0x60, MINECRAFT_1_19_4, true), + map(0x62, MINECRAFT_1_20_2, true)); + clientbound.register( + TitleClearPacket.class, + TitleClearPacket::new, + map(0x10, MINECRAFT_1_17, true), + map(0x0D, MINECRAFT_1_19, true), + map(0x0C, MINECRAFT_1_19_3, true), + map(0x0E, MINECRAFT_1_19_4, true), + map(0x0F, MINECRAFT_1_20_2, true)); + clientbound.register( + LegacyPlayerListItem.class, + LegacyPlayerListItem::new, + map(0x38, MINECRAFT_1_7_2, false), + map(0x2D, MINECRAFT_1_9, false), + map(0x2E, MINECRAFT_1_12_1, false), + map(0x30, MINECRAFT_1_13, false), + map(0x33, MINECRAFT_1_14, false), + map(0x34, MINECRAFT_1_15, false), + map(0x33, MINECRAFT_1_16, false), + map(0x32, MINECRAFT_1_16_2, false), + map(0x36, MINECRAFT_1_17, false), + map(0x34, MINECRAFT_1_19, false), + map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); + clientbound.register( + RemovePlayerInfo.class, + RemovePlayerInfo::new, + map(0x35, MINECRAFT_1_19_3, false), + map(0x39, MINECRAFT_1_19_4, false), + map(0x3B, MINECRAFT_1_20_2, false)); + clientbound.register( + UpsertPlayerInfo.class, + UpsertPlayerInfo::new, + map(0x36, MINECRAFT_1_19_3, false), + map(0x3A, MINECRAFT_1_19_4, false), + map(0x3C, MINECRAFT_1_20_2, false)); + clientbound.register( + SystemChat.class, + SystemChat::new, + map(0x5F, MINECRAFT_1_19, true), + map(0x62, MINECRAFT_1_19_1, true), + map(0x60, MINECRAFT_1_19_3, true), + map(0x64, MINECRAFT_1_19_4, true), + map(0x67, MINECRAFT_1_20_2, true)); + clientbound.register( + PlayerChatCompletion.class, + PlayerChatCompletion::new, + map(0x15, MINECRAFT_1_19_1, true), + map(0x14, MINECRAFT_1_19_3, true), + map(0x16, MINECRAFT_1_19_4, true), + map(0x17, MINECRAFT_1_20_2, true)); + clientbound.register( + ServerData.class, + ServerData::new, + map(0x3F, MINECRAFT_1_19, false), + map(0x42, MINECRAFT_1_19_1, false), + map(0x41, MINECRAFT_1_19_3, false), + map(0x45, MINECRAFT_1_19_4, false), + map(0x47, MINECRAFT_1_20_2, false)); + clientbound.register(StartUpdate.class, StartUpdate::new, map(0x65, MINECRAFT_1_20_2, false)); } }, LOGIN { { + serverbound.register(ServerLogin.class, ServerLogin::new, map(0x00, MINECRAFT_1_7_2, false)); serverbound.register( - ServerLogin.class, ServerLogin::new, map(0x00, MINECRAFT_1_7_2, false)); + EncryptionResponse.class, EncryptionResponse::new, map(0x01, MINECRAFT_1_7_2, false)); serverbound.register( - EncryptionResponse.class, - EncryptionResponse::new, - map(0x01, MINECRAFT_1_7_2, false)); + LoginPluginResponse.class, LoginPluginResponse::new, map(0x02, MINECRAFT_1_13, false)); serverbound.register( - LoginPluginResponse.class, - LoginPluginResponse::new, - map(0x02, MINECRAFT_1_13, false)); - serverbound.register( - LoginAcknowledged.class, - LoginAcknowledged::new, - map(0x03, MINECRAFT_1_20_2, false)); + LoginAcknowledged.class, LoginAcknowledged::new, map(0x03, MINECRAFT_1_20_2, false)); + clientbound.register(Disconnect.class, Disconnect::new, map(0x00, MINECRAFT_1_7_2, false)); clientbound.register( - Disconnect.class, Disconnect::new, map(0x00, MINECRAFT_1_7_2, false)); - clientbound.register( - EncryptionRequest.class, - EncryptionRequest::new, - map(0x01, MINECRAFT_1_7_2, false)); + EncryptionRequest.class, EncryptionRequest::new, map(0x01, MINECRAFT_1_7_2, false)); clientbound.register( - ServerLoginSuccess.class, - ServerLoginSuccess::new, - map(0x02, MINECRAFT_1_7_2, false)); + ServerLoginSuccess.class, ServerLoginSuccess::new, map(0x02, MINECRAFT_1_7_2, false)); clientbound.register( - SetCompression.class, - SetCompression::new, - map(0x03, MINECRAFT_1_8, false)); + SetCompression.class, SetCompression::new, map(0x03, MINECRAFT_1_8, false)); clientbound.register( - LoginPluginMessage.class, - LoginPluginMessage::new, - map(0x04, MINECRAFT_1_13, false)); + LoginPluginMessage.class, LoginPluginMessage::new, map(0x04, MINECRAFT_1_13, false)); } }; @@ -611,7 +561,7 @@ public enum StateRegistry { protected final PacketRegistry serverbound = new PacketRegistry(SERVERBOUND); public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry( - Direction direction, ProtocolVersion version) { + Direction direction, ProtocolVersion version) { return (direction == SERVERBOUND ? serverbound : clientbound).getProtocolRegistry(version); } @@ -647,7 +597,7 @@ ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) { }

void register( - Class

clazz, Supplier

packetSupplier, PacketMapping... mappings) { + Class

clazz, Supplier

packetSupplier, PacketMapping... mappings) { if (mappings.length == 0) { throw new IllegalArgumentException("At least one mapping must be provided."); } @@ -664,21 +614,20 @@

void register( } if (from.compareTo(lastValid) > 0) { throw new IllegalArgumentException( - "Last mapping version cannot be higher than highest mapping version"); + "Last mapping version cannot be higher than highest mapping version"); } } ProtocolVersion to = - current == next - ? lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS) - : next.protocolVersion; + current == next + ? lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS) + : next.protocolVersion; - ProtocolVersion lastInList = - lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS); + ProtocolVersion lastInList = lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS); if (from.compareTo(to) >= 0 && from != lastInList) { throw new IllegalArgumentException( - String.format( - "Next mapping version (%s) should be lower then current (%s)", to, from)); + String.format( + "Next mapping version (%s) should be lower then current (%s)", to, from)); } for (ProtocolVersion protocol : EnumSet.range(from, to)) { @@ -688,23 +637,23 @@

void register( ProtocolRegistry registry = this.versions.get(protocol); if (registry == null) { throw new IllegalArgumentException( - "Unknown protocol version " + current.protocolVersion); + "Unknown protocol version " + current.protocolVersion); } if (registry.packetIdToSupplier.containsKey(current.id)) { throw new IllegalArgumentException( - "Can not register class " - + clazz.getSimpleName() - + " with id " - + current.id - + " for " - + registry.version - + " because another packet is already registered"); + "Can not register class " + + clazz.getSimpleName() + + " with id " + + current.id + + " for " + + registry.version + + " because another packet is already registered"); } if (registry.packetClassToId.containsKey(clazz)) { throw new IllegalArgumentException( - clazz.getSimpleName() + " is already registered for version " + registry.version); + clazz.getSimpleName() + " is already registered for version " + registry.version); } if (!current.encodeOnly) { @@ -720,9 +669,9 @@ public class ProtocolRegistry { public final ProtocolVersion version; final IntObjectMap> packetIdToSupplier = - new IntObjectHashMap<>(16, 0.5f); + new IntObjectHashMap<>(16, 0.5f); final Object2IntMap> packetClassToId = - new Object2IntOpenHashMap<>(16, 0.5f); + new Object2IntOpenHashMap<>(16, 0.5f); ProtocolRegistry(final ProtocolVersion version) { this.version = version; @@ -754,9 +703,9 @@ public int getPacketId(final MinecraftPacket packet) { final int id = this.packetClassToId.getInt(packet.getClass()); if (id == Integer.MIN_VALUE) { throw new IllegalArgumentException( - String.format( - "Unable to find id for packet of type %s in %s protocol %s", - packet.getClass().getName(), PacketRegistry.this.direction, this.version)); + String.format( + "Unable to find id for packet of type %s in %s protocol %s", + packet.getClass().getName(), PacketRegistry.this.direction, this.version)); } return id; } @@ -782,10 +731,10 @@ public static final class PacketMapping { private final @Nullable ProtocolVersion lastValidProtocolVersion; PacketMapping( - int id, - ProtocolVersion protocolVersion, - ProtocolVersion lastValidProtocolVersion, - boolean packetDecoding) { + int id, + ProtocolVersion protocolVersion, + ProtocolVersion lastValidProtocolVersion, + boolean packetDecoding) { this.id = id; this.protocolVersion = protocolVersion; this.lastValidProtocolVersion = lastValidProtocolVersion; @@ -795,13 +744,13 @@ public static final class PacketMapping { @Override public String toString() { return "PacketMapping{" - + "id=" - + id - + ", protocolVersion=" - + protocolVersion - + ", encodeOnly=" - + encodeOnly - + '}'; + + "id=" + + id + + ", protocolVersion=" + + protocolVersion + + ", encodeOnly=" + + encodeOnly + + '}'; } @Override @@ -814,8 +763,8 @@ public boolean equals(@Nullable Object o) { } PacketMapping that = (PacketMapping) o; return id == that.id - && protocolVersion == that.protocolVersion - && encodeOnly == that.encodeOnly; + && protocolVersion == that.protocolVersion + && encodeOnly == that.encodeOnly; } @Override @@ -847,10 +796,10 @@ private static PacketMapping map(int id, ProtocolVersion version, boolean encode * @return PacketMapping with the provided arguments */ private static PacketMapping map( - int id, - ProtocolVersion version, - ProtocolVersion lastValidProtocolVersion, - boolean encodeOnly) { + int id, + ProtocolVersion version, + ProtocolVersion lastValidProtocolVersion, + boolean encodeOnly) { return new PacketMapping(id, version, lastValidProtocolVersion, encodeOnly); } } From c24f4f639e1f8dfad2b4a990301cf4cc349a0287 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 3 Oct 2023 14:19:17 +0100 Subject: [PATCH 33/41] Fix support for backend server resource packs & possibly fix plugin messaging during configuration --- .../backend/BackendPlaySessionHandler.java | 88 ++- .../backend/ConfigSessionHandler.java | 137 ++-- .../backend/TransitionSessionHandler.java | 122 ++-- .../connection/client/AuthSessionHandler.java | 258 +++----- .../client/ClientConfigSessionHandler.java | 29 +- .../client/ClientPlaySessionHandler.java | 255 ++++---- .../connection/client/ConnectedPlayer.java | 588 ++++++++---------- .../netty/PlayPacketQueueHandler.java | 25 +- .../protocol/packet/ResourcePackResponse.java | 5 +- 9 files changed, 642 insertions(+), 865 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 063683fa90..63a480afcf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -69,10 +69,10 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { private static final Pattern PLAUSIBLE_SHA1_HASH = Pattern.compile("^[a-z0-9]{40}$"); private static final Logger logger = LogManager.getLogger(BackendPlaySessionHandler.class); - private static final boolean BACKPRESSURE_LOG = Boolean - .getBoolean("velocity.log-server-backpressure"); - private static final int MAXIMUM_PACKETS_TO_FLUSH = Integer - .getInteger("velocity.max-packets-per-flush", 8192); + private static final boolean BACKPRESSURE_LOG = + Boolean.getBoolean("velocity.log-server-backpressure"); + private static final int MAXIMUM_PACKETS_TO_FLUSH = + Integer.getInteger("velocity.max-packets-per-flush", 8192); private final VelocityServer server; private final VelocityServerConnection serverConn; @@ -94,8 +94,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { } this.playerSessionHandler = (ClientPlaySessionHandler) psh; - this.bungeecordMessageResponder = new BungeeCordMessageResponder(server, - serverConn.getPlayer()); + this.bungeecordMessageResponder = + new BungeeCordMessageResponder(server, serverConn.getPlayer()); } @Override @@ -105,8 +105,7 @@ public void activated() { if (server.getConfiguration().isBungeePluginChannelEnabled()) { MinecraftConnection serverMc = serverConn.ensureConnected(); serverMc.write(PluginMessageUtil.constructChannelsPacket(serverMc.getProtocolVersion(), - ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion())) - )); + ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion())))); } } @@ -152,10 +151,8 @@ public boolean handle(BossBar packet) { @Override public boolean handle(ResourcePackRequest packet) { ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl( - Preconditions.checkNotNull(packet.getUrl())) - .setPrompt(packet.getPrompt()) - .setShouldForce(packet.isRequired()) - .setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + Preconditions.checkNotNull(packet.getUrl())).setPrompt(packet.getPrompt()) + .setShouldForce(packet.isRequired()).setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); String hash = packet.getHash(); if (hash != null && !hash.isEmpty()) { @@ -164,8 +161,8 @@ public boolean handle(ResourcePackRequest packet) { } } - ServerResourcePackSendEvent event = new ServerResourcePackSendEvent( - builder.build(), this.serverConn); + ServerResourcePackSendEvent event = + new ServerResourcePackSendEvent(builder.build(), this.serverConn); server.getEventManager().fire(event).thenAcceptAsync(serverResourcePackSendEvent -> { if (playerConnection.isClosed()) { @@ -174,23 +171,19 @@ public boolean handle(ResourcePackRequest packet) { if (serverResourcePackSendEvent.getResult().isAllowed()) { ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { - ((VelocityResourcePackInfo) toSend) - .setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + ((VelocityResourcePackInfo) toSend).setOriginalOrigin( + ResourcePackInfo.Origin.DOWNSTREAM_SERVER); } serverConn.getPlayer().queueResourcePack(toSend); } else if (serverConn.getConnection() != null) { - serverConn.getConnection().write(new ResourcePackResponse( - packet.getHash(), - PlayerResourcePackStatusEvent.Status.DECLINED - )); + serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED)); } }, playerConnection.eventLoop()).exceptionally((ex) -> { if (serverConn.getConnection() != null) { - serverConn.getConnection().write(new ResourcePackResponse( - packet.getHash(), - PlayerResourcePackStatusEvent.Status.DECLINED - )); + serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED)); } logger.error("Exception while handling resource pack send for {}", playerConnection, ex); return null; @@ -228,20 +221,16 @@ public boolean handle(PluginMessage packet) { } byte[] copy = ByteBufUtil.getBytes(packet.content()); - PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, - copy); - server.getEventManager().fire(event) - .thenAcceptAsync(pme -> { - if (pme.getResult().isAllowed() && !playerConnection.isClosed()) { - PluginMessage copied = new PluginMessage(packet.getChannel(), - Unpooled.wrappedBuffer(copy)); - playerConnection.write(copied); - } - }, playerConnection.eventLoop()) - .exceptionally((ex) -> { - logger.error("Exception while handling plugin message {}", packet, ex); - return null; - }); + PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, copy); + server.getEventManager().fire(event).thenAcceptAsync(pme -> { + if (pme.getResult().isAllowed() && !playerConnection.isClosed()) { + PluginMessage copied = new PluginMessage(packet.getChannel(), Unpooled.wrappedBuffer(copy)); + playerConnection.write(copied); + } + }, playerConnection.eventLoop()).exceptionally((ex) -> { + logger.error("Exception while handling plugin message {}", packet, ex); + return null; + }); return true; } @@ -278,8 +267,8 @@ public boolean handle(AvailableCommands commands) { injector.inject(rootNode, serverConn.getPlayer()); } - server.getEventManager().fire( - new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode)) + server.getEventManager() + .fire(new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode)) .thenAcceptAsync(event -> playerConnection.write(commands), playerConnection.eventLoop()) .exceptionally((ex) -> { logger.error("Exception while handling available commands for {}", playerConnection, ex); @@ -290,18 +279,13 @@ public boolean handle(AvailableCommands commands) { @Override public boolean handle(ServerData packet) { - server.getServerListPingHandler().getInitialPing(this.serverConn.getPlayer()) - .thenComposeAsync( - ping -> server.getEventManager() - .fire(new ProxyPingEvent(this.serverConn.getPlayer(), ping)), - playerConnection.eventLoop() - ) - .thenAcceptAsync(pingEvent -> - this.playerConnection.write( - new ServerData(pingEvent.getPing().getDescriptionComponent(), - pingEvent.getPing().getFavicon().orElse(null), - packet.isSecureChatEnforced()) - ), playerConnection.eventLoop()); + server.getServerListPingHandler().getInitialPing(this.serverConn.getPlayer()).thenComposeAsync( + ping -> server.getEventManager() + .fire(new ProxyPingEvent(this.serverConn.getPlayer(), ping)), + playerConnection.eventLoop()).thenAcceptAsync(pingEvent -> this.playerConnection.write( + new ServerData(pingEvent.getPing().getDescriptionComponent(), + pingEvent.getPing().getFavicon().orElse(null), packet.isSecureChatEnforced())), + playerConnection.eventLoop()); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 9e398f5ba1..713207f7fa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -37,10 +37,12 @@ import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; import com.velocitypowered.proxy.protocol.packet.config.RegistrySync; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.config.TagsUpdate; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import java.io.IOException; import java.util.concurrent.CompletableFuture; +import java.util.regex.Pattern; import net.kyori.adventure.text.Component; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -51,8 +53,8 @@ */ public class ConfigSessionHandler implements MinecraftSessionHandler { + private static final Pattern PLAUSIBLE_SHA1_HASH = Pattern.compile("^[a-z0-9]{40}$"); private static final Logger logger = LogManager.getLogger(ConfigSessionHandler.class); - private final VelocityServer server; private final VelocityServerConnection serverConn; private final CompletableFuture resultFuture; @@ -62,14 +64,12 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { /** * Creates the new transition handler. * - * @param server the Velocity server instance - * @param serverConn the server connection + * @param server the Velocity server instance + * @param serverConn the server connection * @param resultFuture the result future */ - ConfigSessionHandler( - VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + ConfigSessionHandler(VelocityServer server, VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -77,7 +77,8 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { } @Override - public void deactivated() {} + public void deactivated() { + } @Override public boolean beforeHandle() { @@ -89,6 +90,12 @@ public boolean beforeHandle() { return false; } + @Override + public boolean handle(StartUpdate packet) { + serverConn.ensureConnected().write(packet); + return true; + } + @Override public boolean handle(TagsUpdate packet) { serverConn.getPlayer().getConnection().write(packet); @@ -108,44 +115,30 @@ public boolean handle(ResourcePackRequest packet) { ServerResourcePackSendEvent event = new ServerResourcePackSendEvent(packet.toServerPromptedPack(), this.serverConn); - server - .getEventManager() - .fire(event) - .thenAcceptAsync( - serverResourcePackSendEvent -> { - if (playerConnection.isClosed()) { - return; - } - if (serverResourcePackSendEvent.getResult().isAllowed()) { - ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); - if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { - ((VelocityResourcePackInfo) toSend) - .setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); - } - - serverConn.getPlayer().queueResourcePack(toSend); - } else if (serverConn.getConnection() != null) { - serverConn - .getConnection() - .write( - new ResourcePackResponse( - packet.getHash(), PlayerResourcePackStatusEvent.Status.DECLINED)); - } - }, - playerConnection.eventLoop()) - .exceptionally( - (ex) -> { - if (serverConn.getConnection() != null) { - serverConn - .getConnection() - .write( - new ResourcePackResponse( - packet.getHash(), PlayerResourcePackStatusEvent.Status.DECLINED)); - } - logger.error( - "Exception while handling resource pack send for {}", playerConnection, ex); - return null; - }); + server.getEventManager().fire(event).thenAcceptAsync(serverResourcePackSendEvent -> { + if (playerConnection.isClosed()) { + return; + } + if (serverResourcePackSendEvent.getResult().isAllowed()) { + ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); + if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { + ((VelocityResourcePackInfo) toSend).setOriginalOrigin( + ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + } + + serverConn.getPlayer().queueResourcePack(toSend); + } else if (serverConn.getConnection() != null) { + serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED)); + } + }, playerConnection.eventLoop()).exceptionally((ex) -> { + if (serverConn.getConnection() != null) { + serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED)); + } + logger.error("Exception while handling resource pack send for {}", playerConnection, ex); + return null; + }); return true; } @@ -154,21 +147,15 @@ public boolean handle(ResourcePackRequest packet) { public boolean handle(FinishedUpdate packet) { MinecraftConnection smc = serverConn.ensureConnected(); ClientConfigSessionHandler configHandler = - (ClientConfigSessionHandler) - serverConn.getPlayer().getConnection().getActiveSessionHandler(); + (ClientConfigSessionHandler) serverConn.getPlayer().getConnection() + .getActiveSessionHandler(); smc.setAutoReading(false); - configHandler - .handleBackendFinishUpdate(serverConn) - .thenAcceptAsync( - (unused) -> { - smc.write(new FinishedUpdate()); - smc.setActiveSessionHandler( - StateRegistry.PLAY, - new TransitionSessionHandler(server, serverConn, resultFuture)); - smc.setAutoReading(true); - }, - smc.eventLoop()); + configHandler.handleBackendFinishUpdate(serverConn).thenAcceptAsync((unused) -> { + smc.setActiveSessionHandler(StateRegistry.PLAY, + new TransitionSessionHandler(server, serverConn, resultFuture)); + smc.setAutoReading(true); + }, smc.eventLoop()); return true; } @@ -182,19 +169,14 @@ public boolean handle(Disconnect packet) { @Override public boolean handle(PluginMessage packet) { if (PluginMessageUtil.isMcBrand(packet)) { - serverConn - .getPlayer() - .getConnection() - .write( - PluginMessageUtil.rewriteMinecraftBrand( - packet, server.getVersion(), serverConn.getPlayer().getProtocolVersion())); + serverConn.getPlayer().getConnection().write( + PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), + serverConn.getPlayer().getProtocolVersion())); } else { // TODO: Change this so its usable for mod loaders serverConn.disconnect(); - resultFuture.complete( - ConnectionRequestResults.forDisconnect( - Component.translatable("multiplayer.disconnect.missing_tags"), - serverConn.getServer())); + resultFuture.complete(ConnectionRequestResults.forDisconnect( + Component.translatable("multiplayer.disconnect.missing_tags"), serverConn.getServer())); } return true; } @@ -217,21 +199,16 @@ public void handleGeneric(MinecraftPacket packet) { } private void switchFailure(Throwable cause) { - logger.error( - "Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - serverConn.getPlayer().getUsername(), - cause); + logger.error("Unable to switch to new server {} for {}", serverConn.getServerInfo().getName(), + serverConn.getPlayer().getUsername(), cause); serverConn.getPlayer().disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); resultFuture.completeExceptionally(cause); } - /** Represents the state of the configuration stage. */ + /** + * Represents the state of the configuration stage. + */ public static enum State { - START, - NEGOTIATING, - PLUGIN_MESSAGE_INTERRUPT, - RESOURCE_PACK_INTERRUPT, - COMPLETE + START, NEGOTIATING, PLUGIN_MESSAGE_INTERRUPT, RESOURCE_PACK_INTERRUPT, COMPLETE } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 6384033231..3ff2fbf373 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -42,7 +42,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** A special session handler that catches "last minute" disconnects. */ +/** + * A special session handler that catches "last minute" disconnects. + */ public class TransitionSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(TransitionSessionHandler.class); @@ -55,14 +57,12 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { /** * Creates the new transition handler. * - * @param server the Velocity server instance - * @param serverConn the server connection + * @param server the Velocity server instance + * @param serverConn the server connection * @param resultFuture the result future */ - TransitionSessionHandler( - VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + TransitionSessionHandler(VelocityServer server, VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -108,63 +108,56 @@ public boolean handle(JoinGame packet) { // The goods are in hand! We got JoinGame. Let's transition completely to the new state. smc.setAutoReading(false); - server - .getEventManager() + server.getEventManager() .fire(new ServerConnectedEvent(player, serverConn.getServer(), previousServer)) - .thenRunAsync( - () -> { - // Make sure we can still transition (player might have disconnected here). - if (!serverConn.isActive()) { - // Connection is obsolete. - serverConn.disconnect(); - return; - } - - // Change the client to use the ClientPlaySessionHandler if required. - ClientPlaySessionHandler playHandler; - if (player.getConnection().getActiveSessionHandler() - instanceof ClientPlaySessionHandler) { - playHandler = - (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); - } else { - playHandler = new ClientPlaySessionHandler(server, player); - player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, playHandler); - } - assert playHandler != null; - playHandler.handleBackendJoinGame(packet, serverConn); - - // Set the new play session handler for the server. We will have nothing more to do - // with this connection once this task finishes up. - smc.setActiveSessionHandler( - StateRegistry.PLAY, new BackendPlaySessionHandler(server, serverConn)); - - // Clean up disabling auto-read while the connected event was being processed. - smc.setAutoReading(true); - - // Now set the connected server. - serverConn.getPlayer().setConnectedServer(serverConn); - if (player.getClientSettingsPacket() != null) { - serverConn.ensureConnected().write(player.getClientSettingsPacket()); - } - - // We're done! :) - server - .getEventManager() - .fireAndForget(new ServerPostConnectEvent(player, previousServer)); - resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer())); - }, - smc.eventLoop()) - .exceptionally( - exc -> { - logger.error( - "Unable to switch to new server {} for {}", - serverConn.getServerInfo().getName(), - player.getUsername(), - exc); - player.disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - resultFuture.completeExceptionally(exc); - return null; - }); + .thenRunAsync(() -> { + // Make sure we can still transition (player might have disconnected here). + if (!serverConn.isActive()) { + // Connection is obsolete. + serverConn.disconnect(); + return; + } + + // Change the client to use the ClientPlaySessionHandler if required. + ClientPlaySessionHandler playHandler; + if (player.getConnection() + .getActiveSessionHandler() instanceof ClientPlaySessionHandler) { + playHandler = + (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); + } else { + playHandler = new ClientPlaySessionHandler(server, player); + player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, playHandler); + } + assert playHandler != null; + playHandler.handleBackendJoinGame(packet, serverConn); + + // Set the new play session handler for the server. We will have nothing more to do + // with this connection once this task finishes up. + smc.setActiveSessionHandler(StateRegistry.PLAY, + new BackendPlaySessionHandler(server, serverConn)); + + // Clean up disabling auto-read while the connected event was being processed. + smc.setAutoReading(true); + + // Now set the connected server. + serverConn.getPlayer().setConnectedServer(serverConn); + + if (player.getClientSettingsPacket() != null) { + serverConn.ensureConnected().write(player.getClientSettingsPacket()); + } + + // We're done! :) + server.getEventManager() + .fireAndForget(new ServerPostConnectEvent(player, previousServer)); + resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer())); + }, smc.eventLoop()).exceptionally(exc -> { + logger.error("Unable to switch to new server {} for {}", + serverConn.getServerInfo().getName(), + player.getUsername(), exc); + player.disconnect(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + resultFuture.completeExceptionally(exc); + return null; + }); return true; } @@ -203,8 +196,7 @@ public boolean handle(PluginMessage packet) { existingConnection.setConnectionPhase(IN_TRANSITION); // Tell the player that we're leaving and we just aren't coming back. - existingConnection - .getPhase() + existingConnection.getPhase() .onDepartForNewServer(existingConnection, serverConn.getPlayer()); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index b2519f295c..db31831e6e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -53,7 +53,9 @@ import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** A session handler that is activated to complete the login phase. */ +/** + * A session handler that is activated to complete the login phase. + */ public class AuthSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(AuthSessionHandler.class); @@ -66,11 +68,8 @@ public class AuthSessionHandler implements MinecraftSessionHandler { private final boolean onlineMode; private State loginState = State.START; // 1.20.2+ - AuthSessionHandler( - VelocityServer server, - LoginInboundConnection inbound, - GameProfile profile, - boolean onlineMode) { + AuthSessionHandler(VelocityServer server, LoginInboundConnection inbound, GameProfile profile, + boolean onlineMode) { this.server = Preconditions.checkNotNull(server, "server"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.profile = Preconditions.checkNotNull(profile, "profile"); @@ -81,74 +80,53 @@ public class AuthSessionHandler implements MinecraftSessionHandler { @Override public void activated() { // Some connection types may need to alter the game profile. - profile = - mcConnection - .getType() - .addGameProfileTokensIfRequired( - profile, server.getConfiguration().getPlayerInfoForwardingMode()); + profile = mcConnection.getType().addGameProfileTokensIfRequired(profile, + server.getConfiguration().getPlayerInfoForwardingMode()); GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile, onlineMode); final GameProfile finalProfile = profile; - server - .getEventManager() - .fire(profileRequestEvent) - .thenComposeAsync( - profileEvent -> { - if (mcConnection.isClosed()) { - // The player disconnected after we authenticated them. - return CompletableFuture.completedFuture(null); - } + server.getEventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> { + if (mcConnection.isClosed()) { + // The player disconnected after we authenticated them. + return CompletableFuture.completedFuture(null); + } - // Initiate a regular connection and move over to it. - ConnectedPlayer player = - new ConnectedPlayer( - server, - profileEvent.getGameProfile(), - mcConnection, - inbound.getVirtualHost().orElse(null), - onlineMode, - inbound.getIdentifiedKey()); - this.connectedPlayer = player; - if (!server.canRegisterConnection(player)) { - player.disconnect0( - Component.translatable( - "velocity.error.already-connected-proxy", NamedTextColor.RED), - true); - return CompletableFuture.completedFuture(null); - } + // Initiate a regular connection and move over to it. + ConnectedPlayer player = + new ConnectedPlayer(server, profileEvent.getGameProfile(), mcConnection, + inbound.getVirtualHost().orElse(null), onlineMode, inbound.getIdentifiedKey()); + this.connectedPlayer = player; + if (!server.canRegisterConnection(player)) { + player.disconnect0( + Component.translatable("velocity.error.already-connected-proxy", NamedTextColor.RED), + true); + return CompletableFuture.completedFuture(null); + } - logger.info("{} has connected", player); + logger.info("{} has connected", player); - return server - .getEventManager() - .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) - .thenAcceptAsync( - event -> { - if (!mcConnection.isClosed()) { - // wait for permissions to load, then set the players permission function - final PermissionFunction function = event.createFunction(player); - if (function == null) { - logger.error( - "A plugin permission provider {} provided an invalid permission " - + "function for player {}. This is a bug in the plugin, not in " - + "Velocity. Falling back to the default permission function.", - event.getProvider().getClass().getName(), - player.getUsername()); - } else { - player.setPermissionFunction(function); - } - startLoginCompletion(player); - } - }, - mcConnection.eventLoop()); - }, - mcConnection.eventLoop()) - .exceptionally( - (ex) -> { - logger.error("Exception during connection of {}", finalProfile, ex); - return null; - }); + return server.getEventManager() + .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) + .thenAcceptAsync(event -> { + if (!mcConnection.isClosed()) { + // wait for permissions to load, then set the players permission function + final PermissionFunction function = event.createFunction(player); + if (function == null) { + logger.error("A plugin permission provider {} provided an invalid permission " + + "function for player {}. This is a bug in the plugin, not in " + + "Velocity. Falling back to the default permission function.", + event.getProvider().getClass().getName(), player.getUsername()); + } else { + player.setPermissionFunction(function); + } + startLoginCompletion(player); + } + }, mcConnection.eventLoop()); + }, mcConnection.eventLoop()).exceptionally((ex) -> { + logger.error("Exception during connection of {}", finalProfile, ex); + return null; + }); } private void startLoginCompletion(ConnectedPlayer player) { @@ -183,11 +161,8 @@ private void startLoginCompletion(ConnectedPlayer player) { } } else { if (!Objects.equals(playerKey.getSignatureHolder(), playerUniqueId)) { - logger.warn( - "UUID for Player " - + player.getUsername() - + " mismatches! " - + "Chat/Commands signatures will not work correctly for this player!"); + logger.warn("UUID for Player " + player.getUsername() + " mismatches! " + + "Chat/Commands signatures will not work correctly for this player!"); } } } @@ -201,19 +176,14 @@ public boolean handle(LoginAcknowledged packet) { inbound.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_data")); } else { loginState = State.ACKNOWLEDGED; - mcConnection.setActiveSessionHandler( - StateRegistry.CONFIG, new ClientConfigSessionHandler(server, connectedPlayer)); + mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, + new ClientConfigSessionHandler(server, connectedPlayer)); - server - .getEventManager() - .fire(new PostLoginEvent(connectedPlayer)) - .thenCompose((ignored) -> connectToInitialServer(connectedPlayer)) - .exceptionally( - (ex) -> { - logger.error( - "Exception while connecting {} to initial server", connectedPlayer, ex); - return null; - }); + server.getEventManager().fire(new PostLoginEvent(connectedPlayer)) + .thenCompose((ignored) -> connectToInitialServer(connectedPlayer)).exceptionally((ex) -> { + logger.error("Exception while connecting {} to initial server", connectedPlayer, ex); + return null; + }); } return true; } @@ -221,62 +191,46 @@ public boolean handle(LoginAcknowledged packet) { private void completeLoginProtocolPhaseAndInitialize(ConnectedPlayer player) { mcConnection.setAssociation(player); - server - .getEventManager() - .fire(new LoginEvent(player)) - .thenAcceptAsync( - event -> { - if (mcConnection.isClosed()) { - // The player was disconnected - server - .getEventManager() - .fireAndForget( - new DisconnectEvent( - player, DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); - return; - } + server.getEventManager().fire(new LoginEvent(player)).thenAcceptAsync(event -> { + if (mcConnection.isClosed()) { + // The player was disconnected + server.getEventManager().fireAndForget(new DisconnectEvent(player, + DisconnectEvent.LoginStatus.CANCELLED_BY_USER_BEFORE_COMPLETE)); + return; + } - Optional reason = event.getResult().getReasonComponent(); - if (reason.isPresent()) { - player.disconnect0(reason.get(), true); - } else { - if (!server.registerConnection(player)) { - player.disconnect0( - Component.translatable("velocity.error.already-connected-proxy"), true); - return; - } + Optional reason = event.getResult().getReasonComponent(); + if (reason.isPresent()) { + player.disconnect0(reason.get(), true); + } else { + if (!server.registerConnection(player)) { + player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), + true); + return; + } - ServerLoginSuccess success = new ServerLoginSuccess(); - success.setUsername(player.getUsername()); - success.setProperties(player.getGameProfileProperties()); - success.setUuid(player.getUniqueId()); - mcConnection.write(success); + ServerLoginSuccess success = new ServerLoginSuccess(); + success.setUsername(player.getUsername()); + success.setProperties(player.getGameProfileProperties()); + success.setUuid(player.getUniqueId()); + mcConnection.write(success); - loginState = State.SUCCESS_SENT; - if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - loginState = State.ACKNOWLEDGED; - mcConnection.setActiveSessionHandler( - StateRegistry.PLAY, new InitialConnectSessionHandler(player, server)); - server - .getEventManager() - .fire(new PostLoginEvent(player)) - .thenCompose((ignored) -> connectToInitialServer(player)) - .exceptionally( - (ex) -> { - logger.error( - "Exception while connecting {} to initial server", player, ex); - return null; - }); - } - } - }, - mcConnection.eventLoop()) - .exceptionally( - (ex) -> { - logger.error( - "Exception while completing login initialisation phase for {}", player, ex); - return null; - }); + loginState = State.SUCCESS_SENT; + if (inbound.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { + loginState = State.ACKNOWLEDGED; + mcConnection.setActiveSessionHandler(StateRegistry.PLAY, + new InitialConnectSessionHandler(player, server)); + server.getEventManager().fire(new PostLoginEvent(player)) + .thenCompose((ignored) -> connectToInitialServer(player)).exceptionally((ex) -> { + logger.error("Exception while connecting {} to initial server", player, ex); + return null; + }); + } + } + }, mcConnection.eventLoop()).exceptionally((ex) -> { + logger.error("Exception while completing login initialisation phase for {}", player, ex); + return null; + }); } private CompletableFuture connectToInitialServer(ConnectedPlayer player) { @@ -284,22 +238,16 @@ private CompletableFuture connectToInitialServer(ConnectedPlayer player) { PlayerChooseInitialServerEvent event = new PlayerChooseInitialServerEvent(player, initialFromConfig.orElse(null)); - return server - .getEventManager() - .fire(event) - .thenRunAsync( - () -> { - Optional toTry = event.getInitialServer(); - if (!toTry.isPresent()) { - player.disconnect0( - Component.translatable( - "velocity.error.no-available-servers", NamedTextColor.RED), - true); - return; - } - player.createConnectionRequest(toTry.get()).fireAndForget(); - }, - mcConnection.eventLoop()); + return server.getEventManager().fire(event).thenRunAsync(() -> { + Optional toTry = event.getInitialServer(); + if (!toTry.isPresent()) { + player.disconnect0( + Component.translatable("velocity.error.no-available-servers", NamedTextColor.RED), + true); + return; + } + player.createConnectionRequest(toTry.get()).fireAndForget(); + }, mcConnection.eventLoop()); } @Override @@ -316,8 +264,6 @@ public void disconnected() { } static enum State { - START, - SUCCESS_SENT, - ACKNOWLEDGED + START, SUCCESS_SENT, ACKNOWLEDGED } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index f8bd36c39a..83d9fe91b1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -35,7 +35,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** Handles the client config stage. */ +/** + * Handles the client config stage. + */ public class ClientConfigSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class); @@ -61,7 +63,8 @@ public void activated() { } @Override - public void deactivated() {} + public void deactivated() { + } @Override public boolean handle(KeepAlive packet) { @@ -79,11 +82,6 @@ public boolean handle(KeepAlive packet) { return true; } - @Override - public boolean handle(PluginMessage packet) { - return true; - } - @Override public boolean handle(ClientSettings packet) { player.setClientSettingsPacket(packet); @@ -92,18 +90,18 @@ public boolean handle(ClientSettings packet) { @Override public boolean handle(ResourcePackResponse packet) { - player.getConnection().write(packet); - return true; + if (player.getConnectionInFlight() != null) { + player.getConnectionInFlight().ensureConnected().write(packet); + } + return player.onResourcePackResponse(packet.getStatus()); } @Override public boolean handle(FinishedUpdate packet) { - player - .getConnection() + player.getConnection() .setActiveSessionHandler(StateRegistry.PLAY, new ClientPlaySessionHandler(server, player)); configSwitchFuture.complete(null); - return true; } @@ -149,8 +147,15 @@ public void exception(Throwable throwable) { Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); } + /** + * Handles the backend finishing the config stage. + * + * @param serverConn the server connection + * @return a future that completes when the config stage is finished + */ public CompletableFuture handleBackendFinishUpdate(VelocityServerConnection serverConn) { player.getConnection().write(new FinishedUpdate()); + serverConn.ensureConnected().write(new FinishedUpdate()); return configSwitchFuture; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 69a552c54d..45fc2ced05 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -288,19 +288,15 @@ public boolean handle(TabCompleteRequest packet) { public boolean handle(PluginMessage packet) { // Handling edge case when packet with FML client handshake (state COMPLETE) // arrives after JoinGame packet from destination server - VelocityServerConnection serverConn = - (player.getConnectedServer() == null - && packet.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) - ? player.getConnectionInFlight() - : player.getConnectedServer(); + VelocityServerConnection serverConn = (player.getConnectedServer() == null + && packet.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) + ? player.getConnectionInFlight() : player.getConnectedServer(); MinecraftConnection backendConn = serverConn != null ? serverConn.getConnection() : null; if (serverConn != null && backendConn != null) { if (backendConn.getState() != StateRegistry.PLAY) { - logger.warn( - "A plugin message was received while the backend server was not " - + "ready. Channel: {}. Packet discarded.", - packet.getChannel()); + logger.warn("A plugin message was received while the backend server was not " + + "ready. Channel: {}. Packet discarded.", packet.getChannel()); } else if (PluginMessageUtil.isRegister(packet)) { List channels = PluginMessageUtil.getChannels(packet); List channelIdentifiers = new ArrayList<>(); @@ -311,10 +307,8 @@ public boolean handle(PluginMessage packet) { channelIdentifiers.add(new LegacyChannelIdentifier(channel)); } } - server - .getEventManager() - .fireAndForget( - new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); + server.getEventManager().fireAndForget( + new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isUnregister(packet)) { backendConn.write(packet.retain()); @@ -322,9 +316,8 @@ public boolean handle(PluginMessage packet) { String brand = PluginMessageUtil.readBrandMessage(packet.content()); server.getEventManager().fireAndForget(new PlayerClientBrandEvent(player, brand)); player.setClientBrand(brand); - backendConn.write( - PluginMessageUtil.rewriteMinecraftBrand( - packet, server.getVersion(), player.getProtocolVersion())); + backendConn.write(PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), + player.getProtocolVersion())); } else if (BungeeCordMessageResponder.isBungeeCordMessage(packet)) { return true; } else { @@ -358,31 +351,23 @@ public boolean handle(PluginMessage packet) { } else { byte[] copy = ByteBufUtil.getBytes(packet.content()); PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy); - server - .getEventManager() - .fire(event) - .thenAcceptAsync( - pme -> { - if (pme.getResult().isAllowed()) { - PluginMessage message = - new PluginMessage(packet.getChannel(), Unpooled.wrappedBuffer(copy)); - if (!player.getPhase().consideredComplete() - || !serverConn.getPhase().consideredComplete()) { - // We're still processing the connection (see above), enqueue the packet - // for now. - loginPluginMessages.add(message.retain()); - } else { - backendConn.write(message); - } - } - }, - backendConn.eventLoop()) - .exceptionally( - (ex) -> { - logger.error( - "Exception while handling plugin message packet for {}", player, ex); - return null; - }); + server.getEventManager().fire(event).thenAcceptAsync(pme -> { + if (pme.getResult().isAllowed()) { + PluginMessage message = + new PluginMessage(packet.getChannel(), Unpooled.wrappedBuffer(copy)); + if (!player.getPhase().consideredComplete() + || !serverConn.getPhase().consideredComplete()) { + // We're still processing the connection (see above), enqueue the packet + // for now. + loginPluginMessages.add(message.retain()); + } else { + backendConn.write(message); + } + } + }, backendConn.eventLoop()).exceptionally((ex) -> { + logger.error("Exception while handling plugin message packet for {}", player, ex); + return null; + }); } } } @@ -496,7 +481,7 @@ public CompletableFuture doSwitch() { * Handles the {@code JoinGame} packet. This function is responsible for handling the client-side * switching servers in Velocity. * - * @param joinGame the join game packet + * @param joinGame the join game packet * @param destination the new server we are connecting to */ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection destination) { @@ -542,11 +527,9 @@ public void handleBackendJoinGame(JoinGame joinGame, VelocityServerConnection de // Clear any title from the previous server. if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - player - .getConnection() - .delayedWrite( - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.RESET, player.getProtocolVersion())); + player.getConnection().delayedWrite( + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET, + player.getProtocolVersion())); } // Flush everything @@ -616,45 +599,36 @@ private boolean handleCommandTabComplete(TabCompleteRequest packet) { return false; } - server - .getCommandManager() - .offerBrigadierSuggestions(player, command) - .thenAcceptAsync( - suggestions -> { - if (suggestions.isEmpty()) { - return; - } + server.getCommandManager().offerBrigadierSuggestions(player, command) + .thenAcceptAsync(suggestions -> { + if (suggestions.isEmpty()) { + return; + } - List offers = new ArrayList<>(); - for (Suggestion suggestion : suggestions.getList()) { - String offer = suggestion.getText(); - Component tooltip = null; - if (suggestion.getTooltip() != null - && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { - tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); - } - offers.add(new Offer(offer, tooltip)); - } - int startPos = packet.getCommand().lastIndexOf(' ') + 1; - if (startPos > 0) { - TabCompleteResponse resp = new TabCompleteResponse(); - resp.setTransactionId(packet.getTransactionId()); - resp.setStart(startPos); - resp.setLength(packet.getCommand().length() - startPos); - resp.getOffers().addAll(offers); - player.getConnection().write(resp); - } - }, - player.getConnection().eventLoop()) - .exceptionally( - (ex) -> { - logger.error( - "Exception while handling command tab completion for player {} executing {}", - player, - command, - ex); - return null; - }); + List offers = new ArrayList<>(); + for (Suggestion suggestion : suggestions.getList()) { + String offer = suggestion.getText(); + Component tooltip = null; + if (suggestion.getTooltip() != null + && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { + tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); + } + offers.add(new Offer(offer, tooltip)); + } + int startPos = packet.getCommand().lastIndexOf(' ') + 1; + if (startPos > 0) { + TabCompleteResponse resp = new TabCompleteResponse(); + resp.setTransactionId(packet.getTransactionId()); + resp.setStart(startPos); + resp.setLength(packet.getCommand().length() - startPos); + resp.getOffers().addAll(offers); + player.getConnection().write(resp); + } + }, player.getConnection().eventLoop()).exceptionally((ex) -> { + logger.error("Exception while handling command tab completion for player {} executing {}", + player, command, ex); + return null; + }); return true; // Sorry, handler; we're just gonna have to lie to you here. } @@ -688,48 +662,37 @@ public void handleTabCompleteResponse(TabCompleteResponse response) { private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteResponse response) { String command = request.getCommand().substring(1); - server - .getCommandManager() - .offerBrigadierSuggestions(player, command) - .thenAcceptAsync( - offers -> { - boolean legacy = - player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0; - try { - for (Suggestion suggestion : offers.getList()) { - String offer = suggestion.getText(); - offer = legacy && !offer.startsWith("/") ? "/" + offer : offer; - if (legacy && offer.startsWith(command)) { - offer = offer.substring(command.length()); - } - Component tooltip = null; - if (suggestion.getTooltip() != null - && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { - tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); - } - response.getOffers().add(new Offer(offer, tooltip)); - } - response.getOffers().sort(null); - player.getConnection().write(response); - } catch (Exception e) { - logger.error( - "Unable to provide tab list completions for {} for command '{}'", - player.getUsername(), - command, - e); + server.getCommandManager().offerBrigadierSuggestions(player, command) + .thenAcceptAsync(offers -> { + boolean legacy = + player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_13) < 0; + try { + for (Suggestion suggestion : offers.getList()) { + String offer = suggestion.getText(); + offer = legacy && !offer.startsWith("/") ? "/" + offer : offer; + if (legacy && offer.startsWith(command)) { + offer = offer.substring(command.length()); } - }, - player.getConnection().eventLoop()) - .exceptionally( - (ex) -> { - logger.error( - "Exception while finishing command tab completion," - + " with request {} and response {}", - request, - response, - ex); - return null; - }); + Component tooltip = null; + if (suggestion.getTooltip() != null + && suggestion.getTooltip() instanceof VelocityBrigadierMessage) { + tooltip = ((VelocityBrigadierMessage) suggestion.getTooltip()).asComponent(); + } + response.getOffers().add(new Offer(offer, tooltip)); + } + response.getOffers().sort(null); + player.getConnection().write(response); + } catch (Exception e) { + logger.error("Unable to provide tab list completions for {} for command '{}'", + player.getUsername(), command, e); + } + }, player.getConnection().eventLoop()).exceptionally((ex) -> { + logger.error( + "Exception while finishing command tab completion," + + " with request {} and response {}", + request, response, ex); + return null; + }); } private void finishRegularTabComplete(TabCompleteRequest request, TabCompleteResponse response) { @@ -737,31 +700,25 @@ private void finishRegularTabComplete(TabCompleteRequest request, TabCompleteRes for (Offer offer : response.getOffers()) { offers.add(offer.getText()); } - server - .getEventManager() - .fire(new TabCompleteEvent(player, request.getCommand(), offers)) - .thenAcceptAsync( - e -> { - response.getOffers().clear(); - for (String s : e.getSuggestions()) { - response.getOffers().add(new Offer(s)); - } - player.getConnection().write(response); - }, - player.getConnection().eventLoop()) - .exceptionally( - (ex) -> { - logger.error( - "Exception while finishing regular tab completion," - + " with request {} and response{}", - request, - response, - ex); - return null; - }); + server.getEventManager().fire(new TabCompleteEvent(player, request.getCommand(), offers)) + .thenAcceptAsync(e -> { + response.getOffers().clear(); + for (String s : e.getSuggestions()) { + response.getOffers().add(new Offer(s)); + } + player.getConnection().write(response); + }, player.getConnection().eventLoop()).exceptionally((ex) -> { + logger.error( + "Exception while finishing regular tab completion," + + " with request {} and response{}", + request, response, ex); + return null; + }); } - /** Immediately send any queued messages to the server. */ + /** + * Immediately send any queued messages to the server. + */ public void flushQueuedMessages() { VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection != null) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index d182aaa0ec..4bc2fbb703 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -115,19 +115,17 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.NotNull; -/** Represents a player that is connected to the proxy. */ +/** + * Represents a player that is connected to the proxy. + */ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, KeyIdentifiable, VelocityInboundConnection { private static final int MAX_PLUGIN_CHANNELS = 1024; private static final PlainTextComponentSerializer PASS_THRU_TRANSLATE = - PlainTextComponentSerializer.builder() - .flattener( - ComponentFlattener.basic().toBuilder() - .mapper(KeybindComponent.class, c -> "") - .mapper(TranslatableComponent.class, TranslatableComponent::key) - .build()) - .build(); + PlainTextComponentSerializer.builder().flattener( + ComponentFlattener.basic().toBuilder().mapper(KeybindComponent.class, c -> "") + .mapper(TranslatableComponent.class, TranslatableComponent::key).build()).build(); static final PermissionProvider DEFAULT_PERMISSIONS = s -> PermissionFunction.ALWAYS_UNDEFINED; private static final Logger logger = LogManager.getLogger(ConnectedPlayer.class); @@ -161,14 +159,12 @@ public class ConnectedPlayer private @Nullable ResourcePackInfo pendingResourcePack; private @Nullable ResourcePackInfo appliedResourcePack; private final @NotNull Pointers pointers = - Player.super.pointers().toBuilder() - .withDynamic(Identity.UUID, this::getUniqueId) + Player.super.pointers().toBuilder().withDynamic(Identity.UUID, this::getUniqueId) .withDynamic(Identity.NAME, this::getUsername) .withDynamic(Identity.DISPLAY_NAME, () -> Component.text(this.getUsername())) .withDynamic(Identity.LOCALE, this::getEffectiveLocale) .withStatic(PermissionChecker.POINTER, getPermissionChecker()) - .withStatic(FacetPointers.TYPE, Type.PLAYER) - .build(); + .withStatic(FacetPointers.TYPE, Type.PLAYER).build(); private @Nullable String clientBrand; private @Nullable Locale effectiveLocale; private @Nullable IdentifiedKey playerKey; @@ -176,13 +172,9 @@ public class ConnectedPlayer private final ChatQueue chatQueue; private final ChatBuilderFactory chatBuilderFactory; - ConnectedPlayer( - VelocityServer server, - GameProfile profile, - MinecraftConnection connection, - @Nullable InetSocketAddress virtualHost, - boolean onlineMode, - @Nullable IdentifiedKey playerKey) { + ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection, + @Nullable InetSocketAddress virtualHost, boolean onlineMode, + @Nullable IdentifiedKey playerKey) { this.server = server; this.profile = profile; this.connection = connection; @@ -350,9 +342,8 @@ public ProtocolVersion getProtocolVersion() { * @return the translated message */ public Component translateMessage(Component message) { - Locale locale = - ClosestLocaleMatcher.INSTANCE.lookupClosest( - getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); + Locale locale = ClosestLocaleMatcher.INSTANCE.lookupClosest( + getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); return GlobalTranslator.render(message, locale); } @@ -365,20 +356,15 @@ public void sendMessage(@NonNull Identity identity, @NonNull Component message) } @Override - public void sendMessage( - @NonNull Identity identity, @NonNull Component message, @NonNull MessageType type) { + public void sendMessage(@NonNull Identity identity, @NonNull Component message, + @NonNull MessageType type) { Preconditions.checkNotNull(message, "message"); Preconditions.checkNotNull(type, "type"); Component translated = translateMessage(message); - connection.write( - getChatBuilderFactory() - .builder() - .component(translated) - .forIdentity(identity) - .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM) - .toClient()); + connection.write(getChatBuilderFactory().builder().component(translated).forIdentity(identity) + .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM).toClient()); } @Override @@ -389,8 +375,8 @@ public void sendActionBar(net.kyori.adventure.text.@NonNull Component message) { if (playerVersion.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { // Use the title packet instead. GenericTitlePacket pkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_ACTION_BAR, + playerVersion); pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion).serialize(translated)); connection.write(pkt); } else { @@ -442,8 +428,8 @@ public void showTitle(net.kyori.adventure.title.@NonNull Title title) { GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this.getProtocolVersion()); GenericTitlePacket timesPkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TIMES, + this.getProtocolVersion()); net.kyori.adventure.title.Title.Times times = title.times(); if (times != null) { timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); @@ -453,14 +439,14 @@ public void showTitle(net.kyori.adventure.title.@NonNull Title title) { connection.delayedWrite(timesPkt); GenericTitlePacket subtitlePkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_SUBTITLE, + this.getProtocolVersion()); subtitlePkt.setComponent(serializer.serialize(translateMessage(title.subtitle()))); connection.delayedWrite(subtitlePkt); GenericTitlePacket titlePkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TITLE, + this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage(title.title()))); connection.delayedWrite(titlePkt); @@ -486,21 +472,21 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { if (part == TitlePart.TITLE) { GenericTitlePacket titlePkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TITLE, + this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.SUBTITLE) { GenericTitlePacket titlePkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_SUBTITLE, + this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.TIMES) { Times times = (Times) value; GenericTitlePacket timesPkt = - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); + GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TIMES, + this.getProtocolVersion()); timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); timesPkt.setStay((int) DurationUtils.toTicks(times.stay())); timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut())); @@ -513,18 +499,16 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { @Override public void clearTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write( - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion())); + connection.write(GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.HIDE, + this.getProtocolVersion())); } } @Override public void resetTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write( - GenericTitlePacket.constructTitlePacket( - GenericTitlePacket.ActionType.RESET, this.getProtocolVersion())); + connection.write(GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET, + this.getProtocolVersion())); } } @@ -547,8 +531,8 @@ public ConnectionRequestBuilder createConnectionRequest(RegisteredServer server) return new ConnectionRequestBuilderImpl(server, this.connectedServer); } - private ConnectionRequestBuilder createConnectionRequest( - RegisteredServer server, @Nullable VelocityServerConnection previousConnection) { + private ConnectionRequestBuilder createConnectionRequest(RegisteredServer server, + @Nullable VelocityServerConnection previousConnection) { return new ConnectionRequestBuilderImpl(server, previousConnection); } @@ -584,16 +568,14 @@ public void disconnect(Component reason) { /** * Disconnects the player from the proxy. * - * @param reason the reason for disconnecting the player + * @param reason the reason for disconnecting the player * @param duringLogin whether the disconnect happened during login */ public void disconnect0(Component reason, boolean duringLogin) { Component translated = this.translateMessage(reason); if (server.getConfiguration().isLogPlayerConnections()) { - logger.info( - "{} has disconnected: {}", - this, + logger.info("{} has disconnected: {}", this, LegacyComponentSerializer.legacySection().serialize(translated)); } connection.closeWith(Disconnect.create(translated, this.getProtocolVersion())); @@ -614,12 +596,12 @@ public void resetInFlightConnection() { /** * Handles unexpected disconnects. * - * @param server the server we disconnected from + * @param server the server we disconnected from * @param throwable the exception - * @param safe whether or not we can safely reconnect to a new server + * @param safe whether or not we can safely reconnect to a new server */ - public void handleConnectionException( - RegisteredServer server, Throwable throwable, boolean safe) { + public void handleConnectionException(RegisteredServer server, Throwable throwable, + boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -639,17 +621,13 @@ public void handleConnectionException( Component friendlyError; if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { - friendlyError = - Component.translatable( - "velocity.error.connected-server-error", - Component.text(server.getServerInfo().getName())); + friendlyError = Component.translatable("velocity.error.connected-server-error", + Component.text(server.getServerInfo().getName())); } else { - logger.error( - "{}: unable to connect to server {}", this, server.getServerInfo().getName(), wrapped); - friendlyError = - Component.translatable( - "velocity.error.connecting-server-error", - Component.text(server.getServerInfo().getName())); + logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(), + wrapped); + friendlyError = Component.translatable("velocity.error.connecting-server-error", + Component.text(server.getServerInfo().getName())); } handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe); } @@ -657,12 +635,12 @@ public void handleConnectionException( /** * Handles unexpected disconnects. * - * @param server the server we disconnected from + * @param server the server we disconnected from * @param disconnect the disconnect packet - * @param safe whether or not we can safely reconnect to a new server + * @param safe whether or not we can safely reconnect to a new server */ - public void handleConnectionException( - RegisteredServer server, Disconnect disconnect, boolean safe) { + public void handleConnectionException(RegisteredServer server, Disconnect disconnect, + boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -671,37 +649,22 @@ public void handleConnectionException( Component disconnectReason = GsonComponentSerializer.gson().deserialize(disconnect.getReason()); String plainTextReason = PASS_THRU_TRANSLATE.serialize(disconnectReason); if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { - logger.info( - "{}: kicked from server {}: {}", this, server.getServerInfo().getName(), plainTextReason); - handleConnectionException( - server, - disconnectReason, - Component.translatable( - "velocity.error.moved-to-new-server", - NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), - disconnectReason), - safe); - } else { - logger.error( - "{}: disconnected while connecting to {}: {}", - this, - server.getServerInfo().getName(), + logger.info("{}: kicked from server {}: {}", this, server.getServerInfo().getName(), plainTextReason); - handleConnectionException( - server, - disconnectReason, - Component.translatable( - "velocity.error.cant-connect", - NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), - disconnectReason), - safe); + handleConnectionException(server, disconnectReason, + Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED, + Component.text(server.getServerInfo().getName()), disconnectReason), safe); + } else { + logger.error("{}: disconnected while connecting to {}: {}", this, + server.getServerInfo().getName(), plainTextReason); + handleConnectionException(server, disconnectReason, + Component.translatable("velocity.error.cant-connect", NamedTextColor.RED, + Component.text(server.getServerInfo().getName()), disconnectReason), safe); } } - private void handleConnectionException( - RegisteredServer rs, @Nullable Component kickReason, Component friendlyReason, boolean safe) { + private void handleConnectionException(RegisteredServer rs, @Nullable Component kickReason, + Component friendlyReason, boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -733,99 +696,84 @@ private void handleConnectionException( handleKickEvent(originalEvent, friendlyReason, kickedFromCurrent); } - private void handleKickEvent( - KickedFromServerEvent originalEvent, Component friendlyReason, boolean kickedFromCurrent) { - server - .getEventManager() - .fire(originalEvent) - .thenAcceptAsync( - event -> { - // There can't be any connection in flight now. - connectionInFlight = null; - - // Make sure we clear the current connected server as the connection is invalid. - VelocityServerConnection previousConnection = connectedServer; - if (kickedFromCurrent) { - connectedServer = null; - } + private void handleKickEvent(KickedFromServerEvent originalEvent, Component friendlyReason, + boolean kickedFromCurrent) { + server.getEventManager().fire(originalEvent).thenAcceptAsync(event -> { + // There can't be any connection in flight now. + connectionInFlight = null; - if (!isActive()) { - // If the connection is no longer active, it makes no sense to try and recover it. + // Make sure we clear the current connected server as the connection is invalid. + VelocityServerConnection previousConnection = connectedServer; + if (kickedFromCurrent) { + connectedServer = null; + } + + if (!isActive()) { + // If the connection is no longer active, it makes no sense to try and recover it. + return; + } + + if (event.getResult() instanceof DisconnectPlayer) { + DisconnectPlayer res = (DisconnectPlayer) event.getResult(); + disconnect(res.getReasonComponent()); + } else if (event.getResult() instanceof RedirectPlayer) { + RedirectPlayer res = (RedirectPlayer) event.getResult(); + createConnectionRequest(res.getServer(), previousConnection).connect() + .whenCompleteAsync((status, throwable) -> { + if (throwable != null) { + handleConnectionException( + status != null ? status.getAttemptedConnection() : res.getServer(), throwable, + true); return; } - if (event.getResult() instanceof DisconnectPlayer) { - DisconnectPlayer res = (DisconnectPlayer) event.getResult(); - disconnect(res.getReasonComponent()); - } else if (event.getResult() instanceof RedirectPlayer) { - RedirectPlayer res = (RedirectPlayer) event.getResult(); - createConnectionRequest(res.getServer(), previousConnection) - .connect() - .whenCompleteAsync( - (status, throwable) -> { - if (throwable != null) { - handleConnectionException( - status != null ? status.getAttemptedConnection() : res.getServer(), - throwable, - true); - return; - } - - switch (status.getStatus()) { - // Impossible/nonsensical cases - case ALREADY_CONNECTED: - logger.error( - "{}: already connected to {}", - this, - status.getAttemptedConnection().getServerInfo().getName()); - break; - case CONNECTION_IN_PROGRESS: - // Fatal case - case CONNECTION_CANCELLED: - Component fallbackMsg = res.getMessageComponent(); - if (fallbackMsg == null) { - fallbackMsg = friendlyReason; - } - disconnect(status.getReasonComponent().orElse(fallbackMsg)); - break; - case SERVER_DISCONNECTED: - Component reason = - status - .getReasonComponent() - .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException( - res.getServer(), - Disconnect.create(reason, getProtocolVersion()), - ((Impl) status).isSafe()); - break; - case SUCCESS: - Component requestedMessage = res.getMessageComponent(); - if (requestedMessage == null) { - requestedMessage = friendlyReason; - } - if (requestedMessage != Component.empty()) { - sendMessage(requestedMessage); - } - break; - default: - // The only remaining value is successful (no need to do anything!) - break; - } - }, - connection.eventLoop()); - } else if (event.getResult() instanceof Notify) { - Notify res = (Notify) event.getResult(); - if (event.kickedDuringServerConnect() && previousConnection != null) { - sendMessage(Identity.nil(), res.getMessageComponent()); - } else { - disconnect(res.getMessageComponent()); - } - } else { - // In case someone gets creative, assume we want to disconnect the player. - disconnect(friendlyReason); + switch (status.getStatus()) { + // Impossible/nonsensical cases + case ALREADY_CONNECTED: + logger.error("{}: already connected to {}", this, + status.getAttemptedConnection().getServerInfo().getName()); + break; + case CONNECTION_IN_PROGRESS: + // Fatal case + case CONNECTION_CANCELLED: + Component fallbackMsg = res.getMessageComponent(); + if (fallbackMsg == null) { + fallbackMsg = friendlyReason; + } + disconnect(status.getReasonComponent().orElse(fallbackMsg)); + break; + case SERVER_DISCONNECTED: + Component reason = status.getReasonComponent() + .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + handleConnectionException(res.getServer(), + Disconnect.create(reason, getProtocolVersion()), ((Impl) status).isSafe()); + break; + case SUCCESS: + Component requestedMessage = res.getMessageComponent(); + if (requestedMessage == null) { + requestedMessage = friendlyReason; + } + if (requestedMessage != Component.empty()) { + sendMessage(requestedMessage); + } + break; + default: + // The only remaining value is successful (no need to do anything!) + break; } - }, - connection.eventLoop()); + }, connection.eventLoop()); + } else if (event.getResult() instanceof Notify) { + Notify res = (Notify) event.getResult(); + if (event.kickedDuringServerConnect() && previousConnection != null) { + sendMessage(Identity.nil(), res.getMessageComponent()); + } else { + disconnect(res.getMessageComponent()); + } + } else { + // In case someone gets creative, assume we want to disconnect the player. + disconnect(friendlyReason); + } + }, connection.eventLoop()); } /** @@ -847,16 +795,10 @@ public Optional getNextServerToTry() { */ private Optional getNextServerToTry(@Nullable RegisteredServer current) { if (serversToTry == null) { - String virtualHostStr = - getVirtualHost() - .map(InetSocketAddress::getHostString) - .orElse("") - .toLowerCase(Locale.ROOT); - serversToTry = - server - .getConfiguration() - .getForcedHosts() - .getOrDefault(virtualHostStr, Collections.emptyList()); + String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString).orElse("") + .toLowerCase(Locale.ROOT); + serversToTry = server.getConfiguration().getForcedHosts() + .getOrDefault(virtualHostStr, Collections.emptyList()); } if (serversToTry.isEmpty()) { @@ -934,30 +876,24 @@ void teardown() { if (!connectedPlayer.get().getCurrentServer().isPresent()) { status = LoginStatus.PRE_SERVER_JOIN; } else { - status = - connectedPlayer.get() == this - ? LoginStatus.SUCCESSFUL_LOGIN - : LoginStatus.CONFLICTING_LOGIN; + status = connectedPlayer.get() == this + ? LoginStatus.SUCCESSFUL_LOGIN + : LoginStatus.CONFLICTING_LOGIN; } } else { - status = - connection.isKnownDisconnect() - ? LoginStatus.CANCELLED_BY_PROXY - : LoginStatus.CANCELLED_BY_USER; + status = connection.isKnownDisconnect() + ? LoginStatus.CANCELLED_BY_PROXY + : LoginStatus.CANCELLED_BY_USER; } DisconnectEvent event = new DisconnectEvent(this, status); - server - .getEventManager() - .fire(event) - .whenComplete( - (val, ex) -> { - if (ex == null) { - this.teardownFuture.complete(null); - } else { - this.teardownFuture.completeExceptionally(ex); - } - }); + server.getEventManager().fire(event).whenComplete((val, ex) -> { + if (ex == null) { + this.teardownFuture.complete(null); + } else { + this.teardownFuture.completeExceptionally(ex); + } + }); } public CompletableFuture getTeardownFuture() { @@ -998,21 +934,18 @@ void setClientBrand(String clientBrand) { @Override public void spoofChatInput(String input) { - Preconditions.checkArgument( - input.length() <= LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH, - "input cannot be greater than " - + LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH + Preconditions.checkArgument(input.length() <= LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH, + "input cannot be greater than " + LegacyChat.MAX_SERVERBOUND_MESSAGE_LENGTH + " characters in length"); if (getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) { - this.chatQueue.hijack( - getChatBuilderFactory().builder().asPlayer(this).message(input), + this.chatQueue.hijack(getChatBuilderFactory().builder().asPlayer(this).message(input), (instant, item) -> { item.setTimestamp(instant); return item.toServer(); }); } else { - ensureBackendConnection() - .write(getChatBuilderFactory().builder().asPlayer(this).message(input).toServer()); + ensureBackendConnection().write( + getChatBuilderFactory().builder().asPlayer(this).message(input).toServer()); } } @@ -1094,32 +1027,24 @@ && getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { return pendingResourcePack; } - /** Processes a client response to a sent resource-pack. */ + /** + * Processes a client response to a sent resource-pack. + */ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status status) { final boolean peek = status == PlayerResourcePackStatusEvent.Status.ACCEPTED; final ResourcePackInfo queued = peek ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); - server - .getEventManager() - .fire(new PlayerResourcePackStatusEvent(this, status, queued)) - .thenAcceptAsync( - event -> { - if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED - && event.getPackInfo() != null - && event.getPackInfo().getShouldForce() - && (!event.isOverwriteKick() - || event - .getPlayer() - .getProtocolVersion() - .compareTo(ProtocolVersion.MINECRAFT_1_17) - >= 0)) { - event - .getPlayer() - .disconnect( - Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); - } - }); + server.getEventManager().fire(new PlayerResourcePackStatusEvent(this, status, queued)) + .thenAcceptAsync(event -> { + if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED + && event.getPackInfo() != null && event.getPackInfo().getShouldForce() + && (!event.isOverwriteKick() || event.getPlayer().getProtocolVersion() + .compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0)) { + event.getPlayer() + .disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); + } + }); switch (status) { case ACCEPTED: @@ -1148,7 +1073,9 @@ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status statu && queued.getOriginalOrigin() != ResourcePackInfo.Origin.DOWNSTREAM_SERVER; } - /** Gives an indication about the previous resource pack responses. */ + /** + * Gives an indication about the previous resource pack responses. + */ public @Nullable Boolean getPreviousResourceResponse() { return previousResourceResponse; } @@ -1202,8 +1129,8 @@ private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder { private final RegisteredServer toConnect; private final @Nullable VelocityRegisteredServer previousServer; - ConnectionRequestBuilderImpl( - RegisteredServer toConnect, @Nullable VelocityServerConnection previousConnection) { + ConnectionRequestBuilderImpl(RegisteredServer toConnect, + @Nullable VelocityServerConnection previousConnection) { this.toConnect = Preconditions.checkNotNull(toConnect, "info"); this.previousServer = previousConnection == null ? null : previousConnection.getServer(); } @@ -1214,8 +1141,8 @@ public RegisteredServer getServer() { } private Optional checkServer(RegisteredServer server) { - Preconditions.checkArgument( - server instanceof VelocityRegisteredServer, "Not a valid Velocity server."); + Preconditions.checkArgument(server instanceof VelocityRegisteredServer, + "Not a valid Velocity server."); if (connectionInFlight != null || (connectedServer != null && !connectedServer.hasCompletedJoin())) { return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS); @@ -1232,47 +1159,34 @@ private CompletableFuture> getInitialStatus() { } private CompletableFuture internalConnect() { - return this.getInitialStatus() - .thenCompose( - initialCheck -> { - if (initialCheck.isPresent()) { - return completedFuture(plainResult(initialCheck.get(), toConnect)); - } - - ServerPreConnectEvent event = - new ServerPreConnectEvent(ConnectedPlayer.this, toConnect, previousServer); - return server - .getEventManager() - .fire(event) - .thenComposeAsync( - newEvent -> { - Optional newDest = newEvent.getResult().getServer(); - if (!newDest.isPresent()) { - return completedFuture( - plainResult( - ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, - toConnect)); - } - - RegisteredServer realDestination = newDest.get(); - Optional check = - checkServer(realDestination); - if (check.isPresent()) { - return completedFuture(plainResult(check.get(), realDestination)); - } - - VelocityRegisteredServer vrs = (VelocityRegisteredServer) realDestination; - VelocityServerConnection con = - new VelocityServerConnection( - vrs, previousServer, ConnectedPlayer.this, server); - connectionInFlight = con; - return con.connect() - .whenCompleteAsync( - (result, exception) -> this.resetIfInFlightIs(con), - connection.eventLoop()); - }, - connection.eventLoop()); - }); + return this.getInitialStatus().thenCompose(initialCheck -> { + if (initialCheck.isPresent()) { + return completedFuture(plainResult(initialCheck.get(), toConnect)); + } + + ServerPreConnectEvent event = + new ServerPreConnectEvent(ConnectedPlayer.this, toConnect, previousServer); + return server.getEventManager().fire(event).thenComposeAsync(newEvent -> { + Optional newDest = newEvent.getResult().getServer(); + if (!newDest.isPresent()) { + return completedFuture( + plainResult(ConnectionRequestBuilder.Status.CONNECTION_CANCELLED, toConnect)); + } + + RegisteredServer realDestination = newDest.get(); + Optional check = checkServer(realDestination); + if (check.isPresent()) { + return completedFuture(plainResult(check.get(), realDestination)); + } + + VelocityRegisteredServer vrs = (VelocityRegisteredServer) realDestination; + VelocityServerConnection con = + new VelocityServerConnection(vrs, previousServer, ConnectedPlayer.this, server); + connectionInFlight = con; + return con.connect().whenCompleteAsync((result, exception) -> this.resetIfInFlightIs(con), + connection.eventLoop()); + }, connection.eventLoop()); + }); } private void resetIfInFlightIs(VelocityServerConnection establishedConnection) { @@ -1283,60 +1197,46 @@ private void resetIfInFlightIs(VelocityServerConnection establishedConnection) { @Override public CompletableFuture connect() { - return this.internalConnect() - .whenCompleteAsync( - (status, throwable) -> { - if (status != null && !status.isSuccessful()) { - if (!status.isSafe()) { - handleConnectionException(status.getAttemptedConnection(), throwable, false); - } - } - }, - connection.eventLoop()) - .thenApply(x -> x); + return this.internalConnect().whenCompleteAsync((status, throwable) -> { + if (status != null && !status.isSuccessful()) { + if (!status.isSafe()) { + handleConnectionException(status.getAttemptedConnection(), throwable, false); + } + } + }, connection.eventLoop()).thenApply(x -> x); } @Override public CompletableFuture connectWithIndication() { - return internalConnect() - .whenCompleteAsync( - (status, throwable) -> { - if (throwable != null) { - // TODO: The exception handling from this is not very good. Find a better way. - handleConnectionException( - status != null ? status.getAttemptedConnection() : toConnect, - throwable, - true); - return; - } - - switch (status.getStatus()) { - case ALREADY_CONNECTED: - sendMessage(Identity.nil(), ConnectionMessages.ALREADY_CONNECTED); - break; - case CONNECTION_IN_PROGRESS: - sendMessage(Identity.nil(), ConnectionMessages.IN_PROGRESS); - break; - case CONNECTION_CANCELLED: - // Ignored; the plugin probably already handled this. - break; - case SERVER_DISCONNECTED: - Component reason = - status - .getReasonComponent() - .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException( - toConnect, - Disconnect.create(reason, getProtocolVersion()), - status.isSafe()); - break; - default: - // The only remaining value is successful (no need to do anything!) - break; - } - }, - connection.eventLoop()) - .thenApply(Result::isSuccessful); + return internalConnect().whenCompleteAsync((status, throwable) -> { + if (throwable != null) { + // TODO: The exception handling from this is not very good. Find a better way. + handleConnectionException(status != null ? status.getAttemptedConnection() : toConnect, + throwable, true); + return; + } + + switch (status.getStatus()) { + case ALREADY_CONNECTED: + sendMessage(Identity.nil(), ConnectionMessages.ALREADY_CONNECTED); + break; + case CONNECTION_IN_PROGRESS: + sendMessage(Identity.nil(), ConnectionMessages.IN_PROGRESS); + break; + case CONNECTION_CANCELLED: + // Ignored; the plugin probably already handled this. + break; + case SERVER_DISCONNECTED: + Component reason = status.getReasonComponent() + .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + handleConnectionException(toConnect, Disconnect.create(reason, getProtocolVersion()), + status.isSafe()); + break; + default: + // The only remaining value is successful (no need to do anything!) + break; + } + }, connection.eventLoop()).thenApply(Result::isSuccessful); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index f8ccb3596b..8ad02a2b2e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -21,6 +21,8 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.packet.PluginMessage; +import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; @@ -42,12 +44,20 @@ */ public class PlayPacketQueueHandler extends ChannelDuplexHandler { - private final StateRegistry.PacketRegistry.ProtocolRegistry registry; + private final StateRegistry.PacketRegistry.ProtocolRegistry clientRegistry; + private final StateRegistry.PacketRegistry.ProtocolRegistry serverRegistry; private final Queue queue = PlatformDependent.newMpscQueue(); + /** + * Provides registries for client & server bound packets. + * + * @param version the protocol version + */ public PlayPacketQueueHandler(ProtocolVersion version) { - this.registry = + this.clientRegistry = StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version); + this.serverRegistry = + StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.SERVERBOUND, version); } @Override @@ -60,11 +70,20 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) // If the packet exists in the CONFIG state, we want to always // ensure that it gets sent out to the client - if (this.registry.containsPacket(((MinecraftPacket) msg))) { + if (this.clientRegistry.containsPacket(((MinecraftPacket) msg))) { ctx.write(msg, promise); return; } + if (this.serverRegistry.containsPacket(((MinecraftPacket) msg))) { + MinecraftPacket packet = (MinecraftPacket) msg; + if (packet instanceof ResourcePackResponse + || packet instanceof PluginMessage) { + ctx.write(msg, promise); + return; + } + } + // Otherwise, queue the packet this.queue.offer((MinecraftPacket) msg); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponse.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponse.java index 3b7c936085..4b67cf6954 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponse.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponse.java @@ -73,9 +73,6 @@ public boolean handle(MinecraftSessionHandler handler) { @Override public String toString() { - return "ResourcePackResponse{" - + "hash=" + hash + ", " - + "status=" + status - + '}'; + return "ResourcePackResponse{" + "hash=" + hash + ", " + "status=" + status + '}'; } } From fb9481623941c4d86a7132f84807c11ee10ade7f Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 3 Oct 2023 14:55:45 +0100 Subject: [PATCH 34/41] Code style changes --- .../proxy/connection/MinecraftConnection.java | 99 +++----- .../backend/BackendConfigSessionHandler.java | 52 ---- .../backend/LoginSessionHandler.java | 107 ++++---- .../backend/VelocityServerConnection.java | 121 ++++----- .../client/HandshakeSessionHandler.java | 25 +- .../client/InitialLoginSessionHandler.java | 236 ++++++++---------- .../LegacyForgeHandshakeClientPhase.java | 32 +-- .../connection/registry/ClientConfigData.java | 11 +- .../proxy/network/Connections.java | 4 +- .../network/ServerChannelInitializer.java | 20 +- .../proxy/protocol/ProtocolUtils.java | 139 ++++------- .../netty/PlayPacketQueueHandler.java | 3 +- .../proxy/protocol/packet/ClientSettings.java | 61 ++--- .../proxy/protocol/packet/JoinGame.java | 60 +---- .../protocol/packet/LoginAcknowledged.java | 14 +- .../protocol/packet/ResourcePackRequest.java | 21 +- .../proxy/protocol/packet/ServerLogin.java | 3 +- .../packet/config/ActiveFeatures.java | 8 +- .../packet/config/FinishedUpdate.java | 14 +- .../protocol/packet/config/RegistrySync.java | 8 +- .../protocol/packet/config/StartUpdate.java | 14 +- .../protocol/packet/config/TagsUpdate.java | 8 +- .../proxy/server/PingSessionHandler.java | 7 +- .../server/VelocityRegisteredServer.java | 79 +++--- 24 files changed, 442 insertions(+), 704 deletions(-) delete mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 551d6ebeed..b23b217501 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -95,7 +95,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { * Initializes a new {@link MinecraftConnection} instance. * * @param channel the channel on the connection - * @param server the Velocity instance + * @param server the Velocity instance */ public MinecraftConnection(Channel channel, VelocityServer server) { this.channel = channel; @@ -123,8 +123,7 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { activeSessionHandler.disconnected(); } - if (association != null - && !knownDisconnect + if (association != null && !knownDisconnect && !(activeSessionHandler instanceof StatusSessionHandler) && server.getConfiguration().isLogPlayerConnections()) { logger.info("{} has disconnected", association); @@ -178,10 +177,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E try { activeSessionHandler.exception(cause); } catch (Exception ex) { - logger.error( - "{}: exception handling exception in {}", - (association != null ? association : channel.remoteAddress()), - activeSessionHandler, + logger.error("{}: exception handling exception in {}", + (association != null ? association : channel.remoteAddress()), activeSessionHandler, cause); } } @@ -190,15 +187,14 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E if (cause instanceof ReadTimeoutException) { logger.error("{}: read timed out", association); } else { - boolean frontlineHandler = - activeSessionHandler instanceof InitialLoginSessionHandler - || activeSessionHandler instanceof HandshakeSessionHandler - || activeSessionHandler instanceof StatusSessionHandler; + boolean frontlineHandler = activeSessionHandler instanceof InitialLoginSessionHandler + || activeSessionHandler instanceof HandshakeSessionHandler + || activeSessionHandler instanceof StatusSessionHandler; boolean isQuietDecoderException = cause instanceof QuietDecoderException; boolean willLog = !isQuietDecoderException && !frontlineHandler; if (willLog) { - logger.error( - "{}: exception encountered in {}", association, activeSessionHandler, cause); + logger.error("{}: exception encountered in {}", association, activeSessionHandler, + cause); } else { knownDisconnect = true; } @@ -250,7 +246,9 @@ public void delayedWrite(Object msg) { } } - /** Flushes the connection. */ + /** + * Flushes the connection. + */ public void flush() { if (channel.isActive()) { channel.flush(); @@ -264,28 +262,19 @@ public void flush() { */ public void closeWith(Object msg) { if (channel.isActive()) { - boolean is17 = - this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 - && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; + boolean is17 = this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) < 0 + && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; if (is17 && this.getState() != StateRegistry.STATUS) { - channel - .eventLoop() - .execute( - () -> { - // 1.7.x versions have a race condition with switching protocol states, so just - // explicitly - // close the connection after a short while. - this.setAutoReading(false); - channel - .eventLoop() - .schedule( - () -> { - knownDisconnect = true; - channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); - }, - 250, - TimeUnit.MILLISECONDS); - }); + channel.eventLoop().execute(() -> { + // 1.7.x versions have a race condition with switching protocol states, so just + // explicitly + // close the connection after a short while. + this.setAutoReading(false); + channel.eventLoop().schedule(() -> { + knownDisconnect = true; + channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); + }, 250, TimeUnit.MILLISECONDS); + }); } else { knownDisconnect = true; channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); @@ -310,15 +299,12 @@ public void close(boolean markKnown) { } channel.close(); } else { - channel - .eventLoop() - .execute( - () -> { - if (markKnown) { - knownDisconnect = true; - } - channel.close(); - }); + channel.eventLoop().execute(() -> { + if (markKnown) { + knownDisconnect = true; + } + channel.close(); + }); } } } @@ -382,12 +368,8 @@ public void setState(StateRegistry state) { if (state == StateRegistry.CONFIG) { // Activate the play packet queue - this.channel - .pipeline() - .addAfter( - Connections.MINECRAFT_ENCODER, - Connections.PLAY_PACKET_QUEUE, - new PlayPacketQueueHandler(this.protocolVersion)); + this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE, + new PlayPacketQueueHandler(this.protocolVersion)); } else if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) != null) { // Remove the queue this.channel.pipeline().remove(Connections.PLAY_PACKET_QUEUE); @@ -433,11 +415,11 @@ public void setProtocolVersion(ProtocolVersion protocolVersion) { /** * Sets the session handler for this connection. * - * @param registry the registry of the handler + * @param registry the registry of the handler * @param sessionHandler the handler to use */ - public void setActiveSessionHandler( - StateRegistry registry, MinecraftSessionHandler sessionHandler) { + public void setActiveSessionHandler(StateRegistry registry, + MinecraftSessionHandler sessionHandler) { Preconditions.checkNotNull(registry); ensureInEventLoop(); @@ -479,7 +461,7 @@ public boolean setActiveSessionHandler(StateRegistry registry) { /** * Adds a secondary session handler for this connection. * - * @param registry the registry of the handler + * @param registry the registry of the handler * @param sessionHandler the handler to use */ public void addSessionHandler(StateRegistry registry, MinecraftSessionHandler sessionHandler) { @@ -509,8 +491,7 @@ public void setCompressionThreshold(int threshold) { final ChannelHandler removedEncoder = channel.pipeline().remove(COMPRESSION_ENCODER); if (removedDecoder != null && removedEncoder != null) { - channel - .pipeline() + channel.pipeline() .addBefore(MINECRAFT_DECODER, FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.COMPRESSION_DISABLED); } @@ -553,11 +534,9 @@ public void enableEncryption(byte[] secret) throws GeneralSecurityException { VelocityCipherFactory factory = Natives.cipher.get(); VelocityCipher decryptionCipher = factory.forDecryption(key); VelocityCipher encryptionCipher = factory.forEncryption(key); - channel - .pipeline() + channel.pipeline() .addBefore(FRAME_DECODER, CIPHER_DECODER, new MinecraftCipherDecoder(decryptionCipher)); - channel - .pipeline() + channel.pipeline() .addBefore(FRAME_ENCODER, CIPHER_ENCODER, new MinecraftCipherEncoder(encryptionCipher)); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.ENCRYPTION_ENABLED); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java deleted file mode 100644 index 48d3308d54..0000000000 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendConfigSessionHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2018-2023 Velocity Contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.velocitypowered.proxy.connection.backend; - -import com.velocitypowered.proxy.VelocityServer; -import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; -import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; -import java.util.concurrent.CompletableFuture; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -/** Handles the initial server configuration setup. */ -public class BackendConfigSessionHandler implements MinecraftSessionHandler { - - private static final Logger logger = LogManager.getLogger(BackendConfigSessionHandler.class); - - private final VelocityServer server; - private final VelocityServerConnection serverConn; - private final CompletableFuture resultFuture; - private boolean informationForwarded; - - BackendConfigSessionHandler( - VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { - this.server = server; - this.serverConn = serverConn; - this.resultFuture = resultFuture; - } - - @Override - public boolean handle(StartUpdate packet) { - - return true; - } -} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index 71de19f56e..2b7eaf9bb8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -54,7 +54,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** Handles a player trying to log into the proxy. */ +/** + * Handles a player trying to log into the proxy. + */ public class LoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(LoginSessionHandler.class); @@ -67,10 +69,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private final CompletableFuture resultFuture; private boolean informationForwarded; - LoginSessionHandler( - VelocityServer server, - VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + LoginSessionHandler(VelocityServer server, VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -93,12 +93,9 @@ public boolean handle(LoginPluginMessage packet) { if (packet.content().readableBytes() == 1) { requestedForwardingVersion = packet.content().readByte(); } - ByteBuf forwardingData = - createForwardingData( - configuration.getForwardingSecret(), - serverConn.getPlayerRemoteAddressAsString(), - serverConn.getPlayer(), - requestedForwardingVersion); + ByteBuf forwardingData = createForwardingData(configuration.getForwardingSecret(), + serverConn.getPlayerRemoteAddressAsString(), serverConn.getPlayer(), + requestedForwardingVersion); LoginPluginResponse response = new LoginPluginResponse(packet.getId(), true, forwardingData); mc.write(response); @@ -113,22 +110,16 @@ public boolean handle(LoginPluginMessage packet) { final byte[] contents = ByteBufUtil.getBytes(packet.content()); final MinecraftChannelIdentifier identifier = MinecraftChannelIdentifier.from(packet.getChannel()); - this.server - .getEventManager() + this.server.getEventManager() .fire(new ServerLoginPluginMessageEvent(serverConn, identifier, contents, packet.getId())) - .thenAcceptAsync( - event -> { - if (event.getResult().isAllowed()) { - mc.write( - new LoginPluginResponse( - packet.getId(), - true, - Unpooled.wrappedBuffer(event.getResult().getResponse()))); - } else { - mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); - } - }, - mc.eventLoop()); + .thenAcceptAsync(event -> { + if (event.getResult().isAllowed()) { + mc.write(new LoginPluginResponse(packet.getId(), true, + Unpooled.wrappedBuffer(event.getResult().getResponse()))); + } else { + mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); + } + }, mc.eventLoop()); } return true; } @@ -150,9 +141,8 @@ public boolean handle(SetCompression packet) { public boolean handle(ServerLoginSuccess packet) { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) { - resultFuture.complete( - ConnectionRequestResults.forDisconnect( - MODERN_IP_FORWARDING_FAILURE, serverConn.getServer())); + resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE, + serverConn.getServer())); serverConn.disconnect(); return true; } @@ -163,29 +153,25 @@ public boolean handle(ServerLoginSuccess packet) { // Move into the PLAY phase. MinecraftConnection smc = serverConn.ensureConnected(); if (smc.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_20_2) < 0) { - smc.setActiveSessionHandler( - StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture)); + smc.setActiveSessionHandler(StateRegistry.PLAY, + new TransitionSessionHandler(server, serverConn, resultFuture)); } else { smc.setAutoReading(false); CompletableFuture switchFuture; - if (serverConn.getPlayer().getConnection().getActiveSessionHandler() - instanceof ClientPlaySessionHandler) { - switchFuture = - ((ClientPlaySessionHandler) - serverConn.getPlayer().getConnection().getActiveSessionHandler()) - .doSwitch(); + if (serverConn.getPlayer().getConnection() + .getActiveSessionHandler() instanceof ClientPlaySessionHandler) { + switchFuture = ((ClientPlaySessionHandler) serverConn.getPlayer().getConnection() + .getActiveSessionHandler()).doSwitch(); } else { switchFuture = CompletableFuture.completedFuture(null); } - switchFuture.thenAcceptAsync( - (unused) -> { - smc.write(new LoginAcknowledged()); - // Sync backend - smc.setActiveSessionHandler( - StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture)); - smc.setAutoReading(true); - }, - smc.eventLoop()); + switchFuture.thenAcceptAsync((unused) -> { + smc.write(new LoginAcknowledged()); + // Sync backend + smc.setActiveSessionHandler(StateRegistry.CONFIG, + new ConfigSessionHandler(server, serverConn, resultFuture)); + smc.setAutoReading(true); + }, smc.eventLoop()); } return true; @@ -199,17 +185,15 @@ public void exception(Throwable throwable) { @Override public void disconnected() { if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.LEGACY) { - resultFuture.completeExceptionally( - new QuietRuntimeException( - "The connection to the remote server was unexpectedly closed.\n" - + "This is usually because the remote server " - + "does not have BungeeCord IP forwarding " - + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " - + "for instructions on how to configure player info forwarding correctly.")); + resultFuture.completeExceptionally(new QuietRuntimeException( + "The connection to the remote server was unexpectedly closed.\n" + + "This is usually because the remote server " + + "does not have BungeeCord IP forwarding " + + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " + + "for instructions on how to configure player info forwarding correctly.")); } else { - resultFuture.completeExceptionally( - new QuietRuntimeException( - "The connection to the remote server was unexpectedly closed.")); + resultFuture.completeExceptionally(new QuietRuntimeException( + "The connection to the remote server was unexpectedly closed.")); } } @@ -219,16 +203,15 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) if (requested > VelocityConstants.MODERN_FORWARDING_DEFAULT) { if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { return requested >= VelocityConstants.MODERN_LAZY_SESSION - ? VelocityConstants.MODERN_LAZY_SESSION - : VelocityConstants.MODERN_FORWARDING_DEFAULT; + ? VelocityConstants.MODERN_LAZY_SESSION : VelocityConstants.MODERN_FORWARDING_DEFAULT; } if (player.getIdentifiedKey() != null) { // No enhanced switch on java 11 switch (player.getIdentifiedKey().getKeyRevision()) { case GENERIC_V1: return VelocityConstants.MODERN_FORWARDING_WITH_KEY; - // Since V2 is not backwards compatible we have to throw the key if v2 and requested is - // v1 + // Since V2 is not backwards compatible we have to throw the key if v2 and requested is + // v1 case LINKED_V2: return requested >= VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 @@ -243,8 +226,8 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) return VelocityConstants.MODERN_FORWARDING_DEFAULT; } - private static ByteBuf createForwardingData( - byte[] hmacSecret, String address, ConnectedPlayer player, int requestedVersion) { + private static ByteBuf createForwardingData(byte[] hmacSecret, String address, + ConnectedPlayer player, int requestedVersion) { ByteBuf forwarded = Unpooled.buffer(2048); try { int actualVersion = findForwardingVersion(requestedVersion, player); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 61dba9efdf..b55b4de23a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -56,7 +56,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** Handles a connection from the proxy to some backend server. */ +/** + * Handles a connection from the proxy to some backend server. + */ public class VelocityServerConnection implements MinecraftConnectionAssociation, ServerConnection { private final VelocityRegisteredServer registeredServer; @@ -74,15 +76,13 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, * Initializes a new server connection. * * @param registeredServer the server to connect to - * @param previousServer the server the player is coming from - * @param proxyPlayer the player connecting to the server - * @param server the Velocity proxy instance + * @param previousServer the server the player is coming from + * @param proxyPlayer the player connecting to the server + * @param server the Velocity proxy instance */ - public VelocityServerConnection( - VelocityRegisteredServer registeredServer, - @Nullable VelocityRegisteredServer previousServer, - ConnectedPlayer proxyPlayer, - VelocityServer server) { + public VelocityServerConnection(VelocityRegisteredServer registeredServer, + @Nullable VelocityRegisteredServer previousServer, + ConnectedPlayer proxyPlayer, VelocityServer server) { this.registeredServer = registeredServer; this.previousServer = previousServer; this.proxyPlayer = proxyPlayer; @@ -92,44 +92,41 @@ public VelocityServerConnection( /** * Connects to the server. * - * @return a {@link com.velocitypowered.api.proxy.ConnectionRequestBuilder.Result} representing - * whether or not the connect succeeded + * @return a {@link com.velocitypowered.api.proxy.ConnectionRequestBuilder.Result} + * representing whether the connection succeeded */ public CompletableFuture connect() { CompletableFuture result = new CompletableFuture<>(); // Note: we use the event loop for the connection the player is on. This reduces context // switches. - server - .createBootstrap(proxyPlayer.getConnection().eventLoop()) + server.createBootstrap(proxyPlayer.getConnection().eventLoop()) .handler(server.getBackendChannelInitializer()) .connect(registeredServer.getServerInfo().getAddress()) - .addListener( - (ChannelFutureListener) - future -> { - if (future.isSuccess()) { - connection = new MinecraftConnection(future.channel(), server); - connection.setAssociation(VelocityServerConnection.this); - future.channel().pipeline().addLast(HANDLER, connection); - - // Kick off the connection process - if (!connection.setActiveSessionHandler(StateRegistry.HANDSHAKE)) { - MinecraftSessionHandler handler = - new LoginSessionHandler(server, VelocityServerConnection.this, result); - connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, handler); - connection.addSessionHandler(StateRegistry.LOGIN, handler); - } - - // Set the connection phase, which may, for future forge (or whatever), be - // determined - // at this point already - connectionPhase = connection.getType().getInitialBackendPhase(); - startHandshake(); - } else { - // Complete the result immediately. ConnectedPlayer will reset the in-flight - // connection. - result.completeExceptionally(future.cause()); - } - }); + .addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + connection = new MinecraftConnection(future.channel(), server); + connection.setAssociation(VelocityServerConnection.this); + future.channel().pipeline().addLast(HANDLER, connection); + + // Kick off the connection process + if (!connection.setActiveSessionHandler(StateRegistry.HANDSHAKE)) { + MinecraftSessionHandler handler = + new LoginSessionHandler(server, VelocityServerConnection.this, result); + connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, handler); + connection.addSessionHandler(StateRegistry.LOGIN, handler); + } + + // Set the connection phase, which may, for future forge (or whatever), be + // determined + // at this point already + connectionPhase = connection.getType().getInitialBackendPhase(); + startHandshake(); + } else { + // Complete the result immediately. ConnectedPlayer will reset the in-flight + // connection. + result.completeExceptionally(future.cause()); + } + }); return result; } @@ -147,20 +144,14 @@ private String createLegacyForwardingAddress(UnaryOperator> prope // BungeeCord IP forwarding is simply a special injection after the "address" in the handshake, // separated by \0 (the null byte). In order, you send the original host, the player's IP, their // UUID (undashed), and if you are in online-mode, their login properties (from Mojang). - StringBuilder data = - new StringBuilder() - .append( - proxyPlayer - .getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) - .getHostString()) - .append('\0') - .append(getPlayerRemoteAddressAsString()) - .append('\0') - .append(proxyPlayer.getGameProfile().getUndashedId()) - .append('\0'); - GENERAL_GSON.toJson( - propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); + StringBuilder data = new StringBuilder().append(proxyPlayer.getVirtualHost().orElseGet(() -> + registeredServer.getServerInfo().getAddress()).getHostString()) + .append('\0') + .append(getPlayerRemoteAddressAsString()) + .append('\0') + .append(proxyPlayer.getGameProfile().getUndashedId()).append('\0'); + GENERAL_GSON.toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), + data); return data.toString(); } @@ -183,9 +174,7 @@ private void startHandshake() { // Initiate the handshake. ProtocolVersion protocolVersion = proxyPlayer.getConnection().getProtocolVersion(); String playerVhost = - proxyPlayer - .getVirtualHost() - .orElseGet(() -> registeredServer.getServerInfo().getAddress()) + proxyPlayer.getVirtualHost().orElseGet(() -> registeredServer.getServerInfo().getAddress()) .getHostString(); Handshake handshake = new Handshake(); @@ -253,7 +242,9 @@ public ConnectedPlayer getPlayer() { return proxyPlayer; } - /** Disconnects from the server. */ + /** + * Disconnects from the server. + */ public void disconnect() { if (connection != null) { gracefulDisconnect = true; @@ -264,9 +255,7 @@ public void disconnect() { @Override public String toString() { - return "[server connection] " - + proxyPlayer.getGameProfile().getName() - + " -> " + return "[server connection] " + proxyPlayer.getGameProfile().getName() + " -> " + registeredServer.getServerInfo().getName(); } @@ -279,7 +268,7 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { * Sends a plugin message to the server through this connection. * * @param identifier the channel ID to use - * @param data the data + * @param data the data * @return whether or not the message was sent */ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { @@ -293,7 +282,9 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { return true; } - /** Indicates that we have completed the plugin process. */ + /** + * Indicates that we have completed the plugin process. + */ public void completeJoin() { if (!hasCompletedJoin) { hasCompletedJoin = true; @@ -322,9 +313,7 @@ public Map getPendingPings() { * @return whether or not the player is online */ public boolean isActive() { - return connection != null - && !connection.isClosed() - && !gracefulDisconnect + return connection != null && !connection.isClosed() && !gracefulDisconnect && proxyPlayer.isActive(); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index f7ec0d8977..8b24f777a9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -74,19 +74,17 @@ public boolean handle(LegacyPing packet) { @Override public boolean handle(LegacyHandshake packet) { - connection.closeWith( - LegacyDisconnect.from( - Component.text( - "Your client is extremely old. Please update to a newer version of Minecraft.", - NamedTextColor.RED))); + connection.closeWith(LegacyDisconnect.from(Component.text( + "Your client is extremely old. Please update to a newer version of Minecraft.", + NamedTextColor.RED))); return true; } @Override public boolean handle(Handshake handshake) { InitialInboundConnection ic = - new InitialInboundConnection( - connection, cleanVhost(handshake.getServerAddress()), handshake); + new InitialInboundConnection(connection, cleanVhost(handshake.getServerAddress()), + handshake); StateRegistry nextState = getStateForProtocol(handshake.getNextStatus()); if (nextState == null) { LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus()); @@ -97,8 +95,8 @@ public boolean handle(Handshake handshake) { switch (nextState) { case STATUS: - connection.setActiveSessionHandler( - StateRegistry.STATUS, new StatusSessionHandler(server, ic)); + connection.setActiveSessionHandler(StateRegistry.STATUS, + new StatusSessionHandler(server, ic)); break; case LOGIN: this.handleLogin(handshake, ic); @@ -125,9 +123,8 @@ public boolean handle(Handshake handshake) { private void handleLogin(Handshake handshake, InitialInboundConnection ic) { if (!ProtocolVersion.isSupported(handshake.getProtocolVersion())) { - ic.disconnectQuietly( - Component.translatable("multiplayer.disconnect.outdated_client") - .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); + ic.disconnectQuietly(Component.translatable("multiplayer.disconnect.outdated_client") + .args(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING))); return; } @@ -150,8 +147,8 @@ private void handleLogin(Handshake handshake, InitialInboundConnection ic) { LoginInboundConnection lic = new LoginInboundConnection(ic); server.getEventManager().fireAndForget(new ConnectionHandshakeEvent(lic)); - connection.setActiveSessionHandler( - StateRegistry.LOGIN, new InitialLoginSessionHandler(server, connection, lic)); + connection.setActiveSessionHandler(StateRegistry.LOGIN, + new InitialLoginSessionHandler(server, connection, lic)); } private ConnectionType getHandshakeConnectionType(Handshake handshake) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index c2d72e00b0..e46ac7d83a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -57,15 +57,15 @@ import org.asynchttpclient.Response; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** Handles authenticating the player to Mojang's servers. */ +/** + * Handles authenticating the player to Mojang's servers. + */ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(InitialLoginSessionHandler.class); - private static final String MOJANG_HASJOINED_URL = - System.getProperty( - "mojang.sessionserver", - "https://sessionserver.mojang.com/session/minecraft/hasJoined") - .concat("?username=%s&serverId=%s"); + private static final String MOJANG_HASJOINED_URL = System.getProperty("mojang.sessionserver", + "https://sessionserver.mojang.com/session/minecraft/hasJoined") + .concat("?username=%s&serverId=%s"); private final VelocityServer server; private final MinecraftConnection mcConnection; @@ -75,15 +75,14 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private LoginState currentState = LoginState.LOGIN_PACKET_EXPECTED; private boolean forceKeyAuthentication; - InitialLoginSessionHandler( - VelocityServer server, MinecraftConnection mcConnection, LoginInboundConnection inbound) { + InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection, + LoginInboundConnection inbound) { this.server = Preconditions.checkNotNull(server, "server"); this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); - this.forceKeyAuthentication = - System.getProperties().containsKey("auth.forceSecureProfiles") - ? Boolean.getBoolean("auth.forceSecureProfiles") - : server.getConfiguration().isForceKeyAuthentication(); + this.forceKeyAuthentication = System.getProperties().containsKey("auth.forceSecureProfiles") + ? Boolean.getBoolean("auth.forceSecureProfiles") + : server.getConfiguration().isForceKeyAuthentication(); } @Override @@ -121,61 +120,45 @@ public boolean handle(ServerLogin packet) { this.login = packet; PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername()); - server - .getEventManager() - .fire(event) - .thenRunAsync( - () -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + server.getEventManager().fire(event).thenRunAsync(() -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - PreLoginComponentResult result = event.getResult(); - Optional disconnectReason = result.getReasonComponent(); - if (disconnectReason.isPresent()) { - // The component is guaranteed to be provided if the connection was denied. - inbound.disconnect(disconnectReason.get()); - return; - } + PreLoginComponentResult result = event.getResult(); + Optional disconnectReason = result.getReasonComponent(); + if (disconnectReason.isPresent()) { + // The component is guaranteed to be provided if the connection was denied. + inbound.disconnect(disconnectReason.get()); + return; + } - inbound.loginEventFired( - () -> { - if (mcConnection.isClosed()) { - // The player was disconnected - return; - } + inbound.loginEventFired(() -> { + if (mcConnection.isClosed()) { + // The player was disconnected + return; + } - mcConnection - .eventLoop() - .execute( - () -> { - if (!result.isForceOfflineMode() - && (server.getConfiguration().isOnlineMode() - || result.isOnlineModeAllowed())) { - // Request encryption. - EncryptionRequest request = generateEncryptionRequest(); - this.verify = Arrays.copyOf(request.getVerifyToken(), 4); - mcConnection.write(request); - this.currentState = LoginState.ENCRYPTION_REQUEST_SENT; - } else { - mcConnection.setActiveSessionHandler( - StateRegistry.LOGIN, - new AuthSessionHandler( - server, - inbound, - GameProfile.forOfflinePlayer(login.getUsername()), - false)); - } - }); - }); - }, - mcConnection.eventLoop()) - .exceptionally( - (ex) -> { - logger.error("Exception in pre-login stage", ex); - return null; - }); + mcConnection.eventLoop().execute(() -> { + if (!result.isForceOfflineMode() + && (server.getConfiguration().isOnlineMode() || result.isOnlineModeAllowed())) { + // Request encryption. + EncryptionRequest request = generateEncryptionRequest(); + this.verify = Arrays.copyOf(request.getVerifyToken(), 4); + mcConnection.write(request); + this.currentState = LoginState.ENCRYPTION_REQUEST_SENT; + } else { + mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, + new AuthSessionHandler(server, inbound, + GameProfile.forOfflinePlayer(login.getUsername()), false)); + } + }); + }); + }, mcConnection.eventLoop()).exceptionally((ex) -> { + logger.error("Exception in pre-login stage", ex); + return null; + }); return true; } @@ -203,8 +186,8 @@ public boolean handle(EncryptionResponse packet) { KeyPair serverKeyPair = server.getServerKeyPair(); if (inbound.getIdentifiedKey() != null) { IdentifiedKey playerKey = inbound.getIdentifiedKey(); - if (!playerKey.verifyDataSignature( - packet.getVerifyToken(), verify, Longs.toByteArray(packet.getSalt()))) { + if (!playerKey.verifyDataSignature(packet.getVerifyToken(), verify, + Longs.toByteArray(packet.getSalt()))) { throw new IllegalStateException("Invalid client public signature."); } } else { @@ -219,9 +202,7 @@ public boolean handle(EncryptionResponse packet) { String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString(); String url = - String.format( - MOJANG_HASJOINED_URL, - urlFormParameterEscaper().escape(login.getUsername()), + String.format(MOJANG_HASJOINED_URL, urlFormParameterEscaper().escape(login.getUsername()), serverId); if (server.getConfiguration().shouldPreventClientProxyConnections()) { @@ -230,67 +211,61 @@ public boolean handle(EncryptionResponse packet) { ListenableFuture hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url).execute(); - hasJoinedResponse.addListener( - () -> { - if (mcConnection.isClosed()) { - // The player disconnected after we authenticated them. - return; - } + hasJoinedResponse.addListener(() -> { + if (mcConnection.isClosed()) { + // The player disconnected after we authenticated them. + return; + } - // Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption - // is enabled. - try { - mcConnection.enableEncryption(decryptedSharedSecret); - } catch (GeneralSecurityException e) { - logger.error("Unable to enable encryption for connection", e); - // At this point, the connection is encrypted, but something's wrong on our side and - // we can't do anything about it. - mcConnection.close(true); - return; - } + // Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption + // is enabled. + try { + mcConnection.enableEncryption(decryptedSharedSecret); + } catch (GeneralSecurityException e) { + logger.error("Unable to enable encryption for connection", e); + // At this point, the connection is encrypted, but something's wrong on our side and + // we can't do anything about it. + mcConnection.close(true); + return; + } - try { - Response profileResponse = hasJoinedResponse.get(); - if (profileResponse.getStatusCode() == 200) { - final GameProfile profile = - GENERAL_GSON.fromJson(profileResponse.getResponseBody(), GameProfile.class); - // Not so fast, now we verify the public key for 1.19.1+ - if (inbound.getIdentifiedKey() != null - && inbound.getIdentifiedKey().getKeyRevision() - == IdentifiedKey.Revision.LINKED_V2 - && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { - IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey(); - if (!key.internalAddHolder(profile.getId())) { - inbound.disconnect( - Component.translatable("multiplayer.disconnect.invalid_public_key")); - } - } - // All went well, initialize the session. - mcConnection.setActiveSessionHandler( - StateRegistry.LOGIN, new AuthSessionHandler(server, inbound, profile, true)); - } else if (profileResponse.getStatusCode() == 204) { - // Apparently an offline-mode user logged onto this online-mode proxy. - inbound.disconnect( - Component.translatable("velocity.error.online-mode-only", NamedTextColor.RED)); - } else { - // Something else went wrong - logger.error( - "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", - profileResponse.getStatusCode(), - login.getUsername(), - playerIp); + try { + Response profileResponse = hasJoinedResponse.get(); + if (profileResponse.getStatusCode() == 200) { + final GameProfile profile = + GENERAL_GSON.fromJson(profileResponse.getResponseBody(), GameProfile.class); + // Not so fast, now we verify the public key for 1.19.1+ + if (inbound.getIdentifiedKey() != null + && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 + && inbound.getIdentifiedKey() instanceof IdentifiedKeyImpl) { + IdentifiedKeyImpl key = (IdentifiedKeyImpl) inbound.getIdentifiedKey(); + if (!key.internalAddHolder(profile.getId())) { inbound.disconnect( - Component.translatable("multiplayer.disconnect.authservers_down")); + Component.translatable("multiplayer.disconnect.invalid_public_key")); } - } catch (ExecutionException e) { - logger.error("Unable to authenticate with Mojang", e); - inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); - } catch (InterruptedException e) { - // not much we can do usefully - Thread.currentThread().interrupt(); } - }, - mcConnection.eventLoop()); + // All went well, initialize the session. + mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, + new AuthSessionHandler(server, inbound, profile, true)); + } else if (profileResponse.getStatusCode() == 204) { + // Apparently an offline-mode user logged onto this online-mode proxy. + inbound.disconnect( + Component.translatable("velocity.error.online-mode-only", NamedTextColor.RED)); + } else { + // Something else went wrong + logger.error( + "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", + profileResponse.getStatusCode(), login.getUsername(), playerIp); + inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); + } + } catch (ExecutionException e) { + logger.error("Unable to authenticate with Mojang", e); + inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down")); + } catch (InterruptedException e) { + // not much we can do usefully + Thread.currentThread().interrupt(); + } + }, mcConnection.eventLoop()); } catch (GeneralSecurityException e) { logger.error("Unable to enable encryption", e); mcConnection.close(true); @@ -321,20 +296,15 @@ public void disconnected() { private void assertState(LoginState expectedState) { if (this.currentState != expectedState) { if (MinecraftDecoder.DEBUG) { - logger.error( - "{} Received an unexpected packet requiring state {}, but we are in {}", - inbound, - expectedState, - this.currentState); + logger.error("{} Received an unexpected packet requiring state {}, but we are in {}", + inbound, expectedState, this.currentState); } mcConnection.close(true); } } private enum LoginState { - LOGIN_PACKET_EXPECTED, - LOGIN_PACKET_RECEIVED, - ENCRYPTION_REQUEST_SENT, + LOGIN_PACKET_EXPECTED, LOGIN_PACKET_RECEIVED, ENCRYPTION_REQUEST_SENT, ENCRYPTION_RESPONSE_RECEIVED } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java index aedd0adbb5..0019ba2033 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java @@ -28,7 +28,9 @@ import java.util.List; import javax.annotation.Nullable; -/** Allows for simple tracking of the phase that the Legacy Forge handshake is in. */ +/** + * Allows for simple tracking of the phase that the Legacy Forge handshake is in. + */ public enum LegacyForgeHandshakeClientPhase implements ClientConnectionPhase { /** @@ -53,8 +55,8 @@ public void onFirstJoin(ConnectedPlayer player) { } @Override - boolean onHandle( - ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, PluginMessage message, + MinecraftConnection backendConn) { // If we stay in this phase, we do nothing because it means the packet wasn't handled. // Returning false indicates this return false; @@ -84,8 +86,8 @@ LegacyForgeHandshakeClientPhase nextPhase() { } @Override - boolean onHandle( - ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, PluginMessage message, + MinecraftConnection backendConn) { // Read the mod list if we haven't already. if (!player.getModInfo().isPresent()) { List mods = LegacyForgeUtil.readModList(message); @@ -152,8 +154,8 @@ public boolean consideredComplete() { } @Override - boolean onHandle( - ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, PluginMessage message, + MinecraftConnection backendConn) { super.onHandle(player, message, backendConn); // just in case the timing is awful @@ -168,22 +170,24 @@ boolean onHandle( } }; - @Nullable private final Integer packetToAdvanceOn; + @Nullable + private final Integer packetToAdvanceOn; /** * Creates an instance of the {@link LegacyForgeHandshakeClientPhase}. * * @param packetToAdvanceOn The ID of the packet discriminator that indicates that the client has - * moved onto a new phase, and as such, Velocity should do so too (inspecting {@link - * #nextPhase()}. A null indicates there is no further phase to transition to. + * moved onto a new phase, and as such, Velocity should do so too + * (inspecting {@link #nextPhase()}. A null indicates there is + * no further phase to transition to. */ LegacyForgeHandshakeClientPhase(Integer packetToAdvanceOn) { this.packetToAdvanceOn = packetToAdvanceOn; } @Override - public final boolean handle( - ConnectedPlayer player, PluginMessage message, VelocityServerConnection server) { + public final boolean handle(ConnectedPlayer player, PluginMessage message, + VelocityServerConnection server) { if (server != null) { MinecraftConnection backendConn = server.getConnection(); if (backendConn != null @@ -206,8 +210,8 @@ public final boolean handle( /** * Handles the phase tasks. * - * @param player The player - * @param message The message to handle + * @param player The player + * @param message The message to handle * @param backendConn The backend connection to write to, if required. * @return true if handled, false otherwise. */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java index 9d0aa6496f..1bca74515b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/ClientConfigData.java @@ -34,12 +34,8 @@ public class ClientConfigData { private final Key[] features; private final String brand; - private ClientConfigData( - @Nullable VelocityResourcePackInfo resourcePackInfo, - DataTag tag, - RegistrySync registry, - Key[] features, - String brand) { + private ClientConfigData(@Nullable VelocityResourcePackInfo resourcePackInfo, DataTag tag, + RegistrySync registry, Key[] features, String brand) { this.resourcePackInfo = resourcePackInfo; this.tag = tag; this.registry = registry; @@ -86,7 +82,8 @@ public static class Builder { private Key[] features; private String brand; - private Builder() {} + private Builder() { + } /** * Clears the builder. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java index 6e55242384..27ec4ba8b8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/Connections.java @@ -17,7 +17,9 @@ package com.velocitypowered.proxy.network; -/** Constants used for the pipeline. */ +/** + * Constants used for the pipeline. + */ public class Connections { public static final String CIPHER_DECODER = "cipher-decoder"; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java index 4d7d97c3b8..2033fcb2a6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -42,7 +42,9 @@ import io.netty.handler.timeout.ReadTimeoutHandler; import java.util.concurrent.TimeUnit; -/** Server channel initializer. */ +/** + * Server channel initializer. + */ @SuppressWarnings("WeakerAccess") public class ServerChannelInitializer extends ChannelInitializer { @@ -54,21 +56,17 @@ public ServerChannelInitializer(final VelocityServer server) { @Override protected void initChannel(final Channel ch) { - ch.pipeline() - .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast( - READ_TIMEOUT, - new ReadTimeoutHandler( - this.server.getConfiguration().getReadTimeout(), TimeUnit.MILLISECONDS)) - .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) + ch.pipeline().addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()).addLast(READ_TIMEOUT, + new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), + TimeUnit.MILLISECONDS)).addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); final MinecraftConnection connection = new MinecraftConnection(ch, this.server); - connection.setActiveSessionHandler( - StateRegistry.HANDSHAKE, new HandshakeSessionHandler(connection, this.server)); + connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, + new HandshakeSessionHandler(connection, this.server)); ch.pipeline().addLast(Connections.HANDLER, connection); if (this.server.getConfiguration().isProxyProtocol()) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index d6a6479582..d50037da33 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -46,20 +46,17 @@ import net.kyori.adventure.nbt.CompoundBinaryTag; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -/** Utilities for writing and reading data in the Minecraft protocol. */ +/** + * Utilities for writing and reading data in the Minecraft protocol. + */ public enum ProtocolUtils { ; private static final GsonComponentSerializer PRE_1_16_SERIALIZER = - GsonComponentSerializer.builder() - .downsampleColors() - .emitLegacyHoverEvent() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) - .build(); - private static final GsonComponentSerializer MODERN_SERIALIZER = - GsonComponentSerializer.builder() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) - .build(); + GsonComponentSerializer.builder().downsampleColors().emitLegacyHoverEvent() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE).build(); + private static final GsonComponentSerializer MODERN_SERIALIZER = GsonComponentSerializer.builder() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE).build(); public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB private static final QuietDecoderException BAD_VARINT_CACHED = @@ -82,9 +79,8 @@ public enum ProtocolUtils { public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); if (read == Integer.MIN_VALUE) { - throw MinecraftDecoder.DEBUG - ? new CorruptedFrameException("Bad VarInt decoded") - : BAD_VARINT_CACHED; + throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") : + BAD_VARINT_CACHED; } return read; } @@ -123,7 +119,7 @@ public static int varIntBytes(int value) { /** * Writes a Minecraft-style VarInt to the specified {@code buf}. * - * @param buf the buffer to read from + * @param buf the buffer to read from * @param value the integer to write */ public static void writeVarInt(ByteBuf buf, int value) { @@ -150,18 +146,12 @@ private static void writeVarIntFull(ByteBuf buf, int value) { int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14); buf.writeMedium(w); } else if ((value & (0xFFFFFFFF << 28)) == 0) { - int w = - (value & 0x7F | 0x80) << 24 - | (((value >>> 7) & 0x7F | 0x80) << 16) - | ((value >>> 14) & 0x7F | 0x80) << 8 - | (value >>> 21); + int w = (value & 0x7F | 0x80) << 24 | (((value >>> 7) & 0x7F | 0x80) << 16) + | ((value >>> 14) & 0x7F | 0x80) << 8 | (value >>> 21); buf.writeInt(w); } else { - int w = - (value & 0x7F | 0x80) << 24 - | ((value >>> 7) & 0x7F | 0x80) << 16 - | ((value >>> 14) & 0x7F | 0x80) << 8 - | ((value >>> 21) & 0x7F | 0x80); + int w = (value & 0x7F | 0x80) << 24 | ((value >>> 7) & 0x7F | 0x80) << 16 + | ((value >>> 14) & 0x7F | 0x80) << 8 | ((value >>> 21) & 0x7F | 0x80); buf.writeInt(w); buf.writeByte(value >>> 28); } @@ -171,7 +161,7 @@ private static void writeVarIntFull(ByteBuf buf, int value) { * Writes the specified {@code value} as a 21-bit Minecraft VarInt to the specified {@code buf}. * The upper 11 bits will be discarded. * - * @param buf the buffer to read from + * @param buf the buffer to read from * @param value the integer to write */ public static void write21BitVarInt(ByteBuf buf, int value) { @@ -203,10 +193,8 @@ private static String readString(ByteBuf buf, int cap, int length) { // consider the length of a UTF-8 character, which can be up to 3 bytes. We do an initial // sanity check and then check again to make sure our optimistic guess was good. checkFrame(length <= cap * 3, "Bad string size (got %s, maximum is %s)", length, cap); - checkFrame( - buf.isReadable(length), - "Trying to read a string that is too long (wanted %s, only have %s)", - length, + checkFrame(buf.isReadable(length), + "Trying to read a string that is too long (wanted %s, only have %s)", length, buf.readableBytes()); String str = buf.toString(buf.readerIndex(), length, StandardCharsets.UTF_8); buf.skipBytes(length); @@ -255,10 +243,8 @@ public static void writeKey(ByteBuf buf, Key key) { public static Key[] readKeyArray(ByteBuf buf) { int length = readVarInt(buf); checkFrame(length >= 0, "Got a negative-length array (%s)", length); - checkFrame( - buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", - length, + checkFrame(buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", length, buf.readableBytes()); Key[] ret = new Key[length]; @@ -271,7 +257,7 @@ public static Key[] readKeyArray(ByteBuf buf) { /** * Writes a standard Mojang Text namespaced:key array to the buffer. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param keys the keys to write */ public static void writeKeyArray(ByteBuf buf, Key[] keys) { @@ -297,10 +283,8 @@ public static byte[] readByteArray(ByteBuf buf, int cap) { int length = readVarInt(buf); checkFrame(length >= 0, "Got a negative-length array (%s)", length); checkFrame(length <= cap, "Bad array size (got %s, maximum is %s)", length, cap); - checkFrame( - buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", - length, + checkFrame(buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", length, buf.readableBytes()); byte[] array = new byte[length]; buf.readBytes(array); @@ -364,7 +348,7 @@ public static UUID readUuidIntArray(ByteBuf buf) { /** * Writes an UUID as an Integer Array to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param uuid the UUID to write */ public static void writeUuidIntArray(ByteBuf buf, UUID uuid) { @@ -377,7 +361,7 @@ public static void writeUuidIntArray(ByteBuf buf, UUID uuid) { /** * Reads a {@link net.kyori.adventure.nbt.CompoundBinaryTag} from the {@code buf}. * - * @param buf the buffer to read from + * @param buf the buffer to read from * @param reader the NBT reader to use * @return {@link net.kyori.adventure.nbt.CompoundBinaryTag} the CompoundTag from the buffer */ @@ -393,7 +377,7 @@ public static CompoundBinaryTag readCompoundTag(ByteBuf buf, BinaryTagIO.Reader /** * Writes a CompoundTag to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param compoundTag the CompoundTag to write */ public static void writeCompoundTag(ByteBuf buf, CompoundBinaryTag compoundTag) { @@ -422,7 +406,7 @@ public static String[] readStringArray(ByteBuf buf) { /** * Writes a String Array to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param stringArray the array to write */ public static void writeStringArray(ByteBuf buf, String[] stringArray) { @@ -441,10 +425,8 @@ public static void writeStringArray(ByteBuf buf, String[] stringArray) { public static int[] readVarIntArray(ByteBuf buf) { int length = readVarInt(buf); checkFrame(length >= 0, "Got a negative-length array (%s)", length); - checkFrame( - buf.isReadable(length), - "Trying to read an array that is too long (wanted %s, only have %s)", - length, + checkFrame(buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", length, buf.readableBytes()); int[] ret = new int[length]; for (int i = 0; i < length; i++) { @@ -456,7 +438,7 @@ public static int[] readVarIntArray(ByteBuf buf) { /** * Writes an Integer Array to the {@code buf}. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param intArray the array to write */ public static void writeVarIntArray(ByteBuf buf, int[] intArray) { @@ -469,7 +451,7 @@ public static void writeVarIntArray(ByteBuf buf, int[] intArray) { /** * Writes a list of {@link com.velocitypowered.api.util.GameProfile.Property} to the buffer. * - * @param buf the buffer to write to + * @param buf the buffer to write to * @param properties the properties to serialize */ public static void writeProperties(ByteBuf buf, List properties) { @@ -523,11 +505,8 @@ public static byte[] readByteArray17(ByteBuf buf) { // No vanilla packet should give a 3 byte packet int len = readExtendedForgeShort(buf); - checkArgument( - len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", - FORGE_MAX_ARRAY_LENGTH, - len); + checkArgument(len <= FORGE_MAX_ARRAY_LENGTH, + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); byte[] ret = new byte[len]; buf.readBytes(ret); @@ -546,11 +525,8 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { // No vanilla packet should give a 3 byte packet int len = readExtendedForgeShort(buf); - checkFrame( - len <= FORGE_MAX_ARRAY_LENGTH, - "Cannot receive array longer than %s (got %s bytes)", - FORGE_MAX_ARRAY_LENGTH, - len); + checkFrame(len <= FORGE_MAX_ARRAY_LENGTH, "Cannot receive array longer than %s (got %s bytes)", + FORGE_MAX_ARRAY_LENGTH, len); return buf.readRetainedSlice(len); } @@ -558,22 +534,17 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { /** * Writes an byte array for legacy version 1.7 to the specified {@code buf} * - * @param b array - * @param buf buf + * @param b array + * @param buf buf * @param allowExtended forge */ public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { - checkFrame( - b.length <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", - FORGE_MAX_ARRAY_LENGTH, - b.length); + checkFrame(b.length <= FORGE_MAX_ARRAY_LENGTH, + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, b.length); } else { - checkFrame( - b.length <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", - b.length); + checkFrame(b.length <= Short.MAX_VALUE, + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -586,22 +557,18 @@ public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended /** * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf} * - * @param b array - * @param buf buf + * @param b array + * @param buf buf * @param allowExtended forge */ public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { - checkFrame( - b.readableBytes() <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", - FORGE_MAX_ARRAY_LENGTH, + checkFrame(b.readableBytes() <= FORGE_MAX_ARRAY_LENGTH, + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, b.readableBytes()); } else { - checkFrame( - b.readableBytes() <= Short.MAX_VALUE, - "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", - b.readableBytes()); + checkFrame(b.readableBytes() <= Short.MAX_VALUE, + "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.readableBytes()); } // Write a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for // Forge only) @@ -630,7 +597,7 @@ public static int readExtendedForgeShort(ByteBuf buf) { /** * Writes a Minecraft-style extended short to the specified {@code buf}. * - * @param buf buf to write + * @param buf buf to write * @param toWrite the extended short to write */ public static void writeExtendedForgeShort(ByteBuf buf, int toWrite) { @@ -673,7 +640,7 @@ public static GsonComponentSerializer getJsonChatSerializer(ProtocolVersion vers /** * Writes a players {@link IdentifiedKey} to the buffer. * - * @param buf the buffer + * @param buf the buffer * @param playerKey the key to write */ public static void writePlayerKey(ByteBuf buf, IdentifiedKey playerKey) { @@ -693,15 +660,15 @@ public static IdentifiedKey readPlayerKey(ProtocolVersion version, ByteBuf buf) byte[] key = ProtocolUtils.readByteArray(buf); byte[] signature = ProtocolUtils.readByteArray(buf, 4096); IdentifiedKey.Revision revision = - version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 - ? IdentifiedKey.Revision.GENERIC_V1 + version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; return new IdentifiedKeyImpl(revision, key, expiry, signature); } - /** Represents the direction in which a packet flows. */ + /** + * Represents the direction in which a packet flows. + */ public enum Direction { - SERVERBOUND, - CLIENTBOUND + SERVERBOUND, CLIENTBOUND } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index 8ad02a2b2e..afde1f7d13 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -77,8 +77,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) if (this.serverRegistry.containsPacket(((MinecraftPacket) msg))) { MinecraftPacket packet = (MinecraftPacket) msg; - if (packet instanceof ResourcePackResponse - || packet instanceof PluginMessage) { + if (packet instanceof ResourcePackResponse || packet instanceof PluginMessage) { ctx.write(msg, promise); return; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index 34e8d73325..f7138921f9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -37,17 +37,12 @@ public class ClientSettings implements MinecraftPacket { private boolean chatFilteringEnabled; // Added in 1.17 private boolean clientListingAllowed; // Added in 1.18, overwrites server-list "anonymous" mode - public ClientSettings() {} - - public ClientSettings( - String locale, - byte viewDistance, - int chatVisibility, - boolean chatColors, - short skinParts, - int mainHand, - boolean chatFilteringEnabled, - boolean clientListingAllowed) { + public ClientSettings() { + } + + public ClientSettings(String locale, byte viewDistance, int chatVisibility, boolean chatColors, + short skinParts, int mainHand, boolean chatFilteringEnabled, + boolean clientListingAllowed) { this.locale = locale; this.viewDistance = viewDistance; this.chatVisibility = chatVisibility; @@ -126,25 +121,10 @@ public void setClientListingAllowed(boolean clientListingAllowed) { @Override public String toString() { - return "ClientSettings{" - + "locale='" - + locale - + '\'' - + ", viewDistance=" - + viewDistance - + ", chatVisibility=" - + chatVisibility - + ", chatColors=" - + chatColors - + ", skinParts=" - + skinParts - + ", mainHand=" - + mainHand - + ", chatFilteringEnabled=" - + chatFilteringEnabled - + ", clientListingAllowed=" - + clientListingAllowed - + '}'; + return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance + + ", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" + + skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + chatFilteringEnabled + + ", clientListingAllowed=" + clientListingAllowed + '}'; } @Override @@ -216,12 +196,9 @@ public boolean equals(@Nullable final Object o) { return false; } final ClientSettings that = (ClientSettings) o; - return viewDistance == that.viewDistance - && chatVisibility == that.chatVisibility - && chatColors == that.chatColors - && difficulty == that.difficulty - && skinParts == that.skinParts - && mainHand == that.mainHand + return viewDistance == that.viewDistance && chatVisibility == that.chatVisibility + && chatColors == that.chatColors && difficulty == that.difficulty + && skinParts == that.skinParts && mainHand == that.mainHand && chatFilteringEnabled == that.chatFilteringEnabled && clientListingAllowed == that.clientListingAllowed && Objects.equals(locale, that.locale); @@ -229,15 +206,7 @@ public boolean equals(@Nullable final Object o) { @Override public int hashCode() { - return Objects.hash( - locale, - viewDistance, - chatVisibility, - chatColors, - difficulty, - skinParts, - mainHand, - chatFilteringEnabled, - clientListingAllowed); + return Objects.hash(locale, viewDistance, chatVisibility, chatColors, difficulty, skinParts, + mainHand, chatFilteringEnabled, clientListingAllowed); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index fdbfbb65bb..938d1190aa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -186,53 +186,16 @@ public CompoundBinaryTag getRegistry() { @Override public String toString() { - return "JoinGame{" - + "entityId=" - + entityId - + ", gamemode=" - + gamemode - + ", dimension=" - + dimension - + ", partialHashedSeed=" - + partialHashedSeed - + ", difficulty=" - + difficulty - + ", isHardcore=" - + isHardcore - + ", maxPlayers=" - + maxPlayers - + ", levelType='" - + levelType - + '\'' - + ", viewDistance=" - + viewDistance - + ", reducedDebugInfo=" - + reducedDebugInfo - + ", showRespawnScreen=" - + showRespawnScreen - + ", doLimitedCrafting=" - + doLimitedCrafting - + ", levelNames=" - + levelNames - + ", registry='" - + registry - + '\'' - + ", dimensionInfo='" - + dimensionInfo - + '\'' - + ", currentDimensionData='" - + currentDimensionData - + '\'' - + ", previousGamemode=" - + previousGamemode - + ", simulationDistance=" - + simulationDistance - + ", lastDeathPosition='" - + lastDeathPosition - + '\'' - + ", portalCooldown=" - + portalCooldown - + '}'; + return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" + + dimension + ", partialHashedSeed=" + partialHashedSeed + ", difficulty=" + difficulty + + ", isHardcore=" + isHardcore + ", maxPlayers=" + maxPlayers + ", levelType='" + levelType + + '\'' + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo + + ", showRespawnScreen=" + showRespawnScreen + ", doLimitedCrafting=" + doLimitedCrafting + + ", levelNames=" + levelNames + ", registry='" + registry + '\'' + ", dimensionInfo='" + + dimensionInfo + '\'' + ", currentDimensionData='" + currentDimensionData + '\'' + + ", previousGamemode=" + previousGamemode + ", simulationDistance=" + simulationDistance + + ", lastDeathPosition='" + lastDeathPosition + '\'' + ", portalCooldown=" + portalCooldown + + '}'; } @Override @@ -360,8 +323,9 @@ private void decode1202Up(ByteBuf buf, ProtocolVersion version) { this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug); // optional death location - if (buf.readBoolean()) + if (buf.readBoolean()) { this.lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong()); + } this.portalCooldown = ProtocolUtils.readVarInt(buf); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java index 7b9a26ed2b..1f79410045 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledged.java @@ -26,16 +26,18 @@ public class LoginAcknowledged implements MinecraftPacket { @Override - public void decode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + } @Override - public void encode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + } @Override - public int expectedMaxLength( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java index e63c979234..c80b97c162 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequest.java @@ -109,10 +109,8 @@ public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVer public VelocityResourcePackInfo toServerPromptedPack() { ResourcePackInfo.Builder builder = - new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url)) - .setPrompt(prompt) - .setShouldForce(isRequired) - .setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url)).setPrompt(prompt) + .setShouldForce(isRequired).setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); if (hash != null && !hash.isEmpty()) { if (PLAUSIBLE_SHA1_HASH.matcher(hash).matches()) { @@ -129,18 +127,7 @@ public boolean handle(MinecraftSessionHandler handler) { @Override public String toString() { - return "ResourcePackRequest{" - + "url='" - + url - + '\'' - + ", hash='" - + hash - + '\'' - + ", isRequired=" - + isRequired - + ", prompt='" - + prompt - + '\'' - + '}'; + return "ResourcePackRequest{" + "url='" + url + '\'' + ", hash='" + hash + '\'' + + ", isRequired=" + isRequired + ", prompt='" + prompt + '\'' + '}'; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java index 2ad44eed72..ba8d9ae2c9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java @@ -39,7 +39,8 @@ public class ServerLogin implements MinecraftPacket { private @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3 private @Nullable UUID holderUuid; // Used for key revision 2 - public ServerLogin() {} + public ServerLogin() { + } public ServerLogin(String username, @Nullable IdentifiedKey playerKey) { this.username = Preconditions.checkNotNull(username, "username"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java index 0773540b41..de2a5047c5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeatures.java @@ -45,14 +45,14 @@ public Key[] getActiveFeatures() { } @Override - public void decode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { activeFeatures = ProtocolUtils.readKeyArray(buf); } @Override - public void encode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { ProtocolUtils.writeKeyArray(buf, activeFeatures); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java index 59aed0c139..866819b487 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdate.java @@ -26,16 +26,18 @@ public class FinishedUpdate implements MinecraftPacket { @Override - public void decode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + } @Override - public void encode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + } @Override - public int expectedMaxLength( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java index 9ae5d1fb9e..74c275401b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySync.java @@ -32,14 +32,14 @@ public RegistrySync() { // NBT change in 1.20.2 makes it difficult to parse this packet. @Override - public void decode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { this.replace(buf.readRetainedSlice(buf.readableBytes())); } @Override - public void encode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { buf.writeBytes(content()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java index aff9f87a9a..d1c25fa27c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdate.java @@ -26,16 +26,18 @@ public class StartUpdate implements MinecraftPacket { @Override - public void decode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + } @Override - public void encode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {} + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + } @Override - public int expectedMaxLength( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java index 90061b4797..79b432158d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdate.java @@ -39,8 +39,8 @@ public TagsUpdate() { } @Override - public void decode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { ImmutableMap.Builder> builder = ImmutableMap.builder(); int size = ProtocolUtils.readVarInt(buf); for (int i = 0; i < size; i++) { @@ -60,8 +60,8 @@ public void decode( } @Override - public void encode( - ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { ProtocolUtils.writeVarInt(buf, tags.size()); for (Map.Entry> entry : tags.entrySet()) { ProtocolUtils.writeString(buf, entry.getKey()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index f9a64359f7..6b72020764 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -43,11 +43,8 @@ public class PingSessionHandler implements MinecraftSessionHandler { private final ProtocolVersion version; private boolean completed = false; - PingSessionHandler( - CompletableFuture result, - RegisteredServer server, - MinecraftConnection connection, - ProtocolVersion version) { + PingSessionHandler(CompletableFuture result, RegisteredServer server, + MinecraftConnection connection, ProtocolVersion version) { this.result = result; this.server = server; this.connection = connection; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index 22bc33f203..70cbcec588 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -60,7 +60,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** Represents a server registered on the proxy. */ +/** + * Represents a server registered on the proxy. + */ public class VelocityRegisteredServer implements RegisteredServer, ForwardingAudience { private final @Nullable VelocityServer server; @@ -96,7 +98,7 @@ public CompletableFuture ping() { * Pings the specified server using the specified event {@code loop}, claiming to be {@code * version}. * - * @param loop the event loop to use + * @param loop the event loop to use * @param pingOptions the options to apply to this ping * @return the server list ping response */ @@ -105,50 +107,30 @@ public CompletableFuture ping(@Nullable EventLoop loop, PingOptions throw new IllegalStateException("No Velocity proxy instance available"); } CompletableFuture pingFuture = new CompletableFuture<>(); - server - .createBootstrap(loop) - .handler( - new ChannelInitializer() { - @Override - protected void initChannel(Channel ch) throws Exception { - ch.pipeline() - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) - .addLast( - READ_TIMEOUT, - new ReadTimeoutHandler( - pingOptions.getTimeout() == 0 - ? server.getConfiguration().getReadTimeout() - : pingOptions.getTimeout(), - TimeUnit.MILLISECONDS)) - .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) - .addLast( - MINECRAFT_DECODER, - new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) - .addLast( - MINECRAFT_ENCODER, - new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); - - ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); - } - }) - .connect(serverInfo.getAddress()) - .addListener( - (ChannelFutureListener) - future -> { - if (future.isSuccess()) { - MinecraftConnection conn = - future.channel().pipeline().get(MinecraftConnection.class); - conn.setActiveSessionHandler( - StateRegistry.HANDSHAKE, - new PingSessionHandler( - pingFuture, - VelocityRegisteredServer.this, - conn, - pingOptions.getProtocolVersion())); - } else { - pingFuture.completeExceptionally(future.cause()); - } - }); + server.createBootstrap(loop).handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline().addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(READ_TIMEOUT, new ReadTimeoutHandler( + pingOptions.getTimeout() == 0 + ? server.getConfiguration().getReadTimeout() + : pingOptions.getTimeout(), TimeUnit.MILLISECONDS)) + .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) + .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) + .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); + + ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); + } + }).connect(serverInfo.getAddress()).addListener((ChannelFutureListener) future -> { + if (future.isSuccess()) { + MinecraftConnection conn = future.channel().pipeline().get(MinecraftConnection.class); + conn.setActiveSessionHandler(StateRegistry.HANDSHAKE, + new PingSessionHandler(pingFuture, VelocityRegisteredServer.this, conn, + pingOptions.getProtocolVersion())); + } else { + pingFuture.completeExceptionally(future.cause()); + } + }); return pingFuture; } @@ -170,14 +152,13 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, byte[] data) { * afterwards. * * @param identifier the channel ID to use - * @param data the data + * @param data the data * @return whether or not the message was sent */ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { for (ConnectedPlayer player : players.values()) { VelocityServerConnection serverConnection = player.getConnectedServer(); - if (serverConnection != null - && serverConnection.getConnection() != null + if (serverConnection != null && serverConnection.getConnection() != null && serverConnection.getServer() == this) { return serverConnection.sendPluginMessage(identifier, data); } From b789257848b39d6c8fbeba87af614310e60638ea Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 3 Oct 2023 15:27:15 +0100 Subject: [PATCH 35/41] Allow serverbound config packets to pass through freely --- .gitignore | 2 ++ .../proxy/protocol/netty/PlayPacketQueueHandler.java | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index f90c93da90..97eb7c9e00 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,8 @@ gradle-app.setting logs/ /velocity.toml /forwarding.secret +forwarding.secret +velocity.toml server-icon.png /bin/ run/ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index afde1f7d13..9736443319 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -21,8 +21,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.packet.PluginMessage; -import com.velocitypowered.proxy.protocol.packet.ResourcePackResponse; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPromise; @@ -76,11 +74,8 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) } if (this.serverRegistry.containsPacket(((MinecraftPacket) msg))) { - MinecraftPacket packet = (MinecraftPacket) msg; - if (packet instanceof ResourcePackResponse || packet instanceof PluginMessage) { - ctx.write(msg, promise); - return; - } + ctx.write(msg, promise); + return; } // Otherwise, queue the packet From 1b07659916a647fd6225bed16f108d595a747670 Mon Sep 17 00:00:00 2001 From: Paul19988 Date: Tue, 3 Oct 2023 15:31:31 +0100 Subject: [PATCH 36/41] incorporate changes recommended by Wesley1808 --- .../proxy/connection/MinecraftConnection.java | 8 +++++--- .../proxy/protocol/netty/MinecraftEncoder.java | 4 ++++ .../protocol/netty/PlayPacketQueueHandler.java | 18 +++++------------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index b23b217501..bac5cc7802 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -363,13 +363,15 @@ public void setState(StateRegistry state) { ensureInEventLoop(); this.state = state; - this.channel.pipeline().get(MinecraftEncoder.class).setState(state); - this.channel.pipeline().get(MinecraftDecoder.class).setState(state); + MinecraftEncoder encoder = channel.pipeline().get(MinecraftEncoder.class); + MinecraftDecoder decoder = channel.pipeline().get(MinecraftDecoder.class); + encoder.setState(state); + decoder.setState(state); if (state == StateRegistry.CONFIG) { // Activate the play packet queue this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE, - new PlayPacketQueueHandler(this.protocolVersion)); + new PlayPacketQueueHandler(this.protocolVersion, encoder.getDirection())); } else if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) != null) { // Remove the queue this.channel.pipeline().remove(Connections.PLAY_PACKET_QUEUE); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java index 313b7858d2..7133f1d26a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java @@ -62,4 +62,8 @@ public void setState(StateRegistry state) { this.state = state; this.setProtocolVersion(registry.version); } + + public ProtocolUtils.Direction getDirection() { + return direction; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java index 9736443319..612de451e9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueHandler.java @@ -42,8 +42,7 @@ */ public class PlayPacketQueueHandler extends ChannelDuplexHandler { - private final StateRegistry.PacketRegistry.ProtocolRegistry clientRegistry; - private final StateRegistry.PacketRegistry.ProtocolRegistry serverRegistry; + private final StateRegistry.PacketRegistry.ProtocolRegistry registry; private final Queue queue = PlatformDependent.newMpscQueue(); /** @@ -51,11 +50,9 @@ public class PlayPacketQueueHandler extends ChannelDuplexHandler { * * @param version the protocol version */ - public PlayPacketQueueHandler(ProtocolVersion version) { - this.clientRegistry = - StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.CLIENTBOUND, version); - this.serverRegistry = - StateRegistry.CONFIG.getProtocolRegistry(ProtocolUtils.Direction.SERVERBOUND, version); + public PlayPacketQueueHandler(ProtocolVersion version, ProtocolUtils.Direction direction) { + this.registry = + StateRegistry.CONFIG.getProtocolRegistry(direction, version); } @Override @@ -68,12 +65,7 @@ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) // If the packet exists in the CONFIG state, we want to always // ensure that it gets sent out to the client - if (this.clientRegistry.containsPacket(((MinecraftPacket) msg))) { - ctx.write(msg, promise); - return; - } - - if (this.serverRegistry.containsPacket(((MinecraftPacket) msg))) { + if (this.registry.containsPacket(((MinecraftPacket) msg))) { ctx.write(msg, promise); return; } From c076f0498c282142a819f7cc45126181f1f09118 Mon Sep 17 00:00:00 2001 From: Gero Date: Fri, 6 Oct 2023 10:56:02 +0200 Subject: [PATCH 37/41] Support switch to config state by backend server --- .../proxy/connection/MinecraftConnection.java | 20 ++++++++++++------ .../backend/BackendPlaySessionHandler.java | 21 +++++++++++++++++++ .../backend/ConfigSessionHandler.java | 8 +++++-- .../client/ClientPlaySessionHandler.java | 14 +++++++++++++ 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index bac5cc7802..39c909ed78 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -363,21 +363,29 @@ public void setState(StateRegistry state) { ensureInEventLoop(); this.state = state; - MinecraftEncoder encoder = channel.pipeline().get(MinecraftEncoder.class); - MinecraftDecoder decoder = channel.pipeline().get(MinecraftDecoder.class); - encoder.setState(state); - decoder.setState(state); + this.channel.pipeline().get(MinecraftEncoder.class).setState(state); + this.channel.pipeline().get(MinecraftDecoder.class).setState(state); if (state == StateRegistry.CONFIG) { // Activate the play packet queue - this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE, - new PlayPacketQueueHandler(this.protocolVersion, encoder.getDirection())); + addPlayPacketQueueHandler(); } else if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) != null) { // Remove the queue this.channel.pipeline().remove(Connections.PLAY_PACKET_QUEUE); } } + /** + * Adds the play packet queue handler. + */ + public void addPlayPacketQueueHandler() { + if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE) == null) { + this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE, + new PlayPacketQueueHandler(this.protocolVersion, + channel.pipeline().get(MinecraftEncoder.class).getDirection())); + } + } + public ProtocolVersion getProtocolVersion() { return protocolVersion; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 63a480afcf..d30976f5ad 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -39,6 +39,8 @@ import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo; import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.BossBar; import com.velocitypowered.proxy.protocol.packet.ClientSettings; @@ -52,12 +54,14 @@ import com.velocitypowered.proxy.protocol.packet.ServerData; import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfo; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.timeout.ReadTimeoutException; +import java.util.concurrent.CompletableFuture; import java.util.regex.Pattern; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -119,6 +123,23 @@ public boolean beforeHandle() { return false; } + @Override + public boolean handle(StartUpdate packet) { + MinecraftConnection smc = serverConn.ensureConnected(); + smc.setAutoReading(false); + CompletableFuture.runAsync(() -> { + playerConnection.write(packet); + playerConnection.getChannel().pipeline() + .get(MinecraftEncoder.class).setState(StateRegistry.CONFIG); + // Make sure we don't send any play packets to the player after update start + playerConnection.addPlayPacketQueueHandler(); + }, playerConnection.eventLoop()).exceptionally((ex) -> { + logger.error("Error switching player connection to config state:", ex); + return null; + }); + return true; + } + @Override public boolean handle(KeepAlive packet) { serverConn.getPendingPings().put(packet.getRandomId(), System.currentTimeMillis()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 713207f7fa..6614480c25 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -152,8 +152,12 @@ public boolean handle(FinishedUpdate packet) { smc.setAutoReading(false); configHandler.handleBackendFinishUpdate(serverConn).thenAcceptAsync((unused) -> { - smc.setActiveSessionHandler(StateRegistry.PLAY, - new TransitionSessionHandler(server, serverConn, resultFuture)); + if (serverConn == serverConn.getPlayer().getConnectedServer()) { + smc.setActiveSessionHandler(StateRegistry.PLAY); + } else { + smc.setActiveSessionHandler(StateRegistry.PLAY, + new TransitionSessionHandler(server, serverConn, resultFuture)); + } smc.setAutoReading(true); }, smc.eventLoop()); return true; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 45fc2ced05..f2058977d5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -385,6 +385,18 @@ public boolean handle(ResourcePackResponse packet) { public boolean handle(FinishedUpdate packet) { // Complete client switch player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG); + VelocityServerConnection serverConnection = player.getConnectedServer(); + if (serverConnection != null) { + MinecraftConnection smc = serverConnection.ensureConnected(); + CompletableFuture.runAsync(() -> { + smc.write(packet); + smc.setActiveSessionHandler(StateRegistry.CONFIG); + smc.setAutoReading(true); + }, smc.eventLoop()).exceptionally((ex) -> { + logger.error("Error forwarding config state acknowledgement to server:", ex); + return null; + }); + } configSwitchFuture.complete(null); return true; } @@ -472,6 +484,8 @@ public CompletableFuture doSwitch() { player.clearHeaderAndFooter(); } + spawned = false; + player.getConnection().write(new StartUpdate()); return configSwitchFuture; From fadf8396b887dc7520fea5a18c21868d8038fa85 Mon Sep 17 00:00:00 2001 From: Gero Date: Sat, 7 Oct 2023 15:13:10 +0200 Subject: [PATCH 38/41] Reapply resource pack after config state --- .../proxy/connection/backend/ConfigSessionHandler.java | 10 +++++++++- .../proxy/connection/client/ConnectedPlayer.java | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 6614480c25..0fbae4809b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -59,6 +59,8 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { private final VelocityServerConnection serverConn; private final CompletableFuture resultFuture; + private ResourcePackInfo resourcePackToApply; + private State state; /** @@ -77,7 +79,9 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { } @Override - public void deactivated() { + public void activated() { + resourcePackToApply = serverConn.getPlayer().getAppliedResourcePack(); + serverConn.getPlayer().clearAppliedResourcePack(); } @Override @@ -126,6 +130,7 @@ public boolean handle(ResourcePackRequest packet) { ResourcePackInfo.Origin.DOWNSTREAM_SERVER); } + resourcePackToApply = null; serverConn.getPlayer().queueResourcePack(toSend); } else if (serverConn.getConnection() != null) { serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), @@ -158,6 +163,9 @@ public boolean handle(FinishedUpdate packet) { smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture)); } + if (serverConn.getPlayer().getAppliedResourcePack() == null && resourcePackToApply != null) { + serverConn.getPlayer().queueResourcePack(resourcePackToApply); + } smc.setAutoReading(true); }, smc.eventLoop()); return true; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 4bc2fbb703..bdd6ddb79e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -1027,6 +1027,13 @@ && getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { return pendingResourcePack; } + /** + * Clears the applied resource pack field. + */ + public void clearAppliedResourcePack() { + appliedResourcePack = null; + } + /** * Processes a client response to a sent resource-pack. */ From f71bcfa32cb225de97d9b7f26afd9811530c1342 Mon Sep 17 00:00:00 2001 From: Gero Date: Sat, 7 Oct 2023 21:39:45 +0200 Subject: [PATCH 39/41] Add play packet queue after sending StartUpdate --- .../backend/BackendPlaySessionHandler.java | 17 ++------------- .../client/ClientPlaySessionHandler.java | 3 +-- .../connection/client/ConnectedPlayer.java | 21 ++++++++++++++++++- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index d30976f5ad..352bcd03b6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -39,8 +39,6 @@ import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo; import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.StateRegistry; -import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.BossBar; import com.velocitypowered.proxy.protocol.packet.ClientSettings; @@ -61,7 +59,6 @@ import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.timeout.ReadTimeoutException; -import java.util.concurrent.CompletableFuture; import java.util.regex.Pattern; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -125,18 +122,8 @@ public boolean beforeHandle() { @Override public boolean handle(StartUpdate packet) { - MinecraftConnection smc = serverConn.ensureConnected(); - smc.setAutoReading(false); - CompletableFuture.runAsync(() -> { - playerConnection.write(packet); - playerConnection.getChannel().pipeline() - .get(MinecraftEncoder.class).setState(StateRegistry.CONFIG); - // Make sure we don't send any play packets to the player after update start - playerConnection.addPlayPacketQueueHandler(); - }, playerConnection.eventLoop()).exceptionally((ex) -> { - logger.error("Error switching player connection to config state:", ex); - return null; - }); + serverConn.ensureConnected().setAutoReading(false); + serverConn.getPlayer().switchToConfigState(); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index f2058977d5..5b35cd25f3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -65,7 +65,6 @@ import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChat; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommand; import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdate; -import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.util.CharacterUtil; @@ -486,7 +485,7 @@ public CompletableFuture doSwitch() { spawned = false; - player.getConnection().write(new StartUpdate()); + player.switchToConfigState(); return configSwitchFuture; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index bdd6ddb79e..7e495b386c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -59,6 +59,7 @@ import com.velocitypowered.proxy.connection.util.VelocityInboundConnection; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.packet.ClientSettings; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; @@ -69,6 +70,7 @@ import com.velocitypowered.proxy.protocol.packet.chat.ChatType; import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderFactory; import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChat; +import com.velocitypowered.proxy.protocol.packet.config.StartUpdate; import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.server.VelocityRegisteredServer; import com.velocitypowered.proxy.tablist.InternalTabList; @@ -1092,13 +1094,30 @@ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status statu * by Velocity as it will not match the ID last sent by the server. */ public void sendKeepAlive() { - if (connection.getState() == StateRegistry.PLAY) { + if (connection.getState() == StateRegistry.PLAY + || connection.getState() == StateRegistry.CONFIG) { KeepAlive keepAlive = new KeepAlive(); keepAlive.setRandomId(ThreadLocalRandom.current().nextLong()); connection.write(keepAlive); } } + /** + * Switches the connection to the client into config state. + */ + public void switchToConfigState() { + CompletableFuture.runAsync(() -> { + connection.write(new StartUpdate()); + connection.getChannel().pipeline() + .get(MinecraftEncoder.class).setState(StateRegistry.CONFIG); + // Make sure we don't send any play packets to the player after update start + connection.addPlayPacketQueueHandler(); + }, connection.eventLoop()).exceptionally((ex) -> { + logger.error("Error switching player connection to config state:", ex); + return null; + }); + } + /** * Gets the current "phase" of the connection, mostly used for tracking modded negotiation for * legacy forge servers and provides methods for performing phase specific actions. From 3f6e69bb19f3b10e0b9e019e43c78791281c14ab Mon Sep 17 00:00:00 2001 From: Gero Date: Sat, 7 Oct 2023 23:31:24 +0200 Subject: [PATCH 40/41] Make sure to decode packets with the correct state registry --- .../connection/backend/BackendPlaySessionHandler.java | 7 ++++++- .../proxy/connection/backend/ConfigSessionHandler.java | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 352bcd03b6..8e2be693b1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -39,6 +39,8 @@ import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo; import com.velocitypowered.proxy.connection.util.ConnectionMessages; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.packet.AvailableCommands; import com.velocitypowered.proxy.protocol.packet.BossBar; import com.velocitypowered.proxy.protocol.packet.ClientSettings; @@ -122,7 +124,10 @@ public boolean beforeHandle() { @Override public boolean handle(StartUpdate packet) { - serverConn.ensureConnected().setAutoReading(false); + MinecraftConnection smc = serverConn.ensureConnected(); + smc.setAutoReading(false); + // Even when not auto reading messages are still decoded. Decode them with the correct state + smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.CONFIG); serverConn.getPlayer().switchToConfigState(); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 0fbae4809b..d84ae49cee 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -30,6 +30,7 @@ import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.packet.Disconnect; import com.velocitypowered.proxy.protocol.packet.KeepAlive; import com.velocitypowered.proxy.protocol.packet.PluginMessage; @@ -156,6 +157,8 @@ public boolean handle(FinishedUpdate packet) { .getActiveSessionHandler(); smc.setAutoReading(false); + // Even when not auto reading messages are still decoded. Decode them with the correct state + smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.PLAY); configHandler.handleBackendFinishUpdate(serverConn).thenAcceptAsync((unused) -> { if (serverConn == serverConn.getPlayer().getConnectedServer()) { smc.setActiveSessionHandler(StateRegistry.PLAY); From 31807642d8e0ccb785e4c760324acccc57de5d78 Mon Sep 17 00:00:00 2001 From: bluegreensea Date: Tue, 10 Oct 2023 15:12:51 +0800 Subject: [PATCH 41/41] Revert nearly all reformatting --- .../proxy/connection/MinecraftConnection.java | 15 +- .../backend/BackendPlaySessionHandler.java | 37 +++-- .../backend/LoginSessionHandler.java | 27 ++-- .../backend/TransitionSessionHandler.java | 25 +-- .../backend/VelocityServerConnection.java | 11 +- .../connection/client/AuthSessionHandler.java | 14 +- .../client/ClientPlaySessionHandler.java | 36 +++-- .../connection/client/ConnectedPlayer.java | 147 +++++++++--------- .../client/HandshakeSessionHandler.java | 11 +- .../client/InitialLoginSessionHandler.java | 29 ++-- .../LegacyForgeHandshakeClientPhase.java | 24 +-- .../network/ServerChannelInitializer.java | 9 +- .../proxy/protocol/ProtocolUtils.java | 32 ++-- .../proxy/protocol/StateRegistry.java | 84 ++++------ .../proxy/protocol/packet/ClientSettings.java | 24 ++- .../proxy/protocol/packet/ServerLogin.java | 4 +- .../proxy/server/PingSessionHandler.java | 6 +- .../server/VelocityRegisteredServer.java | 4 +- 18 files changed, 279 insertions(+), 260 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 39c909ed78..bb0c4db725 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -153,8 +153,8 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception } } else if (msg instanceof HAProxyMessage) { HAProxyMessage proxyMessage = (HAProxyMessage) msg; - this.remoteAddress = - new InetSocketAddress(proxyMessage.sourceAddress(), proxyMessage.sourcePort()); + this.remoteAddress = new InetSocketAddress(proxyMessage.sourceAddress(), + proxyMessage.sourcePort()); } else if (msg instanceof ByteBuf) { activeSessionHandler.handleUnknown((ByteBuf) msg); } @@ -266,8 +266,7 @@ public void closeWith(Object msg) { && this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_7_2) >= 0; if (is17 && this.getState() != StateRegistry.STATUS) { channel.eventLoop().execute(() -> { - // 1.7.x versions have a race condition with switching protocol states, so just - // explicitly + // 1.7.x versions have a race condition with switching protocol states, so just explicitly // close the connection after a short while. this.setAutoReading(false); channel.eventLoop().schedule(() -> { @@ -501,13 +500,13 @@ public void setCompressionThreshold(int threshold) { final ChannelHandler removedEncoder = channel.pipeline().remove(COMPRESSION_ENCODER); if (removedDecoder != null && removedEncoder != null) { - channel.pipeline() - .addBefore(MINECRAFT_DECODER, FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE); + channel.pipeline().addBefore(MINECRAFT_DECODER, FRAME_ENCODER, + MinecraftVarintLengthEncoder.INSTANCE); channel.pipeline().fireUserEventTriggered(VelocityConnectionEvent.COMPRESSION_DISABLED); } } else { - MinecraftCompressDecoder decoder = - (MinecraftCompressDecoder) channel.pipeline().get(COMPRESSION_DECODER); + MinecraftCompressDecoder decoder = (MinecraftCompressDecoder) channel.pipeline() + .get(COMPRESSION_DECODER); MinecraftCompressorAndLengthEncoder encoder = (MinecraftCompressorAndLengthEncoder) channel.pipeline().get(COMPRESSION_ENCODER); if (decoder != null && encoder != null) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 8e2be693b1..ffa0c83919 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -97,8 +97,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { } this.playerSessionHandler = (ClientPlaySessionHandler) psh; - this.bungeecordMessageResponder = - new BungeeCordMessageResponder(server, serverConn.getPlayer()); + this.bungeecordMessageResponder = new BungeeCordMessageResponder(server, + serverConn.getPlayer()); } @Override @@ -108,7 +108,8 @@ public void activated() { if (server.getConfiguration().isBungeePluginChannelEnabled()) { MinecraftConnection serverMc = serverConn.ensureConnected(); serverMc.write(PluginMessageUtil.constructChannelsPacket(serverMc.getProtocolVersion(), - ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion())))); + ImmutableList.of(getBungeeCordChannel(serverMc.getProtocolVersion())) + )); } } @@ -164,8 +165,10 @@ public boolean handle(BossBar packet) { @Override public boolean handle(ResourcePackRequest packet) { ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl( - Preconditions.checkNotNull(packet.getUrl())).setPrompt(packet.getPrompt()) - .setShouldForce(packet.isRequired()).setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + Preconditions.checkNotNull(packet.getUrl())) + .setPrompt(packet.getPrompt()) + .setShouldForce(packet.isRequired()) + .setOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); String hash = packet.getHash(); if (hash != null && !hash.isEmpty()) { @@ -174,8 +177,8 @@ public boolean handle(ResourcePackRequest packet) { } } - ServerResourcePackSendEvent event = - new ServerResourcePackSendEvent(builder.build(), this.serverConn); + ServerResourcePackSendEvent event = new ServerResourcePackSendEvent( + builder.build(), this.serverConn); server.getEventManager().fire(event).thenAcceptAsync(serverResourcePackSendEvent -> { if (playerConnection.isClosed()) { @@ -184,19 +187,23 @@ public boolean handle(ResourcePackRequest packet) { if (serverResourcePackSendEvent.getResult().isAllowed()) { ResourcePackInfo toSend = serverResourcePackSendEvent.getProvidedResourcePack(); if (toSend != serverResourcePackSendEvent.getReceivedResourcePack()) { - ((VelocityResourcePackInfo) toSend).setOriginalOrigin( - ResourcePackInfo.Origin.DOWNSTREAM_SERVER); + ((VelocityResourcePackInfo) toSend) + .setOriginalOrigin(ResourcePackInfo.Origin.DOWNSTREAM_SERVER); } serverConn.getPlayer().queueResourcePack(toSend); } else if (serverConn.getConnection() != null) { - serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), - PlayerResourcePackStatusEvent.Status.DECLINED)); + serverConn.getConnection().write(new ResourcePackResponse( + packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED + )); } }, playerConnection.eventLoop()).exceptionally((ex) -> { if (serverConn.getConnection() != null) { - serverConn.getConnection().write(new ResourcePackResponse(packet.getHash(), - PlayerResourcePackStatusEvent.Status.DECLINED)); + serverConn.getConnection().write(new ResourcePackResponse( + packet.getHash(), + PlayerResourcePackStatusEvent.Status.DECLINED + )); } logger.error("Exception while handling resource pack send for {}", playerConnection, ex); return null; @@ -280,8 +287,8 @@ public boolean handle(AvailableCommands commands) { injector.inject(rootNode, serverConn.getPlayer()); } - server.getEventManager() - .fire(new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode)) + server.getEventManager().fire( + new PlayerAvailableCommandsEvent(serverConn.getPlayer(), rootNode)) .thenAcceptAsync(event -> playerConnection.write(commands), playerConnection.eventLoop()) .exceptionally((ex) -> { logger.error("Exception while handling available commands for {}", playerConnection, ex); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java index 2b7eaf9bb8..e9801c3157 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java @@ -70,7 +70,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { private boolean informationForwarded; LoginSessionHandler(VelocityServer server, VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; @@ -108,14 +108,14 @@ public boolean handle(LoginPluginMessage packet) { } final byte[] contents = ByteBufUtil.getBytes(packet.content()); - final MinecraftChannelIdentifier identifier = - MinecraftChannelIdentifier.from(packet.getChannel()); - this.server.getEventManager() - .fire(new ServerLoginPluginMessageEvent(serverConn, identifier, contents, packet.getId())) + final MinecraftChannelIdentifier identifier = MinecraftChannelIdentifier + .from(packet.getChannel()); + this.server.getEventManager().fire(new ServerLoginPluginMessageEvent(serverConn, identifier, + contents, packet.getId())) .thenAcceptAsync(event -> { if (event.getResult().isAllowed()) { - mc.write(new LoginPluginResponse(packet.getId(), true, - Unpooled.wrappedBuffer(event.getResult().getResponse()))); + mc.write(new LoginPluginResponse(packet.getId(), true, Unpooled + .wrappedBuffer(event.getResult().getResponse()))); } else { mc.write(new LoginPluginResponse(packet.getId(), false, Unpooled.EMPTY_BUFFER)); } @@ -192,8 +192,9 @@ public void disconnected() { + "correctly enabled.\nSee https://velocitypowered.com/wiki/users/forwarding/ " + "for instructions on how to configure player info forwarding correctly.")); } else { - resultFuture.completeExceptionally(new QuietRuntimeException( - "The connection to the remote server was unexpectedly closed.")); + resultFuture.completeExceptionally( + new QuietRuntimeException("The connection to the remote server was unexpectedly closed.") + ); } } @@ -203,15 +204,15 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) if (requested > VelocityConstants.MODERN_FORWARDING_DEFAULT) { if (player.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_19_3) >= 0) { return requested >= VelocityConstants.MODERN_LAZY_SESSION - ? VelocityConstants.MODERN_LAZY_SESSION : VelocityConstants.MODERN_FORWARDING_DEFAULT; + ? VelocityConstants.MODERN_LAZY_SESSION + : VelocityConstants.MODERN_FORWARDING_DEFAULT; } if (player.getIdentifiedKey() != null) { // No enhanced switch on java 11 switch (player.getIdentifiedKey().getKeyRevision()) { case GENERIC_V1: return VelocityConstants.MODERN_FORWARDING_WITH_KEY; - // Since V2 is not backwards compatible we have to throw the key if v2 and requested is - // v1 + // Since V2 is not backwards compatible we have to throw the key if v2 and requested is v1 case LINKED_V2: return requested >= VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 ? VelocityConstants.MODERN_FORWARDING_WITH_KEY_V2 @@ -227,7 +228,7 @@ private static int findForwardingVersion(int requested, ConnectedPlayer player) } private static ByteBuf createForwardingData(byte[] hmacSecret, String address, - ConnectedPlayer player, int requestedVersion) { + ConnectedPlayer player, int requestedVersion) { ByteBuf forwarded = Unpooled.buffer(2048); try { int actualVersion = findForwardingVersion(requestedVersion, player); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index 3ff2fbf373..30d1f42424 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -61,13 +61,14 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { * @param serverConn the server connection * @param resultFuture the result future */ - TransitionSessionHandler(VelocityServer server, VelocityServerConnection serverConn, - CompletableFuture resultFuture) { + TransitionSessionHandler(VelocityServer server, + VelocityServerConnection serverConn, + CompletableFuture resultFuture) { this.server = server; this.serverConn = serverConn; this.resultFuture = resultFuture; - this.bungeecordMessageResponder = - new BungeeCordMessageResponder(server, serverConn.getPlayer()); + this.bungeecordMessageResponder = new BungeeCordMessageResponder(server, + serverConn.getPlayer()); } @Override @@ -147,8 +148,8 @@ public boolean handle(JoinGame packet) { } // We're done! :) - server.getEventManager() - .fireAndForget(new ServerPostConnectEvent(player, previousServer)); + server.getEventManager().fireAndForget(new ServerPostConnectEvent(player, + previousServer)); resultFuture.complete(ConnectionRequestResults.successful(serverConn.getServer())); }, smc.eventLoop()).exceptionally(exc -> { logger.error("Unable to switch to new server {} for {}", @@ -171,8 +172,8 @@ public boolean handle(Disconnect packet) { // the client. if (connection.getType() == ConnectionTypes.LEGACY_FORGE && !serverConn.getPhase().consideredComplete()) { - resultFuture.complete( - ConnectionRequestResults.forUnsafeDisconnect(packet, serverConn.getServer())); + resultFuture.complete(ConnectionRequestResults.forUnsafeDisconnect(packet, + serverConn.getServer())); } else { resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer())); } @@ -196,8 +197,8 @@ public boolean handle(PluginMessage packet) { existingConnection.setConnectionPhase(IN_TRANSITION); // Tell the player that we're leaving and we just aren't coming back. - existingConnection.getPhase() - .onDepartForNewServer(existingConnection, serverConn.getPlayer()); + existingConnection.getPhase().onDepartForNewServer(existingConnection, + serverConn.getPlayer()); } } return true; @@ -209,7 +210,7 @@ public boolean handle(PluginMessage packet) { @Override public void disconnected() { - resultFuture.completeExceptionally( - new IOException("Unexpectedly disconnected from remote server")); + resultFuture + .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index b55b4de23a..9a4b7d72dc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -81,8 +81,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, * @param server the Velocity proxy instance */ public VelocityServerConnection(VelocityRegisteredServer registeredServer, - @Nullable VelocityRegisteredServer previousServer, - ConnectedPlayer proxyPlayer, VelocityServer server) { + @Nullable VelocityRegisteredServer previousServer, + ConnectedPlayer proxyPlayer, VelocityServer server) { this.registeredServer = registeredServer; this.previousServer = previousServer; this.proxyPlayer = proxyPlayer; @@ -149,9 +149,10 @@ private String createLegacyForwardingAddress(UnaryOperator> prope .append('\0') .append(getPlayerRemoteAddressAsString()) .append('\0') - .append(proxyPlayer.getGameProfile().getUndashedId()).append('\0'); - GENERAL_GSON.toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), - data); + .append(proxyPlayer.getGameProfile().getUndashedId()) + .append('\0'); + GENERAL_GSON + .toJson(propertiesTransform.apply(proxyPlayer.getGameProfile().getProperties()), data); return data.toString(); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java index db31831e6e..603cf686a6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/AuthSessionHandler.java @@ -68,8 +68,8 @@ public class AuthSessionHandler implements MinecraftSessionHandler { private final boolean onlineMode; private State loginState = State.START; // 1.20.2+ - AuthSessionHandler(VelocityServer server, LoginInboundConnection inbound, GameProfile profile, - boolean onlineMode) { + AuthSessionHandler(VelocityServer server, LoginInboundConnection inbound, + GameProfile profile, boolean onlineMode) { this.server = Preconditions.checkNotNull(server, "server"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.profile = Preconditions.checkNotNull(profile, "profile"); @@ -82,8 +82,8 @@ public void activated() { // Some connection types may need to alter the game profile. profile = mcConnection.getType().addGameProfileTokensIfRequired(profile, server.getConfiguration().getPlayerInfoForwardingMode()); - GameProfileRequestEvent profileRequestEvent = - new GameProfileRequestEvent(inbound, profile, onlineMode); + GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile, + onlineMode); final GameProfile finalProfile = profile; server.getEventManager().fire(profileRequestEvent).thenComposeAsync(profileEvent -> { @@ -93,9 +93,9 @@ public void activated() { } // Initiate a regular connection and move over to it. - ConnectedPlayer player = - new ConnectedPlayer(server, profileEvent.getGameProfile(), mcConnection, - inbound.getVirtualHost().orElse(null), onlineMode, inbound.getIdentifiedKey()); + ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(), + mcConnection, inbound.getVirtualHost().orElse(null), onlineMode, + inbound.getIdentifiedKey()); this.connectedPlayer = player; if (!server.canRegisterConnection(player)) { player.disconnect0( diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 5b35cd25f3..d2da3aa8ec 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -287,9 +287,11 @@ public boolean handle(TabCompleteRequest packet) { public boolean handle(PluginMessage packet) { // Handling edge case when packet with FML client handshake (state COMPLETE) // arrives after JoinGame packet from destination server - VelocityServerConnection serverConn = (player.getConnectedServer() == null - && packet.getChannel().equals(LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) - ? player.getConnectionInFlight() : player.getConnectedServer(); + VelocityServerConnection serverConn = + (player.getConnectedServer() == null + && packet.getChannel().equals( + LegacyForgeConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) + ? player.getConnectionInFlight() : player.getConnectedServer(); MinecraftConnection backendConn = serverConn != null ? serverConn.getConnection() : null; if (serverConn != null && backendConn != null) { @@ -306,8 +308,9 @@ public boolean handle(PluginMessage packet) { channelIdentifiers.add(new LegacyChannelIdentifier(channel)); } } - server.getEventManager().fireAndForget( - new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); + server.getEventManager() + .fireAndForget( + new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channelIdentifiers))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isUnregister(packet)) { backendConn.write(packet.retain()); @@ -315,8 +318,9 @@ public boolean handle(PluginMessage packet) { String brand = PluginMessageUtil.readBrandMessage(packet.content()); server.getEventManager().fireAndForget(new PlayerClientBrandEvent(player, brand)); player.setClientBrand(brand); - backendConn.write(PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), - player.getProtocolVersion())); + backendConn.write( + PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), + player.getProtocolVersion())); } else if (BungeeCordMessageResponder.isBungeeCordMessage(packet)) { return true; } else { @@ -333,8 +337,8 @@ public boolean handle(PluginMessage packet) { ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel()); if (id == null) { // We don't have any plugins listening on this channel, process the packet now. - if (!player.getPhase().consideredComplete() - || !serverConn.getPhase().consideredComplete()) { + if (!player.getPhase().consideredComplete() || !serverConn.getPhase() + .consideredComplete()) { // The client is trying to send messages too early. This is primarily caused by mods, // but further aggravated by Velocity. To work around these issues, we will queue any // non-FML handshake messages to be sent once the FML handshake has completed or the @@ -352,12 +356,11 @@ public boolean handle(PluginMessage packet) { PluginMessageEvent event = new PluginMessageEvent(player, serverConn, id, copy); server.getEventManager().fire(event).thenAcceptAsync(pme -> { if (pme.getResult().isAllowed()) { - PluginMessage message = - new PluginMessage(packet.getChannel(), Unpooled.wrappedBuffer(copy)); - if (!player.getPhase().consideredComplete() - || !serverConn.getPhase().consideredComplete()) { - // We're still processing the connection (see above), enqueue the packet - // for now. + PluginMessage message = new PluginMessage(packet.getChannel(), + Unpooled.wrappedBuffer(copy)); + if (!player.getPhase().consideredComplete() || !serverConn.getPhase() + .consideredComplete()) { + // We're still processing the connection (see above), enqueue the packet for now. loginPluginMessages.add(message.retain()); } else { backendConn.write(message); @@ -697,7 +700,8 @@ private void finishCommandTabComplete(TabCompleteRequest request, TabCompleteRes player.getConnection().write(response); } catch (Exception e) { logger.error("Unable to provide tab list completions for {} for command '{}'", - player.getUsername(), command, e); + player.getUsername(), command, + e); } }, player.getConnection().eventLoop()).exceptionally((ex) -> { logger.error( diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 7e495b386c..c922e933a0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -120,8 +120,8 @@ /** * Represents a player that is connected to the proxy. */ -public class ConnectedPlayer - implements MinecraftConnectionAssociation, Player, KeyIdentifiable, VelocityInboundConnection { +public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, KeyIdentifiable, + VelocityInboundConnection { private static final int MAX_PLUGIN_CHANNELS = 1024; private static final PlainTextComponentSerializer PASS_THRU_TRANSLATE = @@ -133,12 +133,10 @@ public class ConnectedPlayer private static final Logger logger = LogManager.getLogger(ConnectedPlayer.class); private final Identity identity = new IdentityImpl(); - /** * The actual Minecraft connection. This is actually a wrapper object around the Netty channel. */ private final MinecraftConnection connection; - private final @Nullable InetSocketAddress virtualHost; private GameProfile profile; private PermissionFunction permissionFunction; @@ -175,8 +173,8 @@ public class ConnectedPlayer private final ChatBuilderFactory chatBuilderFactory; ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection, - @Nullable InetSocketAddress virtualHost, boolean onlineMode, - @Nullable IdentifiedKey playerKey) { + @Nullable InetSocketAddress virtualHost, boolean onlineMode, + @Nullable IdentifiedKey playerKey) { this.server = server; this.profile = profile; this.connection = connection; @@ -344,8 +342,8 @@ public ProtocolVersion getProtocolVersion() { * @return the translated message */ public Component translateMessage(Component message) { - Locale locale = ClosestLocaleMatcher.INSTANCE.lookupClosest( - getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); + Locale locale = ClosestLocaleMatcher.INSTANCE + .lookupClosest(getEffectiveLocale() == null ? Locale.getDefault() : getEffectiveLocale()); return GlobalTranslator.render(message, locale); } @@ -353,20 +351,22 @@ public Component translateMessage(Component message) { public void sendMessage(@NonNull Identity identity, @NonNull Component message) { Component translated = translateMessage(message); - connection.write( - getChatBuilderFactory().builder().component(translated).forIdentity(identity).toClient()); + connection.write(getChatBuilderFactory().builder() + .component(translated).forIdentity(identity).toClient()); } @Override public void sendMessage(@NonNull Identity identity, @NonNull Component message, - @NonNull MessageType type) { + @NonNull MessageType type) { Preconditions.checkNotNull(message, "message"); Preconditions.checkNotNull(type, "type"); Component translated = translateMessage(message); - connection.write(getChatBuilderFactory().builder().component(translated).forIdentity(identity) - .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM).toClient()); + connection.write(getChatBuilderFactory().builder() + .component(translated).forIdentity(identity) + .setType(type == MessageType.CHAT ? ChatType.CHAT : ChatType.SYSTEM) + .toClient()); } @Override @@ -376,16 +376,17 @@ public void sendActionBar(net.kyori.adventure.text.@NonNull Component message) { ProtocolVersion playerVersion = getProtocolVersion(); if (playerVersion.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { // Use the title packet instead. - GenericTitlePacket pkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_ACTION_BAR, - playerVersion); - pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion).serialize(translated)); + GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion); + pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion) + .serialize(translated)); connection.write(pkt); } else { // Due to issues with action bar packets, we'll need to convert the text message into a // legacy message and then inject the legacy text into a component... yuck! JsonObject object = new JsonObject(); - object.addProperty("text", LegacyComponentSerializer.legacySection().serialize(translated)); + object.addProperty("text", LegacyComponentSerializer.legacySection() + .serialize(translated)); LegacyChat legacyChat = new LegacyChat(); legacyChat.setMessage(object.toString()); legacyChat.setType(LegacyChat.GAME_INFO_TYPE); @@ -427,11 +428,10 @@ public void sendPlayerListHeaderAndFooter(final Component header, final Componen @Override public void showTitle(net.kyori.adventure.title.@NonNull Title title) { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - GsonComponentSerializer serializer = - ProtocolUtils.getJsonChatSerializer(this.getProtocolVersion()); - GenericTitlePacket timesPkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TIMES, - this.getProtocolVersion()); + GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this + .getProtocolVersion()); + GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); net.kyori.adventure.title.Title.Times times = title.times(); if (times != null) { timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); @@ -440,15 +440,13 @@ public void showTitle(net.kyori.adventure.title.@NonNull Title title) { } connection.delayedWrite(timesPkt); - GenericTitlePacket subtitlePkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_SUBTITLE, - this.getProtocolVersion()); + GenericTitlePacket subtitlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); subtitlePkt.setComponent(serializer.serialize(translateMessage(title.subtitle()))); connection.delayedWrite(subtitlePkt); - GenericTitlePacket titlePkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TITLE, - this.getProtocolVersion()); + GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage(title.title()))); connection.delayedWrite(titlePkt); @@ -469,26 +467,23 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { return; } - GsonComponentSerializer serializer = - ProtocolUtils.getJsonChatSerializer(this.getProtocolVersion()); + GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this + .getProtocolVersion()); if (part == TitlePart.TITLE) { - GenericTitlePacket titlePkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TITLE, - this.getProtocolVersion()); + GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.SUBTITLE) { - GenericTitlePacket titlePkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_SUBTITLE, - this.getProtocolVersion()); + GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(translateMessage((Component) value))); connection.write(titlePkt); } else if (part == TitlePart.TIMES) { Times times = (Times) value; - GenericTitlePacket timesPkt = - GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.SET_TIMES, - this.getProtocolVersion()); + GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TIMES, this.getProtocolVersion()); timesPkt.setFadeIn((int) DurationUtils.toTicks(times.fadeIn())); timesPkt.setStay((int) DurationUtils.toTicks(times.stay())); timesPkt.setFadeOut((int) DurationUtils.toTicks(times.fadeOut())); @@ -501,16 +496,16 @@ public void sendTitlePart(@NotNull TitlePart part, @NotNull T value) { @Override public void clearTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write(GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.HIDE, - this.getProtocolVersion())); + connection.write(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.HIDE, this.getProtocolVersion())); } } @Override public void resetTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write(GenericTitlePacket.constructTitlePacket(GenericTitlePacket.ActionType.RESET, - this.getProtocolVersion())); + connection.write(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.RESET, this.getProtocolVersion())); } } @@ -603,7 +598,7 @@ public void resetInFlightConnection() { * @param safe whether or not we can safely reconnect to a new server */ public void handleConnectionException(RegisteredServer server, Throwable throwable, - boolean safe) { + boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -642,7 +637,7 @@ public void handleConnectionException(RegisteredServer server, Throwable throwab * @param safe whether or not we can safely reconnect to a new server */ public void handleConnectionException(RegisteredServer server, Disconnect disconnect, - boolean safe) { + boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -655,18 +650,20 @@ public void handleConnectionException(RegisteredServer server, Disconnect discon plainTextReason); handleConnectionException(server, disconnectReason, Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), disconnectReason), safe); + Component.text(server.getServerInfo().getName()), + disconnectReason), safe); } else { logger.error("{}: disconnected while connecting to {}: {}", this, server.getServerInfo().getName(), plainTextReason); handleConnectionException(server, disconnectReason, Component.translatable("velocity.error.cant-connect", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), disconnectReason), safe); + Component.text(server.getServerInfo().getName()), + disconnectReason), safe); } } - private void handleConnectionException(RegisteredServer rs, @Nullable Component kickReason, - Component friendlyReason, boolean safe) { + private void handleConnectionException(RegisteredServer rs, + @Nullable Component kickReason, Component friendlyReason, boolean safe) { if (!isActive()) { // If the connection is no longer active, it makes no sense to try and recover it. return; @@ -693,8 +690,8 @@ private void handleConnectionException(RegisteredServer rs, @Nullable Component } result = Notify.create(friendlyReason); } - KickedFromServerEvent originalEvent = - new KickedFromServerEvent(this, rs, kickReason, !kickedFromCurrent, result); + KickedFromServerEvent originalEvent = new KickedFromServerEvent(this, rs, kickReason, + !kickedFromCurrent, result); handleKickEvent(originalEvent, friendlyReason, kickedFromCurrent); } @@ -797,10 +794,11 @@ public Optional getNextServerToTry() { */ private Optional getNextServerToTry(@Nullable RegisteredServer current) { if (serversToTry == null) { - String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString).orElse("") + String virtualHostStr = getVirtualHost().map(InetSocketAddress::getHostString) + .orElse("") .toLowerCase(Locale.ROOT); - serversToTry = server.getConfiguration().getForcedHosts() - .getOrDefault(virtualHostStr, Collections.emptyList()); + serversToTry = server.getConfiguration().getForcedHosts().getOrDefault(virtualHostStr, + Collections.emptyList()); } if (serversToTry.isEmpty()) { @@ -878,14 +876,12 @@ void teardown() { if (!connectedPlayer.get().getCurrentServer().isPresent()) { status = LoginStatus.PRE_SERVER_JOIN; } else { - status = connectedPlayer.get() == this - ? LoginStatus.SUCCESSFUL_LOGIN + status = connectedPlayer.get() == this ? LoginStatus.SUCCESSFUL_LOGIN : LoginStatus.CONFLICTING_LOGIN; } } else { - status = connection.isKnownDisconnect() - ? LoginStatus.CANCELLED_BY_PROXY - : LoginStatus.CANCELLED_BY_USER; + status = connection.isKnownDisconnect() ? LoginStatus.CANCELLED_BY_PROXY : + LoginStatus.CANCELLED_BY_USER; } DisconnectEvent event = new DisconnectEvent(this, status); @@ -904,8 +900,8 @@ public CompletableFuture getTeardownFuture() { @Override public String toString() { - boolean isPlayerAddressLoggingEnabled = - server.getConfiguration().isPlayerAddressLoggingEnabled(); + boolean isPlayerAddressLoggingEnabled = server.getConfiguration() + .isPlayerAddressLoggingEnabled(); String playerIp = isPlayerAddressLoggingEnabled ? getRemoteAddress().toString() : ""; return "[connected player] " + profile.getName() + " (" + playerIp + ")"; @@ -946,8 +942,8 @@ public void spoofChatInput(String input) { return item.toServer(); }); } else { - ensureBackendConnection().write( - getChatBuilderFactory().builder().asPlayer(this).message(input).toServer()); + ensureBackendConnection().write(getChatBuilderFactory().builder() + .asPlayer(this).message(input).toServer()); } } @@ -992,8 +988,8 @@ private void tickResourcePackQueue() { // Unless its 1.17+ and forced it will come back denied anyway while (!outstandingResourcePacks.isEmpty()) { queued = outstandingResourcePacks.peek(); - if (queued.getShouldForce() - && getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { + if (queued.getShouldForce() && getProtocolVersion() + .compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { break; } onResourcePackResponse(PlayerResourcePackStatusEvent.Status.DECLINED); @@ -1041,17 +1037,18 @@ public void clearAppliedResourcePack() { */ public boolean onResourcePackResponse(PlayerResourcePackStatusEvent.Status status) { final boolean peek = status == PlayerResourcePackStatusEvent.Status.ACCEPTED; - final ResourcePackInfo queued = - peek ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); + final ResourcePackInfo queued = peek + ? outstandingResourcePacks.peek() : outstandingResourcePacks.poll(); server.getEventManager().fire(new PlayerResourcePackStatusEvent(this, status, queued)) .thenAcceptAsync(event -> { if (event.getStatus() == PlayerResourcePackStatusEvent.Status.DECLINED && event.getPackInfo() != null && event.getPackInfo().getShouldForce() - && (!event.isOverwriteKick() || event.getPlayer().getProtocolVersion() - .compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0)) { - event.getPlayer() - .disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); + && (!event.isOverwriteKick() || event.getPlayer() + .getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) + ) { + event.getPlayer().disconnect(Component + .translatable("multiplayer.requiredTexturePrompt.disconnect")); } }); @@ -1156,7 +1153,7 @@ private class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder { private final @Nullable VelocityRegisteredServer previousServer; ConnectionRequestBuilderImpl(RegisteredServer toConnect, - @Nullable VelocityServerConnection previousConnection) { + @Nullable VelocityServerConnection previousConnection) { this.toConnect = Preconditions.checkNotNull(toConnect, "info"); this.previousServer = previousConnection == null ? null : previousConnection.getServer(); } @@ -1169,8 +1166,8 @@ public RegisteredServer getServer() { private Optional checkServer(RegisteredServer server) { Preconditions.checkArgument(server instanceof VelocityRegisteredServer, "Not a valid Velocity server."); - if (connectionInFlight != null - || (connectedServer != null && !connectedServer.hasCompletedJoin())) { + if (connectionInFlight != null || (connectedServer != null + && !connectedServer.hasCompletedJoin())) { return Optional.of(ConnectionRequestBuilder.Status.CONNECTION_IN_PROGRESS); } if (connectedServer != null diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index 8b24f777a9..079ce035f8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -76,15 +76,15 @@ public boolean handle(LegacyPing packet) { public boolean handle(LegacyHandshake packet) { connection.closeWith(LegacyDisconnect.from(Component.text( "Your client is extremely old. Please update to a newer version of Minecraft.", - NamedTextColor.RED))); + NamedTextColor.RED) + )); return true; } @Override public boolean handle(Handshake handshake) { - InitialInboundConnection ic = - new InitialInboundConnection(connection, cleanVhost(handshake.getServerAddress()), - handshake); + InitialInboundConnection ic = new InitialInboundConnection(connection, + cleanVhost(handshake.getServerAddress()), handshake); StateRegistry nextState = getStateForProtocol(handshake.getNextStatus()); if (nextState == null) { LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus()); @@ -208,7 +208,8 @@ private static class LegacyInboundConnection implements VelocityInboundConnectio private final MinecraftConnection connection; private final LegacyPing ping; - private LegacyInboundConnection(MinecraftConnection connection, LegacyPing ping) { + private LegacyInboundConnection(MinecraftConnection connection, + LegacyPing ping) { this.connection = connection; this.ping = ping; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index e46ac7d83a..1409dc4bad 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -63,9 +63,10 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private static final Logger logger = LogManager.getLogger(InitialLoginSessionHandler.class); - private static final String MOJANG_HASJOINED_URL = System.getProperty("mojang.sessionserver", - "https://sessionserver.mojang.com/session/minecraft/hasJoined") - .concat("?username=%s&serverId=%s"); + private static final String MOJANG_HASJOINED_URL = + System.getProperty("mojang.sessionserver", + "https://sessionserver.mojang.com/session/minecraft/hasJoined") + .concat("?username=%s&serverId=%s"); private final VelocityServer server; private final MinecraftConnection mcConnection; @@ -76,7 +77,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { private boolean forceKeyAuthentication; InitialLoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection, - LoginInboundConnection inbound) { + LoginInboundConnection inbound) { this.server = Preconditions.checkNotNull(server, "server"); this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection"); this.inbound = Preconditions.checkNotNull(inbound, "inbound"); @@ -201,16 +202,15 @@ public boolean handle(EncryptionResponse packet) { String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic()); String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString(); - String url = - String.format(MOJANG_HASJOINED_URL, urlFormParameterEscaper().escape(login.getUsername()), - serverId); + String url = String.format(MOJANG_HASJOINED_URL, + urlFormParameterEscaper().escape(login.getUsername()), serverId); if (server.getConfiguration().shouldPreventClientProxyConnections()) { url += "&ip=" + urlFormParameterEscaper().escape(playerIp); } - ListenableFuture hasJoinedResponse = - server.getAsyncHttpClient().prepareGet(url).execute(); + ListenableFuture hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) + .execute(); hasJoinedResponse.addListener(() -> { if (mcConnection.isClosed()) { // The player disconnected after we authenticated them. @@ -232,8 +232,8 @@ public boolean handle(EncryptionResponse packet) { try { Response profileResponse = hasJoinedResponse.get(); if (profileResponse.getStatusCode() == 200) { - final GameProfile profile = - GENERAL_GSON.fromJson(profileResponse.getResponseBody(), GameProfile.class); + final GameProfile profile = GENERAL_GSON.fromJson(profileResponse.getResponseBody(), + GameProfile.class); // Not so fast, now we verify the public key for 1.19.1+ if (inbound.getIdentifiedKey() != null && inbound.getIdentifiedKey().getKeyRevision() == IdentifiedKey.Revision.LINKED_V2 @@ -297,14 +297,17 @@ private void assertState(LoginState expectedState) { if (this.currentState != expectedState) { if (MinecraftDecoder.DEBUG) { logger.error("{} Received an unexpected packet requiring state {}, but we are in {}", - inbound, expectedState, this.currentState); + inbound, + expectedState, this.currentState); } mcConnection.close(true); } } private enum LoginState { - LOGIN_PACKET_EXPECTED, LOGIN_PACKET_RECEIVED, ENCRYPTION_REQUEST_SENT, + LOGIN_PACKET_EXPECTED, + LOGIN_PACKET_RECEIVED, + ENCRYPTION_REQUEST_SENT, ENCRYPTION_RESPONSE_RECEIVED } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java index 0019ba2033..19b09c1227 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeClientPhase.java @@ -55,8 +55,9 @@ public void onFirstJoin(ConnectedPlayer player) { } @Override - boolean onHandle(ConnectedPlayer player, PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, + PluginMessage message, + MinecraftConnection backendConn) { // If we stay in this phase, we do nothing because it means the packet wasn't handled. // Returning false indicates this return false; @@ -86,8 +87,9 @@ LegacyForgeHandshakeClientPhase nextPhase() { } @Override - boolean onHandle(ConnectedPlayer player, PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, + PluginMessage message, + MinecraftConnection backendConn) { // Read the mod list if we haven't already. if (!player.getModInfo().isPresent()) { List mods = LegacyForgeUtil.readModList(message); @@ -154,8 +156,9 @@ public boolean consideredComplete() { } @Override - boolean onHandle(ConnectedPlayer player, PluginMessage message, - MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, + PluginMessage message, + MinecraftConnection backendConn) { super.onHandle(player, message, backendConn); // just in case the timing is awful @@ -186,8 +189,9 @@ boolean onHandle(ConnectedPlayer player, PluginMessage message, } @Override - public final boolean handle(ConnectedPlayer player, PluginMessage message, - VelocityServerConnection server) { + public final boolean handle(ConnectedPlayer player, + PluginMessage message, + VelocityServerConnection server) { if (server != null) { MinecraftConnection backendConn = server.getConnection(); if (backendConn != null @@ -215,7 +219,9 @@ public final boolean handle(ConnectedPlayer player, PluginMessage message, * @param backendConn The backend connection to write to, if required. * @return true if handled, false otherwise. */ - boolean onHandle(ConnectedPlayer player, PluginMessage message, MinecraftConnection backendConn) { + boolean onHandle(ConnectedPlayer player, + PluginMessage message, + MinecraftConnection backendConn) { // Send the packet on to the server. backendConn.write(message.retain()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java index 2033fcb2a6..ef8e6b1cbf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -56,10 +56,13 @@ public ServerChannelInitializer(final VelocityServer server) { @Override protected void initChannel(final Channel ch) { - ch.pipeline().addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) - .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()).addLast(READ_TIMEOUT, + ch.pipeline() + .addLast(LEGACY_PING_DECODER, new LegacyPingDecoder()) + .addLast(FRAME_DECODER, new MinecraftVarintFrameDecoder()) + .addLast(READ_TIMEOUT, new ReadTimeoutHandler(this.server.getConfiguration().getReadTimeout(), - TimeUnit.MILLISECONDS)).addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) + TimeUnit.MILLISECONDS)) + .addLast(LEGACY_PING_ENCODER, LegacyPingEncoder.INSTANCE) .addLast(FRAME_ENCODER, MinecraftVarintLengthEncoder.INSTANCE) .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index d50037da33..e65ee056b2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -53,10 +53,15 @@ public enum ProtocolUtils { ; private static final GsonComponentSerializer PRE_1_16_SERIALIZER = - GsonComponentSerializer.builder().downsampleColors().emitLegacyHoverEvent() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE).build(); - private static final GsonComponentSerializer MODERN_SERIALIZER = GsonComponentSerializer.builder() - .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE).build(); + GsonComponentSerializer.builder() + .downsampleColors() + .emitLegacyHoverEvent() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .build(); + private static final GsonComponentSerializer MODERN_SERIALIZER = + GsonComponentSerializer.builder() + .legacyHoverEventSerializer(VelocityLegacyHoverEventSerializer.INSTANCE) + .build(); public static final int DEFAULT_MAX_STRING_SIZE = 65536; // 64KiB private static final QuietDecoderException BAD_VARINT_CACHED = @@ -79,8 +84,8 @@ public enum ProtocolUtils { public static int readVarInt(ByteBuf buf) { int read = readVarIntSafely(buf); if (read == Integer.MIN_VALUE) { - throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") : - BAD_VARINT_CACHED; + throw MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") + : BAD_VARINT_CACHED; } return read; } @@ -525,8 +530,8 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { // No vanilla packet should give a 3 byte packet int len = readExtendedForgeShort(buf); - checkFrame(len <= FORGE_MAX_ARRAY_LENGTH, "Cannot receive array longer than %s (got %s bytes)", - FORGE_MAX_ARRAY_LENGTH, len); + checkFrame(len <= FORGE_MAX_ARRAY_LENGTH, + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); return buf.readRetainedSlice(len); } @@ -541,7 +546,8 @@ public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { if (allowExtended) { checkFrame(b.length <= FORGE_MAX_ARRAY_LENGTH, - "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, b.length); + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.length); } else { checkFrame(b.length <= Short.MAX_VALUE, "Cannot send array longer than Short.MAX_VALUE (got %s bytes)", b.length); @@ -659,9 +665,8 @@ public static IdentifiedKey readPlayerKey(ProtocolVersion version, ByteBuf buf) long expiry = buf.readLong(); byte[] key = ProtocolUtils.readByteArray(buf); byte[] signature = ProtocolUtils.readByteArray(buf, 4096); - IdentifiedKey.Revision revision = - version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 ? IdentifiedKey.Revision.GENERIC_V1 - : IdentifiedKey.Revision.LINKED_V2; + IdentifiedKey.Revision revision = version.compareTo(ProtocolVersion.MINECRAFT_1_19) == 0 + ? IdentifiedKey.Revision.GENERIC_V1 : IdentifiedKey.Revision.LINKED_V2; return new IdentifiedKeyImpl(revision, key, expiry, signature); } @@ -669,6 +674,7 @@ public static IdentifiedKey readPlayerKey(ProtocolVersion version, ByteBuf buf) * Represents the direction in which a packet flows. */ public enum Direction { - SERVERBOUND, CLIENTBOUND + SERVERBOUND, + CLIENTBOUND } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 90dc1acb82..8845dbeae4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -108,9 +108,11 @@ /** Registry of all Minecraft protocol states and the packets for each state. */ public enum StateRegistry { + HANDSHAKE { { - serverbound.register(Handshake.class, Handshake::new, map(0x00, MINECRAFT_1_7_2, false)); + serverbound.register(Handshake.class, Handshake::new, + map(0x00, MINECRAFT_1_7_2, false)); } }, STATUS { @@ -162,9 +164,7 @@ public enum StateRegistry { serverbound.fallback = false; clientbound.fallback = false; - serverbound.register( - TabCompleteRequest.class, - TabCompleteRequest::new, + serverbound.register(TabCompleteRequest.class, TabCompleteRequest::new, map(0x14, MINECRAFT_1_7_2, false), map(0x01, MINECRAFT_1_9, false), map(0x02, MINECRAFT_1_12, false), @@ -184,19 +184,13 @@ public enum StateRegistry { map(0x03, MINECRAFT_1_12, false), map(0x02, MINECRAFT_1_12_1, false), map(0x03, MINECRAFT_1_14, MINECRAFT_1_18_2, false)); - serverbound.register( - KeyedPlayerCommand.class, - KeyedPlayerCommand::new, + serverbound.register(KeyedPlayerCommand.class, KeyedPlayerCommand::new, map(0x03, MINECRAFT_1_19, false), map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); - serverbound.register( - KeyedPlayerChat.class, - KeyedPlayerChat::new, + serverbound.register(KeyedPlayerChat.class, KeyedPlayerChat::new, map(0x04, MINECRAFT_1_19, false), map(0x05, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); - serverbound.register( - SessionPlayerCommand.class, - SessionPlayerCommand::new, + serverbound.register(SessionPlayerCommand.class, SessionPlayerCommand::new, map(0x04, MINECRAFT_1_19_3, false)); serverbound.register( SessionPlayerChat.class, @@ -281,9 +275,7 @@ public enum StateRegistry { map(0x0F, MINECRAFT_1_15, true), map(0x0E, MINECRAFT_1_16, true), map(0x0F, MINECRAFT_1_17, MINECRAFT_1_18_2, true)); - clientbound.register( - TabCompleteResponse.class, - TabCompleteResponse::new, + clientbound.register(TabCompleteResponse.class, TabCompleteResponse::new, map(0x3A, MINECRAFT_1_7_2, false), map(0x0E, MINECRAFT_1_9, false), map(0x10, MINECRAFT_1_13, false), @@ -437,9 +429,7 @@ public enum StateRegistry { map(0x4F, MINECRAFT_1_14, true), map(0x50, MINECRAFT_1_15, true), map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true)); - clientbound.register( - TitleSubtitlePacket.class, - TitleSubtitlePacket::new, + clientbound.register(TitleSubtitlePacket.class, TitleSubtitlePacket::new, map(0x57, MINECRAFT_1_17, true), map(0x58, MINECRAFT_1_18, true), map(0x5B, MINECRAFT_1_19_1, true), @@ -495,9 +485,7 @@ public enum StateRegistry { map(0x36, MINECRAFT_1_17, false), map(0x34, MINECRAFT_1_19, false), map(0x37, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); - clientbound.register( - RemovePlayerInfo.class, - RemovePlayerInfo::new, + clientbound.register(RemovePlayerInfo.class, RemovePlayerInfo::new, map(0x35, MINECRAFT_1_19_3, false), map(0x39, MINECRAFT_1_19_4, false), map(0x3B, MINECRAFT_1_20_2, false)); @@ -560,8 +548,8 @@ public enum StateRegistry { protected final PacketRegistry clientbound = new PacketRegistry(CLIENTBOUND); protected final PacketRegistry serverbound = new PacketRegistry(SERVERBOUND); - public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry( - Direction direction, ProtocolVersion version) { + public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry(Direction direction, + ProtocolVersion version) { return (direction == SERVERBOUND ? serverbound : clientbound).getProtocolRegistry(version); } @@ -596,8 +584,8 @@ ProtocolRegistry getProtocolRegistry(final ProtocolVersion version) { return registry; } -

void register( - Class

clazz, Supplier

packetSupplier, PacketMapping... mappings) { +

void register(Class

clazz, Supplier

packetSupplier, + PacketMapping... mappings) { if (mappings.length == 0) { throw new IllegalArgumentException("At least one mapping must be provided."); } @@ -617,17 +605,14 @@

void register( "Last mapping version cannot be higher than highest mapping version"); } } - ProtocolVersion to = - current == next - ? lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS) - : next.protocolVersion; + ProtocolVersion to = current == next ? lastValid != null + ? lastValid : getLast(SUPPORTED_VERSIONS) : next.protocolVersion; ProtocolVersion lastInList = lastValid != null ? lastValid : getLast(SUPPORTED_VERSIONS); if (from.compareTo(to) >= 0 && from != lastInList) { - throw new IllegalArgumentException( - String.format( - "Next mapping version (%s) should be lower then current (%s)", to, from)); + throw new IllegalArgumentException(String.format( + "Next mapping version (%s) should be lower then current (%s)", to, from)); } for (ProtocolVersion protocol : EnumSet.range(from, to)) { @@ -702,10 +687,10 @@ public class ProtocolRegistry { public int getPacketId(final MinecraftPacket packet) { final int id = this.packetClassToId.getInt(packet.getClass()); if (id == Integer.MIN_VALUE) { - throw new IllegalArgumentException( - String.format( - "Unable to find id for packet of type %s in %s protocol %s", - packet.getClass().getName(), PacketRegistry.this.direction, this.version)); + throw new IllegalArgumentException(String.format( + "Unable to find id for packet of type %s in %s protocol %s", + packet.getClass().getName(), PacketRegistry.this.direction, this.version + )); } return id; } @@ -730,11 +715,8 @@ public static final class PacketMapping { private final boolean encodeOnly; private final @Nullable ProtocolVersion lastValidProtocolVersion; - PacketMapping( - int id, - ProtocolVersion protocolVersion, - ProtocolVersion lastValidProtocolVersion, - boolean packetDecoding) { + PacketMapping(int id, ProtocolVersion protocolVersion, + ProtocolVersion lastValidProtocolVersion, boolean packetDecoding) { this.id = id; this.protocolVersion = protocolVersion; this.lastValidProtocolVersion = lastValidProtocolVersion; @@ -776,8 +758,8 @@ public int hashCode() { /** * Creates a PacketMapping using the provided arguments. * - * @param id Packet Id - * @param version Protocol version + * @param id Packet Id + * @param version Protocol version * @param encodeOnly When true packet decoding will be disabled * @return PacketMapping with the provided arguments */ @@ -789,17 +771,15 @@ private static PacketMapping map(int id, ProtocolVersion version, boolean encode /** * Creates a PacketMapping using the provided arguments. * - * @param id Packet Id - * @param version Protocol version - * @param encodeOnly When true packet decoding will be disabled + * @param id Packet Id + * @param version Protocol version + * @param encodeOnly When true packet decoding will be disabled * @param lastValidProtocolVersion Last version this Mapping is valid at * @return PacketMapping with the provided arguments */ - private static PacketMapping map( - int id, - ProtocolVersion version, - ProtocolVersion lastValidProtocolVersion, - boolean encodeOnly) { + private static PacketMapping map(int id, ProtocolVersion version, + ProtocolVersion lastValidProtocolVersion, boolean encodeOnly) { return new PacketMapping(id, version, lastValidProtocolVersion, encodeOnly); } + } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java index f7138921f9..a42d1ee90a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettings.java @@ -41,8 +41,7 @@ public ClientSettings() { } public ClientSettings(String locale, byte viewDistance, int chatVisibility, boolean chatColors, - short skinParts, int mainHand, boolean chatFilteringEnabled, - boolean clientListingAllowed) { + short skinParts, int mainHand, boolean chatFilteringEnabled, boolean clientListingAllowed) { this.locale = locale; this.viewDistance = viewDistance; this.chatVisibility = chatVisibility; @@ -196,9 +195,12 @@ public boolean equals(@Nullable final Object o) { return false; } final ClientSettings that = (ClientSettings) o; - return viewDistance == that.viewDistance && chatVisibility == that.chatVisibility - && chatColors == that.chatColors && difficulty == that.difficulty - && skinParts == that.skinParts && mainHand == that.mainHand + return viewDistance == that.viewDistance + && chatVisibility == that.chatVisibility + && chatColors == that.chatColors + && difficulty == that.difficulty + && skinParts == that.skinParts + && mainHand == that.mainHand && chatFilteringEnabled == that.chatFilteringEnabled && clientListingAllowed == that.clientListingAllowed && Objects.equals(locale, that.locale); @@ -206,7 +208,15 @@ public boolean equals(@Nullable final Object o) { @Override public int hashCode() { - return Objects.hash(locale, viewDistance, chatVisibility, chatColors, difficulty, skinParts, - mainHand, chatFilteringEnabled, clientListingAllowed); + return Objects.hash( + locale, + viewDistance, + chatVisibility, + chatColors, + difficulty, + skinParts, + mainHand, + chatFilteringEnabled, + clientListingAllowed); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java index ba8d9ae2c9..57c8c61c27 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLogin.java @@ -32,8 +32,8 @@ public class ServerLogin implements MinecraftPacket { - private static final QuietDecoderException EMPTY_USERNAME = - new QuietDecoderException("Empty username!"); + private static final QuietDecoderException EMPTY_USERNAME = new QuietDecoderException( + "Empty username!"); private @Nullable String username; private @Nullable IdentifiedKey playerKey; // Introduced in 1.19.3 diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java index 6b72020764..4ed43e86b1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/PingSessionHandler.java @@ -44,7 +44,7 @@ public class PingSessionHandler implements MinecraftSessionHandler { private boolean completed = false; PingSessionHandler(CompletableFuture result, RegisteredServer server, - MinecraftConnection connection, ProtocolVersion version) { + MinecraftConnection connection, ProtocolVersion version) { this.result = result; this.server = server; this.connection = connection; @@ -73,8 +73,8 @@ public boolean handle(StatusResponse packet) { completed = true; connection.close(true); - ServerPing ping = - VelocityServer.getPingGsonInstance(version).fromJson(packet.getStatus(), ServerPing.class); + ServerPing ping = VelocityServer.getPingGsonInstance(version).fromJson(packet.getStatus(), + ServerPing.class); result.complete(ping); return true; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index 70cbcec588..928b4ee726 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -98,7 +98,7 @@ public CompletableFuture ping() { * Pings the specified server using the specified event {@code loop}, claiming to be {@code * version}. * - * @param loop the event loop to use + * @param loop the event loop to use * @param pingOptions the options to apply to this ping * @return the server list ping response */ @@ -159,7 +159,7 @@ public boolean sendPluginMessage(ChannelIdentifier identifier, ByteBuf data) { for (ConnectedPlayer player : players.values()) { VelocityServerConnection serverConnection = player.getConnectedServer(); if (serverConnection != null && serverConnection.getConnection() != null - && serverConnection.getServer() == this) { + && serverConnection.getServer() == this) { return serverConnection.sendPluginMessage(identifier, data); } }