diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index f98d0d75f7..192153a085 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -53,6 +53,7 @@ import com.velocitypowered.proxy.network.ConnectionManager; import com.velocitypowered.proxy.plugin.VelocityPluginManager; import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.packet.uuidrewrite.TabListUuidRewriter; import com.velocitypowered.proxy.protocol.util.FaviconSerializer; import com.velocitypowered.proxy.protocol.util.GameProfileSerializer; import com.velocitypowered.proxy.scheduler.VelocityScheduler; @@ -654,6 +655,9 @@ public void unregisterConnection(ConnectedPlayer connection) { connectionsByName.remove(connection.getUsername().toLowerCase(Locale.US), connection); connectionsByUuid.remove(connection.getUniqueId(), connection); connection.disconnected(); + + // [fallen's fork] player uuid rewrite - + TabListUuidRewriter.onPlayerDisconnect(this, connection); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/uuidrewrite/TabListUuidRewriter.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/uuidrewrite/TabListUuidRewriter.java index b36e8dfa40..97e3a21de6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/uuidrewrite/TabListUuidRewriter.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/uuidrewrite/TabListUuidRewriter.java @@ -17,13 +17,18 @@ package com.velocitypowered.proxy.protocol.packet.uuidrewrite; +import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.config.PlayerInfoForwarding; +import com.velocitypowered.proxy.connection.backend.VelocityServerConnection; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; +import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket; import com.velocitypowered.proxy.protocol.packet.RemovePlayerInfoPacket; import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket; -import java.util.LinkedHashMap; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -34,26 +39,53 @@ */ public class TabListUuidRewriter { - // offline / server uuid -> online / client uuid - // this cache is necessary, cuz during processing the RemovePlayerInfoPacket, the player might have already disconnected - private static final Map uuidMappingCache = new LinkedHashMap<>(16, 0.75f, true); - + @SuppressWarnings("BooleanMethodIsAlwaysInverted") private static boolean shouldRewrite(VelocityServer server) { var config = server.getConfiguration(); return config.isOnlineMode() && config.getPlayerInfoForwardingMode() == PlayerInfoForwarding.NONE; } + // offline / server uuid -> online / client uuid private static Map makeUuidMappingView(VelocityServer server) { - synchronized (uuidMappingCache) { - for (Player player : server.getAllPlayers()) { - uuidMappingCache.put(player.getOfflineUuid(), player.getUniqueId()); - } + Map view = new HashMap<>(); + for (Player player : server.getAllPlayers()) { + view.put(player.getOfflineUuid(), player.getUniqueId()); + } + return view; + } - // allow at most 1024 players to disconnect at the same time - while (uuidMappingCache.size() > server.getAllPlayers().size() + 1024) { - uuidMappingCache.remove(uuidMappingCache.keySet().iterator().next()); + // [fallen's fork] player uuid rewrite + // send the missing player tab-list removal packets to other players in the mc server + // see bungeecord net.md_5.bungee.connection.UpstreamBridge#disconnected + public static void onPlayerDisconnect(VelocityServer server, ConnectedPlayer player) { + if (!shouldRewrite(server)) { + return; + } + + VelocityServerConnection connectedServer = player.getConnectedServer(); + if (connectedServer == null) { + return; + } + + var oldPacket = new LegacyPlayerListItemPacket( + LegacyPlayerListItemPacket.REMOVE_PLAYER, + Collections.singletonList(new LegacyPlayerListItemPacket.Item(player.getUniqueId())) + ); + var newPacket = new RemovePlayerInfoPacket( + Collections.singleton(player.getUniqueId()) + ); + + for (Player otherPlayer : connectedServer.getServer().getPlayersConnected()) { + if (otherPlayer != player && otherPlayer instanceof ConnectedPlayer) { + var connection = ((ConnectedPlayer)otherPlayer).getConnection(); + MinecraftPacket packet; + if (connection.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) { + packet = newPacket; + } else { + packet = oldPacket; + } + connection.write(packet); } - return Map.copyOf(uuidMappingCache); } } @@ -126,10 +158,6 @@ public static void rewrite(VelocityServer server, RemovePlayerInfoPacket packet) .map(serverUuid -> Optional.ofNullable(uuidMapping.get(serverUuid)).orElse(serverUuid)) .collect(Collectors.toList()); - synchronized (uuidMappingCache) { - packet.getProfilesToRemove().forEach(uuidMappingCache::remove); - } - packet.setProfilesToRemove(newProfiles); } }