diff --git a/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 02825718a..1ee9006e9 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -4,7 +4,7 @@ import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packets.Disconnect; import com.velocitypowered.proxy.protocol.packets.JoinGame; -import com.velocitypowered.proxy.protocol.packets.Ping; +import com.velocitypowered.proxy.protocol.packets.KeepAlive; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.packets.Respawn; import io.netty.buffer.ByteBuf; @@ -18,7 +18,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { @Override public void handle(MinecraftPacket packet) { - if (packet instanceof Ping) { + if (packet instanceof KeepAlive) { // Forward onto the server connection.getChannel().write(packet); } else if (packet instanceof Disconnect) { diff --git a/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 601800189..cf23f7bf4 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -6,11 +6,13 @@ import com.velocitypowered.proxy.data.ServerInfo; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packets.Chat; import com.velocitypowered.proxy.protocol.packets.JoinGame; -import com.velocitypowered.proxy.protocol.packets.Ping; +import com.velocitypowered.proxy.protocol.packets.KeepAlive; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.packets.Respawn; import io.netty.buffer.ByteBuf; import io.netty.channel.EventLoop; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.net.InetSocketAddress; import java.util.concurrent.ScheduledFuture; @@ -18,6 +20,8 @@ import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; public class ClientPlaySessionHandler implements MinecraftSessionHandler { + private static final Logger logger = LogManager.getLogger(ClientPlaySessionHandler.class); + private final ConnectedPlayer player; private ScheduledFuture pingTask; private long lastPing = -1; @@ -35,19 +39,19 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } private void ping() { - long randomId = ThreadLocalRandom.current().nextLong(); + long randomId = ThreadLocalRandom.current().nextInt(); lastPing = randomId; - Ping ping = new Ping(); - ping.setRandomId(randomId); - player.getConnection().write(ping); + KeepAlive keepAlive = new KeepAlive(); + keepAlive.setRandomId(randomId); + player.getConnection().write(keepAlive); } @Override public void handle(MinecraftPacket packet) { - if (packet instanceof Ping) { - Ping ping = (Ping) packet; - if (ping.getRandomId() != lastPing) { - throw new IllegalStateException("Client sent invalid ping; expected " + lastPing + ", got " + ping.getRandomId()); + if (packet instanceof KeepAlive) { + KeepAlive keepAlive = (KeepAlive) packet; + if (keepAlive.getRandomId() != lastPing) { + throw new IllegalStateException("Client sent invalid keepAlive; expected " + lastPing + ", got " + keepAlive.getRandomId()); } // Do not forward the packet to the player's server, because we handle pings for all servers already. diff --git a/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java b/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java index 1cc6a9f00..bced97e73 100644 --- a/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java +++ b/src/main/java/com/velocitypowered/proxy/connection/client/StatusSessionHandler.java @@ -1,20 +1,16 @@ package com.velocitypowered.proxy.connection.client; import com.google.common.base.Preconditions; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.config.VelocityConfiguration; import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.packets.Ping; +import com.velocitypowered.proxy.protocol.packets.KeepAlive; +import com.velocitypowered.proxy.protocol.packets.StatusPing; import com.velocitypowered.proxy.protocol.packets.StatusRequest; import com.velocitypowered.proxy.protocol.packets.StatusResponse; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.data.ServerPing; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import net.kyori.text.Component; -import net.kyori.text.TextComponent; -import net.kyori.text.serializer.GsonComponentSerializer; public class StatusSessionHandler implements MinecraftSessionHandler { private final MinecraftConnection connection; @@ -25,10 +21,10 @@ public class StatusSessionHandler implements MinecraftSessionHandler { @Override public void handle(MinecraftPacket packet) { - Preconditions.checkArgument(packet instanceof Ping || packet instanceof StatusRequest, + Preconditions.checkArgument(packet instanceof StatusPing|| packet instanceof StatusRequest, "Unrecognized packet type " + packet.getClass().getName()); - if (packet instanceof Ping) { + if (packet instanceof StatusPing) { // Just send back the client's packet, no processing to do here. connection.closeWith(packet); return; diff --git a/src/main/java/com/velocitypowered/proxy/protocol/ProtocolConstants.java b/src/main/java/com/velocitypowered/proxy/protocol/ProtocolConstants.java index 768c17fb0..9c99def6f 100644 --- a/src/main/java/com/velocitypowered/proxy/protocol/ProtocolConstants.java +++ b/src/main/java/com/velocitypowered/proxy/protocol/ProtocolConstants.java @@ -3,10 +3,14 @@ package com.velocitypowered.proxy.protocol; import java.util.Arrays; public enum ProtocolConstants { ; - public static final int MINECRAFT_1_12 = 340; + public static final int MINECRAFT_1_12 = 335; + public static final int MINECRAFT_1_12_1 = 338; + public static final int MINECRAFT_1_12_2 = 340; - private static final int[] SUPPORTED_VERSIONS = new int[] { - MINECRAFT_1_12 + public static final int[] SUPPORTED_VERSIONS = new int[] { + MINECRAFT_1_12, + MINECRAFT_1_12_1, + MINECRAFT_1_12_2 }; public static boolean isSupported(int version) { diff --git a/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index d4e52fe95..540db697a 100644 --- a/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -4,67 +4,70 @@ import com.velocitypowered.proxy.protocol.packets.*; import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectMap; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.function.Supplier; import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12; +import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12_1; +import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12_2; public enum StateRegistry { HANDSHAKE { { SERVERBOUND.register(Handshake.class, Handshake::new, - generic(0x00)); + lowestVersion(0x00)); } }, STATUS { { SERVERBOUND.register(StatusRequest.class, StatusRequest::new, - generic(0x00)); - SERVERBOUND.register(Ping.class, Ping::new, - generic(0x01)); + lowestVersion(0x00)); + SERVERBOUND.register(StatusPing.class, StatusPing::new, + lowestVersion(0x01)); CLIENTBOUND.register(StatusResponse.class, StatusResponse::new, - generic(0x00)); - CLIENTBOUND.register(Ping.class, Ping::new, - generic(0x01)); + lowestVersion(0x00)); + CLIENTBOUND.register(StatusPing.class, StatusPing::new, + lowestVersion(0x01)); } }, PLAY { { SERVERBOUND.register(Chat.class, Chat::new, - map(0x02, MINECRAFT_1_12)); - SERVERBOUND.register(Ping.class, Ping::new, - map(0x0b, MINECRAFT_1_12)); + map(0x03, MINECRAFT_1_12), + map(0x02, MINECRAFT_1_12_2)); + SERVERBOUND.register(KeepAlive.class, KeepAlive::new, + map(0x0C, MINECRAFT_1_12), + map(0x0B, MINECRAFT_1_12_1)); CLIENTBOUND.register(Chat.class, Chat::new, map(0x0F, MINECRAFT_1_12)); CLIENTBOUND.register(Disconnect.class, Disconnect::new, map(0x1A, MINECRAFT_1_12)); - CLIENTBOUND.register(Ping.class, Ping::new, + CLIENTBOUND.register(KeepAlive.class, KeepAlive::new, map(0x1F, MINECRAFT_1_12)); CLIENTBOUND.register(JoinGame.class, JoinGame::new, map(0x23, MINECRAFT_1_12)); CLIENTBOUND.register(Respawn.class, Respawn::new, - map(0x35, MINECRAFT_1_12)); + map(0x34, MINECRAFT_1_12), + map(0x35, MINECRAFT_1_12_2)); } }, LOGIN { { SERVERBOUND.register(ServerLogin.class, ServerLogin::new, - generic(0x00)); + lowestVersion(0x00)); SERVERBOUND.register(EncryptionResponse.class, EncryptionResponse::new, - generic(0x01)); + lowestVersion(0x01)); CLIENTBOUND.register(Disconnect.class, Disconnect::new, - generic(0x00)); + lowestVersion(0x00)); CLIENTBOUND.register(EncryptionRequest.class, EncryptionRequest::new, - generic(0x01)); + lowestVersion(0x01)); CLIENTBOUND.register(ServerLoginSuccess.class, ServerLoginSuccess::new, - generic(0x02)); + lowestVersion(0x02)); CLIENTBOUND.register(SetCompression.class, SetCompression::new, - generic(0x03)); + lowestVersion(0x03)); } }; @@ -72,20 +75,25 @@ public enum StateRegistry { public final PacketRegistry SERVERBOUND = new PacketRegistry(ProtocolConstants.Direction.SERVERBOUND); public static class PacketRegistry { + private static final IntObjectMap LINKED_PROTOCOL_VERSIONS = new IntObjectHashMap<>(); + + static { + LINKED_PROTOCOL_VERSIONS.put(MINECRAFT_1_12, new int[] { MINECRAFT_1_12_1 }); + LINKED_PROTOCOL_VERSIONS.put(MINECRAFT_1_12_1, new int[] { MINECRAFT_1_12_2 }); + } + private final ProtocolConstants.Direction direction; private final IntObjectMap versions = new IntObjectHashMap<>(); public PacketRegistry(ProtocolConstants.Direction direction) { this.direction = direction; + for (int version : ProtocolConstants.SUPPORTED_VERSIONS) { + versions.put(version, new ProtocolVersion(version)); + } } public ProtocolVersion getVersion(final int version) { - ProtocolVersion result = null; - for (final IntObjectMap.PrimitiveEntry entry : this.versions.entries()) { - if (entry.key() <= version) { - result = entry.value(); - } - } + ProtocolVersion result = versions.get(version); if (result == null) { throw new IllegalArgumentException("Could not find data for protocol version " + version); } @@ -105,6 +113,17 @@ public enum StateRegistry { } version.packetIdToSupplier.put(mapping.id, packetSupplier); version.packetClassToId.put(clazz, mapping.id); + + int[] linked = LINKED_PROTOCOL_VERSIONS.get(mapping.protocolVersion); + if (linked != null) { + links: for (int i : linked) { + // Make sure that later mappings override this one. + for (PacketMapping m : mappings) { + if (i == m.protocolVersion) continue links; + } + register(clazz, packetSupplier, map(mapping.id, i)); + } + } } } @@ -135,6 +154,14 @@ public enum StateRegistry { } return id; } + + @Override + public String toString() { + return "ProtocolVersion{" + + "id=" + id + + ", packetClassToId=" + packetClassToId + + '}'; + } } } @@ -174,7 +201,7 @@ public enum StateRegistry { return new PacketMapping(id, version); } - private static PacketMapping generic(int id) { - return new PacketMapping(id, 0); + private static PacketMapping lowestVersion(int id) { + return new PacketMapping(id, MINECRAFT_1_12); } } diff --git a/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java b/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java index df493a771..625e68d5b 100644 --- a/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java +++ b/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java @@ -17,6 +17,7 @@ public class MinecraftDecoder extends MessageToMessageDecoder { public MinecraftDecoder(ProtocolConstants.Direction direction) { this.state = StateRegistry.HANDSHAKE; this.direction = Preconditions.checkNotNull(direction, "direction"); + this.setProtocolVersion(ProtocolConstants.MINECRAFT_1_12); } @Override @@ -57,6 +58,7 @@ public class MinecraftDecoder extends MessageToMessageDecoder { public void setState(StateRegistry state) { this.state = state; + this.setProtocolVersion(protocolVersion.id); } public ProtocolConstants.Direction getDirection() { diff --git a/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java b/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java index 7cc6e346b..833504616 100644 --- a/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java +++ b/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java @@ -17,6 +17,7 @@ public class MinecraftEncoder extends MessageToByteEncoder { public MinecraftEncoder(ProtocolConstants.Direction direction) { this.state = StateRegistry.HANDSHAKE; this.direction = Preconditions.checkNotNull(direction, "direction"); + this.setProtocolVersion(ProtocolConstants.MINECRAFT_1_12); } @Override @@ -40,6 +41,7 @@ public class MinecraftEncoder extends MessageToByteEncoder { public void setState(StateRegistry state) { this.state = state; + this.setProtocolVersion(protocolVersion.id); } public ProtocolConstants.Direction getDirection() { diff --git a/src/main/java/com/velocitypowered/proxy/protocol/packets/KeepAlive.java b/src/main/java/com/velocitypowered/proxy/protocol/packets/KeepAlive.java new file mode 100644 index 000000000..9197c2691 --- /dev/null +++ b/src/main/java/com/velocitypowered/proxy/protocol/packets/KeepAlive.java @@ -0,0 +1,45 @@ +package com.velocitypowered.proxy.protocol.packets; + +import com.velocitypowered.proxy.protocol.ProtocolConstants; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +import static com.velocitypowered.proxy.protocol.ProtocolConstants.MINECRAFT_1_12_2; + +public class KeepAlive implements MinecraftPacket { + private long randomId; + + public long getRandomId() { + return randomId; + } + + public void setRandomId(long randomId) { + this.randomId = randomId; + } + + @Override + public String toString() { + return "KeepAlive{" + + "randomId=" + randomId + + '}'; + } + + @Override + public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + if (protocolVersion >= MINECRAFT_1_12_2) { + randomId = buf.readLong(); + } else { + randomId = ProtocolUtils.readVarInt(buf); + } + } + + @Override + public void encode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { + if (protocolVersion >= MINECRAFT_1_12_2) { + buf.writeLong(randomId); + } else { + ProtocolUtils.writeVarInt(buf, (int) randomId); + } + } +} diff --git a/src/main/java/com/velocitypowered/proxy/protocol/packets/Ping.java b/src/main/java/com/velocitypowered/proxy/protocol/packets/StatusPing.java similarity index 61% rename from src/main/java/com/velocitypowered/proxy/protocol/packets/Ping.java rename to src/main/java/com/velocitypowered/proxy/protocol/packets/StatusPing.java index c1a3ad3e7..5d55e002a 100644 --- a/src/main/java/com/velocitypowered/proxy/protocol/packets/Ping.java +++ b/src/main/java/com/velocitypowered/proxy/protocol/packets/StatusPing.java @@ -1,27 +1,12 @@ package com.velocitypowered.proxy.protocol.packets; -import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolConstants; import io.netty.buffer.ByteBuf; -public class Ping implements MinecraftPacket { +public class StatusPing implements MinecraftPacket { private long randomId; - public long getRandomId() { - return randomId; - } - - public void setRandomId(long randomId) { - this.randomId = randomId; - } - - @Override - public String toString() { - return "Ping{" + - "randomId=" + randomId + - '}'; - } - @Override public void decode(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion) { randomId = buf.readLong();