--- a/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundPlayerInfoUpdatePacket.java
@@ -29,12 +29,46 @@
         this.actions = EnumSet.of(action);
         this.entries = List.of(new ClientboundPlayerInfoUpdatePacket.Entry(player));
     }
+    // Paper start
+    public ClientboundPlayerInfoUpdatePacket(EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions, List<ClientboundPlayerInfoUpdatePacket.Entry> entries) {
+        this.actions = actions;
+        this.entries = entries;
+    }
+
+    public ClientboundPlayerInfoUpdatePacket(EnumSet<ClientboundPlayerInfoUpdatePacket.Action> actions, ClientboundPlayerInfoUpdatePacket.Entry entry) {
+        this.actions = actions;
+        this.entries = List.of(entry);
+    }
+    // Paper end
 
     public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection<ServerPlayer> players) {
         EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
         return new ClientboundPlayerInfoUpdatePacket(enumSet, players);
     }
 
+    // Paper start
+    public static ClientboundPlayerInfoUpdatePacket createPlayerInitializing(Collection<ServerPlayer> players, ServerPlayer forPlayer) {
+        final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
+        final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = new java.util.ArrayList<>(players.size());
+        final org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer bukkitEntity = forPlayer.getBukkitEntity();
+        for (final ServerPlayer player : players) {
+            entries.add(new ClientboundPlayerInfoUpdatePacket.Entry(player, bukkitEntity.isListed(player.getBukkitEntity())));
+        }
+        return new ClientboundPlayerInfoUpdatePacket(enumSet, entries);
+    }
+
+    public static ClientboundPlayerInfoUpdatePacket createSinglePlayerInitializing(ServerPlayer player, boolean listed) {
+        final EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.INITIALIZE_CHAT, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
+        final List<ClientboundPlayerInfoUpdatePacket.Entry> entries = List.of(new Entry(player, listed));
+        return new ClientboundPlayerInfoUpdatePacket(enumSet, entries);
+    }
+
+    public static ClientboundPlayerInfoUpdatePacket updateListed(UUID playerInfoId, boolean listed) {
+        EnumSet<ClientboundPlayerInfoUpdatePacket.Action> enumSet = EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
+        return new ClientboundPlayerInfoUpdatePacket(enumSet, new ClientboundPlayerInfoUpdatePacket.Entry(playerInfoId, listed));
+    }
+    // Paper end
+
     public ClientboundPlayerInfoUpdatePacket(FriendlyByteBuf buf) {
         this.actions = buf.readEnumSet(ClientboundPlayerInfoUpdatePacket.Action.class);
         this.entries = buf.readList((buf2) -> {
@@ -96,7 +130,13 @@
         INITIALIZE_CHAT((serialized, buf) -> {
             serialized.chatSession = buf.readNullable(RemoteChatSession.Data::read);
         }, (buf, entry) -> {
-            buf.writeNullable(entry.chatSession, RemoteChatSession.Data::write);
+            // Paper start
+            RemoteChatSession.Data chatSession = entry.chatSession;
+            if (chatSession != null && chatSession.profilePublicKey().hasExpired()) {
+                chatSession = null;
+            }
+            buf.writeNullable(chatSession, RemoteChatSession.Data::write);
+            // Paper end
         }),
         UPDATE_GAME_MODE((serialized, buf) -> {
             serialized.gameMode = GameType.byId(buf.readVarInt());
@@ -138,8 +178,18 @@
 
     public static record Entry(UUID profileId, @Nullable GameProfile profile, boolean listed, int latency, GameType gameMode, @Nullable Component displayName, @Nullable RemoteChatSession.Data chatSession) {
         Entry(ServerPlayer player) {
-            this(player.getUUID(), player.getGameProfile(), true, player.connection.latency(), player.gameMode.getGameModeForPlayer(), player.getTabListDisplayName(), Optionull.map(player.getChatSession(), RemoteChatSession::asData));
+            // Paper start - add listed
+            this(player, true);
         }
+        Entry(ServerPlayer player, boolean listed) {
+            this(player.getUUID(), player.getGameProfile(), listed, player.connection.latency(), player.gameMode.getGameModeForPlayer(), player.getTabListDisplayName(), Optionull.map(player.getChatSession(), RemoteChatSession::asData));
+            // Paper end - add listed
+        }
+        // Paper start
+        Entry(UUID profileId, boolean listed) {
+            this(profileId, null, listed, 0, GameType.DEFAULT_MODE, null, null);
+        }
+        // Paper end
     }
 
     static class EntryBuilder {
