Break up StateRegistry

This commit is contained in:
Andrew Steinborn
2025-10-19 02:33:36 -04:00
parent 287a9b28f1
commit c7b715f8ab
78 changed files with 1883 additions and 1207 deletions

View File

@@ -0,0 +1,797 @@
/*
* Copyright (C) 2025 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 <https://www.gnu.org/licenses/>.
*/
package com.velocitypowered.proxy.protocol;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_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_13;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14_4;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_15;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_15_2;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_1;
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_17_1;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_18_2;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_1;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_3;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_19_4;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_2;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_3;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_20_5;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_2;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_4;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_5;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_6;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_21_9;
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_1;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9_4;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.protocol.packet.AvailableCommandsPacket;
import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
import com.velocitypowered.proxy.protocol.packet.DialogClearPacket;
import com.velocitypowered.proxy.protocol.packet.DialogShowPacket;
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
import com.velocitypowered.proxy.protocol.packet.EncryptionRequestPacket;
import com.velocitypowered.proxy.protocol.packet.EncryptionResponsePacket;
import com.velocitypowered.proxy.protocol.packet.HandshakePacket;
import com.velocitypowered.proxy.protocol.packet.HeaderAndFooterPacket;
import com.velocitypowered.proxy.protocol.packet.JoinGamePacket;
import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket;
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket;
import com.velocitypowered.proxy.protocol.packet.LoginAcknowledgedPacket;
import com.velocitypowered.proxy.protocol.packet.LoginPluginMessagePacket;
import com.velocitypowered.proxy.protocol.packet.LoginPluginResponsePacket;
import com.velocitypowered.proxy.protocol.packet.PingIdentifyPacket;
import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket;
import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfoPacket;
import com.velocitypowered.proxy.protocol.packet.RemoveResourcePackPacket;
import com.velocitypowered.proxy.protocol.packet.ResourcePackRequestPacket;
import com.velocitypowered.proxy.protocol.packet.ResourcePackResponsePacket;
import com.velocitypowered.proxy.protocol.packet.RespawnPacket;
import com.velocitypowered.proxy.protocol.packet.ServerDataPacket;
import com.velocitypowered.proxy.protocol.packet.ServerLoginPacket;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccessPacket;
import com.velocitypowered.proxy.protocol.packet.ServerboundCookieResponsePacket;
import com.velocitypowered.proxy.protocol.packet.ServerboundCustomClickActionPacket;
import com.velocitypowered.proxy.protocol.packet.SetCompressionPacket;
import com.velocitypowered.proxy.protocol.packet.StatusPingPacket;
import com.velocitypowered.proxy.protocol.packet.StatusRequestPacket;
import com.velocitypowered.proxy.protocol.packet.StatusResponsePacket;
import com.velocitypowered.proxy.protocol.packet.TabCompleteRequestPacket;
import com.velocitypowered.proxy.protocol.packet.TabCompleteResponsePacket;
import com.velocitypowered.proxy.protocol.packet.TransferPacket;
import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket;
import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket;
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
import com.velocitypowered.proxy.protocol.packet.chat.SystemChatPacket;
import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerChatPacket;
import com.velocitypowered.proxy.protocol.packet.chat.keyed.KeyedPlayerCommandPacket;
import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatPacket;
import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerChatPacket;
import com.velocitypowered.proxy.protocol.packet.chat.session.SessionPlayerCommandPacket;
import com.velocitypowered.proxy.protocol.packet.chat.session.UnsignedPlayerCommandPacket;
import com.velocitypowered.proxy.protocol.packet.config.ActiveFeaturesPacket;
import com.velocitypowered.proxy.protocol.packet.config.ClientboundCustomReportDetailsPacket;
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductAcceptPacket;
import com.velocitypowered.proxy.protocol.packet.config.CodeOfConductPacket;
import com.velocitypowered.proxy.protocol.packet.config.FinishedUpdatePacket;
import com.velocitypowered.proxy.protocol.packet.config.KnownPacksPacket;
import com.velocitypowered.proxy.protocol.packet.config.RegistrySyncPacket;
import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket;
import com.velocitypowered.proxy.protocol.packet.config.TagsUpdatePacket;
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 com.velocitypowered.proxy.protocol.registry.MultiVersionPacketRegistry;
import com.velocitypowered.proxy.protocol.registry.MultiVersionPacketRegistry.VersionRange;
import com.velocitypowered.proxy.protocol.registry.ProtocolToPacketRegistry;
import com.velocitypowered.proxy.protocol.registry.SimplePacketRegistry;
/**
* Defines the packet mappings for all protocol states and versions supported by Velocity.
*/
public class ProtocolStates {
public static final ProtocolToPacketRegistry HANDSHAKE_CLIENTBOUND;
public static final ProtocolToPacketRegistry HANDSHAKE_SERVERBOUND;
public static final ProtocolToPacketRegistry STATUS_SERVERBOUND;
public static final ProtocolToPacketRegistry STATUS_CLIENTBOUND;
public static final ProtocolToPacketRegistry CONFIG_SERVERBOUND;
public static final ProtocolToPacketRegistry CONFIG_CLIENTBOUND;
public static final ProtocolToPacketRegistry PLAY_SERVERBOUND;
public static final ProtocolToPacketRegistry PLAY_CLIENTBOUND;
public static final ProtocolToPacketRegistry LOGIN_SERVERBOUND;
public static final ProtocolToPacketRegistry LOGIN_CLIENTBOUND;
static {
HANDSHAKE_CLIENTBOUND = new SimplePacketRegistry(Direction.CLIENTBOUND);
SimplePacketRegistry handshakeServerbound = new SimplePacketRegistry(Direction.SERVERBOUND);
handshakeServerbound.register(0x00, HandshakePacket.class, HandshakePacket.Codec.INSTANCE);
HANDSHAKE_SERVERBOUND = handshakeServerbound;
SimplePacketRegistry statusServerbound = new SimplePacketRegistry(Direction.SERVERBOUND);
statusServerbound.register(0x00,
StatusRequestPacket.class, StatusRequestPacket.Codec.INSTANCE);
statusServerbound.register(0x01, StatusPingPacket.class, StatusPingPacket.Codec.INSTANCE);
STATUS_SERVERBOUND = statusServerbound;
SimplePacketRegistry statusClientbound = new SimplePacketRegistry(Direction.CLIENTBOUND);
statusClientbound.register(0x00,
StatusResponsePacket.class, StatusResponsePacket.Codec.INSTANCE);
statusClientbound.register(0x01, StatusPingPacket.class, StatusPingPacket.Codec.INSTANCE);
STATUS_CLIENTBOUND = statusClientbound;
CONFIG_SERVERBOUND = MultiVersionPacketRegistry.builder(Direction.SERVERBOUND)
.register(ClientSettingsPacket.class, ClientSettingsPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, 0x00))
.register(ServerboundCookieResponsePacket.class,
ServerboundCookieResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x01))
.register(PluginMessagePacket.class, PluginMessagePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x01),
VersionRange.of(MINECRAFT_1_20_5, 0x02))
.register(FinishedUpdatePacket.class, FinishedUpdatePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x02),
VersionRange.of(MINECRAFT_1_20_5, 0x03))
.register(KeepAlivePacket.class, KeepAlivePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x03),
VersionRange.of(MINECRAFT_1_20_5, 0x04))
.register(PingIdentifyPacket.class, PingIdentifyPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x04),
VersionRange.of(MINECRAFT_1_20_5, 0x05))
.register(ResourcePackResponsePacket.class, ResourcePackResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x05),
VersionRange.of(MINECRAFT_1_20_5, 0x06))
.register(KnownPacksPacket.class, KnownPacksPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x07))
.register(ServerboundCustomClickActionPacket.class,
ServerboundCustomClickActionPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21_6, 0x08))
.register(CodeOfConductAcceptPacket.class, CodeOfConductAcceptPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21_9, 0x09))
.build();
CONFIG_CLIENTBOUND = MultiVersionPacketRegistry.builder(Direction.CLIENTBOUND)
.register(ClientboundCookieRequestPacket.class,
ClientboundCookieRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x00))
.register(PluginMessagePacket.class, PluginMessagePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x00),
VersionRange.of(MINECRAFT_1_20_5, 0x01))
.register(DisconnectPacket.class, new DisconnectPacket.Codec(StateRegistry.CONFIG),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x01),
VersionRange.of(MINECRAFT_1_20_5, 0x02))
.register(FinishedUpdatePacket.class, FinishedUpdatePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x02),
VersionRange.of(MINECRAFT_1_20_5, 0x03))
.register(KeepAlivePacket.class, KeepAlivePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x03),
VersionRange.of(MINECRAFT_1_20_5, 0x04))
.register(PingIdentifyPacket.class, PingIdentifyPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x04),
VersionRange.of(MINECRAFT_1_20_5, 0x05))
.register(RegistrySyncPacket.class, RegistrySyncPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x05),
VersionRange.of(MINECRAFT_1_20_5, 0x07))
.register(RemoveResourcePackPacket.class, RemoveResourcePackPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x06),
VersionRange.of(MINECRAFT_1_20_5, 0x08))
.register(ResourcePackRequestPacket.class, ResourcePackRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x06),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x07),
VersionRange.of(MINECRAFT_1_20_5, 0x09))
.register(ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x0A))
.register(TransferPacket.class, TransferPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x0B))
.register(ActiveFeaturesPacket.class, ActiveFeaturesPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x07),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x08),
VersionRange.of(MINECRAFT_1_20_5, 0x0C))
.register(TagsUpdatePacket.class, TagsUpdatePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x08),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x09),
VersionRange.of(MINECRAFT_1_20_5, 0x0D))
.register(KnownPacksPacket.class, KnownPacksPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x0E))
.register(ClientboundCustomReportDetailsPacket.class,
ClientboundCustomReportDetailsPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21, 0x0F))
.register(ClientboundServerLinksPacket.class, ClientboundServerLinksPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21, 0x10))
.register(DialogClearPacket.class, DialogClearPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21_6, 0x11))
.register(DialogShowPacket.class, new DialogShowPacket.Codec(StateRegistry.CONFIG),
VersionRange.of(MINECRAFT_1_21_6, 0x12))
.register(CodeOfConductPacket.class, CodeOfConductPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21_9, 0x13))
.build();
LOGIN_SERVERBOUND = MultiVersionPacketRegistry.builder(Direction.SERVERBOUND)
.register(ServerLoginPacket.class, ServerLoginPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, 0x00))
.register(EncryptionResponsePacket.class, EncryptionResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, 0x01))
.register(LoginPluginResponsePacket.class, LoginPluginResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_13, 0x02))
.register(LoginAcknowledgedPacket.class, LoginAcknowledgedPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, 0x03))
.register(ServerboundCookieResponsePacket.class,
ServerboundCookieResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x04))
.build();
LOGIN_CLIENTBOUND = MultiVersionPacketRegistry.builder(Direction.CLIENTBOUND)
.register(DisconnectPacket.class, new DisconnectPacket.Codec(StateRegistry.LOGIN),
VersionRange.of(MINECRAFT_1_7_2, 0x00))
.register(EncryptionRequestPacket.class, EncryptionRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, 0x01))
.register(ServerLoginSuccessPacket.class, ServerLoginSuccessPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, 0x02))
.register(SetCompressionPacket.class, SetCompressionPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_8, 0x03))
.register(LoginPluginMessagePacket.class, LoginPluginMessagePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_13, 0x04))
.register(ClientboundCookieRequestPacket.class,
ClientboundCookieRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, 0x05))
.build();
// PLAY state is much larger, will continue below
PLAY_SERVERBOUND = buildPlayServerbound();
PLAY_CLIENTBOUND = buildPlayClientbound();
}
private static ProtocolToPacketRegistry buildPlayServerbound() {
return MultiVersionPacketRegistry.builder(Direction.SERVERBOUND)
.register(TabCompleteRequestPacket.class, TabCompleteRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x14),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x01),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x02),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x01),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x05),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_18_2, 0x06),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x08),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x09),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x08),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x09),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x0A),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x0B),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x0D),
VersionRange.of(MINECRAFT_1_21_6, 0x0E))
.register(LegacyChatPacket.class, LegacyChatPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x01),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x02),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x03),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_13, 0x02),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_18_2, 0x03))
.register(ChatAcknowledgementPacket.class, ChatAcknowledgementPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_21, 0x03),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x04),
VersionRange.of(MINECRAFT_1_21_6, 0x05))
.register(KeyedPlayerCommandPacket.class, KeyedPlayerCommandPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x03),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x04))
.register(KeyedPlayerChatPacket.class, KeyedPlayerChatPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x04),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x05))
.register(SessionPlayerCommandPacket.class, SessionPlayerCommandPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_20_3, 0x04),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x05),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x06),
VersionRange.of(MINECRAFT_1_21_6, 0x07))
.register(UnsignedPlayerCommandPacket.class, UnsignedPlayerCommandPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x04),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x05),
VersionRange.of(MINECRAFT_1_21_6, 0x06))
.register(SessionPlayerChatPacket.class, SessionPlayerChatPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_20_3, 0x05),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x06),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x07),
VersionRange.of(MINECRAFT_1_21_6, 0x08))
.register(ClientSettingsPacket.class, ClientSettingsPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x15),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x04),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x05),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_13, 0x04),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_18_2, 0x05),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x07),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x08),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x07),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x08),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x09),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x0A),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x0C),
VersionRange.of(MINECRAFT_1_21_6, 0x0D))
.register(ServerboundCookieResponsePacket.class,
ServerboundCookieResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x11),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x13),
VersionRange.of(MINECRAFT_1_21_6, 0x14))
.register(PluginMessagePacket.class, PluginMessagePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x17),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x09),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x0A),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x09),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x0A),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_16_4, 0x0B),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x0A),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x0C),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x0D),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x0C),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x0D),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x0F),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x10),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x12),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x14),
VersionRange.of(MINECRAFT_1_21_6, 0x15))
.register(KeepAlivePacket.class, KeepAlivePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x00),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x0B),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x0C),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x0B),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x0E),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_15_2, 0x0F),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_4, 0x10),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x0F),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x11),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x12),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x11),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x12),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x14),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x15),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x18),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x1A),
VersionRange.of(MINECRAFT_1_21_6, 0x1B))
.register(ResourcePackResponsePacket.class, ResourcePackResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_8, 0x19),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x16),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x18),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x1D),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_15_2, 0x1F),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x20),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_18_2, 0x21),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x23),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_20, 0x24),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x27),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x28),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x2B),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_2, 0x2D),
VersionRange.of(MINECRAFT_1_21_4, MINECRAFT_1_21_4, 0x2F),
VersionRange.of(MINECRAFT_1_21_6, 0x30))
.register(FinishedUpdatePacket.class, FinishedUpdatePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x0B),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x0C),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x0E),
VersionRange.of(MINECRAFT_1_21_6, 0x0F))
.build();
}
private static ProtocolToPacketRegistry buildPlayClientbound() {
return MultiVersionPacketRegistry.builder(Direction.CLIENTBOUND)
.register(BossBarPacket.class, BossBarPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_14, 0x0C),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x0D),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_4, 0x0C),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x0D),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19_3, 0x0A),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x0B),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_21_4, 0x0A),
VersionRange.of(MINECRAFT_1_21_5, 0x09))
.register(LegacyChatPacket.class, LegacyChatPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x02),
VersionRange.encodeOnly(MINECRAFT_1_9, MINECRAFT_1_12, 0x0F),
VersionRange.encodeOnly(MINECRAFT_1_13, MINECRAFT_1_13, 0x0E),
VersionRange.encodeOnly(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x0F),
VersionRange.encodeOnly(MINECRAFT_1_16, MINECRAFT_1_16_4, 0x0E),
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x0F))
.register(TabCompleteResponsePacket.class, TabCompleteResponsePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x3A),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_12, 0x0E),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_14, 0x10),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x11),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x10),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x0F),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x11),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19_1, 0x0E),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x0D),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x0F),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_21_4, 0x10),
VersionRange.of(MINECRAFT_1_21_5, 0x0F))
.register(AvailableCommandsPacket.class, AvailableCommandsPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_14, 0x11),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x12),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x11),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x10),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x12),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19_1, 0x0F),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x0E),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x10),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_21_4, 0x11),
VersionRange.of(MINECRAFT_1_21_5, 0x10))
.register(ClientboundCookieRequestPacket.class,
ClientboundCookieRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21_4, 0x16),
VersionRange.of(MINECRAFT_1_21_5, 0x15))
.register(ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x5D),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x61),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x63),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x65),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x67),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x6E),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x6D),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x72))
.register(ClientboundStopSoundPacket.class, ClientboundStopSoundPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x5F),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x63),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x66),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x68),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x6A),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x71),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x70),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x75))
.register(PluginMessagePacket.class, PluginMessagePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x3F),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_12, 0x18),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x19),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_14, 0x18),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x19),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x18),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x17),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x18),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x15),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x16),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x15),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x17),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x18),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21_4, 0x19),
VersionRange.of(MINECRAFT_1_21_5, 0x18))
.register(DisconnectPacket.class, new DisconnectPacket.Codec(StateRegistry.PLAY),
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x40),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_12, 0x1A),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x1B),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_14, 0x1A),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x1B),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x1A),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x19),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x1A),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x17),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x19),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x17),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x1A),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x1B),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21_4, 0x1D),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x1C),
VersionRange.of(MINECRAFT_1_21_9, 0x20))
.register(KeepAlivePacket.class, KeepAlivePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x00),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_12, 0x1F),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x21),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_14_4, 0x20),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x21),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x20),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x1F),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x21),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x1E),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x20),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x1F),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x23),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x24),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x26),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x27),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x26),
VersionRange.of(MINECRAFT_1_21_9, 0x2B))
.register(JoinGamePacket.class, JoinGamePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x01),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_12, 0x23),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_14, 0x25),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x26),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x25),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x24),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x26),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x23),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x25),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x24),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x28),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x29),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x2B),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x2C),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x2B),
VersionRange.of(MINECRAFT_1_21_9, 0x30))
.register(RespawnPacket.class, RespawnPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x07),
VersionRange.encodeOnly(MINECRAFT_1_9, MINECRAFT_1_11, 0x33),
VersionRange.encodeOnly(MINECRAFT_1_12, MINECRAFT_1_12, 0x34),
VersionRange.encodeOnly(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x35),
VersionRange.encodeOnly(MINECRAFT_1_13, MINECRAFT_1_13, 0x38),
VersionRange.encodeOnly(MINECRAFT_1_14, MINECRAFT_1_14, 0x3A),
VersionRange.encodeOnly(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x3B),
VersionRange.encodeOnly(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x3A),
VersionRange.encodeOnly(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x39),
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x3D),
VersionRange.encodeOnly(MINECRAFT_1_19, MINECRAFT_1_19, 0x3B),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x3E),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x3D),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x41),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x43),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x45),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x47),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x4C),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x4B),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x50))
.register(RemoveResourcePackPacket.class, RemoveResourcePackPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x43),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x45),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x4A),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x49),
VersionRange.of(MINECRAFT_1_21_9, 0x4E))
.register(ResourcePackRequestPacket.class, ResourcePackRequestPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_8, 0x48),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_11, 0x32),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x33),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x34),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x37),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_14, 0x39),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x3A),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x39),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x38),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x3C),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x3A),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x3D),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x3C),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x40),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x42),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x44),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x46),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x4B),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x4A),
VersionRange.of(MINECRAFT_1_21_9, 0x4F))
.register(HeaderAndFooterPacket.class, HeaderAndFooterPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_8, MINECRAFT_1_8, 0x47),
VersionRange.encodeOnly(MINECRAFT_1_9, MINECRAFT_1_9_1, 0x48),
VersionRange.encodeOnly(MINECRAFT_1_9_4, MINECRAFT_1_11, 0x47),
VersionRange.encodeOnly(MINECRAFT_1_12, MINECRAFT_1_12, 0x49),
VersionRange.encodeOnly(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x4A),
VersionRange.encodeOnly(MINECRAFT_1_13, MINECRAFT_1_13, 0x4E),
VersionRange.encodeOnly(MINECRAFT_1_14, MINECRAFT_1_14, 0x53),
VersionRange.encodeOnly(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x54),
VersionRange.encodeOnly(MINECRAFT_1_16, MINECRAFT_1_16_4, 0x53),
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_17_1, 0x5E),
VersionRange.encodeOnly(MINECRAFT_1_18, MINECRAFT_1_18_2, 0x5F),
VersionRange.encodeOnly(MINECRAFT_1_19, MINECRAFT_1_19, 0x60),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x63),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x61),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x65),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x68),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x6A),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x6D),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x74),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x73),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x78))
.register(LegacyTitlePacket.class, LegacyTitlePacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_8, MINECRAFT_1_11, 0x45),
VersionRange.encodeOnly(MINECRAFT_1_12, MINECRAFT_1_12, 0x47),
VersionRange.encodeOnly(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x48),
VersionRange.encodeOnly(MINECRAFT_1_13, MINECRAFT_1_13, 0x4B),
VersionRange.encodeOnly(MINECRAFT_1_14, MINECRAFT_1_14_4, 0x4F),
VersionRange.encodeOnly(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x50),
VersionRange.encodeOnly(MINECRAFT_1_16, MINECRAFT_1_16_4, 0x4F))
.register(TitleSubtitlePacket.class, TitleSubtitlePacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_17_1, 0x57),
VersionRange.encodeOnly(MINECRAFT_1_18, MINECRAFT_1_18_2, 0x58),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x5B),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x59),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x5D),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x5F),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x61),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x63),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x6A),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x69),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x6E))
.register(TitleTextPacket.class, TitleTextPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_17_1, 0x59),
VersionRange.encodeOnly(MINECRAFT_1_18, MINECRAFT_1_18_2, 0x5A),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x5D),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x5B),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x5F),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x61),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x63),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x65),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x6C),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x6B),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x70))
.register(TitleActionbarPacket.class, TitleActionbarPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x41),
VersionRange.encodeOnly(MINECRAFT_1_19, MINECRAFT_1_19, 0x40),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x43),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x42),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x46),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x48),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x4A),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x4C),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x51),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x50),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x55))
.register(TitleTimesPacket.class, TitleTimesPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_17_1, 0x5A),
VersionRange.encodeOnly(MINECRAFT_1_18, MINECRAFT_1_18_2, 0x5B),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x5E),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x5C),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x60),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x62),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x64),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x66),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x6D),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x6C),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x71))
.register(TitleClearPacket.class, TitleClearPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x10),
VersionRange.encodeOnly(MINECRAFT_1_19, MINECRAFT_1_19_1, 0x0D),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x0C),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x0E),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_21_4, 0x0F),
VersionRange.encodeOnly(MINECRAFT_1_21_5, 0x0E))
.register(LegacyPlayerListItemPacket.class, LegacyPlayerListItemPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_7_2, MINECRAFT_1_8, 0x38),
VersionRange.of(MINECRAFT_1_9, MINECRAFT_1_12, 0x2D),
VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_12_1, 0x2E),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_13, 0x30),
VersionRange.of(MINECRAFT_1_14, MINECRAFT_1_14, 0x33),
VersionRange.of(MINECRAFT_1_15, MINECRAFT_1_15_2, 0x34),
VersionRange.of(MINECRAFT_1_16, MINECRAFT_1_16_1, 0x33),
VersionRange.of(MINECRAFT_1_16_2, MINECRAFT_1_16_4, 0x32),
VersionRange.of(MINECRAFT_1_17, MINECRAFT_1_18_2, 0x36),
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x34),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x37))
.register(RemovePlayerInfoPacket.class, RemovePlayerInfoPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x35),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x39),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x3B),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x3D),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x3F),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x3E),
VersionRange.of(MINECRAFT_1_21_9, 0x43))
.register(UpsertPlayerInfoPacket.class, UpsertPlayerInfoPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x36),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x3A),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x3C),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x3E),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x40),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x3F),
VersionRange.of(MINECRAFT_1_21_9, 0x44))
.register(ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x6B),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x72),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x71),
VersionRange.of(MINECRAFT_1_21_9, 0x76))
.register(SystemChatPacket.class, SystemChatPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_19, MINECRAFT_1_19, 0x5F),
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x62),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x60),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x64),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x67),
VersionRange.encodeOnly(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x69),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x6C),
VersionRange.encodeOnly(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x73),
VersionRange.encodeOnly(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x72),
VersionRange.encodeOnly(MINECRAFT_1_21_9, 0x77))
.register(PlayerChatCompletionPacket.class, PlayerChatCompletionPacket.Codec.INSTANCE,
VersionRange.encodeOnly(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x15),
VersionRange.encodeOnly(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x14),
VersionRange.encodeOnly(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x16),
VersionRange.encodeOnly(MINECRAFT_1_20_2, MINECRAFT_1_20_3, 0x17),
VersionRange.encodeOnly(MINECRAFT_1_20_5, MINECRAFT_1_21_4, 0x18),
VersionRange.encodeOnly(MINECRAFT_1_21_5, 0x17))
.register(ServerDataPacket.class, ServerDataPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19, MINECRAFT_1_19, 0x3F),
VersionRange.of(MINECRAFT_1_19_1, MINECRAFT_1_19_1, 0x42),
VersionRange.of(MINECRAFT_1_19_3, MINECRAFT_1_19_3, 0x41),
VersionRange.of(MINECRAFT_1_19_4, MINECRAFT_1_20, 0x45),
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x47),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x49),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x4B),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x50),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x4F),
VersionRange.of(MINECRAFT_1_21_9, 0x54))
.register(StartUpdatePacket.class, StartUpdatePacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_2, MINECRAFT_1_20_2, 0x65),
VersionRange.of(MINECRAFT_1_20_3, MINECRAFT_1_20_3, 0x67),
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x69),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_4, 0x70),
VersionRange.of(MINECRAFT_1_21_5, MINECRAFT_1_21_6, 0x6F),
VersionRange.of(MINECRAFT_1_21_9, 0x74))
.register(BundleDelimiterPacket.class, BundleDelimiterPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_19_4, 0x00))
.register(TransferPacket.class, TransferPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_20_5, MINECRAFT_1_21, 0x73),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_6, 0x7A),
VersionRange.of(MINECRAFT_1_21_9, 0x7F))
.register(ClientboundCustomReportDetailsPacket.class,
ClientboundCustomReportDetailsPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21, MINECRAFT_1_21, 0x7A),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_6, 0x81),
VersionRange.of(MINECRAFT_1_21_9, 0x86))
.register(ClientboundServerLinksPacket.class, ClientboundServerLinksPacket.Codec.INSTANCE,
VersionRange.of(MINECRAFT_1_21, MINECRAFT_1_21, 0x7B),
VersionRange.of(MINECRAFT_1_21_2, MINECRAFT_1_21_6, 0x82),
VersionRange.of(MINECRAFT_1_21_9, 0x87))
.build();
}
public static ProtocolToPacketRegistry handshake(Direction direction) {
return direction == Direction.SERVERBOUND ? HANDSHAKE_SERVERBOUND : HANDSHAKE_CLIENTBOUND;
}
public static ProtocolToPacketRegistry status(Direction direction) {
return direction == Direction.SERVERBOUND ? STATUS_SERVERBOUND : STATUS_CLIENTBOUND;
}
public static ProtocolToPacketRegistry login(Direction direction) {
return direction == Direction.SERVERBOUND ? LOGIN_SERVERBOUND : LOGIN_CLIENTBOUND;
}
public static ProtocolToPacketRegistry configuration(Direction direction) {
return direction == Direction.SERVERBOUND ? CONFIG_SERVERBOUND : CONFIG_CLIENTBOUND;
}
public static ProtocolToPacketRegistry play(Direction direction) {
return direction == Direction.SERVERBOUND ? PLAY_SERVERBOUND : PLAY_CLIENTBOUND;
}
/**
* Looks up the packet registry for the specified state and direction.
*
* @param registry the protocol state
* @param direction the packet direction
* @return the packet registry for the specified state and direction
*/
public static ProtocolToPacketRegistry lookup(StateRegistry registry, Direction direction) {
return switch (registry) {
case HANDSHAKE -> handshake(direction);
case STATUS -> status(direction);
case LOGIN -> login(direction);
case CONFIG -> configuration(direction);
case PLAY -> play(direction);
};
}
}

View File

@@ -20,8 +20,10 @@ package com.velocitypowered.proxy.protocol.netty;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import com.velocitypowered.proxy.util.except.QuietRuntimeException; import com.velocitypowered.proxy.util.except.QuietRuntimeException;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@@ -39,8 +41,9 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
+ "information, launch Velocity with -Dvelocity.packet-decode-logging=true to see more."); + "information, launch Velocity with -Dvelocity.packet-decode-logging=true to see more.");
private final ProtocolUtils.Direction direction; private final ProtocolUtils.Direction direction;
private ProtocolVersion version;
private StateRegistry state; private StateRegistry state;
private StateRegistry.PacketRegistry.ProtocolRegistry registry; private PacketRegistry registry;
/** /**
* Creates a new {@code MinecraftDecoder} decoding packets from the specified {@code direction}. * Creates a new {@code MinecraftDecoder} decoding packets from the specified {@code direction}.
@@ -49,8 +52,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
*/ */
public MinecraftDecoder(ProtocolUtils.Direction direction) { public MinecraftDecoder(ProtocolUtils.Direction direction) {
this.direction = Preconditions.checkNotNull(direction, "direction"); this.direction = Preconditions.checkNotNull(direction, "direction");
this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry( this.version = ProtocolVersion.MINIMUM_VERSION;
direction, ProtocolVersion.MINIMUM_VERSION); this.registry = ProtocolStates.handshake(direction).forVersion(ProtocolVersion.MINIMUM_VERSION);
this.state = StateRegistry.HANDSHAKE; this.state = StateRegistry.HANDSHAKE;
} }
@@ -82,11 +85,13 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
MinecraftPacket packet; MinecraftPacket packet;
try { try {
packet = codec.decode(buf, direction, registry.version); packet = codec.decode(buf, direction, this.version);
} catch (Exception e) { } catch (Exception e) {
throw handleDecodeFailure(e, codec, packetId); throw handleDecodeFailure(e, codec, packetId);
} }
System.out.println(packet);
if (buf.isReadable()) { if (buf.isReadable()) {
throw handleOverflow(packet, buf.readerIndex(), buf.writerIndex()); throw handleOverflow(packet, buf.readerIndex(), buf.writerIndex());
} }
@@ -100,8 +105,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
private void doLengthSanityChecks(ByteBuf buf, private void doLengthSanityChecks(ByteBuf buf,
com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec) com.velocitypowered.proxy.protocol.PacketCodec<? extends MinecraftPacket> codec)
throws Exception { throws Exception {
int expectedMinLen = codec.decodeExpectedMinLength(buf, direction, registry.version); int expectedMinLen = codec.decodeExpectedMinLength(buf, direction, this.version);
int expectedMaxLen = codec.decodeExpectedMaxLength(buf, direction, registry.version); int expectedMaxLen = codec.decodeExpectedMaxLength(buf, direction, this.version);
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) { if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
throw handleOverflow(codec, expectedMaxLen, buf.readableBytes()); throw handleOverflow(codec, expectedMaxLen, buf.readableBytes());
} }
@@ -153,17 +158,18 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
} }
private String getExtraConnectionDetail(int packetId) { private String getExtraConnectionDetail(int packetId) {
return "Direction " + direction + " Protocol " + registry.version + " State " + state return "Direction " + direction + " Protocol " + this.version + " State " + state
+ " ID 0x" + Integer.toHexString(packetId); + " ID 0x" + Integer.toHexString(packetId);
} }
public void setProtocolVersion(ProtocolVersion protocolVersion) { public void setProtocolVersion(ProtocolVersion protocolVersion) {
this.registry = state.getProtocolRegistry(direction, protocolVersion); this.version = protocolVersion;
this.registry = ProtocolStates.lookup(this.state, this.direction).forVersion(protocolVersion);
} }
public void setState(StateRegistry state) { public void setState(StateRegistry state) {
this.state = state; this.state = state;
this.setProtocolVersion(registry.version); this.registry = ProtocolStates.lookup(this.state, this.direction).forVersion(this.version);
} }
public ProtocolUtils.Direction getDirection() { public ProtocolUtils.Direction getDirection() {

View File

@@ -21,8 +21,10 @@ import com.google.common.base.Preconditions;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.PacketCodec; import com.velocitypowered.proxy.protocol.PacketCodec;
import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
@@ -33,8 +35,9 @@ import io.netty.handler.codec.MessageToByteEncoder;
public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> { public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
private final ProtocolUtils.Direction direction; private final ProtocolUtils.Direction direction;
private ProtocolVersion version;
private StateRegistry state; private StateRegistry state;
private StateRegistry.PacketRegistry.ProtocolRegistry registry; private PacketRegistry registry;
/** /**
* Creates a new {@code MinecraftEncoder} encoding packets for the specified {@code direction}. * Creates a new {@code MinecraftEncoder} encoding packets for the specified {@code direction}.
@@ -43,8 +46,8 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
*/ */
public MinecraftEncoder(ProtocolUtils.Direction direction) { public MinecraftEncoder(ProtocolUtils.Direction direction) {
this.direction = Preconditions.checkNotNull(direction, "direction"); this.direction = Preconditions.checkNotNull(direction, "direction");
this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry( this.version = ProtocolVersion.MINIMUM_VERSION;
direction, ProtocolVersion.MINIMUM_VERSION); this.registry = ProtocolStates.handshake(direction).forVersion(ProtocolVersion.MINIMUM_VERSION);
this.state = StateRegistry.HANDSHAKE; this.state = StateRegistry.HANDSHAKE;
} }
@@ -52,13 +55,14 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected void encode(ChannelHandlerContext ctx, MinecraftPacket msg, ByteBuf out) { protected void encode(ChannelHandlerContext ctx, MinecraftPacket msg, ByteBuf out) {
PacketCodec<MinecraftPacket> codec = (PacketCodec<MinecraftPacket>) this.registry.getCodec(msg.getClass()); PacketCodec<MinecraftPacket> codec = (PacketCodec<MinecraftPacket>) this.registry.getCodec(msg.getClass());
System.out.println(msg);
if (codec == null) { if (codec == null) {
throw new IllegalArgumentException("No codec found for packet: " + msg.getClass()); throw new IllegalArgumentException("No codec found for packet: " + msg.getClass());
} }
int packetId = this.registry.getPacketId(msg); int packetId = this.registry.getPacketId(msg);
ProtocolUtils.writeVarInt(out, packetId); ProtocolUtils.writeVarInt(out, packetId);
codec.encode(msg, out, direction, registry.version); codec.encode(msg, out, direction, version);
} }
@Override @Override
@@ -71,7 +75,7 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
int hint = -1; int hint = -1;
if (codec != null) { if (codec != null) {
hint = codec.encodeSizeHint(msg, direction, registry.version); hint = codec.encodeSizeHint(msg, direction, version);
} }
if (hint < 0) { if (hint < 0) {
@@ -84,12 +88,13 @@ public class MinecraftEncoder extends MessageToByteEncoder<MinecraftPacket> {
} }
public void setProtocolVersion(final ProtocolVersion protocolVersion) { public void setProtocolVersion(final ProtocolVersion protocolVersion) {
this.registry = state.getProtocolRegistry(direction, protocolVersion); this.version = protocolVersion;
this.registry = ProtocolStates.lookup(this.state, this.direction).forVersion(protocolVersion);
} }
public void setState(StateRegistry state) { public void setState(StateRegistry state) {
this.state = state; this.state = state;
this.setProtocolVersion(registry.version); this.registry = ProtocolStates.lookup(state, this.direction).forVersion(version);
} }
public ProtocolUtils.Direction getDirection() { public ProtocolUtils.Direction getDirection() {

View File

@@ -21,8 +21,10 @@ import static io.netty.util.ByteProcessor.FIND_NON_NUL;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.PacketCodec; import com.velocitypowered.proxy.protocol.PacketCodec;
import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import com.velocitypowered.proxy.util.except.QuietDecoderException; import com.velocitypowered.proxy.util.except.QuietDecoderException;
import com.velocitypowered.proxy.util.except.QuietRuntimeException; import com.velocitypowered.proxy.util.except.QuietRuntimeException;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
@@ -50,7 +52,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
new QuietDecoderException("Unknown packet"); new QuietDecoderException("Unknown packet");
private final ProtocolUtils.Direction direction; private final ProtocolUtils.Direction direction;
private final StateRegistry.PacketRegistry.ProtocolRegistry registry; private final PacketRegistry registry;
private StateRegistry state; private StateRegistry state;
/** /**
@@ -60,8 +62,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
*/ */
public MinecraftVarintFrameDecoder(ProtocolUtils.Direction direction) { public MinecraftVarintFrameDecoder(ProtocolUtils.Direction direction) {
this.direction = direction; this.direction = direction;
this.registry = StateRegistry.HANDSHAKE.getProtocolRegistry( this.registry = ProtocolStates.handshake(direction).forVersion(ProtocolVersion.MINIMUM_VERSION);
direction, ProtocolVersion.MINIMUM_VERSION);
this.state = StateRegistry.HANDSHAKE; this.state = StateRegistry.HANDSHAKE;
} }
@@ -110,9 +111,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
} }
private boolean validateServerboundHandshakePacket(ByteBuf in, int length) throws Exception { private boolean validateServerboundHandshakePacket(ByteBuf in, int length) throws Exception {
StateRegistry.PacketRegistry.ProtocolRegistry registry =
state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION);
final int index = in.readerIndex(); final int index = in.readerIndex();
final int packetId = readRawVarInt21(in); final int packetId = readRawVarInt21(in);
// Index hasn't changed, we've read nothing // Index hasn't changed, we've read nothing
@@ -130,8 +128,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
// We 'technically' have the incoming bytes of a payload here, and so, these can actually parse // We 'technically' have the incoming bytes of a payload here, and so, these can actually parse
// the packet if needed, so, we'll take advantage of the existing methods // the packet if needed, so, we'll take advantage of the existing methods
int expectedMinLen = codec.decodeExpectedMinLength(in, direction, registry.version); int expectedMinLen = codec.decodeExpectedMinLength(in, direction, ProtocolVersion.MINIMUM_VERSION);
int expectedMaxLen = codec.decodeExpectedMaxLength(in, direction, registry.version); int expectedMaxLen = codec.decodeExpectedMaxLength(in, direction, ProtocolVersion.MINIMUM_VERSION);
if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) { if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) {
throw handleOverflow(expectedMaxLen, in.readableBytes()); throw handleOverflow(expectedMaxLen, in.readableBytes());
} }

View File

@@ -19,8 +19,9 @@ package com.velocitypowered.proxy.protocol.netty;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
@@ -41,7 +42,7 @@ import org.jetbrains.annotations.NotNull;
*/ */
public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler { public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler {
private final StateRegistry.PacketRegistry.ProtocolRegistry registry; private final PacketRegistry registry;
private final Queue<Object> queue = new ArrayDeque<>(); private final Queue<Object> queue = new ArrayDeque<>();
/** /**
@@ -50,7 +51,7 @@ public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler {
* @param version the protocol version * @param version the protocol version
*/ */
public PlayPacketQueueInboundHandler(ProtocolVersion version, ProtocolUtils.Direction direction) { public PlayPacketQueueInboundHandler(ProtocolVersion version, ProtocolUtils.Direction direction) {
this.registry = StateRegistry.CONFIG.getProtocolRegistry(direction, version); this.registry = ProtocolStates.configuration(direction).forVersion(version);
} }
@Override @Override
@@ -58,7 +59,7 @@ public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler {
if (msg instanceof final MinecraftPacket packet) { if (msg instanceof final MinecraftPacket packet) {
// If the packet exists in the CONFIG state, we want to always // If the packet exists in the CONFIG state, we want to always
// ensure that it gets handled by the current handler // ensure that it gets handled by the current handler
if (this.registry.containsPacket(packet)) { if (this.registry.canDecodePacket(packet)) {
ctx.fireChannelRead(msg); ctx.fireChannelRead(msg);
return; return;
} }

View File

@@ -19,8 +19,9 @@ package com.velocitypowered.proxy.protocol.netty;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolStates;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.registry.PacketRegistry;
import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
@@ -42,7 +43,7 @@ import org.jetbrains.annotations.NotNull;
*/ */
public class PlayPacketQueueOutboundHandler extends ChannelDuplexHandler { public class PlayPacketQueueOutboundHandler extends ChannelDuplexHandler {
private final StateRegistry.PacketRegistry.ProtocolRegistry registry; private final PacketRegistry registry;
private final Queue<MinecraftPacket> queue = new ArrayDeque<>(); private final Queue<MinecraftPacket> queue = new ArrayDeque<>();
/** /**
@@ -51,7 +52,7 @@ public class PlayPacketQueueOutboundHandler extends ChannelDuplexHandler {
* @param version the protocol version * @param version the protocol version
*/ */
public PlayPacketQueueOutboundHandler(ProtocolVersion version, ProtocolUtils.Direction direction) { public PlayPacketQueueOutboundHandler(ProtocolVersion version, ProtocolUtils.Direction direction) {
this.registry = StateRegistry.CONFIG.getProtocolRegistry(direction, version); this.registry = ProtocolStates.configuration(direction).forVersion(version);
} }
@Override @Override
@@ -63,7 +64,7 @@ public class PlayPacketQueueOutboundHandler extends ChannelDuplexHandler {
// If the packet exists in the CONFIG state, we want to always // If the packet exists in the CONFIG state, we want to always
// ensure that it gets sent out to the client // ensure that it gets sent out to the client
if (this.registry.containsPacket(packet)) { if (this.registry.canDecodePacket(packet)) {
ctx.write(msg, promise); ctx.write(msg, promise);
return; return;
} }

View File

@@ -86,6 +86,8 @@ public final class AvailableCommandsPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<AvailableCommandsPacket> { public static class Codec implements PacketCodec<AvailableCommandsPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public AvailableCommandsPacket decode(ByteBuf buf, Direction direction, public AvailableCommandsPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -122,6 +122,8 @@ public record BossBarPacket(UUID uuid, int action, @Nullable ComponentHolder nam
} }
public static class Codec implements PacketCodec<BossBarPacket> { public static class Codec implements PacketCodec<BossBarPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public BossBarPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public BossBarPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -36,10 +36,12 @@ public final class BundleDelimiterPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<BundleDelimiterPacket> { public static class Codec implements PacketCodec<BundleDelimiterPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public BundleDelimiterPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public BundleDelimiterPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return BundleDelimiterPacket.INSTANCE;
} }
@Override @Override

View File

@@ -141,6 +141,8 @@ public final class ClientSettingsPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<ClientSettingsPacket> { public static class Codec implements PacketCodec<ClientSettingsPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientSettingsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ClientSettingsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -38,6 +38,8 @@ public record ClientboundCookieRequestPacket(Key key) implements MinecraftPacket
} }
public static class Codec implements PacketCodec<ClientboundCookieRequestPacket> { public static class Codec implements PacketCodec<ClientboundCookieRequestPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientboundCookieRequestPacket decode(ByteBuf buf, Direction direction, public ClientboundCookieRequestPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -37,6 +37,8 @@ public record ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRan
} }
public static class Codec implements PacketCodec<ClientboundSoundEntityPacket> { public static class Codec implements PacketCodec<ClientboundSoundEntityPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientboundSoundEntityPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ClientboundSoundEntityPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -42,6 +42,8 @@ public record ClientboundStopSoundPacket(@Nullable Sound.Source source,
} }
public static class Codec implements PacketCodec<ClientboundStopSoundPacket> { public static class Codec implements PacketCodec<ClientboundStopSoundPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientboundStopSoundPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ClientboundStopSoundPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -34,6 +34,8 @@ public record ClientboundStoreCookiePacket(Key key, byte[] payload) implements M
} }
public static class Codec implements PacketCodec<ClientboundStoreCookiePacket> { public static class Codec implements PacketCodec<ClientboundStoreCookiePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientboundStoreCookiePacket decode(ByteBuf buf, Direction direction, public ClientboundStoreCookiePacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -37,10 +37,12 @@ public final class DialogClearPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<DialogClearPacket> { public static class Codec implements PacketCodec<DialogClearPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public DialogClearPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public DialogClearPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return DialogClearPacket.INSTANCE;
} }
@Override @Override

View File

@@ -79,6 +79,8 @@ public final class EncryptionRequestPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<EncryptionRequestPacket> { public static class Codec implements PacketCodec<EncryptionRequestPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public EncryptionRequestPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public EncryptionRequestPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -85,6 +85,8 @@ public final class EncryptionResponsePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<EncryptionResponsePacket> { public static class Codec implements PacketCodec<EncryptionResponsePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public EncryptionResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public EncryptionResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -104,6 +104,8 @@ public final class HandshakePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<HandshakePacket> { public static class Codec implements PacketCodec<HandshakePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public HandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public HandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion ignored) { ProtocolVersion ignored) {

View File

@@ -52,6 +52,8 @@ public record HeaderAndFooterPacket(ComponentHolder header,
} }
public static class Codec implements PacketCodec<HeaderAndFooterPacket> { public static class Codec implements PacketCodec<HeaderAndFooterPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public HeaderAndFooterPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public HeaderAndFooterPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -196,6 +196,8 @@ public final class JoinGamePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<JoinGamePacket> { public static class Codec implements PacketCodec<JoinGamePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public JoinGamePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public JoinGamePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -43,6 +43,8 @@ public record KeepAlivePacket(long randomId) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<KeepAlivePacket> { public static class Codec implements PacketCodec<KeepAlivePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public KeepAlivePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public KeepAlivePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -37,6 +37,8 @@ public final class LegacyHandshakePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<LegacyHandshakePacket> { public static class Codec implements PacketCodec<LegacyHandshakePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LegacyHandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LegacyHandshakePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -64,6 +64,8 @@ public final class LegacyPingPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<LegacyPingPacket> { public static class Codec implements PacketCodec<LegacyPingPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LegacyPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LegacyPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -64,6 +64,8 @@ public final class LegacyPlayerListItemPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<LegacyPlayerListItemPacket> { public static class Codec implements PacketCodec<LegacyPlayerListItemPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LegacyPlayerListItemPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LegacyPlayerListItemPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -37,10 +37,12 @@ public final class LoginAcknowledgedPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<LoginAcknowledgedPacket> { public static class Codec implements PacketCodec<LoginAcknowledgedPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LoginAcknowledgedPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LoginAcknowledgedPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return LoginAcknowledgedPacket.INSTANCE;
} }
@Override @Override

View File

@@ -61,6 +61,8 @@ public final class LoginPluginMessagePacket extends DefaultByteBufHolder impleme
} }
public static class Codec implements PacketCodec<LoginPluginMessagePacket> { public static class Codec implements PacketCodec<LoginPluginMessagePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LoginPluginMessagePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LoginPluginMessagePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -70,6 +70,8 @@ public final class LoginPluginResponsePacket extends DefaultByteBufHolder
} }
public static class Codec implements PacketCodec<LoginPluginResponsePacket> { public static class Codec implements PacketCodec<LoginPluginResponsePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LoginPluginResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LoginPluginResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -32,6 +32,8 @@ public record PingIdentifyPacket(int id) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<PingIdentifyPacket> { public static class Codec implements PacketCodec<PingIdentifyPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public PingIdentifyPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public PingIdentifyPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -94,6 +94,8 @@ public final class PluginMessagePacket extends DefaultByteBufHolder implements M
} }
public static class Codec implements PacketCodec<PluginMessagePacket> { public static class Codec implements PacketCodec<PluginMessagePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public PluginMessagePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public PluginMessagePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -39,6 +39,8 @@ public record RemovePlayerInfoPacket(Collection<UUID> profilesToRemove) implemen
} }
public static class Codec implements PacketCodec<RemovePlayerInfoPacket> { public static class Codec implements PacketCodec<RemovePlayerInfoPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public RemovePlayerInfoPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public RemovePlayerInfoPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -39,6 +39,8 @@ public record RemoveResourcePackPacket(@Nullable UUID id) implements MinecraftPa
} }
public static class Codec implements PacketCodec<RemoveResourcePackPacket> { public static class Codec implements PacketCodec<RemoveResourcePackPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public RemoveResourcePackPacket decode(ByteBuf buf, Direction direction, public RemoveResourcePackPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -103,6 +103,8 @@ public final class ResourcePackRequestPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<ResourcePackRequestPacket> { public static class Codec implements PacketCodec<ResourcePackRequestPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ResourcePackRequestPacket decode(ByteBuf buf, Direction direction, public ResourcePackRequestPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -49,6 +49,8 @@ public record ResourcePackResponsePacket(UUID id, String hash,
} }
public static class Codec implements PacketCodec<ResourcePackResponsePacket> { public static class Codec implements PacketCodec<ResourcePackResponsePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ResourcePackResponsePacket decode(ByteBuf buf, Direction direction, public ResourcePackResponsePacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -151,6 +151,8 @@ public final class RespawnPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<RespawnPacket> { public static class Codec implements PacketCodec<RespawnPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public RespawnPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public RespawnPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -61,6 +61,8 @@ public final class ServerDataPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<ServerDataPacket> { public static class Codec implements PacketCodec<ServerDataPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ServerDataPacket decode(ByteBuf buf, Direction direction, public ServerDataPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -83,6 +83,8 @@ public final class ServerLoginPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<ServerLoginPacket> { public static class Codec implements PacketCodec<ServerLoginPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ServerLoginPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ServerLoginPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -71,6 +71,8 @@ public final class ServerLoginSuccessPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<ServerLoginSuccessPacket> { public static class Codec implements PacketCodec<ServerLoginSuccessPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ServerLoginSuccessPacket decode(ByteBuf buf, Direction direction, public ServerLoginSuccessPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -44,6 +44,8 @@ public record ServerboundCookieResponsePacket(Key key,
} }
public static class Codec implements PacketCodec<ServerboundCookieResponsePacket> { public static class Codec implements PacketCodec<ServerboundCookieResponsePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ServerboundCookieResponsePacket decode(ByteBuf buf, Direction direction, public ServerboundCookieResponsePacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -79,6 +79,8 @@ public class ServerboundCustomClickActionPacket extends DefaultByteBufHolder
} }
public static class Codec implements PacketCodec<ServerboundCustomClickActionPacket> { public static class Codec implements PacketCodec<ServerboundCustomClickActionPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ServerboundCustomClickActionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ServerboundCustomClickActionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -43,6 +43,8 @@ public record SetCompressionPacket(int threshold) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<SetCompressionPacket> { public static class Codec implements PacketCodec<SetCompressionPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public SetCompressionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public SetCompressionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -33,6 +33,8 @@ public record StatusPingPacket(long randomId) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<StatusPingPacket> { public static class Codec implements PacketCodec<StatusPingPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public StatusPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public StatusPingPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -43,10 +43,12 @@ public final class StatusRequestPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<StatusRequestPacket> { public static class Codec implements PacketCodec<StatusRequestPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public StatusRequestPacket decode(ByteBuf buf, Direction direction, public StatusRequestPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return StatusRequestPacket.INSTANCE;
} }
@Override @Override

View File

@@ -57,6 +57,8 @@ public final class StatusResponsePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<StatusResponsePacket> { public static class Codec implements PacketCodec<StatusResponsePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public StatusResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public StatusResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -89,6 +89,8 @@ public final class TabCompleteRequestPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<TabCompleteRequestPacket> { public static class Codec implements PacketCodec<TabCompleteRequestPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TabCompleteRequestPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TabCompleteRequestPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -97,6 +97,8 @@ public final class TabCompleteResponsePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<TabCompleteResponsePacket> { public static class Codec implements PacketCodec<TabCompleteResponsePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TabCompleteResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TabCompleteResponsePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -50,6 +50,8 @@ public record TransferPacket(String host, int port) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<TransferPacket> { public static class Codec implements PacketCodec<TransferPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TransferPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TransferPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -64,6 +64,8 @@ public final class UpsertPlayerInfoPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<UpsertPlayerInfoPacket> { public static class Codec implements PacketCodec<UpsertPlayerInfoPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public UpsertPlayerInfoPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public UpsertPlayerInfoPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -39,6 +39,8 @@ public record ChatAcknowledgementPacket(int offset) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<ChatAcknowledgementPacket> { public static class Codec implements PacketCodec<ChatAcknowledgementPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ChatAcknowledgementPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ChatAcknowledgementPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -58,6 +58,8 @@ public final class PlayerChatCompletionPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<PlayerChatCompletionPacket> { public static class Codec implements PacketCodec<PlayerChatCompletionPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public PlayerChatCompletionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public PlayerChatCompletionPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -60,6 +60,8 @@ public final class SystemChatPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<SystemChatPacket> { public static class Codec implements PacketCodec<SystemChatPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public SystemChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public SystemChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -81,6 +81,8 @@ public final class KeyedPlayerChatPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<KeyedPlayerChatPacket> { public static class Codec implements PacketCodec<KeyedPlayerChatPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public KeyedPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public KeyedPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -95,6 +95,8 @@ public final class KeyedPlayerCommandPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<KeyedPlayerCommandPacket> { public static class Codec implements PacketCodec<KeyedPlayerCommandPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public KeyedPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public KeyedPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -45,6 +45,8 @@ public record LegacyChatPacket(String message, byte type, @Nullable UUID sender)
} }
public static class Codec implements PacketCodec<LegacyChatPacket> { public static class Codec implements PacketCodec<LegacyChatPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LegacyChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LegacyChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -85,6 +85,8 @@ public class SessionPlayerChatPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<SessionPlayerChatPacket> { public static class Codec implements PacketCodec<SessionPlayerChatPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public SessionPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public SessionPlayerChatPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -89,6 +89,8 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<SessionPlayerCommandPacket> { public static class Codec implements PacketCodec<SessionPlayerCommandPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public SessionPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public SessionPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -56,6 +56,8 @@ public final class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacke
} }
public static class Codec implements PacketCodec<UnsignedPlayerCommandPacket> { public static class Codec implements PacketCodec<UnsignedPlayerCommandPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public UnsignedPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public UnsignedPlayerCommandPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -41,6 +41,8 @@ public record ActiveFeaturesPacket(Key[] activeFeatures) implements MinecraftPac
} }
public static class Codec implements PacketCodec<ActiveFeaturesPacket> { public static class Codec implements PacketCodec<ActiveFeaturesPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ActiveFeaturesPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ActiveFeaturesPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -28,16 +28,14 @@ import java.util.Map;
public record ClientboundCustomReportDetailsPacket(Map<String, String> details) implements MinecraftPacket { public record ClientboundCustomReportDetailsPacket(Map<String, String> details) implements MinecraftPacket {
public ClientboundCustomReportDetailsPacket() {
this(Map.of());
}
@Override @Override
public boolean handle(MinecraftSessionHandler handler) { public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this); return handler.handle(this);
} }
public static class Codec implements PacketCodec<ClientboundCustomReportDetailsPacket> { public static class Codec implements PacketCodec<ClientboundCustomReportDetailsPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientboundCustomReportDetailsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ClientboundCustomReportDetailsPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -62,6 +62,8 @@ public record ClientboundServerLinksPacket(List<ServerLink> serverLinks) impleme
} }
public static class Codec implements PacketCodec<ClientboundServerLinksPacket> { public static class Codec implements PacketCodec<ClientboundServerLinksPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public ClientboundServerLinksPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public ClientboundServerLinksPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) { ProtocolVersion version) {

View File

@@ -37,10 +37,12 @@ public final class CodeOfConductAcceptPacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<CodeOfConductAcceptPacket> { public static class Codec implements PacketCodec<CodeOfConductAcceptPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public CodeOfConductAcceptPacket decode(ByteBuf buf, Direction direction, public CodeOfConductAcceptPacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return CodeOfConductAcceptPacket.INSTANCE;
} }
@Override @Override

View File

@@ -77,6 +77,8 @@ public class CodeOfConductPacket extends DefaultByteBufHolder implements Minecra
} }
public static class Codec implements PacketCodec<CodeOfConductPacket> { public static class Codec implements PacketCodec<CodeOfConductPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public CodeOfConductPacket decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) { public CodeOfConductPacket decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) {
return new CodeOfConductPacket(buf.readRetainedSlice(buf.readableBytes())); return new CodeOfConductPacket(buf.readRetainedSlice(buf.readableBytes()));

View File

@@ -36,10 +36,12 @@ public final class FinishedUpdatePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<FinishedUpdatePacket> { public static class Codec implements PacketCodec<FinishedUpdatePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public FinishedUpdatePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public FinishedUpdatePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return FinishedUpdatePacket.INSTANCE;
} }
@Override @Override

View File

@@ -49,6 +49,8 @@ public record KnownPacksPacket(KnownPack[] packs) implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<KnownPacksPacket> { public static class Codec implements PacketCodec<KnownPacksPacket> {
public static final Codec INSTANCE = new Codec();
private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64); private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64);
private static final QuietDecoderException TOO_MANY_PACKS = private static final QuietDecoderException TOO_MANY_PACKS =
new QuietDecoderException("too many known packs"); new QuietDecoderException("too many known packs");

View File

@@ -42,6 +42,8 @@ public final class RegistrySyncPacket extends DefaultByteBufHolder implements Mi
} }
public static class Codec implements PacketCodec<RegistrySyncPacket> { public static class Codec implements PacketCodec<RegistrySyncPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public RegistrySyncPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public RegistrySyncPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -36,10 +36,12 @@ public final class StartUpdatePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<StartUpdatePacket> { public static class Codec implements PacketCodec<StartUpdatePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public StartUpdatePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public StartUpdatePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {
return INSTANCE; return StartUpdatePacket.INSTANCE;
} }
@Override @Override

View File

@@ -46,6 +46,8 @@ public final class TagsUpdatePacket implements MinecraftPacket {
} }
public static class Codec implements PacketCodec<TagsUpdatePacket> { public static class Codec implements PacketCodec<TagsUpdatePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TagsUpdatePacket decode(ByteBuf buf, Direction direction, public TagsUpdatePacket decode(ByteBuf buf, Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -78,6 +78,8 @@ public final class LegacyTitlePacket extends GenericTitlePacket {
} }
public static class Codec implements PacketCodec<LegacyTitlePacket> { public static class Codec implements PacketCodec<LegacyTitlePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public LegacyTitlePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public LegacyTitlePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -51,6 +51,8 @@ public final class TitleActionbarPacket extends GenericTitlePacket {
} }
public static class Codec implements PacketCodec<TitleActionbarPacket> { public static class Codec implements PacketCodec<TitleActionbarPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TitleActionbarPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TitleActionbarPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -49,6 +49,8 @@ public final class TitleClearPacket extends GenericTitlePacket {
} }
public static class Codec implements PacketCodec<TitleClearPacket> { public static class Codec implements PacketCodec<TitleClearPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TitleClearPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TitleClearPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -51,6 +51,8 @@ public final class TitleSubtitlePacket extends GenericTitlePacket {
} }
public static class Codec implements PacketCodec<TitleSubtitlePacket> { public static class Codec implements PacketCodec<TitleSubtitlePacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TitleSubtitlePacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TitleSubtitlePacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -51,6 +51,8 @@ public final class TitleTextPacket extends GenericTitlePacket {
} }
public static class Codec implements PacketCodec<TitleTextPacket> { public static class Codec implements PacketCodec<TitleTextPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TitleTextPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TitleTextPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -66,6 +66,8 @@ public final class TitleTimesPacket extends GenericTitlePacket {
} }
public static class Codec implements PacketCodec<TitleTimesPacket> { public static class Codec implements PacketCodec<TitleTimesPacket> {
public static final Codec INSTANCE = new Codec();
@Override @Override
public TitleTimesPacket decode(ByteBuf buf, ProtocolUtils.Direction direction, public TitleTimesPacket decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) { ProtocolVersion protocolVersion) {

View File

@@ -0,0 +1,376 @@
/*
* Copyright (C) 2025 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 <https://www.gnu.org/licenses/>.
*/
package com.velocitypowered.proxy.protocol.registry;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.PacketCodec;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap;
import it.unimi.dsi.fastutil.Hash.Strategy;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* A multi-version packet registry that supports different packet ID mappings across protocol
* versions. This implementation optimizes memory usage by reusing mapping data structures across
* versions when the mappings are identical.
*/
public class MultiVersionPacketRegistry implements ProtocolToPacketRegistry {
private final Map<ProtocolVersion, VersionMapping> versionMappings;
private MultiVersionPacketRegistry(
Map<ProtocolVersion, VersionMapping> versionMappings) {
this.versionMappings = versionMappings;
}
@Override
public PacketRegistry forVersion(ProtocolVersion version) {
VersionMapping mapping = this.versionMappings.get(version);
if (mapping == null) {
throw new IllegalArgumentException(String.format("Invalid version %s", version));
}
return mapping;
}
/**
* Holds the packet mappings for a specific protocol version or a range of versions.
* Instances are shared across versions when the mappings are identical.
*/
private static class VersionMapping implements PacketRegistry {
final IntObjectMap<PacketCodec<? extends MinecraftPacket>> packetIdToCodec;
final Map<Class<? extends MinecraftPacket>, PacketCodec<? extends MinecraftPacket>>
packetClassToCodec;
final Object2IntMap<Class<? extends MinecraftPacket>> packetClassToId;
final Direction direction;
final ProtocolVersion version;
VersionMapping(Direction direction, ProtocolVersion version) {
this.direction = direction;
this.version = version;
this.packetIdToCodec = new IntObjectHashMap<>(16, 0.5f);
this.packetClassToCodec = new HashMap<>(16, 0.5f);
this.packetClassToId = new Object2IntOpenHashMap<>(16, 0.5f);
this.packetClassToId.defaultReturnValue(Integer.MIN_VALUE);
}
void register(int id, Class<? extends MinecraftPacket> packet,
PacketCodec<? extends MinecraftPacket> codec, boolean encodeOnly) {
if (!encodeOnly) {
this.packetIdToCodec.put(id, codec);
}
this.packetClassToCodec.put(packet, codec);
this.packetClassToId.put(packet, id);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
VersionMapping that = (VersionMapping) o;
return Objects.equals(packetIdToCodec, that.packetIdToCodec)
&& Objects.equals(packetClassToCodec, that.packetClassToCodec)
&& Objects.equals(packetClassToId, that.packetClassToId)
&& Objects.equals(direction, that.direction)
&& Objects.equals(version, that.version);
}
public boolean equalsNonStrict(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
VersionMapping that = (VersionMapping) o;
return Objects.equals(packetIdToCodec, that.packetIdToCodec)
&& Objects.equals(packetClassToCodec, that.packetClassToCodec)
&& Objects.equals(packetClassToId, that.packetClassToId);
}
@Override
public int hashCode() {
return Objects.hash(packetIdToCodec, packetClassToCodec, packetClassToId, direction, version);
}
public int hashCodeNonStrict() {
return Objects.hash(packetIdToCodec, packetClassToCodec, packetClassToId);
}
@Override
public @Nullable PacketCodec<? extends MinecraftPacket> getCodec(int id) {
return packetIdToCodec.get(id);
}
@Override
@SuppressWarnings("unchecked")
public <T extends MinecraftPacket> @Nullable PacketCodec<T> getCodec(Class<T> packetClass) {
return (PacketCodec<T>) packetClassToCodec.get(packetClass);
}
@Override
public int getPacketId(MinecraftPacket packet) {
final int id = packetClassToId.getInt(packet.getClass());
if (id == Integer.MIN_VALUE) {
throw new IllegalArgumentException(String.format(
"Unable to find id for packet of type %s in %s protocol %s",
packet.getClass().getName(), direction, version
));
}
return id;
}
@Override
public boolean canDecodePacket(MinecraftPacket packet) {
return packetClassToId.containsKey(packet.getClass());
}
}
/**
* Creates a new builder for constructing a multi-version packet registry.
*
* @param direction the packet direction (clientbound or serverbound)
* @return a new builder instance
*/
public static Builder builder(Direction direction) {
return new Builder(direction);
}
/**
* Builder for constructing a MultiVersionPacketRegistry with optimized memory usage.
*/
public static class Builder {
private final Direction direction;
private final Map<ProtocolVersion, VersionMapping> workingMappings =
new EnumMap<>(ProtocolVersion.class);
private Builder(Direction direction) {
this.direction = direction;
}
/**
* Registers a packet for a specific protocol version with a given ID.
*
* @param packetClass the packet class
* @param codec the packet codec
* @param version the protocol version
* @param packetId the packet ID
* @param <T> the packet type
* @return this builder
*/
public <T extends MinecraftPacket> Builder register(
Class<T> packetClass,
PacketCodec<T> codec,
ProtocolVersion version,
int packetId) {
return register(packetClass, codec, version, null, packetId, false);
}
/**
* Registers a packet for a range of protocol versions with a given ID.
*
* @param packetClass the packet class
* @param codec the packet codec
* @param startVersion the starting protocol version (inclusive)
* @param endVersion the ending protocol version (inclusive), or null for all future versions
* @param packetId the packet ID
* @param encodeOnly if true, the packet will only be registered for encoding, not decoding
* @param <T> the packet type
* @return this builder
*/
public <T extends MinecraftPacket> Builder register(
Class<T> packetClass,
PacketCodec<T> codec,
ProtocolVersion startVersion,
@Nullable ProtocolVersion endVersion,
int packetId,
boolean encodeOnly) {
ProtocolVersion end = endVersion != null ? endVersion : ProtocolVersion.MAXIMUM_VERSION;
// Validate version range
if (startVersion.greaterThan(end)) {
throw new IllegalArgumentException(String.format(
"Start version %s is greater than end version %s", startVersion, end
));
}
// Register for all versions in the range
for (ProtocolVersion version : ProtocolVersion.values()) {
if (version.isLegacy() || version.isUnknown()) {
continue;
}
if (version.noLessThan(startVersion) && version.noGreaterThan(end)) {
VersionMapping versionMapping = workingMappings.computeIfAbsent(version, v -> new VersionMapping(direction, version));
if (versionMapping.packetClassToCodec.containsKey(packetClass)) {
throw new IllegalArgumentException(String.format(
"Packet %s already registered for version %s", packetClass.getName(), version
));
}
versionMapping.register(packetId, packetClass, codec, encodeOnly);
}
}
return this;
}
/**
* Registers a packet for multiple version ranges.
*
* @param packetClass the packet class
* @param codec the packet codec
* @param ranges the version ranges to register
* @param <T> the packet type
* @return this builder
*/
public <T extends MinecraftPacket> Builder register(
Class<T> packetClass,
PacketCodec<T> codec,
VersionRange... ranges) {
if (ranges.length == 0) {
throw new IllegalArgumentException("At least one version range must be provided");
}
for (VersionRange range : ranges) {
register(packetClass, codec, range.start, range.end, range.packetId, range.encodeOnly);
}
return this;
}
/**
* Builds the multi-version packet registry, optimizing memory by reusing identical mappings
* across versions.
*
* @return the constructed registry
*/
public MultiVersionPacketRegistry build() {
// Optimize by reusing identical mappings across versions
Map<ProtocolVersion, VersionMapping> optimized = new EnumMap<>(ProtocolVersion.class);
Map<VersionMapping, VersionMapping> deduplicationMap = new Object2ObjectOpenCustomHashMap<>(
new Strategy<>() {
@Override
public int hashCode(VersionMapping o) {
return o.hashCodeNonStrict();
}
@Override
public boolean equals(VersionMapping a, VersionMapping b) {
return a.equalsNonStrict(b);
}
});
for (Map.Entry<ProtocolVersion, VersionMapping> entry : workingMappings.entrySet()) {
VersionMapping mapping = entry.getValue();
VersionMapping canonical = deduplicationMap.get(mapping);
if (canonical == null) {
// First time seeing this mapping, use it as the canonical version
deduplicationMap.put(mapping, mapping);
canonical = mapping;
}
// Reuse the canonical mapping
optimized.put(entry.getKey(), canonical);
}
return new MultiVersionPacketRegistry(Collections.unmodifiableMap(optimized));
}
}
/**
* Represents a version range for packet registration.
*/
public static class VersionRange {
final ProtocolVersion start;
final @Nullable ProtocolVersion end;
final int packetId;
final boolean encodeOnly;
private VersionRange(
ProtocolVersion start,
@Nullable ProtocolVersion end,
int packetId,
boolean encodeOnly) {
this.start = start;
this.end = end;
this.packetId = packetId;
this.encodeOnly = encodeOnly;
}
/**
* Creates a version range starting from the specified version and continuing to all future
* versions.
*
* @param start the starting version
* @param packetId the packet ID
* @return a new version range
*/
public static VersionRange of(ProtocolVersion start, int packetId) {
return new VersionRange(start, null, packetId, false);
}
/**
* Creates a version range from start to end (inclusive).
*
* @param start the starting version
* @param end the ending version
* @param packetId the packet ID
* @return a new version range
*/
public static VersionRange of(ProtocolVersion start, ProtocolVersion end, int packetId) {
return new VersionRange(start, end, packetId, false);
}
/**
* Creates an encode-only version range starting from the specified version.
*
* @param start the starting version
* @param packetId the packet ID
* @return a new version range
*/
public static VersionRange encodeOnly(ProtocolVersion start, int packetId) {
return new VersionRange(start, null, packetId, true);
}
/**
* Creates an encode-only version range from start to end (inclusive).
*
* @param start the starting version
* @param end the ending version
* @param packetId the packet ID
* @return a new version range
*/
public static VersionRange encodeOnly(
ProtocolVersion start, ProtocolVersion end, int packetId) {
return new VersionRange(start, end, packetId, true);
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2025 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 <https://www.gnu.org/licenses/>.
*/
package com.velocitypowered.proxy.protocol.registry;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.PacketCodec;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Interface for retrieving packet codecs and IDs for a specific protocol version.
*/
public interface PacketRegistry {
@Nullable
PacketCodec<? extends MinecraftPacket> getCodec(final int id);
<T extends MinecraftPacket> @Nullable PacketCodec<T> getCodec(
final Class<T> packetClass);
int getPacketId(final MinecraftPacket packet);
boolean canDecodePacket(MinecraftPacket packet);
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2025 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 <https://www.gnu.org/licenses/>.
*/
package com.velocitypowered.proxy.protocol.registry;
import com.velocitypowered.api.network.ProtocolVersion;
/**
* Registry mapping protocol versions to their packet registries.
*/
public interface ProtocolToPacketRegistry {
PacketRegistry forVersion(ProtocolVersion version);
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2025 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 <https://www.gnu.org/licenses/>.
*/
package com.velocitypowered.proxy.protocol.registry;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.PacketCodec;
import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
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.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Extremely simple packet registry implementation that assumes every protocol version is
* the same.
*/
public class SimplePacketRegistry implements PacketRegistry, ProtocolToPacketRegistry {
private final IntObjectMap<PacketCodec<? extends MinecraftPacket>> packetIdToCodec =
new IntObjectHashMap<>(16, 0.5f);
private final Map<Class<? extends MinecraftPacket>, PacketCodec<? extends MinecraftPacket>> packetClassToCodec =
new HashMap<>(16, 0.5f);
private final Object2IntMap<Class<? extends MinecraftPacket>> packetClassToId =
new Object2IntOpenHashMap<>(16, 0.5f);
private final Direction direction;
public SimplePacketRegistry(Direction direction) {
this.direction = direction;
this.packetClassToId.defaultReturnValue(Integer.MIN_VALUE);
}
/**
* Registers a packet for this protocol version.
*
* @param id the packet ID
* @param packet the packet class
* @param codec the packet codec
*/
public void register(int id, Class<? extends MinecraftPacket> packet, PacketCodec<? extends MinecraftPacket> codec) {
this.packetIdToCodec.put(id, codec);
this.packetClassToCodec.put(packet, codec);
this.packetClassToId.put(packet, id);
}
@Override
public @Nullable PacketCodec<? extends MinecraftPacket> getCodec(int id) {
return this.packetIdToCodec.get(id);
}
@Override
public @Nullable <T extends MinecraftPacket> PacketCodec<T> getCodec(Class<T> packetClass) {
return (PacketCodec<T>) this.packetClassToCodec.get(packetClass);
}
@Override
public int getPacketId(MinecraftPacket packet) {
final int id = this.packetClassToId.getInt(packet.getClass());
if (id == Integer.MIN_VALUE) {
throw new IllegalArgumentException(String.format(
"Unable to find id for packet of type %s in %s phase %s",
packet.getClass().getName(), direction, this
));
}
return id;
}
@Override
public boolean canDecodePacket(MinecraftPacket packet) {
return packetClassToId.containsKey(packet.getClass());
}
@Override
public PacketRegistry forVersion(ProtocolVersion version) {
return this;
}
}

View File

@@ -18,6 +18,7 @@
package com.velocitypowered.proxy.protocol; package com.velocitypowered.proxy.protocol;
import static com.google.common.collect.Iterables.getLast; import static com.google.common.collect.Iterables.getLast;
import static com.velocitypowered.api.network.ProtocolVersion.MAXIMUM_VERSION;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_11; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_11;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_12; 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_1;
@@ -25,136 +26,414 @@ 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_13;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14; 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_14_2;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_14_4;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_15; 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;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_2; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_16_2;
import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; 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.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.protocol.packet.HandshakePacket; import com.velocitypowered.proxy.protocol.packet.HandshakePacket;
import com.velocitypowered.proxy.protocol.packet.StatusPingPacket; import com.velocitypowered.proxy.protocol.packet.StatusPingPacket;
import com.velocitypowered.proxy.protocol.registry.MultiVersionPacketRegistry;
import com.velocitypowered.proxy.protocol.registry.MultiVersionPacketRegistry.VersionRange;
import com.velocitypowered.proxy.protocol.registry.SimplePacketRegistry;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
class PacketRegistryTest { class PacketRegistryTest {
private StateRegistry.PacketRegistry setupRegistry() { /**
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry( * Sets up a multi-version registry with HandshakePacket mapped to different IDs across version
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY); * ranges.
registry.register(HandshakePacket.class, new HandshakePacket.Codec(), */
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, null, false), private MultiVersionPacketRegistry setupRegistry() {
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false), return MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_15, MINECRAFT_1_16, false)); .register(HandshakePacket.class, new HandshakePacket.Codec(),
return registry; VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_11, 0x01),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_14_4, 0x00),
VersionRange.of(MINECRAFT_1_15, MAXIMUM_VERSION, 0x00))
.build();
} }
// ==================== Basic Functionality Tests ====================
@Test @Test
void packetRegistryWorks() { void packetRegistryWorks() {
StateRegistry.PacketRegistry registry = setupRegistry(); MultiVersionPacketRegistry registry = setupRegistry();
PacketCodec<?> packet = registry.getProtocolRegistry(MINECRAFT_1_12).getCodec(0); PacketCodec<?> packet = registry.forVersion(MINECRAFT_1_12).getCodec(0);
assertNotNull(packet, "Packet was not found in registry"); assertNotNull(packet, "Packet was not found in registry");
assertEquals(HandshakePacket.Codec.class, packet.getClass(), "Registry returned wrong class"); assertEquals(HandshakePacket.Codec.class, packet.getClass(), "Registry returned wrong class");
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12).getPacketId(new HandshakePacket()), assertEquals(0, registry.forVersion(MINECRAFT_1_12).getPacketId(new HandshakePacket()),
"Registry did not return the correct packet ID"); "Registry did not return the correct packet ID");
} }
@Test @Test
void packetRegistryLinkingWorks() { void packetRegistryLinkingWorks() {
StateRegistry.PacketRegistry registry = setupRegistry(); MultiVersionPacketRegistry registry = setupRegistry();
PacketCodec<?> packet = registry.getProtocolRegistry(MINECRAFT_1_12_1).getCodec(0); PacketCodec<?> packet = registry.forVersion(MINECRAFT_1_12_1).getCodec(0);
assertNotNull(packet, "Packet was not found in registry"); assertNotNull(packet, "Packet was not found in registry");
assertEquals(HandshakePacket.Codec.class, packet.getClass(), "Registry returned wrong class"); assertEquals(HandshakePacket.Codec.class, packet.getClass(), "Registry returned wrong class");
HandshakePacket handshakePacket = new HandshakePacket(); HandshakePacket handshakePacket = new HandshakePacket();
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_12_1).getPacketId(handshakePacket), assertEquals(0, registry.forVersion(MINECRAFT_1_12_1).getPacketId(handshakePacket),
"Registry did not return the correct packet ID"); "Registry did not return the correct packet ID");
assertEquals(0, registry.getProtocolRegistry(MINECRAFT_1_14_2).getPacketId(handshakePacket), assertEquals(0, registry.forVersion(MINECRAFT_1_14_2).getPacketId(handshakePacket),
"Registry did not return the correct packet ID"); "Registry did not return the correct packet ID");
assertEquals(1, registry.getProtocolRegistry(MINECRAFT_1_11).getPacketId(handshakePacket), assertEquals(1, registry.forVersion(MINECRAFT_1_11).getPacketId(handshakePacket),
"Registry did not return the correct packet ID"); "Registry did not return the correct packet ID");
assertNull(registry.getProtocolRegistry(MINECRAFT_1_14_2).getCodec(0x01), assertNull(registry.forVersion(MINECRAFT_1_14_2).getCodec(0x01),
"Registry should return a null"); "Registry should return a null");
assertNull(registry.getProtocolRegistry(MINECRAFT_1_16_2).getCodec(0), // 1.16_2 is >= 1.15, so it should have codec for 0x00 from the last range
"Registry should return null"); assertNotNull(registry.forVersion(MINECRAFT_1_16_2).getCodec(0),
} "1.16_2 should have codec for 0x00 from 1.15+ range");
@Test
void failOnNoMappings() {
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
assertThrows(IllegalArgumentException.class,
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec()));
assertThrows(IllegalArgumentException.class,
() -> registry.getProtocolRegistry(ProtocolVersion.UNKNOWN)
.getPacketId(new HandshakePacket()));
}
@Test
void failOnWrongOrder() {
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
assertThrows(IllegalArgumentException.class,
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false),
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false)));
assertThrows(IllegalArgumentException.class,
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, null, false)));
assertThrows(IllegalArgumentException.class,
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_13, MINECRAFT_1_8, false)));
assertThrows(IllegalArgumentException.class,
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_8, MINECRAFT_1_14, false),
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_16, null, false)));
}
@Test
void failOnDuplicate() {
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false));
assertThrows(IllegalArgumentException.class,
() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12, null, false)));
assertThrows(IllegalArgumentException.class,
() -> registry.register(StatusPingPacket.class, new StatusPingPacket.Codec(),
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_13, null, false)));
}
@Test
void shouldNotFailWhenRegisterLatestProtocolVersion() {
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry(
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY);
assertDoesNotThrow(() -> registry.register(HandshakePacket.class, new HandshakePacket.Codec(),
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_8, null, false),
new StateRegistry.PacketMapping(0x01, getLast(ProtocolVersion.SUPPORTED_VERSIONS),
null, false)));
} }
@Test @Test
void registrySuppliesCorrectPacketsByProtocol() { void registrySuppliesCorrectPacketsByProtocol() {
StateRegistry.PacketRegistry registry = new StateRegistry.PacketRegistry( MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
ProtocolUtils.Direction.CLIENTBOUND, StateRegistry.PLAY); .register(HandshakePacket.class, new HandshakePacket.Codec(),
registry.register(HandshakePacket.class, new HandshakePacket.Codec(), VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x00),
new StateRegistry.PacketMapping(0x00, MINECRAFT_1_12, null, false), VersionRange.of(MINECRAFT_1_12_1, MINECRAFT_1_12_2, 0x01),
new StateRegistry.PacketMapping(0x01, MINECRAFT_1_12_1, null, false), VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_14_4, 0x02))
new StateRegistry.PacketMapping(0x02, MINECRAFT_1_13, null, false)); .build();
assertNotNull(registry.forVersion(MINECRAFT_1_12).getCodec(0x00));
assertEquals(HandshakePacket.Codec.class, assertEquals(HandshakePacket.Codec.class,
registry.getProtocolRegistry(MINECRAFT_1_12).getCodec(0x00).getClass()); registry.forVersion(MINECRAFT_1_12).getCodec(0x00).getClass());
assertNotNull(registry.forVersion(MINECRAFT_1_12_1).getCodec(0x01));
assertEquals(HandshakePacket.Codec.class, assertEquals(HandshakePacket.Codec.class,
registry.getProtocolRegistry(MINECRAFT_1_12_1).getCodec(0x01).getClass()); registry.forVersion(MINECRAFT_1_12_1).getCodec(0x01).getClass());
assertNotNull(registry.forVersion(MINECRAFT_1_12_2).getCodec(0x01));
assertEquals(HandshakePacket.Codec.class, assertEquals(HandshakePacket.Codec.class,
registry.getProtocolRegistry(MINECRAFT_1_12_2).getCodec(0x01).getClass()); registry.forVersion(MINECRAFT_1_12_2).getCodec(0x01).getClass());
assertNotNull(registry.forVersion(MINECRAFT_1_13).getCodec(0x02));
assertEquals(HandshakePacket.Codec.class, assertEquals(HandshakePacket.Codec.class,
registry.getProtocolRegistry(MINECRAFT_1_13).getCodec(0x02).getClass()); registry.forVersion(MINECRAFT_1_13).getCodec(0x02).getClass());
assertNotNull(registry.forVersion(MINECRAFT_1_14_2).getCodec(0x02));
assertEquals(HandshakePacket.Codec.class, assertEquals(HandshakePacket.Codec.class,
registry.getProtocolRegistry(MINECRAFT_1_14_2).getCodec(0x02).getClass()); registry.forVersion(MINECRAFT_1_14_2).getCodec(0x02).getClass());
}
// ==================== Error Handling Tests ====================
@Test
void failOnNoMappings() {
assertThrows(IllegalArgumentException.class,
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.build()
.forVersion(ProtocolVersion.UNKNOWN));
}
@Test
void failOnWrongVersionOrder() {
// End version before start version
assertThrows(IllegalArgumentException.class,
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_13, 0x01),
VersionRange.of(MINECRAFT_1_8, 0x00))
.build());
}
@Test
void failOnInvalidRangeStartGreaterThanEnd() {
// Single VersionRange with start > end
assertThrows(IllegalArgumentException.class,
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_13, MINECRAFT_1_8, 0x01))
.build());
}
@Test
void failOnDuplicateVersionRanges() {
// Two ranges covering the same version
assertThrows(IllegalArgumentException.class,
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_13, 0x01),
VersionRange.of(MINECRAFT_1_13, 0x01))
.build());
}
@Test
void failOnOverlappingVersionRanges() {
// Same packet registered twice with overlapping versions should fail
assertThrows(IllegalArgumentException.class,
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_14, 0x01))
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_16, 0x00))
.build());
}
@Test
void failOnDuplicatePacketClass() {
// Same packet class registered twice for overlapping versions
assertThrows(IllegalArgumentException.class,
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_14, 0x00))
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_12, 0x01))
.build());
}
@Test
void allowDifferentPacketsWithSameIdInDifferentVersions() {
// Different packets can have the same ID in different version ranges
assertDoesNotThrow(
() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_12, 0x00))
.register(StatusPingPacket.class, new StatusPingPacket.Codec(),
VersionRange.of(MINECRAFT_1_13, MAXIMUM_VERSION, 0x00))
.build());
}
@Test
void failOnInvalidPacketIdLookup() {
MultiVersionPacketRegistry registry = setupRegistry();
// Try to get packet ID for a packet type that doesn't exist in the registry
assertThrows(IllegalArgumentException.class,
() -> registry.forVersion(MINECRAFT_1_12).getPacketId(new StatusPingPacket(0L)));
}
// ==================== Edge Cases and Boundaries ====================
@Test
void shouldNotFailWhenRegisterLatestProtocolVersion() {
assertDoesNotThrow(() -> MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_8, MINECRAFT_1_14_4, 0x00),
VersionRange.of(getLast(ProtocolVersion.SUPPORTED_VERSIONS), 0x01))
.build());
}
@Test
void versionBoundaryTransition() {
// Test that version boundaries are handled correctly
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_12, MINECRAFT_1_12, 0x00),
VersionRange.of(MINECRAFT_1_13, MAXIMUM_VERSION, 0x01))
.build();
// 1.12 should have ID 0x00
assertEquals(0x00, registry.forVersion(MINECRAFT_1_12).getPacketId(new HandshakePacket()));
// 1.13 should have ID 0x01
assertEquals(0x01, registry.forVersion(MINECRAFT_1_13).getPacketId(new HandshakePacket()));
}
@Test
void multiplePacketsInSingleRegistry() {
// Test registry with multiple packet types
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_12, 0x00))
.register(StatusPingPacket.class, new StatusPingPacket.Codec(),
VersionRange.of(MINECRAFT_1_12, 0x01))
.build();
assertEquals(0x00, registry.forVersion(MINECRAFT_1_12).getPacketId(new HandshakePacket()));
assertEquals(0x01, registry.forVersion(MINECRAFT_1_12).getPacketId(new StatusPingPacket(0L)));
assertNotNull(registry.forVersion(MINECRAFT_1_12).getCodec(0x00));
assertNotNull(registry.forVersion(MINECRAFT_1_12).getCodec(0x01));
}
// ==================== Encode-Only Tests ====================
@Test
void encodeOnlyPacketsCanBeEncoded() {
// Encode-only packets should be decodable by class but not by ID
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.encodeOnly(MINECRAFT_1_12, 0x00))
.build();
// Should be able to get codec by class
assertNotNull(registry.forVersion(MINECRAFT_1_12).getCodec(HandshakePacket.class));
// Should NOT be able to get codec by ID
assertNull(registry.forVersion(MINECRAFT_1_12).getCodec(0x00));
}
@Test
void encodeOnlyPacketMultipleVersions() {
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.encodeOnly(MINECRAFT_1_8, MINECRAFT_1_12, 0x00),
VersionRange.of(MINECRAFT_1_13, 0x01))
.build();
// 1.8-1.12 should be encode-only (no decode by ID)
assertNull(registry.forVersion(MINECRAFT_1_12).getCodec(0x00));
assertNotNull(registry.forVersion(MINECRAFT_1_12).getCodec(HandshakePacket.class));
// 1.13+ should be decodable by ID
assertNotNull(registry.forVersion(MINECRAFT_1_13).getCodec(0x01));
}
// ==================== Codec Retrieval Tests ====================
@Test
void getCodecByClassWorks() {
MultiVersionPacketRegistry registry = setupRegistry();
PacketCodec<HandshakePacket> codec = registry.forVersion(MINECRAFT_1_12)
.getCodec(HandshakePacket.class);
assertNotNull(codec, "Should be able to retrieve codec by class");
assertEquals(HandshakePacket.Codec.class, codec.getClass());
}
@Test
void getCodecByClassReturnsNullForUnregisteredPacket() {
MultiVersionPacketRegistry registry = setupRegistry();
PacketCodec<StatusPingPacket> codec = registry.forVersion(MINECRAFT_1_12)
.getCodec(StatusPingPacket.class);
assertNull(codec, "Should return null for unregistered packet class");
}
@Test
void getCodecByIdReturnsNullForInvalidId() {
MultiVersionPacketRegistry registry = setupRegistry();
PacketCodec<?> codec = registry.forVersion(MINECRAFT_1_12).getCodec(0xFF);
assertNull(codec, "Should return null for invalid packet ID");
}
// ==================== CanDecodePacket Tests ====================
@Test
void canDecodePacketReturnsTrue() {
MultiVersionPacketRegistry registry = setupRegistry();
assertTrue(registry.forVersion(MINECRAFT_1_12).canDecodePacket(new HandshakePacket()),
"Should be able to decode HandshakePacket in 1.12");
}
@Test
void canDecodePacketReturnsFalse() {
MultiVersionPacketRegistry registry = setupRegistry();
assertFalse(registry.forVersion(MINECRAFT_1_12).canDecodePacket(new StatusPingPacket(0L)),
"Should not be able to decode StatusPingPacket in 1.12");
}
@Test
void encodeOnlyPacketCanBeIdentified() {
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.encodeOnly(MINECRAFT_1_12, 0x00))
.build();
// Encode-only packets can still be identified by class for encoding purposes
assertTrue(registry.forVersion(MINECRAFT_1_12).canDecodePacket(new HandshakePacket()),
"Encode-only packets can be identified for encoding");
// But cannot be decoded by ID (not in packetIdToCodec)
assertNull(registry.forVersion(MINECRAFT_1_12).getCodec(0x00),
"Encode-only packets cannot be decoded from ID");
}
// ==================== SimplePacketRegistry Tests ====================
@Test
void simplePacketRegistryWorks() {
SimplePacketRegistry registry = new SimplePacketRegistry(ProtocolUtils.Direction.CLIENTBOUND);
registry.register(0x00, HandshakePacket.class, new HandshakePacket.Codec());
PacketCodec<?> codec = registry.getCodec(0x00);
assertNotNull(codec, "Should retrieve codec by ID");
assertEquals(HandshakePacket.Codec.class, codec.getClass());
}
@Test
void simplePacketRegistryCodecByClass() {
SimplePacketRegistry registry = new SimplePacketRegistry(ProtocolUtils.Direction.CLIENTBOUND);
registry.register(0x00, HandshakePacket.class, new HandshakePacket.Codec());
PacketCodec<HandshakePacket> codec = registry.getCodec(HandshakePacket.class);
assertNotNull(codec, "Should retrieve codec by class");
assertEquals(HandshakePacket.Codec.class, codec.getClass());
}
@Test
void simplePacketRegistryGetPacketId() {
SimplePacketRegistry registry = new SimplePacketRegistry(ProtocolUtils.Direction.CLIENTBOUND);
registry.register(0x42, HandshakePacket.class, new HandshakePacket.Codec());
int id = registry.getPacketId(new HandshakePacket());
assertEquals(0x42, id, "Should return correct packet ID");
}
@Test
void simplePacketRegistryFailsOnUnregisteredPacket() {
SimplePacketRegistry registry = new SimplePacketRegistry(ProtocolUtils.Direction.CLIENTBOUND);
registry.register(0x00, HandshakePacket.class, new HandshakePacket.Codec());
assertThrows(IllegalArgumentException.class,
() -> registry.getPacketId(new StatusPingPacket(0L)),
"Should fail when packet is not registered");
}
@Test
void simplePacketRegistryCanDecodePacket() {
SimplePacketRegistry registry = new SimplePacketRegistry(ProtocolUtils.Direction.CLIENTBOUND);
registry.register(0x00, HandshakePacket.class, new HandshakePacket.Codec());
assertTrue(registry.canDecodePacket(new HandshakePacket()),
"Should be able to decode registered packet");
assertFalse(registry.canDecodePacket(new StatusPingPacket(0L)),
"Should not be able to decode unregistered packet");
}
// ==================== Direction Tests ====================
@Test
void registriesWithDifferentDirections() {
// CLIENTBOUND registry
MultiVersionPacketRegistry clientbound = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_12, 0x00))
.build();
// SERVERBOUND registry with different ID
MultiVersionPacketRegistry serverbound = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.SERVERBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_12, 0x01))
.build();
assertEquals(0x00, clientbound.forVersion(MINECRAFT_1_12).getPacketId(new HandshakePacket()));
assertEquals(0x01, serverbound.forVersion(MINECRAFT_1_12).getPacketId(new HandshakePacket()));
}
// ==================== Wide Version Range Tests ====================
@Test
void wideVersionRangeSpanningManyVersions() {
// Register packet across many versions with same ID
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_8, MAXIMUM_VERSION, 0x00))
.build();
// Should work for all supported versions in range
assertEquals(0x00, registry.forVersion(MINECRAFT_1_8).getPacketId(new HandshakePacket()));
assertEquals(0x00, registry.forVersion(MINECRAFT_1_12).getPacketId(new HandshakePacket()));
assertEquals(0x00, registry.forVersion(MINECRAFT_1_16_2).getPacketId(new HandshakePacket()));
}
@Test
void nullEndVersionRangeHandling() {
// Test with null end version (should extend to MAXIMUM_VERSION)
MultiVersionPacketRegistry registry = MultiVersionPacketRegistry.builder(ProtocolUtils.Direction.CLIENTBOUND)
.register(HandshakePacket.class, new HandshakePacket.Codec(),
VersionRange.of(MINECRAFT_1_15, 0x00))
.build();
assertEquals(0x00, registry.forVersion(MINECRAFT_1_15).getPacketId(new HandshakePacket()));
assertEquals(0x00, registry.forVersion(MINECRAFT_1_16_2).getPacketId(new HandshakePacket()));
} }
} }