|  | 
| 22 | 22 | package com.cryptomorin.xseries.messages; | 
| 23 | 23 | 
 | 
| 24 | 24 | import com.cryptomorin.xseries.ReflectionUtils; | 
| 25 |  | -import com.google.common.base.Strings; | 
| 26 |  | -import org.apache.commons.lang.StringUtils; | 
| 27 |  | -import org.bukkit.ChatColor; | 
| 28 | 25 | import org.bukkit.configuration.ConfigurationSection; | 
| 29 | 26 | import org.bukkit.entity.Player; | 
| 30 | 27 | 
 | 
|  | 
| 48 | 45 |  * PacketPlayOutTitle: https://wiki.vg/Protocol#Title | 
| 49 | 46 |  * | 
| 50 | 47 |  * @author Crypto Morin | 
| 51 |  | - * @version 2.0.0.1 | 
|  | 48 | + * @version 2.0.1 | 
| 52 | 49 |  * @see ReflectionUtils | 
| 53 | 50 |  */ | 
| 54 | 51 | public final class Titles { | 
| @@ -233,54 +230,58 @@ public static void clearTitle(@Nonnull Player player) { | 
| 233 | 230 |     /** | 
| 234 | 231 |      * Changes the tablist header and footer message for a player. | 
| 235 | 232 |      * This is not fully completed as it's not used a lot. | 
|  | 233 | +     * <p> | 
|  | 234 | +     * Headers and footers cannot be null because the client will simply | 
|  | 235 | +     * ignore the packet. | 
| 236 | 236 |      * | 
| 237 |  | -     * @param player the player to change the tablist for. | 
| 238 |  | -     * @param header the header of the tablist. | 
| 239 |  | -     * @param footer the footer of the tablist. | 
|  | 237 | +     * @param header  the header of the tablist. | 
|  | 238 | +     * @param footer  the footer of the tablist. | 
|  | 239 | +     * @param players players to send this change to. | 
| 240 | 240 |      * | 
|  | 241 | +     * @return the packet. | 
| 241 | 242 |      * @since 1.0.0 | 
| 242 | 243 |      */ | 
| 243 |  | -    public static void sendTabList(@Nonnull Player player, @Nullable String header, @Nullable String footer) { | 
| 244 |  | -        Objects.requireNonNull(player, "Cannot update tab for null player"); | 
| 245 |  | -        header = Strings.isNullOrEmpty(header) ? | 
| 246 |  | -                "" : StringUtils.replace(ChatColor.translateAlternateColorCodes('&', header), "%player%", player.getDisplayName()); | 
| 247 |  | -        footer = Strings.isNullOrEmpty(footer) ? | 
| 248 |  | -                "" : StringUtils.replace(ChatColor.translateAlternateColorCodes('&', footer), "%player%", player.getDisplayName()); | 
|  | 244 | +    @Nonnull | 
|  | 245 | +    public static Object sendTabList(@Nonnull String header, @Nonnull String footer, Player... players) { | 
|  | 246 | +        Objects.requireNonNull(players, "Cannot send tab title to null players"); | 
|  | 247 | +        Objects.requireNonNull(header, "Tab title header cannot be null"); | 
|  | 248 | +        Objects.requireNonNull(footer, "Tab title footer cannot be null"); | 
| 249 | 249 | 
 | 
| 250 | 250 |         try { | 
| 251 | 251 |             Class<?> IChatBaseComponent = ReflectionUtils.getNMSClass("network.chat", "IChatBaseComponent"); | 
| 252 |  | -            Class<?> packetClass = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutPlayerListHeaderFooter"); | 
|  | 252 | +            Class<?> PacketPlayOutPlayerListHeaderFooter = ReflectionUtils.getNMSClass("network.protocol.game", "PacketPlayOutPlayerListHeaderFooter"); | 
| 253 | 253 | 
 | 
| 254 | 254 |             Method chatComponentBuilderMethod = IChatBaseComponent.getDeclaredClasses()[0].getMethod("a", String.class); | 
| 255 | 255 |             Object tabHeader = chatComponentBuilderMethod.invoke(null, "{\"text\":\"" + header + "\"}"); | 
| 256 | 256 |             Object tabFooter = chatComponentBuilderMethod.invoke(null, "{\"text\":\"" + footer + "\"}"); | 
| 257 | 257 | 
 | 
| 258 | 258 |             Object packet; | 
| 259 | 259 |             if (ReflectionUtils.supports(17)) { | 
| 260 |  | -                packet = packetClass.getConstructor(IChatBaseComponent, IChatBaseComponent).newInstance(tabHeader, tabFooter); | 
|  | 260 | +                packet = PacketPlayOutPlayerListHeaderFooter.getConstructor(IChatBaseComponent, IChatBaseComponent).newInstance(tabHeader, tabFooter); | 
| 261 | 261 |             } else { | 
| 262 |  | -                packet = packetClass.getConstructor().newInstance(); | 
|  | 262 | +                packet = PacketPlayOutPlayerListHeaderFooter.getConstructor().newInstance(); | 
| 263 | 263 | 
 | 
| 264 | 264 |                 Field aField; | 
| 265 | 265 |                 Field bField; | 
| 266 | 266 |                 try { | 
| 267 |  | -                    aField = packet.getClass().getDeclaredField("a"); | 
| 268 |  | -                    bField = packet.getClass().getDeclaredField("b"); | 
|  | 267 | +                    aField = PacketPlayOutPlayerListHeaderFooter.getDeclaredField("a"); | 
|  | 268 | +                    bField = PacketPlayOutPlayerListHeaderFooter.getDeclaredField("b"); | 
| 269 | 269 |                 } catch (Exception ex) { | 
| 270 |  | -                    aField = packet.getClass().getDeclaredField("header"); | 
| 271 |  | -                    bField = packet.getClass().getDeclaredField("footer"); | 
|  | 270 | +                    aField = PacketPlayOutPlayerListHeaderFooter.getDeclaredField("header"); | 
|  | 271 | +                    bField = PacketPlayOutPlayerListHeaderFooter.getDeclaredField("footer"); | 
| 272 | 272 |                 } | 
| 273 | 273 | 
 | 
| 274 | 274 |                 aField.setAccessible(true); | 
| 275 | 275 |                 aField.set(packet, tabHeader); | 
| 276 | 276 | 
 | 
| 277 | 277 |                 bField.setAccessible(true); | 
| 278 | 278 |                 bField.set(packet, tabFooter); | 
| 279 |  | - | 
| 280 | 279 |             } | 
| 281 |  | -            ReflectionUtils.sendPacket(player, packet); | 
|  | 280 | + | 
|  | 281 | +            for (Player player : players) ReflectionUtils.sendPacket(player, packet); | 
|  | 282 | +            return packet; | 
| 282 | 283 |         } catch (Exception ex) { | 
| 283 |  | -            ex.printStackTrace(); | 
|  | 284 | +            throw new RuntimeException(ex); | 
| 284 | 285 |         } | 
| 285 | 286 |     } | 
| 286 | 287 | } | 
0 commit comments