diff --git a/src/main/java/net/william278/velocitab/packet/PlayerChannelHandler.java b/src/main/java/net/william278/velocitab/packet/PlayerChannelHandler.java index 28f7af6..699d8f3 100644 --- a/src/main/java/net/william278/velocitab/packet/PlayerChannelHandler.java +++ b/src/main/java/net/william278/velocitab/packet/PlayerChannelHandler.java @@ -56,6 +56,13 @@ public class PlayerChannelHandler extends ChannelDuplexHandler { forceGameMode(minecraftPacket.getEntries()); } + //fix for duplicate entries + if (minecraftPacket.containsAction(UpsertPlayerInfoPacket.Action.ADD_PLAYER)) { + minecraftPacket.getEntries().stream() + .filter(entry -> entry.getProfile() != null && !entry.getProfile().getId().equals(entry.getProfileId())) + .forEach(entry -> entry.setListed(false)); + } + if (!minecraftPacket.containsAction(UpsertPlayerInfoPacket.Action.ADD_PLAYER) && !minecraftPacket.containsAction(UpsertPlayerInfoPacket.Action.UPDATE_LISTED)) { super.write(ctx, msg, promise); return; diff --git a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java index c8d88e5..839c83e 100644 --- a/src/main/java/net/william278/velocitab/tab/PlayerTabList.java +++ b/src/main/java/net/william278/velocitab/tab/PlayerTabList.java @@ -39,6 +39,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.slf4j.event.Level; +import java.lang.reflect.Field; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -212,6 +213,8 @@ public class PlayerTabList { tabPlayer.getTeamName(plugin).thenAccept(t -> s.updateRole(tabPlayer, t, false)); }); + fixDuplicateEntries(joined); + // Fire event without listening for result plugin.getServer().getEventManager().fireAndForget(new PlayerAddedToTabEvent(tabPlayer, group)); }) @@ -231,6 +234,22 @@ public class PlayerTabList { .orElse(""); } + @SuppressWarnings("unchecked") + private void fixDuplicateEntries(@NotNull Player target) { + try { + final Field entriesField = target.getTabList().getClass().getDeclaredField("entries"); + entriesField.setAccessible(true); + final Map entries = (Map) entriesField.get(target.getTabList()); + entries.entrySet().stream() + .filter(entry -> entry.getValue().getProfile() != null) + .filter(entry -> entry.getValue().getProfile().getId().equals(target.getUniqueId())) + .filter(entry -> !entry.getKey().equals(target.getUniqueId())) + .forEach(entry -> target.getTabList().removeEntry(entry.getKey())); + } catch (Throwable error) { + plugin.log(Level.ERROR, "Failed to fix duplicate entries", error); + } + } + protected void removePlayer(@NotNull Player target) { removePlayer(target, null); } @@ -409,11 +428,9 @@ public class PlayerTabList { .forEach(player -> { final int latency = (int) player.getPlayer().getPing(); final Set players = group.getTabPlayers(plugin, player); - players.forEach(p -> { - p.getPlayer().getTabList().getEntries().stream() - .filter(e -> e.getProfile().getId().equals(player.getPlayer().getUniqueId())).findFirst() - .ifPresent(entry -> entry.setLatency(Math.max(latency, 0))); - }); + players.forEach(p -> p.getPlayer().getTabList().getEntries().stream() + .filter(e -> e.getProfile().getId().equals(player.getPlayer().getUniqueId())).findFirst() + .ifPresent(entry -> entry.setLatency(Math.max(latency, 0)))); }); }