diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index dfe230e318..96d7b4ffe3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -55,6 +55,7 @@ import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket; import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket; import com.velocitypowered.proxy.protocol.packet.DisconnectPacket; +import com.velocitypowered.proxy.protocol.packet.HeaderAndFooterPacket; import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket; import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket; @@ -338,6 +339,16 @@ public boolean handle(TabCompleteResponsePacket packet) { return true; } + @Override + public boolean handle(HeaderAndFooterPacket packet) { + // Snoop the backend's player list header/footer so the proxy's tracked values stay in sync + // with what the player actually sees. + serverConn.getPlayer().setPlayerListHeaderAndFooterSilent( + packet.getHeader().getComponent(), + packet.getFooter().getComponent()); + return false; + } + @Override public boolean handle(LegacyPlayerListItemPacket packet) { serverConn.getPlayer().getTabList().processLegacy(packet); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index 47d59a7186..de11c42fbd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -479,6 +479,12 @@ public Component getPlayerListFooter() { return this.playerListFooter; } + public void setPlayerListHeaderAndFooterSilent(@NonNull final Component header, + @NonNull final Component footer) { + this.playerListHeader = header; + this.playerListFooter = footer; + } + @Override public void sendPlayerListHeader(@NonNull final Component header) { this.sendPlayerListHeaderAndFooter(header, this.playerListFooter); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 2971087685..eb7a412fcd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -623,28 +623,28 @@ public enum StateRegistry { clientbound.register( HeaderAndFooterPacket.class, HeaderAndFooterPacket::new, - map(0x47, MINECRAFT_1_8, true), - map(0x48, MINECRAFT_1_9, true), - map(0x47, MINECRAFT_1_9_4, true), - map(0x49, MINECRAFT_1_12, true), - map(0x4A, MINECRAFT_1_12_1, true), - map(0x4E, MINECRAFT_1_13, true), - map(0x53, MINECRAFT_1_14, true), - map(0x54, MINECRAFT_1_15, true), - map(0x53, MINECRAFT_1_16, true), - map(0x5E, MINECRAFT_1_17, true), - map(0x5F, MINECRAFT_1_18, true), - map(0x60, MINECRAFT_1_19, true), - map(0x63, MINECRAFT_1_19_1, true), - map(0x61, MINECRAFT_1_19_3, true), - map(0x65, MINECRAFT_1_19_4, true), - map(0x68, MINECRAFT_1_20_2, true), - map(0x6A, MINECRAFT_1_20_3, true), - map(0x6D, MINECRAFT_1_20_5, true), - map(0x74, MINECRAFT_1_21_2, true), - map(0x73, MINECRAFT_1_21_5, true), - map(0x78, MINECRAFT_1_21_9, true), - map(0x7A, MINECRAFT_26_1, true)); + map(0x47, MINECRAFT_1_8, false), + map(0x48, MINECRAFT_1_9, false), + map(0x47, MINECRAFT_1_9_4, false), + map(0x49, MINECRAFT_1_12, false), + map(0x4A, MINECRAFT_1_12_1, false), + map(0x4E, MINECRAFT_1_13, false), + map(0x53, MINECRAFT_1_14, false), + map(0x54, MINECRAFT_1_15, false), + map(0x53, MINECRAFT_1_16, false), + map(0x5E, MINECRAFT_1_17, false), + map(0x5F, MINECRAFT_1_18, false), + map(0x60, MINECRAFT_1_19, false), + map(0x63, MINECRAFT_1_19_1, false), + map(0x61, MINECRAFT_1_19_3, false), + map(0x65, MINECRAFT_1_19_4, false), + map(0x68, MINECRAFT_1_20_2, false), + map(0x6A, MINECRAFT_1_20_3, false), + map(0x6D, MINECRAFT_1_20_5, false), + map(0x74, MINECRAFT_1_21_2, false), + map(0x73, MINECRAFT_1_21_5, false), + map(0x78, MINECRAFT_1_21_9, false), + map(0x7A, MINECRAFT_26_1, false)); clientbound.register( LegacyTitlePacket.class, LegacyTitlePacket::new, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java index 339d026f8f..a52d2a3153 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java @@ -28,11 +28,10 @@ public class HeaderAndFooterPacket implements MinecraftPacket { - private final ComponentHolder header; - private final ComponentHolder footer; + private ComponentHolder header; + private ComponentHolder footer; public HeaderAndFooterPacket() { - throw new UnsupportedOperationException("Decode is not implemented"); } public HeaderAndFooterPacket(ComponentHolder header, ComponentHolder footer) { @@ -50,7 +49,8 @@ public ComponentHolder getFooter() { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - throw new UnsupportedOperationException("Decode is not implemented"); + header = ComponentHolder.read(buf, version); + footer = ComponentHolder.read(buf, version); } @Override