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 8637d76b0..0149970e6 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -54,7 +54,7 @@ public enum ProtocolVersion { MINECRAFT_1_16_2(751, "1.16.2"), MINECRAFT_1_16_3(753, "1.16.3"), MINECRAFT_1_16_4(754, "1.16.4", "1.16.5"), - MINECRAFT_1_17(-1, 15, "1.17"); // Snapshot: 21w07a, future protocol: 755 + MINECRAFT_1_17(-1, 16, "1.17"); // Snapshot: 21w08a, future protocol: 755 private static final int SNAPSHOT_BIT = 30; 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 3dcb3807a..e72f42d64 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java @@ -46,7 +46,12 @@ 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.TitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleSubtitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleTextPacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleTimesPacket; import io.netty.buffer.ByteBuf; public interface MinecraftSessionHandler { @@ -191,7 +196,27 @@ public interface MinecraftSessionHandler { return false; } - default boolean handle(TitlePacket packet) { + default boolean handle(LegacyTitlePacket packet) { + return false; + } + + default boolean handle(TitleTextPacket packet) { + return false; + } + + default boolean handle(TitleSubtitlePacket packet) { + return false; + } + + default boolean handle(TitleActionbarPacket packet) { + return false; + } + + default boolean handle(TitleTimesPacket packet) { + return false; + } + + default boolean handle(TitleClearPacket packet) { return false; } 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 8ac397500..0c2b402eb 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 @@ -53,7 +53,7 @@ import com.velocitypowered.proxy.protocol.packet.Respawn; import com.velocitypowered.proxy.protocol.packet.TabCompleteRequest; import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse; import com.velocitypowered.proxy.protocol.packet.TabCompleteResponse.Offer; -import com.velocitypowered.proxy.protocol.packet.TitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; @@ -400,7 +400,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { // Clear any title from the previous server. if (player.getProtocolVersion().compareTo(MINECRAFT_1_8) >= 0) { player.getConnection() - .delayedWrite(TitlePacket.resetForProtocolVersion(player.getProtocolVersion())); + .delayedWrite(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.RESET, player.getProtocolVersion())); } // Flush everything 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 602c002c1..1a1a0d444 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 @@ -66,7 +66,7 @@ import com.velocitypowered.proxy.protocol.packet.HeaderAndFooter; 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.TitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import com.velocitypowered.proxy.server.VelocityRegisteredServer; import com.velocitypowered.proxy.tablist.VelocityTabList; @@ -262,8 +262,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { if (position == MessagePosition.ACTION_BAR) { if (getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { // We can use the title packet instead. - TitlePacket pkt = new TitlePacket(); - pkt.setAction(TitlePacket.SET_ACTION_BAR); + GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_ACTION_BAR, this.getProtocolVersion()); pkt.setComponent(net.kyori.text.serializer.gson.GsonComponentSerializer.INSTANCE .serialize(component)); connection.write(pkt); @@ -307,8 +307,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { ProtocolVersion playerVersion = getProtocolVersion(); if (playerVersion.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { // Use the title packet instead. - TitlePacket pkt = new TitlePacket(); - pkt.setAction(TitlePacket.SET_ACTION_BAR); + GenericTitlePacket pkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_ACTION_BAR, playerVersion); pkt.setComponent(ProtocolUtils.getJsonChatSerializer(playerVersion) .serialize(message)); connection.write(pkt); @@ -359,17 +359,18 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { GsonComponentSerializer serializer = ProtocolUtils.getJsonChatSerializer(this .getProtocolVersion()); - TitlePacket titlePkt = new TitlePacket(); - titlePkt.setAction(TitlePacket.SET_TITLE); + GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TITLE, this.getProtocolVersion()); titlePkt.setComponent(serializer.serialize(title.title())); connection.delayedWrite(titlePkt); - TitlePacket subtitlePkt = new TitlePacket(); - subtitlePkt.setAction(TitlePacket.SET_SUBTITLE); + GenericTitlePacket subtitlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_SUBTITLE, this.getProtocolVersion()); subtitlePkt.setComponent(serializer.serialize(title.subtitle())); connection.delayedWrite(subtitlePkt); - TitlePacket timesPkt = TitlePacket.timesForProtocolVersion(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())); @@ -385,14 +386,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { @Override public void clearTitle() { if (this.getProtocolVersion().compareTo(ProtocolVersion.MINECRAFT_1_8) >= 0) { - connection.write(TitlePacket.hideForProtocolVersion(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(TitlePacket.resetForProtocolVersion(this.getProtocolVersion())); + connection.write(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.RESET, this.getProtocolVersion())); } } @@ -487,20 +490,23 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { ProtocolVersion protocolVersion = connection.getProtocolVersion(); if (title.equals(Titles.reset())) { - connection.write(TitlePacket.resetForProtocolVersion(protocolVersion)); + connection.write(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.RESET, protocolVersion)); } else if (title.equals(Titles.hide())) { - connection.write(TitlePacket.hideForProtocolVersion(protocolVersion)); + connection.write(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.HIDE, protocolVersion)); } else if (title instanceof TextTitle) { TextTitle tt = (TextTitle) title; if (tt.isResetBeforeSend()) { - connection.delayedWrite(TitlePacket.resetForProtocolVersion(protocolVersion)); + connection.delayedWrite(GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.RESET, protocolVersion)); } Optional titleText = tt.getTitle(); if (titleText.isPresent()) { - TitlePacket titlePkt = new TitlePacket(); - titlePkt.setAction(TitlePacket.SET_TITLE); + GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TITLE, protocolVersion); titlePkt.setComponent(net.kyori.text.serializer.gson.GsonComponentSerializer.INSTANCE .serialize(titleText.get())); connection.delayedWrite(titlePkt); @@ -508,15 +514,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player { Optional subtitleText = tt.getSubtitle(); if (subtitleText.isPresent()) { - TitlePacket titlePkt = new TitlePacket(); - titlePkt.setAction(TitlePacket.SET_SUBTITLE); + GenericTitlePacket titlePkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_SUBTITLE, protocolVersion); titlePkt.setComponent(net.kyori.text.serializer.gson.GsonComponentSerializer.INSTANCE .serialize(subtitleText.get())); connection.delayedWrite(titlePkt); } if (tt.areTimesSet()) { - TitlePacket timesPkt = TitlePacket.timesForProtocolVersion(protocolVersion); + GenericTitlePacket timesPkt = GenericTitlePacket.constructTitlePacket( + GenericTitlePacket.ActionType.SET_TIMES, protocolVersion); timesPkt.setFadeIn(tt.getFadeIn()); timesPkt.setStay(tt.getStay()); timesPkt.setFadeOut(tt.getFadeOut()); 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 c3c25d91c..6baa55046 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -25,6 +25,7 @@ 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_7_2; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; @@ -61,7 +62,12 @@ 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.TitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.LegacyTitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleActionbarPacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleClearPacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleSubtitlePacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleTextPacket; +import com.velocitypowered.proxy.protocol.packet.title.TitleTimesPacket; import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -162,13 +168,13 @@ public enum StateRegistry { map(0x11, MINECRAFT_1_15, false), map(0x10, MINECRAFT_1_16, false), map(0x0F, MINECRAFT_1_16_2, false), - map(0x10, MINECRAFT_1_17, false)); + map(0x11, MINECRAFT_1_17, 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(0x11, MINECRAFT_1_17, false)); + map(0x12, MINECRAFT_1_17, false)); clientbound.register(PluginMessage.class, PluginMessage::new, map(0x3F, MINECRAFT_1_7_2, false), map(0x18, MINECRAFT_1_9, false), @@ -177,7 +183,7 @@ public enum StateRegistry { 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(0x19, MINECRAFT_1_17, false)); clientbound.register(Disconnect.class, Disconnect::new, map(0x40, MINECRAFT_1_7_2, false), map(0x1A, MINECRAFT_1_9, false), @@ -186,7 +192,7 @@ public enum StateRegistry { 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(0x1B, MINECRAFT_1_17, false)); clientbound.register(KeepAlive.class, KeepAlive::new, map(0x00, MINECRAFT_1_7_2, false), map(0x1F, MINECRAFT_1_9, false), @@ -195,7 +201,7 @@ public enum StateRegistry { map(0x21, MINECRAFT_1_15, false), map(0x20, MINECRAFT_1_16, false), map(0x1F, MINECRAFT_1_16_2, false), - map(0x20, MINECRAFT_1_17, false)); + map(0x22, MINECRAFT_1_17, false)); clientbound.register(JoinGame.class, JoinGame::new, map(0x01, MINECRAFT_1_7_2, false), map(0x23, MINECRAFT_1_9, false), @@ -204,7 +210,7 @@ public enum StateRegistry { map(0x26, MINECRAFT_1_15, false), map(0x25, MINECRAFT_1_16, false), map(0x24, MINECRAFT_1_16_2, false), - map(0x25, MINECRAFT_1_17, false)); + map(0x27, MINECRAFT_1_17, false)); clientbound.register(Respawn.class, Respawn::new, map(0x07, MINECRAFT_1_7_2, true), map(0x33, MINECRAFT_1_9, true), @@ -215,7 +221,7 @@ public enum StateRegistry { map(0x3B, MINECRAFT_1_15, true), map(0x3A, MINECRAFT_1_16, true), map(0x39, MINECRAFT_1_16_2, true), - map(0x3A, MINECRAFT_1_17, true)); + map(0x3D, MINECRAFT_1_17, true)); clientbound.register(ResourcePackRequest.class, ResourcePackRequest::new, map(0x48, MINECRAFT_1_8, true), map(0x32, MINECRAFT_1_9, true), @@ -226,7 +232,7 @@ public enum StateRegistry { map(0x3A, MINECRAFT_1_15, true), map(0x39, MINECRAFT_1_16, true), map(0x38, MINECRAFT_1_16_2, true), - map(0x39, MINECRAFT_1_17, true)); + map(0x3C, MINECRAFT_1_17, true)); clientbound.register(HeaderAndFooter.class, HeaderAndFooter::new, map(0x47, MINECRAFT_1_8, true), map(0x48, MINECRAFT_1_9, true), @@ -237,8 +243,8 @@ public enum StateRegistry { map(0x53, MINECRAFT_1_14, true), map(0x54, MINECRAFT_1_15, true), map(0x53, MINECRAFT_1_16, true), - map(0x54, MINECRAFT_1_17, true)); - clientbound.register(TitlePacket.class, TitlePacket::new, + map(0x5E, MINECRAFT_1_17, 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), @@ -246,8 +252,17 @@ public enum StateRegistry { map(0x4B, MINECRAFT_1_13, true), map(0x4F, MINECRAFT_1_14, true), map(0x50, MINECRAFT_1_15, true), - map(0x4F, MINECRAFT_1_16, true), - map(0x50, MINECRAFT_1_17, true)); + map(0x4F, MINECRAFT_1_16, MINECRAFT_1_16_4, true)); + clientbound.register(TitleSubtitlePacket.class, TitleSubtitlePacket::new, // TODO: fix + map(0x57, MINECRAFT_1_17, true)); + clientbound.register(TitleTextPacket.class, TitleTextPacket::new, // TODO: fix + map(0x5A, MINECRAFT_1_17, true)); + clientbound.register(TitleActionbarPacket.class, TitleActionbarPacket::new, // TODO: fix + map(0x41, MINECRAFT_1_17, true)); + clientbound.register(TitleTimesPacket.class, TitleTimesPacket::new, // TODO: fix + map(0x59, MINECRAFT_1_17, true)); + clientbound.register(TitleClearPacket.class, TitleClearPacket::new, // TODO: fix + map(0x10, MINECRAFT_1_17, true)); clientbound.register(PlayerListItem.class, PlayerListItem::new, map(0x38, MINECRAFT_1_7_2, false), map(0x2D, MINECRAFT_1_9, false), @@ -257,7 +272,7 @@ public enum StateRegistry { map(0x34, MINECRAFT_1_15, false), map(0x33, MINECRAFT_1_16, false), map(0x32, MINECRAFT_1_16_2, false), - map(0x33, MINECRAFT_1_17, false)); + map(0x36, MINECRAFT_1_17, false)); } }, LOGIN { @@ -325,8 +340,20 @@ public enum StateRegistry { for (int i = 0; i < mappings.length; i++) { PacketMapping current = mappings[i]; PacketMapping next = (i + 1 < mappings.length) ? mappings[i + 1] : current; + ProtocolVersion from = current.protocolVersion; - ProtocolVersion to = current == next ? getLast(SUPPORTED_VERSIONS) : next.protocolVersion; + ProtocolVersion lastValid = current.lastValidProtocolVersion; + if (lastValid != null) { + if (next != current) { + throw new IllegalArgumentException("Cannot add a mapping after last valid mapping"); + } + if (from.compareTo(lastValid) > 0) { + throw new IllegalArgumentException( + "Last mapping version cannot be higher than highest mapping version"); + } + } + ProtocolVersion to = current == next ? lastValid != null + ? lastValid : getLast(SUPPORTED_VERSIONS) : next.protocolVersion; if (from.compareTo(to) >= 0 && from != getLast(SUPPORTED_VERSIONS)) { throw new IllegalArgumentException(String.format( @@ -414,10 +441,13 @@ public enum StateRegistry { private final int id; private final ProtocolVersion protocolVersion; private final boolean encodeOnly; + private final @Nullable ProtocolVersion lastValidProtocolVersion; - PacketMapping(int id, ProtocolVersion protocolVersion, boolean packetDecoding) { + PacketMapping(int id, ProtocolVersion protocolVersion, + ProtocolVersion lastValidProtocolVersion, boolean packetDecoding) { this.id = id; this.protocolVersion = protocolVersion; + this.lastValidProtocolVersion = lastValidProtocolVersion; this.encodeOnly = packetDecoding; } @@ -459,7 +489,21 @@ public enum StateRegistry { * @return PacketMapping with the provided arguments */ private static PacketMapping map(int id, ProtocolVersion version, boolean encodeOnly) { - return new PacketMapping(id, version, encodeOnly); + return map(id, version, null, encodeOnly); + } + + /** + * 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 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) { + return new PacketMapping(id, version, lastValidProtocolVersion, encodeOnly); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TitlePacket.java deleted file mode 100644 index 49fe876df..000000000 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TitlePacket.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2018 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; -import org.checkerframework.checker.nullness.qual.Nullable; - -public class TitlePacket implements MinecraftPacket { - - public static final int SET_TITLE = 0; - public static final int SET_SUBTITLE = 1; - public static final int SET_ACTION_BAR = 2; - public static final int SET_TIMES = 3; - public static final int SET_TIMES_OLD = 2; - public static final int HIDE = 4; - public static final int HIDE_OLD = 3; - public static final int RESET = 5; - public static final int RESET_OLD = 4; - - private int action; - private @Nullable String component; - private int fadeIn; - private int stay; - private int fadeOut; - - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - throw new UnsupportedOperationException(); // encode only - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - ProtocolUtils.writeVarInt(buf, action); - if (version.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0) { - // 1.11+ shifted the action enum by 1 to handle the action bar - switch (action) { - case SET_TITLE: - case SET_SUBTITLE: - case SET_ACTION_BAR: - if (component == null) { - throw new IllegalStateException("No component found for " + action); - } - ProtocolUtils.writeString(buf, component); - break; - case SET_TIMES: - buf.writeInt(fadeIn); - buf.writeInt(stay); - buf.writeInt(fadeOut); - break; - case HIDE: - case RESET: - break; - default: - throw new UnsupportedOperationException("Unknown action " + action); - } - } else { - switch (action) { - case SET_TITLE: - case SET_SUBTITLE: - if (component == null) { - throw new IllegalStateException("No component found for " + action); - } - ProtocolUtils.writeString(buf, component); - break; - case SET_TIMES_OLD: - buf.writeInt(fadeIn); - buf.writeInt(stay); - buf.writeInt(fadeOut); - break; - case HIDE_OLD: - case RESET_OLD: - break; - default: - throw new UnsupportedOperationException("Unknown action " + action); - } - } - } - - public int getAction() { - return action; - } - - public void setAction(int action) { - this.action = action; - } - - public @Nullable String getComponent() { - return component; - } - - public void setComponent(@Nullable String component) { - this.component = component; - } - - public int getFadeIn() { - return fadeIn; - } - - public void setFadeIn(int fadeIn) { - this.fadeIn = fadeIn; - } - - public int getStay() { - return stay; - } - - public void setStay(int stay) { - this.stay = stay; - } - - public int getFadeOut() { - return fadeOut; - } - - public void setFadeOut(int fadeOut) { - this.fadeOut = fadeOut; - } - - public static TitlePacket hideForProtocolVersion(ProtocolVersion version) { - TitlePacket packet = new TitlePacket(); - packet.setAction(version.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0 ? TitlePacket.HIDE - : TitlePacket.HIDE_OLD); - return packet; - } - - public static TitlePacket resetForProtocolVersion(ProtocolVersion version) { - TitlePacket packet = new TitlePacket(); - packet.setAction(version.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0 ? TitlePacket.RESET - : TitlePacket.RESET_OLD); - return packet; - } - - public static TitlePacket timesForProtocolVersion(ProtocolVersion version) { - TitlePacket packet = new TitlePacket(); - packet.setAction(version.compareTo(ProtocolVersion.MINECRAFT_1_11) >= 0 ? TitlePacket.SET_TIMES - : TitlePacket.SET_TIMES_OLD); - return packet; - } - - @Override - public String toString() { - return "TitlePacket{" - + "action=" + action - + ", component='" + component + '\'' - + ", fadeIn=" + fadeIn - + ", stay=" + stay - + ", fadeOut=" + fadeOut - + '}'; - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } -} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java new file mode 100644 index 000000000..38c890c03 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; +import org.checkerframework.checker.nullness.qual.Nullable; + +public abstract class GenericTitlePacket implements MinecraftPacket { + + public enum ActionType { + SET_TITLE(0), + SET_SUBTITLE(1), + SET_ACTION_BAR(2), + SET_TIMES(3), + HIDE(4), + RESET(5); + + private final int action; + + ActionType(int action) { + this.action = action; + } + + public int getAction(ProtocolVersion version) { + return version.compareTo(ProtocolVersion.MINECRAFT_1_11) < 0 + ? action > 2 ? action - 1 : action : action; + } + } + + + private ActionType action; + + protected void setAction(ActionType action) { + this.action = action; + } + + public final ActionType getAction() { + return action; + } + + public String getComponent() { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public void setComponent(String component) { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public int getFadeIn() { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public void setFadeIn(int fadeIn) { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public int getStay() { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public void setStay(int stay) { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public int getFadeOut() { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + public void setFadeOut(int fadeOut) { + throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); + } + + + + @Override + public final void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion version) { + throw new UnsupportedOperationException(); // encode only + } + + /** + * Creates a version and type dependent TitlePacket. + * + * @param type Action the packet should invoke + * @param version Protocol version of the target player + * @return GenericTitlePacket instance that follows the invoker type/version + */ + public static GenericTitlePacket constructTitlePacket(ActionType type, ProtocolVersion version) { + GenericTitlePacket packet = null; + if (version.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { + switch (type) { + case SET_ACTION_BAR: + packet = new TitleActionbarPacket(); + break; + case SET_SUBTITLE: + packet = new TitleSubtitlePacket(); + break; + case SET_TIMES: + packet = new TitleTimesPacket(); + break; + case SET_TITLE: + packet = new TitleTextPacket(); + break; + case HIDE: + case RESET: + packet = new TitleClearPacket(); + break; + default: + throw new IllegalArgumentException("Invalid ActionType"); + } + } else { + packet = new LegacyTitlePacket(); + } + packet.setAction(type); + return packet; + } + +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java new file mode 100644 index 000000000..7b25325e6 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class LegacyTitlePacket extends GenericTitlePacket { + + private @Nullable String component; + private int fadeIn; + private int stay; + private int fadeOut; + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + if (version.compareTo(ProtocolVersion.MINECRAFT_1_11) < 0 + && getAction() == ActionType.SET_ACTION_BAR) { + throw new IllegalStateException("Action bars are only supported on 1.11 and newer"); + } + ProtocolUtils.writeVarInt(buf, getAction().getAction(version)); + + switch (getAction()) { + case SET_TITLE: + case SET_SUBTITLE: + case SET_ACTION_BAR: + if (component == null) { + throw new IllegalStateException("No component found for " + getAction()); + } + ProtocolUtils.writeString(buf, component); + break; + case SET_TIMES: + buf.writeInt(fadeIn); + buf.writeInt(stay); + buf.writeInt(fadeOut); + break; + case HIDE: + case RESET: + break; + default: + throw new UnsupportedOperationException("Unknown action " + getAction()); + } + + } + + @Override + public void setAction(ActionType action) { + super.setAction(action); + } + + @Override + public @Nullable String getComponent() { + return component; + } + + @Override + public void setComponent(@Nullable String component) { + this.component = component; + } + + @Override + public int getFadeIn() { + return fadeIn; + } + + @Override + public void setFadeIn(int fadeIn) { + this.fadeIn = fadeIn; + } + + @Override + public int getStay() { + return stay; + } + + @Override + public void setStay(int stay) { + this.stay = stay; + } + + @Override + public int getFadeOut() { + return fadeOut; + } + + @Override + public void setFadeOut(int fadeOut) { + this.fadeOut = fadeOut; + } + + @Override + public String toString() { + return "GenericTitlePacket{" + + "action=" + getAction() + + ", component='" + component + '\'' + + ", fadeIn=" + fadeIn + + ", stay=" + stay + + ", fadeOut=" + fadeOut + + '}'; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java new file mode 100644 index 000000000..e875ae3cd --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class TitleActionbarPacket extends GenericTitlePacket { + + private String component; + + public TitleActionbarPacket() { + setAction(ActionType.SET_TITLE); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + ProtocolUtils.writeString(buf, component); + } + + @Override + public String getComponent() { + return component; + } + + @Override + public void setComponent(String component) { + this.component = component; + } + + @Override + public String toString() { + return "TitleActionbarPacket{" + + ", component='" + component + '\'' + + '}'; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java new file mode 100644 index 000000000..8ee0289ab --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class TitleClearPacket extends GenericTitlePacket { + + private boolean resetTimes; + + public TitleClearPacket() { + setAction(ActionType.HIDE); + } + + @Override + public void setAction(ActionType action) { + if (action != ActionType.HIDE && action != ActionType.RESET) { + throw new IllegalArgumentException("TitleClearPacket only accepts CLEAR and RESET actions"); + } + super.setAction(action); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + buf.writeBoolean(getAction() == ActionType.RESET); + } + + @Override + public String toString() { + return "TitleClearPacket{" + + ", reset=" + resetTimes + + '}'; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java new file mode 100644 index 000000000..1640862f7 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class TitleSubtitlePacket extends GenericTitlePacket { + + private String component; + + public TitleSubtitlePacket() { + setAction(ActionType.SET_SUBTITLE); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + ProtocolUtils.writeString(buf, component); + } + + @Override + public String getComponent() { + return component; + } + + @Override + public void setComponent(String component) { + this.component = component; + } + + @Override + public String toString() { + return "TitleSubtitlePacket{" + + ", component='" + component + '\'' + + '}'; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java new file mode 100644 index 000000000..135eb27e4 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class TitleTextPacket extends GenericTitlePacket { + + private String component; + + public TitleTextPacket() { + setAction(ActionType.SET_TITLE); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + ProtocolUtils.writeString(buf, component); + } + + @Override + public String getComponent() { + return component; + } + + @Override + public void setComponent(String component) { + this.component = component; + } + + @Override + public String toString() { + return "TitleTextPacket{" + + ", component='" + component + '\'' + + '}'; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java new file mode 100644 index 000000000..7450caccd --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2018 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.title; + +import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.connection.MinecraftSessionHandler; +import com.velocitypowered.proxy.protocol.ProtocolUtils; +import io.netty.buffer.ByteBuf; + +public class TitleTimesPacket extends GenericTitlePacket { + + private int fadeIn; + private int stay; + private int fadeOut; + + public TitleTimesPacket() { + setAction(ActionType.SET_TIMES); + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + buf.writeInt(fadeIn); + buf.writeInt(stay); + buf.writeInt(fadeOut); + } + + @Override + public int getFadeIn() { + return fadeIn; + } + + @Override + public void setFadeIn(int fadeIn) { + this.fadeIn = fadeIn; + } + + @Override + public int getStay() { + return stay; + } + + @Override + public void setStay(int stay) { + this.stay = stay; + } + + @Override + public int getFadeOut() { + return fadeOut; + } + + @Override + public void setFadeOut(int fadeOut) { + this.fadeOut = fadeOut; + } + + @Override + public String toString() { + return "TitleTimesPacket{" + + ", fadeIn=" + fadeIn + + ", stay=" + stay + + ", fadeOut=" + fadeOut + + '}'; + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } +} diff --git a/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java b/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java index 1780d14ac..b2f6e857a 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/protocol/PacketRegistryTest.java @@ -23,7 +23,11 @@ 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_12_2; 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_14_2; +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_8; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -43,8 +47,9 @@ class PacketRegistryTest { StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry( ProtocolUtils.Direction.CLIENTBOUND); registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, false), - new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, false)); + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, null, false), + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false), + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_15, MINECRAFT_1_16, false)); return registry; } @@ -73,6 +78,8 @@ class PacketRegistryTest { "Registry did not return the correct packet ID"); assertNull(registry.getProtocolRegistry(MINECRAFT_1_14_2).createPacket(0x01), "Registry should return a null"); + assertNull(registry.getProtocolRegistry(MINECRAFT_1_16_2).createPacket(0), + "Registry should return null"); } @Test @@ -91,12 +98,19 @@ class PacketRegistryTest { ProtocolUtils.Direction.CLIENTBOUND); assertThrows(IllegalArgumentException.class, () -> registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, false), - new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, false))); + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false), + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false))); assertThrows(IllegalArgumentException.class, () -> registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, false), - new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, false))); + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false), + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false))); + assertThrows(IllegalArgumentException.class, + () -> registry.register(Handshake.class, Handshake::new, + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, MINECRAFT_1_8, false))); + assertThrows(IllegalArgumentException.class, + () -> registry.register(Handshake.class, Handshake::new, + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, MINECRAFT_1_14, false), + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_16, null, false))); } @Test @@ -104,13 +118,13 @@ class PacketRegistryTest { StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry( ProtocolUtils.Direction.CLIENTBOUND); registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, false)); + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false)); assertThrows(IllegalArgumentException.class, () -> registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12, false))); + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12, null, false))); assertThrows(IllegalArgumentException.class, () -> registry.register(StatusPing.class, StatusPing::new, - new StateRegistry.PacketMapping(0x00, MINECRAFT_1_13, false))); + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_13, null, false))); } @Test @@ -118,9 +132,9 @@ class PacketRegistryTest { StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry( ProtocolUtils.Direction.CLIENTBOUND); assertDoesNotThrow(() -> registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, false), + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false), new StateRegistry.PacketMapping(0x01, getLast(ProtocolVersion.SUPPORTED_VERSIONS), - false))); + null, false))); } @Test @@ -128,9 +142,9 @@ class PacketRegistryTest { StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry( ProtocolUtils.Direction.CLIENTBOUND); registry.register(Handshake.class, Handshake::new, - new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, false), - new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12_1, false), - new StateRegistry.PacketMapping(0x02, MINECRAFT_1_13, false)); + new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false), + new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12_1, null, false), + new StateRegistry.PacketMapping(0x02, MINECRAFT_1_13, null, false)); assertEquals(Handshake.class, registry.getProtocolRegistry(MINECRAFT_1_12).createPacket(0x00).getClass()); assertEquals(Handshake.class,