In one of the recent updates they changed the action bar code for creating the packet. They added an enum which is replacing the byte (nicer code), because of this (and I needed an actionbar) I coded a reflection util that is multi version. I'm not sure if I got the versions right (I don't know when they switched it) so if anyone finds anything wrong with that, pls comment so I may change the code. Here it is (It has one method): Code (Move your mouse to reveal the content) Code (open) Code (close) Code: import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; public class ActionBar { private static final String _VERSION; private static Class<?> _CRAFTPLAYER_CLASS; private static Constructor<?> _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR; private static Method _A_METHOD, _GETHANDLE_METHOD, _SEND_PACKET_METHOD; private static Field _PLAYER_CONNECTION_FIELD; private static Object _GAME_INFO_CONSTANT; static { String name = Bukkit.getServer().getClass().getName(); name = name.substring(name.indexOf("craftbukkit.") + "craftbukkit.".length()); _VERSION = name.substring(0, name.indexOf(".")); try { Class<?> _ICHAT_BASE_COMPONENT_CLASS = Class .forName("net.minecraft.server." + _VERSION + ".IChatBaseComponent"); Class<?> _PACKET_PLAY_OUT_CHAT_CLASS = Class .forName("net.minecraft.server." + _VERSION + ".PacketPlayOutChat"); _CRAFTPLAYER_CLASS = Class.forName("org.bukkit.craftbukkit." + _VERSION + ".entity.CraftPlayer"); Class<?> _ENTITYPLAYER_CLASS = Class.forName("net.minecraft.server." + _VERSION + ".EntityPlayer"); Class<?> _PLAYER_CONNECTION_CLASS = Class.forName("net.minecraft.server." + _VERSION + ".PlayerConnection"); if (_VERSION.contains("1.9")) { _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR = _PACKET_PLAY_OUT_CHAT_CLASS .getConstructor(_ICHAT_BASE_COMPONENT_CLASS, byte.class); } else { Class<?> _CHAT_MESSAGE_TYPE_ENUM = Class .forName("net.minecraft.server." + _VERSION + ".ChatMessageType"); _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR = _PACKET_PLAY_OUT_CHAT_CLASS .getConstructor(_ICHAT_BASE_COMPONENT_CLASS, _CHAT_MESSAGE_TYPE_ENUM); for (Object obj : _CHAT_MESSAGE_TYPE_ENUM.getEnumConstants()) { if (obj.toString().equals("GAME_INFO")) { _GAME_INFO_CONSTANT = obj; } } } _A_METHOD = Class.forName("net.minecraft.server." + _VERSION + ".IChatBaseComponent$ChatSerializer") .getMethod("a", String.class); _GETHANDLE_METHOD = _CRAFTPLAYER_CLASS.getMethod("getHandle"); _SEND_PACKET_METHOD = _PLAYER_CONNECTION_CLASS.getMethod("sendPacket", Class.forName("net.minecraft.server." + _VERSION + ".Packet")); _PLAYER_CONNECTION_FIELD = _ENTITYPLAYER_CLASS.getDeclaredField("playerConnection"); } catch (Exception ex) { ex.printStackTrace(); } } public static void send(Player player, String message) { try { Object messageComponent = _A_METHOD.invoke(null, "{\"text\": \"" + ChatColor.translateAlternateColorCodes('&', message) + "\"}"); if (_VERSION.contains("1.9")) { Object packet = _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR.newInstance(messageComponent, (byte) 2); Object craftPlayer = _CRAFTPLAYER_CLASS.cast(player); Object entityPlayer = _GETHANDLE_METHOD.invoke(craftPlayer); Object playerConnection = _PLAYER_CONNECTION_FIELD.get(entityPlayer); _SEND_PACKET_METHOD.invoke(playerConnection, packet); } else { Object packet = _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR.newInstance(messageComponent, _GAME_INFO_CONSTANT); Object craftPlayer = _CRAFTPLAYER_CLASS.cast(player); Object entityPlayer = _GETHANDLE_METHOD.invoke(craftPlayer); Object playerConnection = _PLAYER_CONNECTION_FIELD.get(entityPlayer); _SEND_PACKET_METHOD.invoke(playerConnection, packet); } } catch (Exception ex) { ex.printStackTrace(); } } } I've tested it for 1.12.2 and it works.
@PhantomUnicorns Nice util. However, the send message could be refined to reduce the amount of repeated lines by only having the thing that changes (the packet instnace) inside of the version check like so: Code: public static void send(Player player, String message) { try { Object messageComponent = _A_METHOD.invoke(null, "{\"text\": \"" + ChatColor.translateAlternateColorCodes('&', message) + "\"}"); Object packet; if (_VERSION.contains("1.9")) packet = _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR.newInstance(messageComponent, (byte) 2); else packet = _PACKET_PLAY_OUT_CHAT_CONSTRUCTOR.newInstance(messageComponent, _GAME_INFO_CONSTANT); Object craftPlayer = _CRAFTPLAYER_CLASS.cast(player); Object entityPlayer = _GETHANDLE_METHOD.invoke(craftPlayer); Object playerConnection = _PLAYER_CONNECTION_FIELD.get(entityPlayer); _SEND_PACKET_METHOD.invoke(playerConnection, packet); } catch (Exception ex) { ex.printStackTrace(); } } (If you wanted, you could also add the version check within the parameters of the newInstance, but I feel that makes it a bit more unreadable.)
Yeah I thought of that but I didn't want a if just in the middle so I decided to base it on two ifs (the if and the else)