diff --git a/TabOverlayCommon b/TabOverlayCommon index 75e4529f..af983094 160000 --- a/TabOverlayCommon +++ b/TabOverlayCommon @@ -1 +1 @@ -Subproject commit 75e4529f58d0bf1d8ace537af7d5a49bbc2e8308 +Subproject commit af983094c422ba7410cc3d322b7e8eb496691638 diff --git a/bungee/src/main/java/codecrafter47/bungeetablistplus/BungeeTabListPlus.java b/bungee/src/main/java/codecrafter47/bungeetablistplus/BungeeTabListPlus.java index 0a245fa5..e21efd0d 100644 --- a/bungee/src/main/java/codecrafter47/bungeetablistplus/BungeeTabListPlus.java +++ b/bungee/src/main/java/codecrafter47/bungeetablistplus/BungeeTabListPlus.java @@ -66,8 +66,10 @@ import lombok.val; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.connection.Connection; import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter; import org.bstats.bungeecord.Metrics; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.error.YAMLException; @@ -185,19 +187,31 @@ public void onLoad() { try { Class.forName("net.md_5.bungee.api.Title"); } catch (ClassNotFoundException ex) { - throw new RuntimeException("You need to run at least BungeeCord version #1671"); + throw new RuntimeException("You need to run at least BungeeCord version #1766"); } try { Connection.class.getMethod("isConnected"); } catch (NoSuchMethodException ex) { - throw new RuntimeException("You need to run at least BungeeCord version #1671"); + throw new RuntimeException("You need to run at least BungeeCord version #1766"); } try { Class.forName("net.md_5.bungee.protocol.packet.PlayerListItemUpdate"); } catch (ClassNotFoundException ex) { - throw new RuntimeException("You need to run at least BungeeCord version #1671"); + throw new RuntimeException("You need to run at least BungeeCord version #1766"); + } + + try { + PlayerListHeaderFooter.class.getMethod("setHeader", BaseComponent.class); + } catch (NoSuchMethodException ex) { + throw new RuntimeException("You need to run at least BungeeCord version #1766"); + } + + try { + Class.forName("net.md_5.bungee.protocol.Either"); + } catch (ClassNotFoundException ex) { + throw new RuntimeException("You need to run at least BungeeCord version #1766"); } INSTANCE = this; diff --git a/bungee/src/main/java/codecrafter47/bungeetablistplus/bridge/BukkitBridge.java b/bungee/src/main/java/codecrafter47/bungeetablistplus/bridge/BukkitBridge.java index b053990a..f77dbab0 100644 --- a/bungee/src/main/java/codecrafter47/bungeetablistplus/bridge/BukkitBridge.java +++ b/bungee/src/main/java/codecrafter47/bungeetablistplus/bridge/BukkitBridge.java @@ -572,7 +572,7 @@ protected void addActiveKey(DataKey key) { try { synchronized (this) { Server connection = getConnection(); - if (connection != null) { + if (connection != null && connection.isConnected()) { if (!requestedDataKeys.contains(key)) { requestedDataKeys.add(key); ByteArrayDataOutput data = ByteStreams.newDataOutput(); diff --git a/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractLegacyTabOverlayHandler.java b/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractLegacyTabOverlayHandler.java index ba8fe50c..1d6a018a 100644 --- a/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractLegacyTabOverlayHandler.java +++ b/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractLegacyTabOverlayHandler.java @@ -37,7 +37,9 @@ import lombok.AllArgsConstructor; import lombok.val; import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.Either; import net.md_5.bungee.protocol.packet.*; import javax.annotation.Nonnull; @@ -248,7 +250,7 @@ private void removeEntry(UUID uuid, String player) { PlayerListItem.Item item = new PlayerListItem.Item(); item.setUuid(uuid); item.setUsername(player); - item.setDisplayName(player); + item.setDisplayName(new TextComponent(player)); item.setPing(9999); pli.setItems(new PlayerListItem.Item[]{item}); pli.setAction(PlayerListItem.Action.REMOVE_PLAYER); @@ -312,7 +314,7 @@ void onActivated() { for (val entry : serverPlayerList.object2IntEntrySet()) { PlayerListItem pli = new PlayerListItem(); PlayerListItem.Item item = new PlayerListItem.Item(); - item.setDisplayName(entry.getKey()); + item.setDisplayName(new TextComponent(entry.getKey())); item.setPing(entry.getIntValue()); pli.setItems(new PlayerListItem.Item[]{item}); pli.setAction(PlayerListItem.Action.ADD_PLAYER); @@ -432,17 +434,12 @@ private void updateSize() { Team t = new Team(); t.setName(slotID[index]); t.setMode((byte) 0); - t.setPrefix(tabOverlay.text0[index]); - t.setDisplayName(""); - t.setSuffix(tabOverlay.text1[index]); + t.setPrefix(Either.left(tabOverlay.text0[index])); + t.setDisplayName(Either.left("")); + t.setSuffix(Either.left(tabOverlay.text1[index])); t.setPlayers(new String[]{slotID[index]}); t.setNameTagVisibility("always"); t.setCollisionRule("always"); - if (is13OrLater) { - t.setDisplayName(EMPTY_JSON_TEXT); - t.setPrefix("{\"text\":\"" + tabOverlay.text0[index] + "\"}"); - t.setSuffix("{\"text\":\"" + tabOverlay.text1[index] + "\"}"); - } sendPacket(t); } } else { @@ -464,7 +461,7 @@ private void updateSlot(CustomTabOverlay tabOverlay, int index) { item.setUuid(slotUUID[index]); item.setUsername(slotID[index]); Property119Handler.setProperties(item, EMPTY_PROPERTIES); - item.setDisplayName(slotID[index]); + item.setDisplayName(new TextComponent(slotID[index])); item.setPing(tabOverlay.ping[index]); pli.setItems(new PlayerListItem.Item[]{item}); pli.setAction(PlayerListItem.Action.ADD_PLAYER); @@ -476,16 +473,11 @@ private void updateText(CustomTabOverlay tabOverlay, int index) { Team packet = new Team(); packet.setName(slotID[index]); packet.setMode((byte) 2); - packet.setPrefix(tabOverlay.text0[index]); - packet.setDisplayName(""); - packet.setSuffix(tabOverlay.text1[index]); + packet.setPrefix(Either.left(tabOverlay.text0[index])); + packet.setDisplayName(Either.left("")); + packet.setSuffix(Either.left(tabOverlay.text1[index])); packet.setNameTagVisibility("always"); packet.setCollisionRule("always"); - if (is13OrLater) { - packet.setDisplayName(EMPTY_JSON_TEXT); - packet.setPrefix("{\"text\":\"" + tabOverlay.text0[index] + "\"}"); - packet.setSuffix("{\"text\":\"" + tabOverlay.text1[index] + "\"}"); - } sendPacket(packet); } } @@ -828,7 +820,7 @@ public boolean isValid() { */ private static String getName(PlayerListItem.Item item) { if (item.getDisplayName() != null) { - return item.getDisplayName(); + return item.getDisplayName().toLegacyText(); } else if (item.getUsername() != null) { return item.getUsername(); } else { diff --git a/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractTabOverlayHandler.java b/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractTabOverlayHandler.java index 1130e800..61d20d19 100644 --- a/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractTabOverlayHandler.java +++ b/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/AbstractTabOverlayHandler.java @@ -32,7 +32,11 @@ import de.codecrafter47.taboverlay.handler.*; import it.unimi.dsi.fastutil.objects.*; import lombok.*; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.Either; import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter; import net.md_5.bungee.protocol.packet.PlayerListItem; import net.md_5.bungee.protocol.packet.Team; @@ -56,12 +60,9 @@ public abstract class AbstractTabOverlayHandler implements PacketHandler, TabOve private static final boolean OPTION_ENABLE_CUSTOM_SLOT_UUID_COLLISION_CHECK = true; private static final boolean OPTION_ENABLE_CONSISTENCY_CHECKS = true; - private static final String EMPTY_JSON_TEXT = "{\"text\":\"\"}"; + private static final BaseComponent EMPTY_TEXT_COMPONENT = new TextComponent(); protected static final String[][] EMPTY_PROPERTIES_ARRAY = new String[0][]; - private static final boolean TEAM_COLLISION_RULE_SUPPORTED; - private static final boolean USE_PROTOCOL_PROPERTY_TYPE; - private static final ImmutableMap DIMENSION_TO_USED_SLOTS; private static final BitSet[] SIZE_TO_USED_SLOTS; @@ -78,23 +79,6 @@ public abstract class AbstractTabOverlayHandler implements PacketHandler, TabOve private static final Set blockedTeams = new HashSet<>(); static { - // check whether this BungeeCord version supports team's collision rule property - boolean methodPresent = false; - try { - Team.class.getDeclaredMethod("setCollisionRule", String.class); - methodPresent = true; - } catch (NoSuchMethodException ignored) { - } - TEAM_COLLISION_RULE_SUPPORTED = methodPresent; - - methodPresent = false; - try { - Class.forName("net.md_5.bungee.protocol.Property"); - methodPresent = true; - } catch (ClassNotFoundException ignored) { - } - USE_PROTOCOL_PROPERTY_TYPE = methodPresent; - // build the dimension to used slots map (for the rectangular tab overlay) val builder = ImmutableMap.builder(); for (int columns = 1; columns <= 4; columns++) { @@ -176,9 +160,9 @@ public abstract class AbstractTabOverlayHandler implements PacketHandler, TabOve private final Object2ObjectMap serverPlayerList = new Object2ObjectOpenHashMap<>(); protected final Set serverTabListPlayers = new ObjectOpenHashSet<>(); @Nullable - protected String serverHeader = null; + protected BaseComponent serverHeader = null; @Nullable - protected String serverFooter = null; + protected BaseComponent serverFooter = null; protected final Object2ObjectMap serverTeams = new Object2ObjectOpenHashMap<>(); protected final Object2ObjectMap playerToTeamMap = new Object2ObjectOpenHashMap<>(); @@ -188,7 +172,6 @@ public abstract class AbstractTabOverlayHandler implements PacketHandler, TabOve private AbstractHeaderFooterOperationModeHandler activeHeaderFooterHandler; private boolean hasCreatedCustomTeams = false; - private boolean areCustomSlotUsersPartOfTeams = false; private final AtomicBoolean updateScheduledFlag = new AtomicBoolean(false); private final Runnable updateTask = this::update; @@ -198,6 +181,8 @@ public abstract class AbstractTabOverlayHandler implements PacketHandler, TabOve private boolean is119OrLater; protected boolean active; + private final Either emptyEither; + public AbstractTabOverlayHandler(Logger logger, Executor eventLoopExecutor, UUID viewerUuid, boolean is18, boolean is13OrLater, boolean is119OrLater) { this.logger = logger; this.eventLoopExecutor = eventLoopExecutor; @@ -207,6 +192,11 @@ public AbstractTabOverlayHandler(Logger logger, Executor eventLoopExecutor, UUID this.is119OrLater = is119OrLater; this.activeContentHandler = new PassThroughContentHandler(); this.activeHeaderFooterHandler = new PassThroughHeaderFooterHandler(); + if (is13OrLater) { + emptyEither = Either.right(EMPTY_TEXT_COMPONENT); + } else { + emptyEither = Either.left(""); + } } protected abstract void sendPacket(DefinedPacket packet); @@ -285,6 +275,7 @@ public PacketListenerResult onTeamPacket(Team packet) { for (String player : packet.getPlayers()) { if (player.equals("")) { block = true; + break; } } if (block) { @@ -328,9 +319,7 @@ public PacketListenerResult onTeamPacket(Team packet) { teamEntry.setSuffix(packet.getSuffix()); teamEntry.setFriendlyFire(packet.getFriendlyFire()); teamEntry.setNameTagVisibility(packet.getNameTagVisibility()); - if (TEAM_COLLISION_RULE_SUPPORTED) { - teamEntry.setCollisionRule(packet.getCollisionRule()); - } + teamEntry.setCollisionRule(packet.getCollisionRule()); teamEntry.setColor(packet.getColor()); } if (packet.getPlayers() != null) { @@ -378,8 +367,8 @@ public PacketListenerResult onPlayerListHeaderFooterPacket(PlayerListHeaderFoote enterHeaderAndFooterOperationMode(HeaderAndFooterOperationMode.PASS_TROUGH); } - this.serverHeader = packet.getHeader() != null ? packet.getHeader() : EMPTY_JSON_TEXT; - this.serverFooter = packet.getFooter() != null ? packet.getFooter() : EMPTY_JSON_TEXT; + this.serverHeader = packet.getHeader() != null ? packet.getHeader() : EMPTY_TEXT_COMPONENT; + this.serverFooter = packet.getFooter() != null ? packet.getFooter() : EMPTY_TEXT_COMPONENT; return result; } @@ -397,7 +386,6 @@ public void onServerSwitch(boolean is13OrLater) { if (isUsingAltRespawn()) { hasCreatedCustomTeams = false; - areCustomSlotUsersPartOfTeams = false; } try { @@ -433,10 +421,10 @@ public void onServerSwitch(boolean is13OrLater) { serverPlayerList.clear(); if (serverHeader != null) { - serverHeader = EMPTY_JSON_TEXT; + serverHeader = EMPTY_TEXT_COMPONENT; } if (serverFooter != null) { - serverFooter = EMPTY_JSON_TEXT; + serverFooter = EMPTY_TEXT_COMPONENT; } serverTabListPlayers.clear(); @@ -674,7 +662,7 @@ PacketListenerResult onTeamPacket(Team packet) { @Override void onServerSwitch() { - sendPacket(new PlayerListHeaderFooter(EMPTY_JSON_TEXT, EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(EMPTY_TEXT_COMPONENT, EMPTY_TEXT_COMPONENT)); } @Override @@ -757,7 +745,7 @@ PacketListenerResult onPlayerListHeaderFooterPacket(PlayerListHeaderFooter packe @Override void onServerSwitch() { - sendPacket(new PlayerListHeaderFooter(EMPTY_JSON_TEXT, EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(EMPTY_TEXT_COMPONENT, EMPTY_TEXT_COMPONENT)); } @Override @@ -778,7 +766,7 @@ void onActivated(AbstractHeaderFooterOperationModeHandler previous) { } // fix header/ footer - sendPacket(new PlayerListHeaderFooter(serverHeader != null ? serverHeader : EMPTY_JSON_TEXT, serverFooter != null ? serverFooter : EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(serverHeader != null ? serverHeader : EMPTY_TEXT_COMPONENT, serverFooter != null ? serverFooter : EMPTY_TEXT_COMPONENT)); } } @@ -995,11 +983,7 @@ PacketListenerResult onPlayerListPacket(PlayerListItem packet) { // 2. add player to correct team sendPacket(createPacketTeamAddPlayers(playerTeamName, new String[]{slotUsername[index]})); // 3. reset custom slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } } @@ -1075,11 +1059,7 @@ void onTeamPacketPreprocess(Team packet) { int slot = playerUsernameToSlotMap.getInt(playerName); if (slot != -1) { // reset slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[slot], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[slot], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[slot], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } } } @@ -1157,11 +1137,7 @@ PacketListenerResult onTeamPacket(Team packet) { filteredPlayers[j++] = playerName; } else { // reset slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[slot], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[slot], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[slot], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } } packet.setPlayers(filteredPlayers); @@ -1235,11 +1211,7 @@ void onServerSwitch() { // 1. remove player from team sendPacket(createPacketTeamRemovePlayers(CUSTOM_SLOT_TEAMNAME[index], new String[]{slotUsername[index]})); // reset slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } // 2. create new custom slot @@ -1342,26 +1314,12 @@ private void createTeamsIfNecessary() { if (!hasCreatedCustomTeams) { hasCreatedCustomTeams = true; - if (is13OrLater) { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[0], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[0], CUSTOM_SLOT_USERNAME_SMILEYS[0], ""})); - } else { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[0], "", "", "", "always", "always", 0, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[0], CUSTOM_SLOT_USERNAME_SMILEYS[0], ""})); - } + sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[0], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[0], CUSTOM_SLOT_USERNAME_SMILEYS[0], ""})); for (int i = 1; i < 80; i++) { - if (is13OrLater) { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[i], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[i], CUSTOM_SLOT_USERNAME_SMILEYS[i]})); - } else { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[i], "", "", "", "always", "always", 0, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[i], CUSTOM_SLOT_USERNAME_SMILEYS[i]})); - } - } - if (is13OrLater) { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[80], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[80]})); - } else { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[80], "", "", "", "always", "always", 0, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[80]})); + sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[i], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[i], CUSTOM_SLOT_USERNAME_SMILEYS[i]})); } - - areCustomSlotUsersPartOfTeams = true; + sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[80], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[80]})); } } @@ -1380,11 +1338,7 @@ void onDeactivated() { // 2. add player to correct team sendPacket(createPacketTeamAddPlayers(playerTeamName, new String[]{slotUsername[index]})); // 3. reset custom slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } } else { customSlots++; @@ -1516,11 +1470,7 @@ void update() { // 2. add player to correct team sendPacket(createPacketTeamAddPlayers(playerTeamName, new String[]{slotUsername[index]})); // 3. reset custom slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } else { // 2. add player to overflow team sendPacket(createPacketTeamAddPlayers(CUSTOM_SLOT_TEAMNAME[80], new String[]{slotUsername[index]})); @@ -1581,7 +1531,6 @@ void update() { // restore player gamemode PlayerListItem packet; List items = new ArrayList<>(serverPlayerList.size()); - items.clear(); for (PlayerListEntry entry : serverPlayerList.values()) { PlayerListItem.Item item = new PlayerListItem.Item(); item.setUuid(entry.getUuid()); @@ -1709,11 +1658,7 @@ void update() { playerUsernameToSlotMap.removeInt(slotUsername[index]); // reset slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } // 2. update slot state @@ -1734,11 +1679,7 @@ void update() { playerUsernameToSlotMap.removeInt(slotUsername[index]); // reset slot team - if (is13OrLater) { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1)); - } else { - sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], "", "", "", "always", "always", 0, (byte) 1)); - } + sendPacket(createPacketTeamUpdate(CUSTOM_SLOT_TEAMNAME[index], emptyEither, emptyEither, emptyEither, "always", "always", is13OrLater ? 21 : 0, (byte) 1)); } freePlayers.add(slotUuid[index]); @@ -2064,7 +2005,7 @@ private void sendQueuedItems() { private abstract class CustomContentTabOverlay extends AbstractContentTabOverlay implements TabOverlayHandle.BatchModifiable { final UUID[] uuid; final Icon[] icon; - final String[] text; + final BaseComponent[] text; final int[] ping; final AtomicInteger batchUpdateRecursionLevel; @@ -2078,8 +2019,8 @@ private CustomContentTabOverlay() { this.uuid = new UUID[80]; this.icon = new Icon[80]; Arrays.fill(this.icon, Icon.DEFAULT_STEVE); - this.text = new String[80]; - Arrays.fill(this.text, EMPTY_JSON_TEXT); + this.text = new BaseComponent[80]; + Arrays.fill(this.text, EMPTY_TEXT_COMPONENT); this.ping = new int[80]; this.batchUpdateRecursionLevel = new AtomicInteger(0); this.dirtyFlagSize = true; @@ -2134,8 +2075,9 @@ void setIconInternal(int index, @Nonnull @NonNull Icon icon) { void setTextInternal(int index, @Nonnull @NonNull String text) { String jsonText = ChatFormat.formattedTextToJson(text); - if (!jsonText.equals(this.text[index])) { - this.text[index] = jsonText; + BaseComponent component = ComponentSerializer.deserialize(jsonText); + if (!component.equals(this.text[index])) { + this.text[index] = component; dirtyFlagsText.set(index); scheduleUpdateIfNotInBatch(); } @@ -2219,7 +2161,7 @@ public void setSize(@Nonnull Dimension size) { if (!oldUsedSlots.get(index)) { uuid[index] = null; icon[index] = Icon.DEFAULT_STEVE; - text[index] = EMPTY_JSON_TEXT; + text[index] = EMPTY_TEXT_COMPONENT; ping[index] = 0; } } @@ -2230,7 +2172,7 @@ public void setSize(@Nonnull Dimension size) { if (!newUsedSlots.get(index)) { uuid[index] = null; icon[index] = Icon.DEFAULT_STEVE; - text[index] = EMPTY_JSON_TEXT; + text[index] = EMPTY_TEXT_COMPONENT; ping[index] = 0; } } @@ -2448,7 +2390,7 @@ void onDeactivated() { @Override void onActivated(AbstractHeaderFooterOperationModeHandler previous) { // remove header/ footer - sendPacket(new PlayerListHeaderFooter(EMPTY_JSON_TEXT, EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(EMPTY_TEXT_COMPONENT, EMPTY_TEXT_COMPONENT)); } @Override @@ -2462,8 +2404,8 @@ void update() { } private final class CustomHeaderAndFooterImpl extends AbstractHeaderFooterTabOverlay implements HeaderAndFooterHandle { - private String header = EMPTY_JSON_TEXT; - private String footer = EMPTY_JSON_TEXT; + private BaseComponent header = EMPTY_TEXT_COMPONENT; + private BaseComponent footer = EMPTY_TEXT_COMPONENT; private volatile boolean headerOrFooterDirty = false; @@ -2498,22 +2440,22 @@ void scheduleUpdateIfNotInBatch() { @Override public void setHeaderFooter(@Nullable String header, @Nullable String footer) { - this.header = ChatFormat.formattedTextToJson(header); - this.footer = ChatFormat.formattedTextToJson(footer); + this.header = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(header)); + this.footer = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(footer)); headerOrFooterDirty = true; scheduleUpdateIfNotInBatch(); } @Override public void setHeader(@Nullable String header) { - this.header = ChatFormat.formattedTextToJson(header); + this.header = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(header)); headerOrFooterDirty = true; scheduleUpdateIfNotInBatch(); } @Override public void setFooter(@Nullable String footer) { - this.footer = ChatFormat.formattedTextToJson(footer); + this.footer = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(footer)); headerOrFooterDirty = true; scheduleUpdateIfNotInBatch(); } @@ -2534,7 +2476,7 @@ private static String[][] toPropertiesArray(ProfileProperty textureProperty) { } } - private static Team createPacketTeamCreate(String name, String displayName, String prefix, String suffix, String nameTagVisibility, String collisionRule, int color, byte friendlyFire, String[] players) { + private static Team createPacketTeamCreate(String name, Either displayName, Either prefix, Either suffix, String nameTagVisibility, String collisionRule, int color, byte friendlyFire, String[] players) { Team team = new Team(); team.setName(name); team.setMode((byte) 0); @@ -2542,9 +2484,7 @@ private static Team createPacketTeamCreate(String name, String displayName, Stri team.setPrefix(prefix); team.setSuffix(suffix); team.setNameTagVisibility(nameTagVisibility); - if (TEAM_COLLISION_RULE_SUPPORTED) { - team.setCollisionRule(collisionRule); - } + team.setCollisionRule(collisionRule); team.setColor(color); team.setFriendlyFire(friendlyFire); team.setPlayers(players); @@ -2558,7 +2498,7 @@ private static Team createPacketTeamRemove(String name) { return team; } - private static Team createPacketTeamUpdate(String name, String displayName, String prefix, String suffix, String nameTagVisibility, String collisionRule, int color, byte friendlyFire) { + private static Team createPacketTeamUpdate(String name, Either displayName, Either prefix, Either suffix, String nameTagVisibility, String collisionRule, int color, byte friendlyFire) { Team team = new Team(); team.setName(name); team.setMode((byte) 2); @@ -2566,9 +2506,7 @@ private static Team createPacketTeamUpdate(String name, String displayName, Stri team.setPrefix(prefix); team.setSuffix(suffix); team.setNameTagVisibility(nameTagVisibility); - if (TEAM_COLLISION_RULE_SUPPORTED) { - team.setCollisionRule(collisionRule); - } + team.setCollisionRule(collisionRule); team.setColor(color); team.setFriendlyFire(friendlyFire); return team; @@ -2601,7 +2539,7 @@ static class PlayerListEntry { private UUID uuid; private String[][] properties; private String username; - private String displayName; + private BaseComponent displayName; private int ping; private int gamemode; @@ -2613,9 +2551,9 @@ private PlayerListEntry(PlayerListItem.Item item) { @Data static class TeamEntry { - private String displayName; - private String prefix; - private String suffix; + private Either displayName; + private Either prefix; + private Either suffix; private byte friendlyFire; private String nameTagVisibility; private String collisionRule; diff --git a/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/NewTabOverlayHandler.java b/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/NewTabOverlayHandler.java index 50fea221..82c296ad 100644 --- a/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/NewTabOverlayHandler.java +++ b/bungee/src/main/java/codecrafter47/bungeetablistplus/handler/NewTabOverlayHandler.java @@ -34,9 +34,13 @@ import it.unimi.dsi.fastutil.objects.*; import lombok.*; import net.md_5.bungee.UserConnection; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.Either; import net.md_5.bungee.protocol.Protocol; import net.md_5.bungee.protocol.packet.*; @@ -58,7 +62,8 @@ public class NewTabOverlayHandler implements PacketHandler, TabOverlayHandler { private static final boolean OPTION_ENABLE_CUSTOM_SLOT_USERNAME_COLLISION_CHECK = true; private static final boolean OPTION_ENABLE_CUSTOM_SLOT_UUID_COLLISION_CHECK = true; - private static final String EMPTY_JSON_TEXT = "{\"text\":\"\"}"; + private static final BaseComponent EMPTY_TEXT_COMPONENT = new TextComponent(); + private static final Either EMPTY_EITHER_TEXT_COMPONENT = Either.right(new TextComponent()); protected static final String[][] EMPTY_PROPERTIES_ARRAY = new String[0][]; private static final ImmutableMap DIMENSION_TO_USED_SLOTS; @@ -149,9 +154,9 @@ public class NewTabOverlayHandler implements PacketHandler, TabOverlayHandler { private final Object2BooleanMap serverPlayerListListed = new Object2BooleanOpenHashMap<>(); @Nullable - protected String serverHeader = null; + protected BaseComponent serverHeader = null; @Nullable - protected String serverFooter = null; + protected BaseComponent serverFooter = null; private final Queue> nextActiveContentHandlerQueue = new ConcurrentLinkedQueue<>(); private final Queue> nextActiveHeaderFooterHandlerQueue = new ConcurrentLinkedQueue<>(); @@ -205,6 +210,12 @@ public PacketListenerResult onPlayerListPacket(PlayerListItem packet) { @Override public PacketListenerResult onPlayerListUpdatePacket(PlayerListItemUpdate packet) { + + if (!active) { + active = true; + scheduleUpdate(); + } + if (packet.getActions().contains(PlayerListItemUpdate.Action.ADD_PLAYER)) { for (PlayerListItem.Item item : packet.getItems()) { if (OPTION_ENABLE_CUSTOM_SLOT_UUID_COLLISION_CHECK) { @@ -263,8 +274,8 @@ public PacketListenerResult onPlayerListHeaderFooterPacket(PlayerListHeaderFoote enterHeaderAndFooterOperationMode(HeaderAndFooterOperationMode.PASS_TROUGH); } - this.serverHeader = packet.getHeader() != null ? packet.getHeader() : EMPTY_JSON_TEXT; - this.serverFooter = packet.getFooter() != null ? packet.getFooter() : EMPTY_JSON_TEXT; + this.serverHeader = packet.getHeader() != null ? packet.getHeader() : EMPTY_TEXT_COMPONENT; + this.serverFooter = packet.getFooter() != null ? packet.getFooter() : EMPTY_TEXT_COMPONENT; return result; } @@ -293,11 +304,13 @@ public void onServerSwitch(boolean is13OrLater) { serverPlayerListListed.clear(); if (serverHeader != null) { - serverHeader = EMPTY_JSON_TEXT; + serverHeader = EMPTY_TEXT_COMPONENT; } if (serverFooter != null) { - serverFooter = EMPTY_JSON_TEXT; + serverFooter = EMPTY_TEXT_COMPONENT; } + + active = false; } @Override @@ -345,7 +358,7 @@ private void update() { updateScheduledFlag.set(false); ChannelWrapper ch = ((UserConnection) player).getCh(); - if (ch.isClosed() || ch.getEncodeProtocol() != Protocol.GAME) { + if (!active || ch.isClosed() || ch.getEncodeProtocol() != Protocol.GAME) { return; } @@ -503,7 +516,7 @@ PacketListenerResult onPlayerListUpdatePacket(PlayerListItemUpdate packet) { @Override void onServerSwitch() { - sendPacket(new PlayerListHeaderFooter(EMPTY_JSON_TEXT, EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(EMPTY_TEXT_COMPONENT, EMPTY_TEXT_COMPONENT)); } @Override @@ -558,7 +571,7 @@ PacketListenerResult onPlayerListHeaderFooterPacket(PlayerListHeaderFooter packe @Override void onServerSwitch() { - sendPacket(new PlayerListHeaderFooter(EMPTY_JSON_TEXT, EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(EMPTY_TEXT_COMPONENT, EMPTY_TEXT_COMPONENT)); } @Override @@ -579,7 +592,7 @@ void onActivated(AbstractHeaderFooterOperationModeHandler previous) { } // fix header/ footer - sendPacket(new PlayerListHeaderFooter(serverHeader != null ? serverHeader : EMPTY_JSON_TEXT, serverFooter != null ? serverFooter : EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(serverHeader != null ? serverHeader : EMPTY_TEXT_COMPONENT, serverFooter != null ? serverFooter : EMPTY_TEXT_COMPONENT)); } } @@ -643,7 +656,9 @@ private String getCustomSlotUsername(int index) { @Override void onServerSwitch() { - // do nothing + if (player.getPendingConnection().getVersion() >= 764) { + clearCustomSlots(); + } } @Override @@ -673,17 +688,22 @@ private void createTeamsIfNecessary() { hasCreatedCustomTeams = true; for (int i = 0; i < 80; i++) { - sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[i], EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, EMPTY_JSON_TEXT, "always", "always", 21, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[i], CUSTOM_SLOT_USERNAME_SMILEYS[i]})); + sendPacket(createPacketTeamCreate(CUSTOM_SLOT_TEAMNAME[i], EMPTY_EITHER_TEXT_COMPONENT, EMPTY_EITHER_TEXT_COMPONENT, EMPTY_EITHER_TEXT_COMPONENT, "always", "always", 21, (byte) 1, new String[]{CUSTOM_SLOT_USERNAME[i], CUSTOM_SLOT_USERNAME_SMILEYS[i]})); } } } @Override void onDeactivated() { + clearCustomSlots(); + } + + private void clearCustomSlots() { int customSlots = 0; for (int index = 0; index < 80; index++) { if (slotState[index] != SlotState.UNUSED) { customSlots++; + dirtySlots.set(index); } } @@ -818,7 +838,7 @@ private boolean isExperimentalTabCompleteSmileys() { private abstract class CustomContentTabOverlay extends AbstractContentTabOverlay implements TabOverlayHandle.BatchModifiable { final Icon[] icon; - final String[] text; + final BaseComponent[] text; final int[] ping; final AtomicInteger batchUpdateRecursionLevel; @@ -830,8 +850,8 @@ private abstract class CustomContentTabOverlay extends AbstractContentTabOverlay private CustomContentTabOverlay() { this.icon = new Icon[80]; Arrays.fill(this.icon, Icon.DEFAULT_STEVE); - this.text = new String[80]; - Arrays.fill(this.text, EMPTY_JSON_TEXT); + this.text = new BaseComponent[80]; + Arrays.fill(this.text, EMPTY_TEXT_COMPONENT); this.ping = new int[80]; this.batchUpdateRecursionLevel = new AtomicInteger(0); this.dirtyFlagSize = true; @@ -877,8 +897,9 @@ void setIconInternal(int index, @Nonnull @NonNull Icon icon) { void setTextInternal(int index, @Nonnull @NonNull String text) { String jsonText = ChatFormat.formattedTextToJson(text); - if (!jsonText.equals(this.text[index])) { - this.text[index] = jsonText; + BaseComponent component = ComponentSerializer.deserialize(jsonText); + if (!component.equals(this.text[index])) { + this.text[index] = component; dirtyFlagsText.set(index); scheduleUpdateIfNotInBatch(); } @@ -945,7 +966,7 @@ public void setSize(@Nonnull Dimension size) { for (int index = newUsedSlots.nextSetBit(0); index >= 0; index = newUsedSlots.nextSetBit(index + 1)) { if (!oldUsedSlots.get(index)) { icon[index] = Icon.DEFAULT_STEVE; - text[index] = EMPTY_JSON_TEXT; + text[index] = EMPTY_TEXT_COMPONENT; ping[index] = 0; } } @@ -955,7 +976,7 @@ public void setSize(@Nonnull Dimension size) { for (int index = oldUsedSlots.nextSetBit(0); index >= 0; index = oldUsedSlots.nextSetBit(index + 1)) { if (!newUsedSlots.get(index)) { icon[index] = Icon.DEFAULT_STEVE; - text[index] = EMPTY_JSON_TEXT; + text[index] = EMPTY_TEXT_COMPONENT; ping[index] = 0; } } @@ -1147,7 +1168,7 @@ void onDeactivated() { @Override void onActivated(AbstractHeaderFooterOperationModeHandler previous) { // remove header/ footer - sendPacket(new PlayerListHeaderFooter(EMPTY_JSON_TEXT, EMPTY_JSON_TEXT)); + sendPacket(new PlayerListHeaderFooter(EMPTY_TEXT_COMPONENT, EMPTY_TEXT_COMPONENT)); } @Override @@ -1161,8 +1182,8 @@ void update() { } private final class CustomHeaderAndFooterImpl extends AbstractHeaderFooterTabOverlay implements HeaderAndFooterHandle { - private String header = EMPTY_JSON_TEXT; - private String footer = EMPTY_JSON_TEXT; + private BaseComponent header = EMPTY_TEXT_COMPONENT; + private BaseComponent footer = EMPTY_TEXT_COMPONENT; private volatile boolean headerOrFooterDirty = false; @@ -1197,22 +1218,22 @@ void scheduleUpdateIfNotInBatch() { @Override public void setHeaderFooter(@Nullable String header, @Nullable String footer) { - this.header = ChatFormat.formattedTextToJson(header); - this.footer = ChatFormat.formattedTextToJson(footer); + this.header = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(header)); + this.footer = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(footer)); headerOrFooterDirty = true; scheduleUpdateIfNotInBatch(); } @Override public void setHeader(@Nullable String header) { - this.header = ChatFormat.formattedTextToJson(header); + this.header = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(header)); headerOrFooterDirty = true; scheduleUpdateIfNotInBatch(); } @Override public void setFooter(@Nullable String footer) { - this.footer = ChatFormat.formattedTextToJson(footer); + this.footer = ComponentSerializer.deserialize(ChatFormat.formattedTextToJson(footer)); headerOrFooterDirty = true; scheduleUpdateIfNotInBatch(); } @@ -1232,7 +1253,7 @@ private static String[][] toPropertiesArray(ProfileProperty textureProperty) { } } - private static Team createPacketTeamCreate(String name, String displayName, String prefix, String suffix, String nameTagVisibility, String collisionRule, int color, byte friendlyFire, String[] players) { + private static Team createPacketTeamCreate(String name, Either displayName, Either prefix, Either suffix, String nameTagVisibility, String collisionRule, int color, byte friendlyFire, String[] players) { Team team = new Team(); team.setName(name); team.setMode((byte) 0);