diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce8f19d1..694625d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [8, 9, 10, 11, 12, 13, 14, 15] + java: [8, 11, 16, 17] steps: - uses: actions/checkout@v2 - name: Set up JDK 1.8 diff --git a/pom.xml b/pom.xml index ad2b52c7..65b5ce30 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ fr.zcraft quartz - 0.0.1 + 0.0.5 pom @@ -50,6 +50,6 @@ quartzlib - ztoaster + diff --git a/quartzlib/pom.xml b/quartzlib/pom.xml index 9963e047..3777c308 100644 --- a/quartzlib/pom.xml +++ b/quartzlib/pom.xml @@ -15,7 +15,7 @@ 1.8 1.8 4.13.1 - 0.0.1-SNAPSHOT + 0.0.5-SNAPSHOT diff --git a/src/main/java/fr/zcraft/quartzlib/components/gui/PromptGui.java b/src/main/java/fr/zcraft/quartzlib/components/gui/PromptGui.java index a28e8a0e..c7f57ba4 100644 --- a/src/main/java/fr/zcraft/quartzlib/components/gui/PromptGui.java +++ b/src/main/java/fr/zcraft/quartzlib/components/gui/PromptGui.java @@ -63,6 +63,7 @@ public class PromptGui extends GuiBase { private Location signLocation; private String contents; + public PromptGui(Callback callback, String contents) { this(callback); this.contents = contents; @@ -70,10 +71,12 @@ public PromptGui(Callback callback, String contents) { /** * Creates a new prompt GUI, using the given callback. + * * @param callback The callback to be given the input text to. */ public PromptGui(Callback callback) { super(); + if (!isAvailable()) { throw new IllegalStateException("Sign-based prompt GUI are not available"); } @@ -81,14 +84,17 @@ public PromptGui(Callback callback) { this.callback = callback; } + /** * Checks if Prompt GUIs can be correctly used on this Minecraft versions. */ public static boolean isAvailable() { + if (!isInitialized) { init(); } return fieldTileEntitySign != null; + } public static void prompt(Player owner, Callback callback) { @@ -103,32 +109,54 @@ private static void init() { isInitialized = true; try { - final Class CraftBlockEntityState = Reflection.getBukkitClassByName("block.CraftBlockEntityState"); - final Class CraftSign = Reflection.getBukkitClassByName("block.CraftSign"); - final Class classTileEntitySign = Reflection.getMinecraftClassByName("TileEntitySign"); + final Class CraftBlockEntityState = + Reflection.getBukkitClassByName("block.CraftBlockEntityState"); + final Class classTileEntitySign + = Reflection.getMinecraft1_17ClassByName("world.level.block.entity.TileEntitySign"); final Class CraftPlayer = Reflection.getBukkitClassByName("entity.CraftPlayer"); - final Class EntityHuman = Reflection.getMinecraftClassByName("EntityHuman"); - + final Class EntityHuman = Reflection.getMinecraft1_17ClassByName("world.entity.player.EntityHuman"); + fieldTileEntitySign = Reflection.getField(CraftBlockEntityState, "tileEntity"); + fieldTileEntitySignEditable = Reflection.getField(classTileEntitySign, "f");//isEditable new name + methodGetHandle = CraftPlayer.getDeclaredMethod("getHandle"); try { - fieldTileEntitySign = Reflection.getField(CraftSign, "sign"); - } catch (NoSuchFieldException e) { // 1.12+ - fieldTileEntitySign = Reflection.getField(CraftBlockEntityState, "tileEntity"); + //1.18+ + methodOpenSign = EntityHuman.getDeclaredMethod("a", classTileEntitySign); + //doesn't work because despite the name found in the jar, this may be an issue from Mojang with a bad + //mapping. The correct name is a and not openTextEdit. + } catch (Exception e) { + methodOpenSign = EntityHuman.getDeclaredMethod("openSign", classTileEntitySign); } - + } catch (Exception ex) { try { - fieldTileEntitySignEditable = Reflection.getField(classTileEntitySign, "isEditable"); - } catch (NoSuchFieldException e) { // 1.11.2 or below - fieldTileEntitySignEditable = null; - } + final Class CraftBlockEntityState = + Reflection.getBukkitClassByName("block.CraftBlockEntityState"); + final Class CraftSign = Reflection.getBukkitClassByName("block.CraftSign"); + final Class classTileEntitySign = Reflection.getMinecraftClassByName("TileEntitySign"); + final Class CraftPlayer = Reflection.getBukkitClassByName("entity.CraftPlayer"); + final Class EntityHuman = Reflection.getMinecraftClassByName("EntityHuman"); + + try { + fieldTileEntitySign = Reflection.getField(CraftSign, "sign"); + } catch (NoSuchFieldException exc) { // 1.12+ + fieldTileEntitySign = Reflection.getField(CraftBlockEntityState, "tileEntity"); + } - methodGetHandle = CraftPlayer.getDeclaredMethod("getHandle"); - methodOpenSign = EntityHuman.getDeclaredMethod("openSign", classTileEntitySign); - } catch (Exception e) { - PluginLogger.error("Unable to initialize Sign Prompt API", e); - fieldTileEntitySign = null; + try { + fieldTileEntitySignEditable = Reflection.getField(classTileEntitySign, "isEditable"); + } catch (NoSuchFieldException exc) { // 1.11.2 or below + fieldTileEntitySignEditable = null; + } + + methodGetHandle = CraftPlayer.getDeclaredMethod("getHandle"); + methodOpenSign = EntityHuman.getDeclaredMethod("openSign", classTileEntitySign); + } catch (Exception exc) { + PluginLogger.error("Unable to initialize Sign Prompt API", exc); + fieldTileEntitySign = null; + } } } + private static String getSignContents(String[] lines) { StringBuilder content = new StringBuilder(lines[0].trim()); @@ -236,6 +264,7 @@ protected void open(final Player player) { RunTask.later(() -> { try { + final Object signTileEntity = fieldTileEntitySign.get(sign); final Object playerEntity = methodGetHandle.invoke(player); @@ -246,6 +275,7 @@ protected void open(final Player player) { } methodOpenSign.invoke(playerEntity, signTileEntity); + } catch (final Throwable e) { PluginLogger.error("Error while opening Sign prompt", e); } diff --git a/src/main/java/fr/zcraft/quartzlib/components/nbt/NBT.java b/src/main/java/fr/zcraft/quartzlib/components/nbt/NBT.java index 57359ae8..58b86114 100644 --- a/src/main/java/fr/zcraft/quartzlib/components/nbt/NBT.java +++ b/src/main/java/fr/zcraft/quartzlib/components/nbt/NBT.java @@ -30,6 +30,7 @@ package fr.zcraft.quartzlib.components.nbt; +import fr.zcraft.quartzlib.tools.PluginLogger; import fr.zcraft.quartzlib.tools.items.ItemUtils; import fr.zcraft.quartzlib.tools.reflection.NMSException; import fr.zcraft.quartzlib.tools.reflection.Reflection; @@ -176,10 +177,10 @@ public static byte fromItemFlags(Set itemFlags) { * @param item The ItemStack to change. * @param tags The tags to place inside the stack. * @return An item stack with the modification applied. It may (if you given - * a CraftItemStack) or may not (else) be the same instance as the given one. + * a CraftItemStack) or may not (else) be the same instance as the given one. * @throws NMSException if the operation cannot be executed. * @see #addToItemStack(ItemStack, Map, boolean) This method is equivalent - * to this one with replace = true. + * to this one with replace = true. */ public static ItemStack addToItemStack(ItemStack item, Map tags) throws NMSException { return addToItemStack(item, tags, true); @@ -197,7 +198,7 @@ public static ItemStack addToItemStack(ItemStack item, Map tags) * @param replace {@code true} to replace the whole set of tags. If {@code * false}, tags will be added. * @return An item stack with the modification applied. It may (if you given - * a CraftItemStack) or may not (else) be the same instance as the given one. + * a CraftItemStack) or may not (else) be the same instance as the given one. * @throws NMSException if the operation cannot be executed. */ public static ItemStack addToItemStack(final ItemStack item, final Map tags, final boolean replace) @@ -241,11 +242,23 @@ public static ItemStack addToItemStack(final ItemStack item, final Map getMinecraftClass(String className) throws NMSException { + return getMinecraftClass("", className); + } + + static Class getMinecraftClass(String prefix, String className) throws NMSException { try { - return Reflection.getMinecraftClassByName(className); + return Reflection + .getMinecraft1_17ClassByName(prefix.equals("") ? className : prefix + "." + className); //1.17+ } catch (ClassNotFoundException ex) { - throw new NMSException("Unable to find class: " + className, ex); + try { + return Reflection.getMinecraftClassByName(className);//Legacy for older version than 1.17 + } catch (ClassNotFoundException e) { + throw new NMSException("Unable to find class: " + prefix + className, e); + } } } @@ -262,8 +275,8 @@ private static void init() throws NMSException { return; // Already initialized } - MC_ITEM_STACK = getMinecraftClass("ItemStack"); - MC_NBT_TAG_COMPOUND = getMinecraftClass("NBTTagCompound"); + MC_ITEM_STACK = getMinecraftClass("world.item", "ItemStack"); + MC_NBT_TAG_COMPOUND = getMinecraftClass("nbt", "NBTTagCompound"); CB_CRAFT_ITEM_META = getCraftBukkitClass("inventory.CraftMetaItem"); } @@ -279,29 +292,49 @@ private static void init() throws NMSException { * @throws NMSException If something goes wrong while extracting the tag. */ private static Object getMcNBTCompound(ItemStack item) throws NMSException { + Object mcItemStack = ItemUtils.getNMSItemStack(item); if (mcItemStack == null) { return null; } try { - Object tag = Reflection.getFieldValue(MC_ITEM_STACK, mcItemStack, "tag"); - - if (tag == null) { - tag = Reflection.instantiate(MC_NBT_TAG_COMPOUND); + Object tagCompound; + try { + //1.18 + tagCompound = Reflection.call(mcItemStack.getClass(), mcItemStack, "t"); + } catch (Exception e) { + //1.17 + tagCompound = Reflection.call(mcItemStack.getClass(), mcItemStack, "a"); + } - try { - Reflection.call(MC_ITEM_STACK, mcItemStack, "setTag", tag); - } catch (NoSuchMethodException e) { - // If the set method change—more resilient, - // as the setTag will only update the field without any kind of callback. - Reflection.setFieldValue(MC_ITEM_STACK, mcItemStack, "tag", tag); - } + if (tagCompound == null) { + tagCompound = Reflection.instantiate(MC_NBT_TAG_COMPOUND); + Reflection.call(MC_ITEM_STACK, mcItemStack, "setTag", tagCompound); } + return tagCompound; + + } catch (Exception exc) { + //Older method + try { + Object tag = Reflection.getFieldValue(MC_ITEM_STACK, mcItemStack, "tag"); + + if (tag == null) { + tag = Reflection.instantiate(MC_NBT_TAG_COMPOUND); + + try { + Reflection.call(MC_ITEM_STACK, mcItemStack, "setTag", tag); + } catch (NoSuchMethodException e) { + // If the set method change—more resilient, + // as the setTag will only update the field without any kind of callback. + Reflection.setFieldValue(MC_ITEM_STACK, mcItemStack, "tag", tag); + } + } - return tag; - } catch (Exception ex) { - throw new NMSException("Unable to retrieve NBT tag from item", ex); + return tag; + } catch (Exception ex) { + throw new NMSException("Unable to retrieve NBT tag from item", ex); + } } } @@ -316,7 +349,6 @@ static Object fromNativeValue(Object value) { if (value == null) { return null; } - NBTType type = NBTType.fromClass(value.getClass()); return type.newTag(value); } diff --git a/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTCompound.java b/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTCompound.java index 52439be7..bf812bf1 100644 --- a/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTCompound.java +++ b/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTCompound.java @@ -30,6 +30,8 @@ package fr.zcraft.quartzlib.components.nbt; +import fr.zcraft.quartzlib.tools.PluginLogger; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -106,12 +108,12 @@ private Map getNbtMap() { } } } - return nmsNbtMap; } /** * Returns the NMS NBTTagCompound instance. + * * @return The NMS NBTTagCompound instance. */ Object getNbtTagCompound() { @@ -120,15 +122,15 @@ Object getNbtTagCompound() { /** * Returns the value to which the specified key is mapped, - * or the specified default value if this map contains no mapping for the key. + * or the specified default value if this map contains no mapping for the key. * If a value is present, but could not be coerced to the given type, - * it is ignored and the default value is returned instead. + * it is ignored and the default value is returned instead. * * @param The type to coerce the mapped value to. * @param key The key * @param defaultValue The default value. * @return the value to which the specified key is mapped, - * or the specified default value if this map contains no mapping for the key. + * or the specified default value if this map contains no mapping for the key. */ public T get(String key, T defaultValue) { return get(key, defaultValue, defaultValue == null ? null : (Class) defaultValue.getClass()); @@ -136,18 +138,18 @@ public T get(String key, T defaultValue) { /** * Returns the value to which the specified key is mapped, - * or the specified default value if this map contains no mapping for the key. + * or the specified default value if this map contains no mapping for the key. * If a value is present, but could not be coerced to the given type, - * it is ignored and the default value is returned instead. + * it is ignored and the default value is returned instead. * This version of the method is recommended if the defaultValue parameter is null, - * so it can have enough type information to protect against wrong NBT types. + * so it can have enough type information to protect against wrong NBT types. * * @param The type to coerce the mapped value to. * @param key The key * @param defaultValue The default value. * @param valueType The type of the expected value. * @return the value to which the specified key is mapped, - * or the specified default value if this map contains no mapping for the key. + * or the specified default value if this map contains no mapping for the key. */ public T get(String key, T defaultValue, Class valueType) { try { @@ -219,7 +221,36 @@ public boolean containsValue(Object value) { @Override public Object put(String key, Object value) { - return NBT.toNativeValue(getNbtMap().put(key, NBT.fromNativeValue(value))); + try { + switch (NBT.fromNativeValue(value).getClass().getName()) { + case "net.minecraft.nbt.NBTTagInt": + Method method; + try { + // Cannot use Reflection.call here because int is casted as an integer and we need the method + // with an int + method = nmsNbtTag.getClass().getMethod("a", String.class, int.class); + method.invoke(nmsNbtTag, key, value); + } catch (Exception e) { + method = nmsNbtTag.getClass().getMethod("setInt", String.class, int.class); + method.invoke(nmsNbtTag, key, value); + } + + break; + default: + PluginLogger.info("Not supported yet " + NBT.fromNativeValue(value).getClass().getName()); + } + return getNbtMap(); + } catch (Exception e) { + try { + return NBT.toNativeValue(getNbtMap()); + } catch (Exception ex) { + PluginLogger.error("Issue while putting tag. " + ex.toString()); + return null; + } + + + } + } @Override diff --git a/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTType.java b/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTType.java index 9ff59f23..d22a0569 100644 --- a/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTType.java +++ b/src/main/java/fr/zcraft/quartzlib/components/nbt/NBTType.java @@ -30,8 +30,11 @@ package fr.zcraft.quartzlib.components.nbt; +import fr.zcraft.quartzlib.tools.PluginLogger; import fr.zcraft.quartzlib.tools.reflection.Reflection; import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -74,9 +77,14 @@ public static NBTType fromId(byte id) { public static NBTType fromNmsNbtTag(Object nmsNbtTag) { try { - return fromId((byte) Reflection.call(nmsNbtTag, "getTypeId")); + //1.18 + return fromId((byte) Reflection.call(nmsNbtTag, "a")); } catch (Exception ex) { - throw new NBTException("Unable to retrieve type of nbt tag", ex); + try { + return fromId((byte) Reflection.call(nmsNbtTag, "getTypeId")); + } catch (Exception e) { + throw new NBTException("Unable to retrieve type of nbt tag", ex); + } } } @@ -123,6 +131,23 @@ public String getNmsClassName() { return nmsClassName; } + public Class get1_17NmsClass() { + if (nmsClassName == null) { + return null; + } + + try { + if (nmsClass == null) { + nmsClass = Reflection.getMinecraft1_17ClassByName("nbt." + nmsClassName); + } + } catch (Exception ex) { + throw new NBTException("Unable to retrieve NBT tag class", ex); + } + + return nmsClass; + } + + public Class getNmsClass() { if (nmsClassName == null) { return null; @@ -152,7 +177,7 @@ public Object newTag(Object value) { final Object tag; switch (this) { case TAG_COMPOUND: - tag = Reflection.instantiate(getNmsClass()); + tag = Reflection.instantiate(get1_17NmsClass()); if (value instanceof NBTCompound) { setData(tag, ((NBTCompound) value).nmsNbtMap); } else { @@ -161,7 +186,7 @@ public Object newTag(Object value) { break; case TAG_LIST: - tag = Reflection.instantiate(getNmsClass()); + tag = Reflection.instantiate(get1_17NmsClass()); if (value instanceof NBTList) { setData(tag, ((NBTList) value).nmsNbtList); } else { @@ -174,14 +199,47 @@ public Object newTag(Object value) { break; default: - Constructor cons = Reflection.findConstructor(getNmsClass(), 1); + Constructor cons = Reflection.findConstructor(get1_17NmsClass(), 1); cons.setAccessible(true); tag = cons.newInstance(value); } - return tag; - } catch (Exception ex) { - throw new NBTException("Unable to create NBT tag", ex); + } catch (Exception e) { + try { + final Object tag; + switch (this) { + case TAG_COMPOUND: + tag = Reflection.instantiate(getNmsClass()); + if (value instanceof NBTCompound) { + setData(tag, ((NBTCompound) value).nmsNbtMap); + } else { + new NBTCompound(tag).putAll((Map) value); + } + break; + + case TAG_LIST: + tag = Reflection.instantiate(getNmsClass()); + if (value instanceof NBTList) { + setData(tag, ((NBTList) value).nmsNbtList); + } else { + new NBTList(tag).addAll((List) value); + } + + // If a NBTTagList is built from scratch, the NMS object is created lately + // and may not have the list's type registered at this point. + NBTList.guessAndWriteTypeToNbtTagList(tag); + break; + + default: + Constructor cons = Reflection.findConstructor(getNmsClass(), 1); + cons.setAccessible(true); + tag = cons.newInstance(value); + } + + return tag; + } catch (Exception ex) { + throw new NBTException("Unable to create NBT tag", ex); + } } } @@ -190,17 +248,72 @@ public Object getData(Object nmsNbtTag) { return null; } try { + switch (getNmsTagFieldName()) { + case "map": + //Since 1.17 "map" became "tags" + //h() return an unmodifiable map + return Reflection.call(nmsNbtTag.getClass(), nmsNbtTag, "h"); + + case "list": + //We recreate the list because there are no getter for the list. + //TODO check if in 1.18 a getter is added for this one. + List list = new ArrayList(); + + for (int i = 0; i < (int) Reflection.call(nmsNbtTag.getClass(), nmsNbtTag, "size"); i++) { + //Strange thing of java a call cast int into integer resulting in the impossibility + // to call the method + final Method method = nmsNbtTag.getClass().getMethod("get", int.class); + + // Cannot use Reflection.call for the same reason as above. + list.add(method.invoke(nmsNbtTag, i)); + } + return list; + case "data": + PluginLogger.info("To be implemented"); + //TODO I don't know what to do here + break; + default: + break; + } + //Fallback used for data right now don't know if this works return Reflection.getFieldValue(nmsNbtTag, getNmsTagFieldName()); - } catch (Exception ex) { - throw new NBTException("Unable to retrieve NBT tag data", ex); + } catch (Exception exc) { + //Older versions than 1.17 (fields are no longer accessible in java 17) + try { + return Reflection.getFieldValue(nmsNbtTag, getNmsTagFieldName()); + } catch (Exception e) { + try { + return Reflection.getFieldValue(nmsNbtTag, getNmsTagFieldName()); + } catch (Exception ex) { + throw new NBTException("Unable to retrieve NBT tag data", ex); + } + } } + + } public void setData(Object nmsNbtTag, Object value) { try { - Reflection.setFieldValue(nmsNbtTag, getNmsTagFieldName(), value); - } catch (Exception ex) { - throw new NBTException("Unable to set NBT tag data", ex); + switch (getNmsTagFieldName()) { + case "map": + Reflection.call(nmsNbtTag.getClass(), nmsNbtTag, "set", getNmsTagFieldName(), value); + break; + case "list": + Reflection.call(nmsNbtTag.getClass(), nmsNbtTag, "set", getNmsTagFieldName(), value); + break; + case "data": + //TODO I don't know what to do here + default: + break; + } + } catch (Exception e) { + try { + Reflection.setFieldValue(nmsNbtTag, getNmsTagFieldName(), value); + } catch (Exception ex) { + throw new NBTException("Unable to set NBT tag data", ex); + } } + } } diff --git a/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java b/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java index de994007..d13eff84 100644 --- a/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java +++ b/src/main/java/fr/zcraft/quartzlib/tools/items/ItemUtils.java @@ -50,7 +50,6 @@ import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.Potion; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -124,7 +123,7 @@ public static ItemStack consumeItem(Player player, ItemStack item) { * @param player The player to give the item to. * @param item The item to give to the player * @return true if the player received the item in its inventory, false if - * it had to be totally or partially dropped on the ground. + * it had to be totally or partially dropped on the ground. */ public static boolean give(final Player player, final ItemStack item) { final Map leftover = player.getInventory().addItem(item); diff --git a/src/main/java/fr/zcraft/quartzlib/tools/reflection/NMSNetwork.java b/src/main/java/fr/zcraft/quartzlib/tools/reflection/NMSNetwork.java index bc400647..89b1842b 100644 --- a/src/main/java/fr/zcraft/quartzlib/tools/reflection/NMSNetwork.java +++ b/src/main/java/fr/zcraft/quartzlib/tools/reflection/NMSNetwork.java @@ -31,8 +31,10 @@ package fr.zcraft.quartzlib.tools.reflection; import fr.zcraft.quartzlib.exceptions.IncompatibleMinecraftVersionException; +import fr.zcraft.quartzlib.tools.PluginLogger; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import org.bukkit.entity.Player; @@ -48,16 +50,44 @@ public final class NMSNetwork { private static final Method sendPacketMethod; static { + Class craftPlayerClass1 = null; + Class entityPlayerClass1 = null; + Class packetClass1 = null; + Method sendPacketMethod1; + try { - craftPlayerClass = Reflection.getBukkitClassByName("entity.CraftPlayer"); - entityPlayerClass = Reflection.getMinecraftClassByName("EntityPlayer"); - - packetClass = Reflection.getMinecraftClassByName("Packet"); - sendPacketMethod = ((Class) Reflection.getMinecraftClassByName("PlayerConnection")) - .getDeclaredMethod("sendPacket", packetClass); - } catch (ClassNotFoundException | NoSuchMethodException e) { - throw new IncompatibleMinecraftVersionException("Cannot load classes needed to send network packets", e); + //1.18+ + craftPlayerClass1 = Reflection.getBukkitClassByName("entity.CraftPlayer"); + entityPlayerClass1 = Reflection.getMinecraft1_17ClassByName("server.level.EntityPlayer"); + packetClass1 = Reflection.getMinecraft1_17ClassByName("network.protocol.Packet"); + sendPacketMethod1 = ((Class) Reflection.getMinecraft1_17ClassByName("server.network.PlayerConnection")) + .getDeclaredMethod("a", packetClass1); + //Was renamed in 1.18 from sendPacket to send but was renamed lambda$15 in the jar... + } catch (Exception exc) { + try { + sendPacketMethod1 = + ((Class) Reflection.getMinecraft1_17ClassByName("server.network.PlayerConnection")) + .getDeclaredMethod("sendPacket", packetClass1); + + } catch (Exception ex) { + try { + craftPlayerClass1 = Reflection.getBukkitClassByName("entity.CraftPlayer"); + entityPlayerClass1 = Reflection.getMinecraftClassByName("EntityPlayer"); + + packetClass1 = Reflection.getMinecraftClassByName("Packet"); + sendPacketMethod1 = ((Class) Reflection.getMinecraftClassByName("PlayerConnection")) + .getDeclaredMethod("sendPacket", packetClass1); + } catch (ClassNotFoundException | NoSuchMethodException e) { + throw new IncompatibleMinecraftVersionException( + "Cannot load classes needed to send network packets", + e); + } + } } + craftPlayerClass = craftPlayerClass1; + entityPlayerClass = entityPlayerClass1; + packetClass = packetClass1; + sendPacketMethod = sendPacketMethod1; } private NMSNetwork() { @@ -68,7 +98,7 @@ private NMSNetwork() { * * @param player The player. * @return The player's handle (reflection-retrieved object, instance of the - * net.minecraft.server.EntityPlayer class). + * net.minecraft.server.EntityPlayer class). * @throws InvocationTargetException if an exception is thrown while the connection * is retrieved. * @throws IncompatibleMinecraftVersionException if an error occurs while loading the classes, @@ -91,7 +121,7 @@ public static Object getPlayerHandle(Player player) throws InvocationTargetExcep * * @param playerHandle The player's handle, as returned by {@link #getPlayerHandle(Player)}. * @return The player's connection (reflection-retrieved object, instance of the - * net.minecraft.server.PlayerConnection class). + * net.minecraft.server.PlayerConnection class). * @throws InvocationTargetException if an exception is thrown while the connection * is retrieved. * @throws IncompatibleMinecraftVersionException if an error occurs while loading the classes, @@ -99,18 +129,35 @@ public static Object getPlayerHandle(Player player) throws InvocationTargetExcep * connection. */ public static Object getPlayerConnection(Object playerHandle) throws InvocationTargetException { + try { + if (!entityPlayerClass.isAssignableFrom(playerHandle.getClass())) { throw new ClassCastException("Cannot retrieve a player connection from another class that " - + "net.minecraft.server..EntityPlayer (got " + playerHandle.getClass().getName() + ")."); + + "net.minecraft.server..EntityPlayer (got " + playerHandle.getClass().getName() + + ")."); } - return Reflection.getFieldValue(playerHandle, "playerConnection"); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new IncompatibleMinecraftVersionException( - "Cannot retrieve standard Bukkit or NBS object while getting a player's connection, " - + "is the current Bukkit/Minecraft version supported by this API?", e); + return Reflection.getFieldValue(playerHandle, "b");//YES they renamed connection as b, that's not what + // you will find when looking at the decompiled bytecode + + } catch (Exception ex) { + try { + if (!entityPlayerClass.isAssignableFrom(playerHandle.getClass())) { + throw new ClassCastException("Cannot retrieve a player connection from another class that " + + "net.minecraft.server..EntityPlayer (got " + + playerHandle.getClass().getName() + + ")."); + } + + return Reflection.getFieldValue(playerHandle, "playerConnection"); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new IncompatibleMinecraftVersionException( + "Cannot retrieve standard Bukkit or NBS object while getting a player's connection, " + + "is the current Bukkit/Minecraft version supported by this API?", e); + } } + } /** @@ -118,7 +165,7 @@ public static Object getPlayerConnection(Object playerHandle) throws InvocationT * * @param player The player. * @return The player's connection (reflection-retrieved object, instance of the - * net.minecraft.server.PlayerConnection class). + * net.minecraft.server.PlayerConnection class). * @throws InvocationTargetException if an exception is thrown while the connection * is retrieved. * @throws IncompatibleMinecraftVersionException if an error occurs while loading the classes, diff --git a/src/main/java/fr/zcraft/quartzlib/tools/reflection/Reflection.java b/src/main/java/fr/zcraft/quartzlib/tools/reflection/Reflection.java index c9674d37..973ee86c 100644 --- a/src/main/java/fr/zcraft/quartzlib/tools/reflection/Reflection.java +++ b/src/main/java/fr/zcraft/quartzlib/tools/reflection/Reflection.java @@ -30,6 +30,7 @@ package fr.zcraft.quartzlib.tools.reflection; +import fr.zcraft.quartzlib.tools.PluginLogger; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -94,6 +95,18 @@ public static Class getBukkitClassByName(String name) throws ClassNotFoundExc return Class.forName(getBukkitPackageName() + "." + name); } + /** + * Returns the {@link Class} of a NMS class from it's name (without the main NMS package) 1.17+. + *

For example, with "Server", this method returns the {@code net.minecraft.v1_X_RX} class.

+ * + * @param name The NMS' class name (without the main Bukkit package). + * @return The class. + * @throws ClassNotFoundException if no class exists with this name in the NMS package. + */ + public static Class getMinecraft1_17ClassByName(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft" + "." + name); + } + /** * Returns the {@link Class} of a NMS class from it's name (without the main NMS package). *

For example, with "Server", this method returns the {@code net.minecraft.server.v1_X_RX.Server} class.

diff --git a/src/main/java/fr/zcraft/quartzlib/tools/text/MessageSender.java b/src/main/java/fr/zcraft/quartzlib/tools/text/MessageSender.java index 7394a5bc..2658045e 100644 --- a/src/main/java/fr/zcraft/quartzlib/tools/text/MessageSender.java +++ b/src/main/java/fr/zcraft/quartzlib/tools/text/MessageSender.java @@ -57,28 +57,26 @@ public final class MessageSender { static { try { - iChatBaseComponentClass = Reflection.getMinecraftClassByName("IChatBaseComponent"); - packetPlayOutChatClass = Reflection.getMinecraftClassByName("PacketPlayOutChat"); + //1.17+ + iChatBaseComponentClass = Reflection.getMinecraft1_17ClassByName("network.chat.IChatBaseComponent"); + packetPlayOutChatClass = Reflection.getMinecraft1_17ClassByName("network.protocol.game.PacketPlayOutChat"); + + chatSerializerClass = + Reflection.getMinecraft1_17ClassByName("network.chat.IChatBaseComponent$ChatSerializer"); - // TODO centralize the chat serialization mechanisms - try { - chatSerializerClass = Reflection.getMinecraftClassByName("ChatSerializer"); - } catch (ClassNotFoundException e) { - chatSerializerClass = Reflection.getMinecraftClassByName("IChatBaseComponent$ChatSerializer"); - } - // We only support 1.8+ if (!nmsVersion.equalsIgnoreCase("v1_8_R1")) { - chatComponentTextClass = Reflection.getMinecraftClassByName("ChatComponentText"); + chatComponentTextClass = Reflection.getMinecraft1_17ClassByName("network.chat.ChatComponentText"); // This enum was introduced in 1.12; before, a byte was directly used. try { - chatMessageTypeEnum = Reflection.getMinecraftClassByName("ChatMessageType"); + chatMessageTypeEnum = Reflection.getMinecraft1_17ClassByName("network.chat.ChatMessageType"); chatMessageByteToTypeMethod = Reflection.findMethod(chatMessageTypeEnum, "a", byte.class); if (chatMessageByteToTypeMethod == null) { - PluginLogger.error("You are using a version of Minecraft ({0}) incompatible with QuartzLib.", - nmsVersion); + PluginLogger + .error("You are using a version of Minecraft ({0}) incompatible with QuartzLib.", + nmsVersion); PluginLogger.error("The MessageSender component will not work" + "due to a change in Minecraft code."); PluginLogger.error("Please report this to the QuartzLib developers" @@ -92,13 +90,13 @@ public final class MessageSender { } } - // For 1.12+, we send action bars using the title packet, as sending them using the chat packet is broken - // (see MC-119145). + try { - packetPlayOutTitleClass = Reflection.getMinecraftClassByName("PacketPlayOutTitle"); + packetPlayOutTitleClass = + Reflection.getMinecraft1_17ClassByName("PacketPlayOutTitle"); //n'existe plus rip final Class titleActionEnum = - Reflection.getMinecraftClassByName("PacketPlayOutTitle$EnumTitleAction"); + Reflection.getMinecraft1_17ClassByName("PacketPlayOutTitle$EnumTitleAction"); for (final Enum actionEnumConstant : titleActionEnum.getEnumConstants()) { if (actionEnumConstant.name().equals("ACTIONBAR")) { actionBarTitleActionEnum = actionEnumConstant; @@ -109,8 +107,65 @@ public final class MessageSender { packetPlayOutTitleClass = null; actionBarTitleActionEnum = null; } - } catch (final Exception e) { - enabled = false; + } catch (Exception ex) { + try { + iChatBaseComponentClass = Reflection.getMinecraftClassByName("IChatBaseComponent"); + packetPlayOutChatClass = Reflection.getMinecraftClassByName("PacketPlayOutChat"); + + // TODO centralize the chat serialization mechanisms + try { + chatSerializerClass = Reflection.getMinecraftClassByName("ChatSerializer"); + } catch (ClassNotFoundException e) { + chatSerializerClass = Reflection.getMinecraftClassByName("IChatBaseComponent$ChatSerializer"); + } + + // We only support 1.8+ + if (!nmsVersion.equalsIgnoreCase("v1_8_R1")) { + chatComponentTextClass = Reflection.getMinecraftClassByName("ChatComponentText"); + + // This enum was introduced in 1.12; before, a byte was directly used. + try { + chatMessageTypeEnum = Reflection.getMinecraftClassByName("ChatMessageType"); + chatMessageByteToTypeMethod = Reflection.findMethod(chatMessageTypeEnum, "a", byte.class); + + if (chatMessageByteToTypeMethod == null) { + PluginLogger + .error("You are using a version of Minecraft ({0}) incompatible with QuartzLib.", + nmsVersion); + PluginLogger.error("The MessageSender component will not work" + + "due to a change in Minecraft code."); + PluginLogger.error("Please report this to the QuartzLib developers" + + "at https://github.com/zDevelopers/QuartzLib/issues, thanks!"); + + chatMessageTypeEnum = null; + } + } catch (ClassNotFoundException e) { + chatMessageTypeEnum = null; + chatMessageByteToTypeMethod = null; + } + } + + // For 1.12+, + // we send action bars using the title packet, as sending them using the chat packet is broken + // (see MC-119145). + try { + packetPlayOutTitleClass = Reflection.getMinecraftClassByName("PacketPlayOutTitle"); + + final Class titleActionEnum = + Reflection.getMinecraftClassByName("PacketPlayOutTitle$EnumTitleAction"); + for (final Enum actionEnumConstant : titleActionEnum.getEnumConstants()) { + if (actionEnumConstant.name().equals("ACTIONBAR")) { + actionBarTitleActionEnum = actionEnumConstant; + break; + } + } + } catch (final Exception e) { + packetPlayOutTitleClass = null; + actionBarTitleActionEnum = null; + } + } catch (final Exception e) { + enabled = false; + } } } @@ -124,19 +179,19 @@ private MessageSender() { * @param message The message to be sent. * @param type The message's type. * @return {@code false} if an error occurred while sending the message.
- * If this happens: - *
    - *
  • - * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link - * MessageSender.MessageType#SYSTEM SYSTEM}, - * and the {@link org.bukkit.command.CommandSender#sendMessage(String) - * sendMessage} method was used as a fallback; - *
  • - *
  • - * or the message's type was {@link - * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. - *
  • - *
+ * If this happens: + *
    + *
  • + * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link + * MessageSender.MessageType#SYSTEM SYSTEM}, + * and the {@link org.bukkit.command.CommandSender#sendMessage(String) + * sendMessage} method was used as a fallback; + *
  • + *
  • + * or the message's type was {@link + * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. + *
  • + *
*/ public static boolean sendMessage(Player receiver, String message, MessageType type) { return sendChatPacket( @@ -151,19 +206,19 @@ public static boolean sendMessage(Player receiver, String message, MessageType t * @param message The message to be sent. * @param type The message's type. * @return {@code false} if an error occurred while sending the message.
- * If this happens: - *
    - *
  • - * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link - * MessageSender.MessageType#SYSTEM SYSTEM}, - * and the {@link org.bukkit.command.CommandSender#sendMessage(String) - * sendMessage} method was used as a fallback; - *
  • - *
  • - * or the message's type was {@link - * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. - *
  • - *
+ * If this happens: + *
    + *
  • + * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link + * MessageSender.MessageType#SYSTEM SYSTEM}, + * and the {@link org.bukkit.command.CommandSender#sendMessage(String) + * sendMessage} method was used as a fallback; + *
  • + *
  • + * or the message's type was {@link + * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. + *
  • + *
*/ public static boolean sendMessage(Player receiver, RawText message, MessageType type) { return sendChatPacket(receiver, type.isJSON() ? message.toJSONString() : message.toFormattedText(), type); @@ -176,20 +231,20 @@ public static boolean sendMessage(Player receiver, RawText message, MessageType * @param message The message to be sent. * @param type The message's type. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message.
- * If this happens: - *
    - *
  • - * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link - * MessageSender.MessageType#SYSTEM SYSTEM}, - * and the {@link org.bukkit.command.CommandSender#sendMessage(String) - * sendMessage} method was used as a fallback; - *
  • - *
  • - * or the message's type was {@link - * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. - *
  • - *
+ * occurred while sending the message.
+ * If this happens: + *
    + *
  • + * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link + * MessageSender.MessageType#SYSTEM SYSTEM}, + * and the {@link org.bukkit.command.CommandSender#sendMessage(String) + * sendMessage} method was used as a fallback; + *
  • + *
  • + * or the message's type was {@link + * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. + *
  • + *
*/ public static boolean sendMessage(UUID receiver, String message, MessageType type) { Player player = Bukkit.getPlayer(receiver); @@ -204,20 +259,20 @@ public static boolean sendMessage(UUID receiver, String message, MessageType typ * @param message The message to be sent. * @param type The message's type. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message.
- * If this happens: - *
    - *
  • - * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link - * MessageSender.MessageType#SYSTEM SYSTEM}, - * and the {@link org.bukkit.command.CommandSender#sendMessage(String) - * sendMessage} method was used as a fallback; - *
  • - *
  • - * or the message's type was {@link - * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. - *
  • - *
+ * occurred while sending the message.
+ * If this happens: + *
    + *
  • + * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link + * MessageSender.MessageType#SYSTEM SYSTEM}, + * and the {@link org.bukkit.command.CommandSender#sendMessage(String) + * sendMessage} method was used as a fallback; + *
  • + *
  • + * or the message's type was {@link + * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. + *
  • + *
*/ public static boolean sendMessage(UUID receiver, RawText message, MessageType type) { Player player = Bukkit.getPlayer(receiver); @@ -236,19 +291,19 @@ public static boolean sendMessage(UUID receiver, RawText message, MessageType ty * @param json The JSON message to be sent. * @param type The message's type. * @return {@code false} if an error occurred while sending the message.
- * If this happens: - *
    - *
  • - * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link - * MessageSender.MessageType#SYSTEM SYSTEM}, - * and the {@link org.bukkit.command.CommandSender#sendMessage(String) - * sendMessage} method was used as a fallback; - *
  • - *
  • - * or the message's type was {@link - * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. - *
  • - *
+ * If this happens: + *
    + *
  • + * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link + * MessageSender.MessageType#SYSTEM SYSTEM}, + * and the {@link org.bukkit.command.CommandSender#sendMessage(String) + * sendMessage} method was used as a fallback; + *
  • + *
  • + * or the message's type was {@link + * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. + *
  • + *
*/ public static boolean sendJSONMessage(Player receiver, String json, MessageType type) { return sendChatPacket(receiver, json, type); @@ -264,20 +319,20 @@ public static boolean sendJSONMessage(Player receiver, String json, MessageType * @param json The message to be sent. * @param type The message's type. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message.
- * If this happens: - *
    - *
  • - * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link - * MessageSender.MessageType#SYSTEM SYSTEM}, - * and the {@link org.bukkit.command.CommandSender#sendMessage(String) - * sendMessage} method was used as a fallback; - *
  • - *
  • - * or the message's type was {@link - * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. - *
  • - *
+ * occurred while sending the message.
+ * If this happens: + *
    + *
  • + * either the message's type was {@link MessageSender.MessageType#CHAT CHAT} or {@link + * MessageSender.MessageType#SYSTEM SYSTEM}, + * and the {@link org.bukkit.command.CommandSender#sendMessage(String) + * sendMessage} method was used as a fallback; + *
  • + *
  • + * or the message's type was {@link + * MessageSender.MessageType#ACTION_BAR ACTION_BAR}, and the message was not sent. + *
  • + *
*/ public static boolean sendJSONMessage(UUID receiver, String json, MessageType type) { Player player = Bukkit.getPlayer(receiver); @@ -292,8 +347,8 @@ public static boolean sendJSONMessage(UUID receiver, String json, MessageType ty * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if an error occurred while sending the message. If this happens, the - * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is - * automatically called as a fallback. + * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is + * automatically called as a fallback. */ public static boolean sendChatMessage(Player receiver, String message) { return sendMessage(receiver, message, MessageType.CHAT); @@ -306,9 +361,9 @@ public static boolean sendChatMessage(Player receiver, String message) { * @param receiver The UUID of the receiver of the message. * @param message The message. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message. If this happens, the {@link - * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically - * called as a fallback. + * occurred while sending the message. If this happens, the {@link + * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically + * called as a fallback. */ public static boolean sendChatMessage(UUID receiver, String message) { return sendMessage(receiver, message, MessageType.CHAT); @@ -321,8 +376,8 @@ public static boolean sendChatMessage(UUID receiver, String message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if an error occurred while sending the message. If this happens, the - * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is - * automatically called as a fallback. + * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is + * automatically called as a fallback. */ public static boolean sendChatMessage(Player receiver, RawText message) { return sendMessage(receiver, message, MessageType.CHAT); @@ -335,9 +390,9 @@ public static boolean sendChatMessage(Player receiver, RawText message) { * @param receiver The UUID of the receiver of the message. * @param message The message. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message. If this happens, the {@link - * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically - * called as a fallback. + * occurred while sending the message. If this happens, the {@link + * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically + * called as a fallback. */ public static boolean sendChatMessage(UUID receiver, RawText message) { return sendMessage(receiver, message, MessageType.CHAT); @@ -351,8 +406,8 @@ public static boolean sendChatMessage(UUID receiver, RawText message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if an error occurred while sending the message. If this happens, the - * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is - * automatically called as a fallback. + * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is + * automatically called as a fallback. */ public static boolean sendSystemMessage(Player receiver, String message) { return sendMessage(receiver, message, MessageType.SYSTEM); @@ -367,9 +422,9 @@ public static boolean sendSystemMessage(Player receiver, String message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message. If this happens, the {@link - * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically - * called as a fallback. + * occurred while sending the message. If this happens, the {@link + * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically + * called as a fallback. */ public static boolean sendSystemMessage(UUID receiver, String message) { return sendMessage(receiver, message, MessageType.SYSTEM); @@ -383,8 +438,8 @@ public static boolean sendSystemMessage(UUID receiver, String message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if an error occurred while sending the message. If this happens, the - * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is - * automatically called as a fallback. + * {@link org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is + * automatically called as a fallback. */ public static boolean sendSystemMessage(Player receiver, RawText message) { return sendMessage(receiver, message, MessageType.SYSTEM); @@ -399,9 +454,9 @@ public static boolean sendSystemMessage(Player receiver, RawText message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message. If this happens, the {@link - * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically - * called as a fallback. + * occurred while sending the message. If this happens, the {@link + * org.bukkit.command.CommandSender#sendMessage(String) sendMessage} method is automatically + * called as a fallback. */ public static boolean sendSystemMessage(UUID receiver, RawText message) { return sendMessage(receiver, message, MessageType.SYSTEM); @@ -413,8 +468,8 @@ public static boolean sendSystemMessage(UUID receiver, RawText message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if an error occurred while sending the message. If this happens, the - * message is not sent at all. Such an error is likely to be caused by an incompatible Bukkit - * version. + * message is not sent at all. Such an error is likely to be caused by an incompatible Bukkit + * version. * @see ActionBar */ public static boolean sendActionBarMessage(Player receiver, String message) { @@ -427,8 +482,8 @@ public static boolean sendActionBarMessage(Player receiver, String message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message. If this happens, the message is not sent at all. Such an - * error is likely to be caused by an incompatible Bukkit version. + * occurred while sending the message. If this happens, the message is not sent at all. Such an + * error is likely to be caused by an incompatible Bukkit version. * @see ActionBar */ public static boolean sendActionBarMessage(UUID receiver, String message) { @@ -441,8 +496,8 @@ public static boolean sendActionBarMessage(UUID receiver, String message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if an error occurred while sending the message. If this happens, the - * message is not sent at all. Such an error is likely to be caused by an incompatible Bukkit - * version. + * message is not sent at all. Such an error is likely to be caused by an incompatible Bukkit + * version. * @see ActionBar */ public static boolean sendActionBarMessage(Player receiver, RawText message) { @@ -455,8 +510,8 @@ public static boolean sendActionBarMessage(Player receiver, RawText message) { * @param receiver The receiver of the message. * @param message The message. * @return {@code false} if no player with the given UUID is currently logged in, or if an error - * occurred while sending the message. If this happens, the message is not sent at all. Such an - * error is likely to be caused by an incompatible Bukkit version. + * occurred while sending the message. If this happens, the message is not sent at all. Such an + * error is likely to be caused by an incompatible Bukkit version. * @see ActionBar */ public static boolean sendActionBarMessage(UUID receiver, RawText message) { @@ -498,13 +553,15 @@ private static boolean sendChatPacket(Player receiver, String content, MessageTy Object baseComponent = iChatBaseComponentClass .cast(Reflection.call(chatSerializerClass, chatSerializerClass, "a", content)); chatPacket = - Reflection.instantiate(packetPlayOutChatClass, baseComponent, type.getMessagePositionByte()); + Reflection + .instantiate(packetPlayOutChatClass, baseComponent, type.getMessagePositionByte()); } else { Object componentText; if (type.isJSON()) { componentText = - iChatBaseComponentClass.cast(Reflection.call(chatSerializerClass, "a", (Object) content)); + iChatBaseComponentClass + .cast(Reflection.call(chatSerializerClass, "a", (Object) content)); } else { componentText = Reflection.instantiate(chatComponentTextClass, content); } @@ -518,7 +575,6 @@ private static boolean sendChatPacket(Player receiver, String content, MessageTy .newInstance(actionBarTitleActionEnum, componentText); } else { final Enum nmsMessageType = type.getMessagePositionEnumValue(); - if (nmsMessageType != null) { try { // 1.16.1+ chat packets constructor require an UUID. To send @@ -541,7 +597,6 @@ private static boolean sendChatPacket(Player receiver, String content, MessageTy } } } - NMSNetwork.sendPacket(receiver, chatPacket); return true; } catch (Exception e) { @@ -618,6 +673,7 @@ public Enum getMessagePositionEnumValue() { /** * Returns if the chat packet wants a JSON-formatted message. + * * @return {@code true} if the chat packet wants a JSON-formatted message, {@code false} else. */ public boolean isJSON() {