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 d1764a5c6..93b1a3720 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -13,6 +13,8 @@ import java.util.Set; public enum ProtocolVersion { UNKNOWN(-1, "Unknown"), LEGACY(-2, "Legacy"), + MINECRAFT_1_7_2(4, "1.7.2"), + MINECRAFT_1_7_6(5, "1.7.6"), MINECRAFT_1_8(47, "1.8"), MINECRAFT_1_9(107, "1.9"), MINECRAFT_1_9_1(108, "1.9.1"), @@ -39,7 +41,7 @@ public enum ProtocolVersion { /** * Represents the lowest supported version. */ - public static final ProtocolVersion MINIMUM_VERSION = MINECRAFT_1_8; + public static final ProtocolVersion MINIMUM_VERSION = MINECRAFT_1_7_2; /** * Represents the highest supported version. */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/ConnectionTypes.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/ConnectionTypes.java index baf97c90f..150ab816e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/ConnectionTypes.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/ConnectionTypes.java @@ -3,6 +3,7 @@ package com.velocitypowered.proxy.connection; import com.velocitypowered.proxy.connection.backend.BackendConnectionPhases; import com.velocitypowered.proxy.connection.client.ClientConnectionPhases; import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConnectionType; +import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeHandshakeClientPhase; import com.velocitypowered.proxy.connection.util.ConnectionTypeImpl; /** @@ -24,6 +25,9 @@ public final class ConnectionTypes { public static final ConnectionType VANILLA = new ConnectionTypeImpl(ClientConnectionPhases.VANILLA, BackendConnectionPhases.VANILLA); + public static final ConnectionType UNDETERMINED_17 = new ConnectionTypeImpl( + LegacyForgeHandshakeClientPhase.NOT_STARTED, BackendConnectionPhases.UNKNOWN); + /** * Indicates that the connection is a 1.8-1.12 Forge * connection. 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 b43fc0a2a..ba6678b78 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 @@ -102,8 +102,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { } if (PluginMessageUtil.isMcBrand(packet)) { - PluginMessage rewritten = PluginMessageUtil.rewriteMinecraftBrand(packet, - server.getVersion()); + PluginMessage rewritten = PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion(), + playerConnection.getProtocolVersion()); playerConnection.write(rewritten); 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 2ae0d08a1..e0bf9dc38 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 @@ -1,6 +1,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_8; import static com.velocitypowered.proxy.protocol.util.PluginMessageUtil.constructChannelsPacket; import com.velocitypowered.api.event.connection.PluginMessageEvent; @@ -177,7 +178,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { player.getKnownChannels().removeAll(PluginMessageUtil.getChannels(packet)); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isMcBrand(packet)) { - backendConn.write(PluginMessageUtil.rewriteMinecraftBrand(packet, server.getVersion())); + backendConn.write(PluginMessageUtil + .rewriteMinecraftBrand(packet, server.getVersion(), player.getProtocolVersion())); } else { if (serverConn.getPhase() == BackendConnectionPhases.IN_TRANSITION) { // We must bypass the currently-connected server when forwarding Forge packets. @@ -347,8 +349,10 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } // Clear any title from the previous server. - player.getConnection() - .delayedWrite(TitlePacket.resetForProtocolVersion(player.getProtocolVersion())); + if (player.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { + player.getConnection() + .delayedWrite(TitlePacket.resetForProtocolVersion(player.getProtocolVersion())); + } // Flush everything player.getConnection().flush(); 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 83c6c86a6..d1a609023 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 @@ -46,6 +46,7 @@ import com.velocitypowered.proxy.protocol.packet.TitlePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.server.VelocityRegisteredServer; import com.velocitypowered.proxy.tablist.VelocityTabList; +import com.velocitypowered.proxy.tablist.VelocityTabListLegacy; import com.velocitypowered.proxy.util.VelocityMessages; import com.velocitypowered.proxy.util.collect.CappedSet; import io.netty.buffer.ByteBufUtil; @@ -104,7 +105,11 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection, @Nullable InetSocketAddress virtualHost) { this.server = server; - this.tabList = new VelocityTabList(connection); + if (connection.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { + this.tabList = new VelocityTabList(connection); + } else { + this.tabList = new VelocityTabListLegacy(connection); + } this.profile = profile; this.connection = connection; this.virtualHost = virtualHost; 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 fdc16fb87..1eb25a2ba 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 @@ -114,6 +114,10 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler { if (handshake.getServerAddress().endsWith(LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN) && 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 + // forge handshake attempts. Also sends a reset handshake packet on every transition. + return ConnectionTypes.UNDETERMINED_17; } else { // For later: See if we can determine Forge 1.13+ here, else this will need to be UNDETERMINED // until later in the cycle (most likely determinable during the LOGIN phase) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java index 6e38f0518..444232869 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginSessionHandler.java @@ -2,6 +2,7 @@ package com.velocitypowered.proxy.connection.client; import static com.google.common.net.UrlEscapers.urlFormParameterEscaper; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; import static com.velocitypowered.proxy.VelocityServer.GSON; import static com.velocitypowered.proxy.connection.VelocityConstants.EMPTY_BYTE_ARRAY; import static com.velocitypowered.proxy.connection.VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL; @@ -260,7 +261,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler { } int threshold = server.getConfiguration().getCompressionThreshold(); - if (threshold >= 0) { + if (threshold >= 0 && mcConnection.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { mcConnection.write(new SetCompression(threshold)); mcConnection.setCompressionThreshold(threshold); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeBackendPhase.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeBackendPhase.java index bf44814aa..c0da5ba99 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeBackendPhase.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/forge/legacy/LegacyForgeHandshakeBackendPhase.java @@ -90,7 +90,7 @@ public enum LegacyForgeHandshakeBackendPhase implements BackendConnectionPhase { @Nullable private final Integer packetToAdvanceOn; /** - * Creates an instance of the {@link LegacyForgeHandshakeClientPhase}. + * Creates an instance of the {@link LegacyForgeHandshakeBackendPhase}. * * @param packetToAdvanceOn The ID of the packet discriminator that indicates * that the server has moved onto a new phase, and 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 907a8640f..555885575 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -3,11 +3,11 @@ package com.velocitypowered.proxy.protocol; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import com.google.common.base.Preconditions; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.util.GameProfile; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; - import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -194,12 +194,161 @@ public enum ProtocolUtils { return properties; } + private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A; + + /** + * Reads an byte array for legacy version 1.7 from the specified {@code buf} + * + * @param buf the buffer to read from + * @return the read byte array + */ + public static byte[] readByteArray17(ByteBuf buf) { + // Read in a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for + // Forge only) + // No vanilla packet should give a 3 byte packet + int len = readExtendedForgeShort(buf); + + Preconditions.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); + return ret; + } + + /** + * Reads a retained {@link ByteBuf} slice of the specified {@code buf} with the 1.7 style length. + * + * @param buf the buffer to read from + * @return the retained slice + */ + public static ByteBuf readRetainedByteBufSlice17(ByteBuf buf) { + // Read in a 2 or 3 byte number that represents the length of the packet. (3 byte "shorts" for + // Forge only) + // No vanilla packet should give a 3 byte packet + int len = readExtendedForgeShort(buf); + + Preconditions.checkArgument(len <= (FORGE_MAX_ARRAY_LENGTH), + "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + + return buf.readRetainedSlice(len); + } + + /** + * Writes an byte array for legacy version 1.7 to the specified {@code buf} + * + * @param b array + * @param buf buf + * @param allowExtended forge + */ + public static void writeByteArray17(byte[] b, ByteBuf buf, boolean allowExtended) { + if (allowExtended) { + Preconditions + .checkArgument(b.length <= (FORGE_MAX_ARRAY_LENGTH), + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.length); + } else { + Preconditions.checkArgument(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) + // No vanilla packet should give a 3 byte packet, this method will still retain vanilla + // behaviour. + writeExtendedForgeShort(buf, b.length); + buf.writeBytes(b); + } + + /** + * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf} + * + * @param b array + * @param buf buf + * @param allowExtended forge + */ + public static void writeByteBuf17(ByteBuf b, ByteBuf buf, boolean allowExtended) { + if (allowExtended) { + Preconditions + .checkArgument(b.readableBytes() <= (FORGE_MAX_ARRAY_LENGTH), + "Cannot send array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, + b.readableBytes()); + } else { + Preconditions.checkArgument(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) + // No vanilla packet should give a 3 byte packet, this method will still retain vanilla + // behaviour. + writeExtendedForgeShort(buf, b.readableBytes()); + buf.writeBytes(b); + } + + /** + * Reads a Minecraft-style extended short from the specified {@code buf}. + * + * @param buf buf to write + * @return read extended short + */ + public static int readExtendedForgeShort(ByteBuf buf) { + int low = buf.readUnsignedShort(); + int high = 0; + if ((low & 0x8000) != 0) { + low = low & 0x7FFF; + high = buf.readUnsignedByte(); + } + return ((high & 0xFF) << 15) | low; + } + + /** + * Writes a Minecraft-style extended short to the specified {@code buf}. + * + * @param buf buf to write + * @param toWrite the extended short to write + */ + public static void writeExtendedForgeShort(ByteBuf buf, int toWrite) { + int low = toWrite & 0x7FFF; + int high = (toWrite & 0x7F8000) >> 15; + if (high != 0) { + low = low | 0x8000; + } + buf.writeShort(low); + if (high != 0) { + buf.writeByte(high); + } + } + + /** + * Reads a non length-prefixed string from the {@code buf}. We need this for the legacy 1.7 + * version, being inconsistent when sending the brand. + * + * @param buf the buffer to read from + * @return the decoded string + */ + public static String readStringWithoutLength(ByteBuf buf) { + int length = buf.readableBytes(); + int cap = DEFAULT_MAX_STRING_SIZE; + checkArgument(length >= 0, "Got a negative-length string (%s)", length); + // `cap` is interpreted as a UTF-8 character length. To cover the full Unicode plane, we must + // consider the length of a UTF-8 character, which can be up to a 4 bytes. We do an initial + // sanity check and then check again to make sure our optimistic guess was good. + checkArgument(length <= cap * 4, "Bad string size (got %s, maximum is %s)", length, cap); + checkState(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); + checkState(str.length() <= cap, "Got a too-long string (got %s, max %s)", + str.length(), cap); + return str; + } + public enum Direction { SERVERBOUND, CLIENTBOUND; public StateRegistry.PacketRegistry.ProtocolRegistry getProtocolRegistry(StateRegistry state, - ProtocolVersion version) { + ProtocolVersion version) { return (this == SERVERBOUND ? state.serverbound : state.clientbound) .getProtocolRegistry(version); } 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 fd5c268b2..4444722cb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -5,6 +5,7 @@ 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_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; @@ -44,14 +45,12 @@ import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; - import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; import java.util.Map; import java.util.Objects; import java.util.function.Supplier; - import org.checkerframework.checker.nullness.qual.Nullable; public enum StateRegistry { @@ -59,20 +58,20 @@ public enum StateRegistry { HANDSHAKE { { serverbound.register(Handshake.class, Handshake::new, - map(0x00, MINECRAFT_1_8, false)); + map(0x00, MINECRAFT_1_7_2, false)); } }, STATUS { { serverbound.register(StatusRequest.class, () -> StatusRequest.INSTANCE, - map(0x00, MINECRAFT_1_8, false)); + map(0x00, MINECRAFT_1_7_2, false)); serverbound.register(StatusPing.class, StatusPing::new, - map(0x01, MINECRAFT_1_8, false)); + map(0x01, MINECRAFT_1_7_2, false)); clientbound.register(StatusResponse.class, StatusResponse::new, - map(0x00, MINECRAFT_1_8, false)); + map(0x00, MINECRAFT_1_7_2, false)); clientbound.register(StatusPing.class, StatusPing::new, - map(0x01, MINECRAFT_1_8, false)); + map(0x01, MINECRAFT_1_7_2, false)); } }, PLAY { @@ -81,33 +80,33 @@ public enum StateRegistry { clientbound.fallback = false; serverbound.register(TabCompleteRequest.class, TabCompleteRequest::new, - map(0x14, MINECRAFT_1_8, false), + 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)); serverbound.register(Chat.class, Chat::new, - map(0x01, MINECRAFT_1_8, false), + 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, false)); serverbound.register(ClientSettings.class, ClientSettings::new, - map(0x15, MINECRAFT_1_8, false), + 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)); serverbound.register(PluginMessage.class, PluginMessage::new, - map(0x17, MINECRAFT_1_8, false), + 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)); serverbound.register(KeepAlive.class, KeepAlive::new, - map(0x00, MINECRAFT_1_8, false), + 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), @@ -123,37 +122,37 @@ public enum StateRegistry { clientbound.register(BossBar.class, BossBar::new, map(0x0C, MINECRAFT_1_9, false)); clientbound.register(Chat.class, Chat::new, - map(0x02, MINECRAFT_1_8, true), + map(0x02, MINECRAFT_1_7_2, true), map(0x0F, MINECRAFT_1_9, true), map(0x0E, MINECRAFT_1_13, true)); clientbound.register(TabCompleteResponse.class, TabCompleteResponse::new, - map(0x3A, MINECRAFT_1_8, false), + map(0x3A, MINECRAFT_1_7_2, false), map(0x0E, MINECRAFT_1_9, false), map(0x10, MINECRAFT_1_13, false)); clientbound.register(AvailableCommands.class, AvailableCommands::new, map(0x11, MINECRAFT_1_13, false)); clientbound.register(PluginMessage.class, PluginMessage::new, - map(0x3F, MINECRAFT_1_8, false), + 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)); clientbound.register(Disconnect.class, Disconnect::new, - map(0x40, MINECRAFT_1_8, false), + 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)); clientbound.register(KeepAlive.class, KeepAlive::new, - map(0x00, MINECRAFT_1_8, false), + 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)); clientbound.register(JoinGame.class, JoinGame::new, - map(0x01, MINECRAFT_1_8, false), + 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)); clientbound.register(Respawn.class, Respawn::new, - map(0x07, MINECRAFT_1_8, true), + 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), @@ -182,7 +181,7 @@ public enum StateRegistry { map(0x4B, MINECRAFT_1_13, true), map(0x4F, MINECRAFT_1_14, true)); clientbound.register(PlayerListItem.class, PlayerListItem::new, - map(0x38, MINECRAFT_1_8, false), + 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), @@ -192,17 +191,17 @@ public enum StateRegistry { LOGIN { { serverbound.register(ServerLogin.class, ServerLogin::new, - map(0x00, MINECRAFT_1_8, false)); + map(0x00, MINECRAFT_1_7_2, false)); serverbound.register(EncryptionResponse.class, EncryptionResponse::new, - map(0x01, MINECRAFT_1_8, false)); + map(0x01, MINECRAFT_1_7_2, false)); serverbound.register(LoginPluginResponse.class, LoginPluginResponse::new, map(0x02, MINECRAFT_1_13, false)); clientbound.register(Disconnect.class, Disconnect::new, - map(0x00, MINECRAFT_1_8, false)); + map(0x00, MINECRAFT_1_7_2, false)); clientbound.register(EncryptionRequest.class, EncryptionRequest::new, - map(0x01, MINECRAFT_1_8, false)); + map(0x01, MINECRAFT_1_7_2, false)); clientbound.register(ServerLoginSuccess.class, ServerLoginSuccess::new, - map(0x02, MINECRAFT_1_8, false)); + map(0x02, MINECRAFT_1_7_2, false)); clientbound.register(SetCompression.class, SetCompression::new, map(0x03, MINECRAFT_1_8, false)); clientbound.register(LoginPluginMessage.class, LoginPluginMessage::new, @@ -246,7 +245,7 @@ public enum StateRegistry { }
void register(Class
clazz, Supplier
packetSupplier,
- PacketMapping... mappings) {
+ PacketMapping... mappings) {
if (mappings.length == 0) {
throw new IllegalArgumentException("At least one mapping must be provided.");
}
@@ -382,8 +381,8 @@ public enum StateRegistry {
/**
* 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
*/
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java
index c4761a667..2321b518f 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Chat.java
@@ -56,7 +56,7 @@ public class Chat implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
message = ProtocolUtils.readString(buf);
- if (direction == ProtocolUtils.Direction.CLIENTBOUND) {
+ if (direction == ProtocolUtils.Direction.CLIENTBOUND && version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
type = buf.readByte();
}
}
@@ -67,7 +67,7 @@ public class Chat implements MinecraftPacket {
throw new IllegalStateException("Message is not specified");
}
ProtocolUtils.writeString(buf, message);
- if (direction == ProtocolUtils.Direction.CLIENTBOUND) {
+ if (direction == ProtocolUtils.Direction.CLIENTBOUND && version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
buf.writeByte(type);
}
}
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 80db8e997..361b1178e 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
@@ -13,6 +13,7 @@ public class ClientSettings implements MinecraftPacket {
private byte viewDistance;
private int chatVisibility;
private boolean chatColors;
+ private byte difficulty; // 1.7 Protocol
private short skinParts;
private int mainHand;
@@ -98,6 +99,11 @@ public class ClientSettings implements MinecraftPacket {
this.viewDistance = buf.readByte();
this.chatVisibility = ProtocolUtils.readVarInt(buf);
this.chatColors = buf.readBoolean();
+
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_7_6) <= 0) {
+ this.difficulty = buf.readByte();
+ }
+
this.skinParts = buf.readUnsignedByte();
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9) >= 0) {
@@ -114,6 +120,11 @@ public class ClientSettings implements MinecraftPacket {
buf.writeByte(viewDistance);
ProtocolUtils.writeVarInt(buf, chatVisibility);
buf.writeBoolean(chatColors);
+
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_7_6) <= 0) {
+ buf.writeByte(difficulty);
+ }
+
buf.writeByte(skinParts);
if (version.compareTo(ProtocolVersion.MINECRAFT_1_9) >= 0) {
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequest.java
index a238226a2..a60165b6e 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequest.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequest.java
@@ -42,15 +42,27 @@ public class EncryptionRequest implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
this.serverId = ProtocolUtils.readString(buf, 20);
- publicKey = ProtocolUtils.readByteArray(buf, 256);
- verifyToken = ProtocolUtils.readByteArray(buf, 16);
+
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ publicKey = ProtocolUtils.readByteArray(buf, 256);
+ verifyToken = ProtocolUtils.readByteArray(buf, 16);
+ } else {
+ publicKey = ProtocolUtils.readByteArray17(buf);
+ verifyToken = ProtocolUtils.readByteArray17(buf);
+ }
}
@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
ProtocolUtils.writeString(buf, this.serverId);
- ProtocolUtils.writeByteArray(buf, publicKey);
- ProtocolUtils.writeByteArray(buf, verifyToken);
+
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ ProtocolUtils.writeByteArray(buf, publicKey);
+ ProtocolUtils.writeByteArray(buf, verifyToken);
+ } else {
+ ProtocolUtils.writeByteArray17(publicKey, buf, false);
+ ProtocolUtils.writeByteArray17(verifyToken, buf, false);
+ }
}
@Override
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponse.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponse.java
index 7d64ca4ca..04316a8f6 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponse.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponse.java
@@ -40,14 +40,24 @@ public class EncryptionResponse implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
- this.sharedSecret = ProtocolUtils.readByteArray(buf, 256);
- this.verifyToken = ProtocolUtils.readByteArray(buf, 128);
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ this.sharedSecret = ProtocolUtils.readByteArray(buf, 256);
+ this.verifyToken = ProtocolUtils.readByteArray(buf, 128);
+ } else {
+ this.sharedSecret = ProtocolUtils.readByteArray17(buf);
+ this.verifyToken = ProtocolUtils.readByteArray17(buf);
+ }
}
@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
- ProtocolUtils.writeByteArray(buf, sharedSecret);
- ProtocolUtils.writeByteArray(buf, verifyToken);
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ ProtocolUtils.writeByteArray(buf, sharedSecret);
+ ProtocolUtils.writeByteArray(buf, verifyToken);
+ } else {
+ ProtocolUtils.writeByteArray17(sharedSecret, buf, false);
+ ProtocolUtils.writeByteArray17(verifyToken, buf, false);
+ }
}
@Override
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 af5eb6774..0b542803f 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
@@ -116,7 +116,9 @@ public class JoinGame implements MinecraftPacket {
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
this.viewDistance = ProtocolUtils.readVarInt(buf);
}
- this.reducedDebugInfo = buf.readBoolean();
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ this.reducedDebugInfo = buf.readBoolean();
+ }
}
@Override
@@ -137,9 +139,11 @@ public class JoinGame implements MinecraftPacket {
}
ProtocolUtils.writeString(buf, levelType);
if (version.compareTo(ProtocolVersion.MINECRAFT_1_14) >= 0) {
- ProtocolUtils.writeVarInt(buf,viewDistance);
+ ProtocolUtils.writeVarInt(buf, viewDistance);
+ }
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ buf.writeBoolean(reducedDebugInfo);
}
- buf.writeBoolean(reducedDebugInfo);
}
@Override
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java
index ac6810a65..32febe2b6 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlive.java
@@ -29,8 +29,10 @@ public class KeepAlive implements MinecraftPacket {
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
if (version.compareTo(ProtocolVersion.MINECRAFT_1_12_2) >= 0) {
randomId = buf.readLong();
- } else {
+ } else if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
randomId = ProtocolUtils.readVarInt(buf);
+ } else {
+ randomId = buf.readInt();
}
}
@@ -38,8 +40,10 @@ public class KeepAlive implements MinecraftPacket {
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
if (version.compareTo(ProtocolVersion.MINECRAFT_1_12_2) >= 0) {
buf.writeLong(randomId);
- } else {
+ } else if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
ProtocolUtils.writeVarInt(buf, (int) randomId);
+ } else {
+ buf.writeInt((int) randomId);
}
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java
index 4c31d92a4..1037ac765 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PlayerListItem.java
@@ -13,6 +13,7 @@ import java.util.List;
import java.util.UUID;
import net.kyori.text.Component;
import net.kyori.text.serializer.gson.GsonComponentSerializer;
+import net.kyori.text.serializer.legacy.LegacyComponentSerializer;
import org.checkerframework.checker.nullness.qual.Nullable;
public class PlayerListItem implements MinecraftPacket {
@@ -43,35 +44,43 @@ public class PlayerListItem implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
- action = ProtocolUtils.readVarInt(buf);
- int length = ProtocolUtils.readVarInt(buf);
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ action = ProtocolUtils.readVarInt(buf);
+ int length = ProtocolUtils.readVarInt(buf);
- for (int i = 0; i < length; i++) {
- Item item = new Item(ProtocolUtils.readUuid(buf));
- items.add(item);
- switch (action) {
- case ADD_PLAYER:
- item.setName(ProtocolUtils.readString(buf));
- item.setProperties(ProtocolUtils.readProperties(buf));
- item.setGameMode(ProtocolUtils.readVarInt(buf));
- item.setLatency(ProtocolUtils.readVarInt(buf));
- item.setDisplayName(readOptionalComponent(buf));
- break;
- case UPDATE_GAMEMODE:
- item.setGameMode(ProtocolUtils.readVarInt(buf));
- break;
- case UPDATE_LATENCY:
- item.setLatency(ProtocolUtils.readVarInt(buf));
- break;
- case UPDATE_DISPLAY_NAME:
- item.setDisplayName(readOptionalComponent(buf));
- break;
- case REMOVE_PLAYER:
- //Do nothing, all that is needed is the uuid
- break;
- default:
- throw new UnsupportedOperationException("Unknown action " + action);
+ for (int i = 0; i < length; i++) {
+ Item item = new Item(ProtocolUtils.readUuid(buf));
+ items.add(item);
+ switch (action) {
+ case ADD_PLAYER:
+ item.setName(ProtocolUtils.readString(buf));
+ item.setProperties(ProtocolUtils.readProperties(buf));
+ item.setGameMode(ProtocolUtils.readVarInt(buf));
+ item.setLatency(ProtocolUtils.readVarInt(buf));
+ item.setDisplayName(readOptionalComponent(buf));
+ break;
+ case UPDATE_GAMEMODE:
+ item.setGameMode(ProtocolUtils.readVarInt(buf));
+ break;
+ case UPDATE_LATENCY:
+ item.setLatency(ProtocolUtils.readVarInt(buf));
+ break;
+ case UPDATE_DISPLAY_NAME:
+ item.setDisplayName(readOptionalComponent(buf));
+ break;
+ case REMOVE_PLAYER:
+ //Do nothing, all that is needed is the uuid
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown action " + action);
+ }
}
+ } else {
+ Item item = new Item();
+ item.setName(ProtocolUtils.readString(buf));
+ action = buf.readBoolean() ? ADD_PLAYER : REMOVE_PLAYER;
+ item.setLatency(buf.readShort());
+ items.add(item);
}
}
@@ -84,34 +93,47 @@ public class PlayerListItem implements MinecraftPacket {
@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
- ProtocolUtils.writeVarInt(buf, action);
- ProtocolUtils.writeVarInt(buf, items.size());
- for (Item item : items) {
- ProtocolUtils.writeUuid(buf, item.getUuid());
- switch (action) {
- case ADD_PLAYER:
- ProtocolUtils.writeString(buf, item.getName());
- ProtocolUtils.writeProperties(buf, item.getProperties());
- ProtocolUtils.writeVarInt(buf, item.getGameMode());
- ProtocolUtils.writeVarInt(buf, item.getLatency());
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ ProtocolUtils.writeVarInt(buf, action);
+ ProtocolUtils.writeVarInt(buf, items.size());
+ for (Item item : items) {
+ ProtocolUtils.writeUuid(buf, item.getUuid());
+ switch (action) {
+ case ADD_PLAYER:
+ ProtocolUtils.writeString(buf, item.getName());
+ ProtocolUtils.writeProperties(buf, item.getProperties());
+ ProtocolUtils.writeVarInt(buf, item.getGameMode());
+ ProtocolUtils.writeVarInt(buf, item.getLatency());
- writeDisplayName(buf, item.getDisplayName());
- break;
- case UPDATE_GAMEMODE:
- ProtocolUtils.writeVarInt(buf, item.getGameMode());
- break;
- case UPDATE_LATENCY:
- ProtocolUtils.writeVarInt(buf, item.getLatency());
- break;
- case UPDATE_DISPLAY_NAME:
- writeDisplayName(buf, item.getDisplayName());
- break;
- case REMOVE_PLAYER:
- //Do nothing, all that is needed is the uuid
- break;
- default:
- throw new UnsupportedOperationException("Unknown action " + action);
+ writeDisplayName(buf, item.getDisplayName());
+ break;
+ case UPDATE_GAMEMODE:
+ ProtocolUtils.writeVarInt(buf, item.getGameMode());
+ break;
+ case UPDATE_LATENCY:
+ ProtocolUtils.writeVarInt(buf, item.getLatency());
+ break;
+ case UPDATE_DISPLAY_NAME:
+ writeDisplayName(buf, item.getDisplayName());
+ break;
+ case REMOVE_PLAYER:
+ //Do nothing, all that is needed is the uuid
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown action " + action);
+ }
}
+ } else {
+ Item item = items.get(0);
+ if (item.getDisplayName() != null) {
+ String displayName = LegacyComponentSerializer.legacy().serialize(item.getDisplayName());
+ ProtocolUtils.writeString(buf,
+ displayName.length() > 16 ? displayName.substring(0, 16) : displayName);
+ } else {
+ ProtocolUtils.writeString(buf, item.getName());
+ }
+ buf.writeBoolean(action != REMOVE_PLAYER);
+ buf.writeShort(item.getLatency());
}
}
@@ -136,6 +158,10 @@ public class PlayerListItem implements MinecraftPacket {
private int latency;
private @Nullable Component displayName;
+ public Item() {
+ uuid = null;
+ }
+
public Item(UUID uuid) {
this.uuid = uuid;
}
@@ -149,7 +175,7 @@ public class PlayerListItem implements MinecraftPacket {
.setDisplayName(entry.getDisplayName().orElse(null));
}
- public UUID getUuid() {
+ public @Nullable UUID getUuid() {
return uuid;
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessage.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessage.java
index e0269f77a..5b9b3f136 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessage.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessage.java
@@ -50,7 +50,12 @@ public class PluginMessage extends DeferredByteBufHolder implements MinecraftPac
if (version.compareTo(ProtocolVersion.MINECRAFT_1_13) >= 0) {
this.channel = transformLegacyToModernChannel(this.channel);
}
- this.replace(buf.readRetainedSlice(buf.readableBytes()));
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ this.replace(buf.readRetainedSlice(buf.readableBytes()));
+ } else {
+ this.replace(ProtocolUtils.readRetainedByteBufSlice17(buf));
+ }
+
}
@Override
@@ -63,7 +68,12 @@ public class PluginMessage extends DeferredByteBufHolder implements MinecraftPac
} else {
ProtocolUtils.writeString(buf, this.channel);
}
- buf.writeBytes(content());
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ buf.writeBytes(content());
+ } else {
+ ProtocolUtils.writeByteBuf17(content(), buf, true); // True for Forge support
+ }
+
}
@Override
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccess.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccess.java
index 0d068bd7a..76b599466 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccess.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccess.java
@@ -1,6 +1,7 @@
package com.velocitypowered.proxy.protocol.packet;
import com.velocitypowered.api.network.ProtocolVersion;
+import com.velocitypowered.api.util.UuidUtils;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
@@ -45,7 +46,11 @@ public class ServerLoginSuccess implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) {
- uuid = UUID.fromString(ProtocolUtils.readString(buf, 36));
+ if (version.compareTo(ProtocolVersion.MINECRAFT_1_7_6) >= 0) {
+ uuid = UUID.fromString(ProtocolUtils.readString(buf, 36));
+ } else {
+ uuid = UuidUtils.fromUndashed(ProtocolUtils.readString(buf, 32));
+ }
username = ProtocolUtils.readString(buf, 16);
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java
index 27afacaf9..e382861fe 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequest.java
@@ -1,6 +1,7 @@
package com.velocitypowered.proxy.protocol.packet;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_13;
+import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9;
import com.google.common.base.MoreObjects;
@@ -83,9 +84,11 @@ public class TabCompleteRequest implements MinecraftPacket {
if (version.compareTo(MINECRAFT_1_9) >= 0) {
this.assumeCommand = buf.readBoolean();
}
- this.hasPosition = buf.readBoolean();
- if (hasPosition) {
- this.position = buf.readLong();
+ if (version.compareTo(MINECRAFT_1_8) >= 0) {
+ this.hasPosition = buf.readBoolean();
+ if (hasPosition) {
+ this.position = buf.readLong();
+ }
}
}
}
@@ -104,9 +107,11 @@ public class TabCompleteRequest implements MinecraftPacket {
if (version.compareTo(MINECRAFT_1_9) >= 0) {
buf.writeBoolean(assumeCommand);
}
- buf.writeBoolean(hasPosition);
- if (hasPosition) {
- buf.writeLong(position);
+ if (version.compareTo(MINECRAFT_1_8) >= 0) {
+ buf.writeBoolean(hasPosition);
+ if (hasPosition) {
+ buf.writeLong(position);
+ }
}
}
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java
index c659826b7..8dea2e01d 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java
@@ -11,9 +11,7 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.packet.PluginMessage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
-import io.netty.util.ByteProcessor;
import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
@@ -127,7 +125,8 @@ public class PluginMessageUtil {
* @param version the proxy version
* @return the rewritten plugin message
*/
- public static PluginMessage rewriteMinecraftBrand(PluginMessage message, ProxyVersion version) {
+ public static PluginMessage rewriteMinecraftBrand(PluginMessage message, ProxyVersion version,
+ ProtocolVersion protocolVersion) {
checkNotNull(message, "message");
checkNotNull(version, "version");
checkArgument(isMcBrand(message), "message is not a brand plugin message");
@@ -135,8 +134,14 @@ public class PluginMessageUtil {
String toAppend = " (" + version.getName() + ")";
ByteBuf rewrittenBuf = Unpooled.buffer();
- String currentBrand = ProtocolUtils.readString(message.content().slice());
- ProtocolUtils.writeString(rewrittenBuf, currentBrand + toAppend);
+
+ if (protocolVersion.compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) {
+ String currentBrand = ProtocolUtils.readString(message.content().slice());
+ ProtocolUtils.writeString(rewrittenBuf, currentBrand + toAppend);
+ } else {
+ String currentBrand = ProtocolUtils.readStringWithoutLength(message.content().slice());
+ rewrittenBuf.writeBytes((currentBrand + toAppend).getBytes());
+ }
return new PluginMessage(message.getChannel(), rewrittenBuf);
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java
index aacf26012..09d8c01d5 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabList.java
@@ -7,6 +7,7 @@ import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter;
import com.velocitypowered.proxy.protocol.packet.PlayerListItem;
+import com.velocitypowered.proxy.protocol.packet.PlayerListItem.Item;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -20,8 +21,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class VelocityTabList implements TabList {
- private final MinecraftConnection connection;
- private final Map