Ive seen so many plugins using this APIs and it makes their plugins looks ugly, no player wants to download a developers plugin that has an API. Unless the plugin is really is awesome. So Im posting a class that everyone should have, this is for Tittles, ActionBar, & Tab. No more of does ugly nasty 3rd party APIs are needed! Code (Text): package net.thevoidmc.ula.Utils; import net.minecraft.server.v1_8_R3.*; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import java.lang.reflect.Field; /** * Created by Ula on 4/24/16. */ public class PacketUtils { public static void sendTitle(Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut) { CraftPlayer craftplayer = (CraftPlayer) player; PlayerConnection connection = craftplayer.getHandle().playerConnection; IChatBaseComponent titleJSON = IChatBaseComponent.ChatSerializer.a("{'text': '" + title + "'}"); IChatBaseComponent subtitleJSON = IChatBaseComponent.ChatSerializer.a("{'text': '" + subtitle + "'}"); PacketPlayOutTitle titlePacket = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.TITLE, titleJSON, fadeIn, stay, fadeOut); PacketPlayOutTitle subtitlePacket = new PacketPlayOutTitle(PacketPlayOutTitle.EnumTitleAction.SUBTITLE, subtitleJSON); connection.sendPacket(titlePacket); connection.sendPacket(subtitlePacket); } public static void sendTabHF(Player player, String header, String footer){ CraftPlayer craftplayer = (CraftPlayer) player; PlayerConnection connection = craftplayer.getHandle().playerConnection; IChatBaseComponent headerJSON = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + header + "\"}"); IChatBaseComponent footerJSON = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + footer + "\"}"); PacketPlayOutPlayerListHeaderFooter packet = new PacketPlayOutPlayerListHeaderFooter(); try { Field headerField = packet.getClass().getDeclaredField("a"); headerField.setAccessible(true); headerField.set(packet, headerJSON); headerField.setAccessible(!headerField.isAccessible()); Field footerField = packet.getClass().getDeclaredField("b"); footerField.setAccessible(true); footerField.set(packet, footerJSON); footerField.setAccessible(!footerField.isAccessible()); } catch (Exception e) { e.printStackTrace(); } connection.sendPacket(packet); } public static void sendActionBar(Player p, String message){ IChatBaseComponent cbc = IChatBaseComponent.ChatSerializer.a("{\"text\": \"" + message + "\"}"); PacketPlayOutChat ppoc = new PacketPlayOutChat(cbc,(byte) 2); ((CraftPlayer) p).getHandle().playerConnection.sendPacket(ppoc); } } Their might be a few people asking how to use it, So here is an Example of how to use with title, its common sense with the others . Code (Text): //PacketUtils.sendTitle(player, Tittle, SubTittle,Fade In, Stay, Fade Out); PacketUtils.sendTitle(p,"OOPS!","Looks like you dont have permission!",10, 60, 10);
I'd tip you with Reflection aswell. Create two parts. One which is much easier, and one which is harder with reflection.
!! NMS && REFLECTION !! Made a class for you which will persist through updates and such. Spoiler: Class Code (Java): public static final class Packets { private Class<?> craftPlayer; private Method craftHandle; private Class<?> iChat; private Class<?> chatSer; private Method chatSerA; private Class<?> packetClass; public static String getServerVersion () { return Bukkit.getServer ().getClass ().getPackage ().getName ().substring (23); } public static Class<?> getNMS(String name) throws Exception { return Class.forName ("net.minecraft.server." + getServerVersion () + "." + name); } public Packets () { try { craftPlayer = Class.forName("org.bukkit.craftbukkit." + getServerVersion () + ".entity.CraftPlayer"); craftHandle = craftPlayer.getMethod ("getHandle"); iChat = getNMS ("IChatBaseComponent"); chatSer = iChat.getDeclaredClasses ()[0]; chatSerA = chatSer.getMethod("a", String.class); packetClass = getNMS("Packet"); } catch (Exception e) { e.printStackTrace (); } } public Object getCraftPlayer(Player player) { try { return craftHandle.invoke (player); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace (); } return null; } public Object getConnection(Object craftPlayer) { try { return craftPlayer.getClass ().getField ("playerConnection"); } catch (NoSuchFieldException e) { e.printStackTrace (); } return null; } public void sendTitle(Player player, String title, String subtitle, int fadeIn, int stay, int fadeOut) { try { Object craftPlayer = getCraftPlayer (player); Object connection = getConnection (craftPlayer); Object titl = chatSerA.invoke (title); Object subt = chatSerA.invoke (subtitle); Class<?> titlePacket = getNMS ("PacketPlayOutTitle"); Constructor<?> titlC = ReflectionUtils.getConstructor (titlePacket, titlePacket.getDeclaredClasses ()[0], iChat, int.class, int.class, int.class); Constructor<?> subtC = ReflectionUtils.getConstructor (titlePacket, titlePacket.getDeclaredClasses()[0], iChat); Object send1 = titlC.newInstance (titlePacket.getDeclaredClasses ()[0].getEnumConstants ()[0], titl, fadeIn, stay, fadeOut); Object send2 = subtC.newInstance (titlePacket.getDeclaredClasses ()[0].getEnumConstants ()[1], subt); Method send = connection.getClass ().getMethod ("sendPacket", packetClass); send.invoke (connection, send1); send.invoke (connection, send2); } catch (Exception e) { e.printStackTrace (); } } public void sendTabHF(Player player, String header, String footer) { Object craftPlayer = getCraftPlayer (player); Object connection = getConnection (craftPlayer); try { Object headerJSON = chatSerA.invoke (header); Object footerJSON = chatSerA.invoke(footer); Object packet = getNMS ("PacketPlayOutPlayerListHeaderFooter").getConstructor ().newInstance (); Field headerField = packet.getClass ().getDeclaredField("a"); headerField.setAccessible(true); headerField.set(packet, headerJSON); headerField.setAccessible(!headerField.isAccessible()); Field footerField = packet.getClass().getDeclaredField("b"); footerField.setAccessible(true); footerField.set(packet, footerJSON); footerField.setAccessible(!footerField.isAccessible()); connection.getClass ().getMethod ("sendPacket", packetClass).invoke (player, packet); }catch (Exception e) { e.printStackTrace (); } } public void sendActionBar(Player player, String message) { Object craftPlayer = getCraftPlayer (player); Object connection = getConnection (craftPlayer); try { Class<?> packet = getNMS ("PacketPlayOutChat"); connection.getClass ().getMethod ("sendPacket", packetClass).invoke (player, packet.getConstructor (iChat, byte.class).newInstance (chatSerA.invoke ("{\"text\": \"" + message + "\"}"), (byte)2)); } catch (Exception e) { e.printStackTrace (); } } }
Why make it harder... Literally just copy and paste that. Import ur version and ur done, that works with 1.8+1.9. Thanks for the tip doe!
Nop Yours work with the one that they build against, and REQUIRES spigot/craftbukkit jar, and not the spigotapi/bukkit jar. So, if they build it with the packages net.minecraft.server.V1_9_2R01, it will only work with that. 1.9.2R02 won't work with the plugin. Mine will.