From e769113e5121bc9286783af7c97b92718c27c13b Mon Sep 17 00:00:00 2001 From: tr7zw Date: Mon, 23 Sep 2019 20:44:20 +0200 Subject: [PATCH] 2.1.0 update Update to 2.1.0: - Fixed 1.12/11 invisible mobs - Fixed an NBTInjector exception that could happen in 1.13.2 - If reflections where unable to get their hook, a NPE was thrown because the logger wasn't yet initialized - The NBTInjector won't enable by default, enable it during onLoad if you want to use it - Prevent /reload when the NBTInjector is enabled to prevent currupt serverstates --- item-nbt-api/pom.xml | 2 +- .../utils/nmsmappings/ReflectionMethod.java | 366 ++++++------ item-nbt-plugin/pom.xml | 12 +- .../java/de/tr7zw/nbtapi/plugin/NBTAPI.java | 301 +++++----- .../tr7zw/nbtapi/plugin/ReloadListener.java | 42 ++ .../tests/entities/EntityCustomNbtTest.java | 81 +-- .../tests/tiles/TilesCustomNBTTest.java | 79 +-- nbt-injector/pom.xml | 4 +- .../tr7zw/nbtinjector/InternalInjectors.java | 557 +++++++++--------- .../de/tr7zw/nbtinjector/NBTInjector.java | 13 +- pom.xml | 2 +- 11 files changed, 761 insertions(+), 698 deletions(-) create mode 100644 item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/ReloadListener.java diff --git a/item-nbt-api/pom.xml b/item-nbt-api/pom.xml index 669b922f6..00e0e08b4 100644 --- a/item-nbt-api/pom.xml +++ b/item-nbt-api/pom.xml @@ -7,7 +7,7 @@ de.tr7zw item-nbt-parent - 2.0.0 + 2.1.0 item-nbt-api diff --git a/item-nbt-api/src/main/java/de/tr7zw/changeme/nbtapi/utils/nmsmappings/ReflectionMethod.java b/item-nbt-api/src/main/java/de/tr7zw/changeme/nbtapi/utils/nmsmappings/ReflectionMethod.java index 28990647f..cc38cd136 100644 --- a/item-nbt-api/src/main/java/de/tr7zw/changeme/nbtapi/utils/nmsmappings/ReflectionMethod.java +++ b/item-nbt-api/src/main/java/de/tr7zw/changeme/nbtapi/utils/nmsmappings/ReflectionMethod.java @@ -1,183 +1,183 @@ -package de.tr7zw.changeme.nbtapi.utils.nmsmappings; - -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Method; -import java.util.logging.Level; - -import org.bukkit.inventory.ItemStack; - -import de.tr7zw.changeme.nbtapi.NbtApiException; -import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; -import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger; - -/** - * This class caches method reflections, keeps track of method name changes between versions and allows early checking for problems - * - * @author tr7zw - * - */ -@SuppressWarnings("javadoc") -public enum ReflectionMethod { - - COMPOUND_SET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, float.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setFloat")), - COMPOUND_SET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setString")), - COMPOUND_SET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setInt")), - COMPOUND_SET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByteArray")), - COMPOUND_SET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setIntArray")), - COMPOUND_SET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, long.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setLong")), - COMPOUND_SET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, short.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setShort")), - COMPOUND_SET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByte")), - COMPOUND_SET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, double.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setDouble")), - COMPOUND_SET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, boolean.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setBoolean")), - COMPOUND_MERGE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping! - COMPOUND_SET(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "set")), - COMPOUND_GET(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get")), - COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getList")), - - COMPOUND_GET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getFloat")), - COMPOUND_GET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getString")), - COMPOUND_GET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getInt")), - COMPOUND_GET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByteArray")), - COMPOUND_GET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getIntArray")), - COMPOUND_GET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getLong")), - COMPOUND_GET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getShort")), - COMPOUND_GET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByte")), - COMPOUND_GET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getDouble")), - COMPOUND_GET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getBoolean")), - COMPOUND_GET_COMPOUND(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getCompound")), - - NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTag")), - NMSITEM_SAVE(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "save")), - NMSITEM_CREATESTACK(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_10_R1, new Since(MinecraftVersion.MC1_7_R4, "createStack")), - - COMPOUND_REMOVE_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "remove")), - COMPOUND_HAS_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "hasKey")), - COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "d")), //FIXME: No Spigot mapping! - COMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys")), - - LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys")), - LIST_REMOVE_KEY(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_9_R1, "remove")), - LIST_SIZE(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "size")), - LIST_SET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_13_R1, "set")), - LEGACY_LIST_ADD(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_13_R2, new Since(MinecraftVersion.MC1_7_R4, "add")), - LIST_ADD(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "add")), - LIST_GET_STRING(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getString")), - LIST_GET_COMPOUND(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get")), - LIST_GET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "g"), new Since(MinecraftVersion.MC1_9_R1, "h"), new Since(MinecraftVersion.MC1_12_R1, "i"), new Since(MinecraftVersion.MC1_13_R1, "get")), - - ITEMSTACK_SET_TAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTag")), - ITEMSTACK_NMSCOPY(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), new Class[]{ItemStack.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asNMSCopy")), - ITEMSTACK_BUKKITMIRROR(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), new Class[]{ClassWrapper.NMS_ITEMSTACK.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asCraftMirror")), - - CRAFT_WORLD_GET_HANDLE(ClassWrapper.CRAFT_WORLD.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getHandle")), - NMS_WORLD_GET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTileEntity")), - NMS_WORLD_SET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz(), ClassWrapper.NMS_TILEENTITY.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTileEntity")), - NMS_WORLD_REMOVE_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "t"), new Since(MinecraftVersion.MC1_9_R1, "s"), new Since(MinecraftVersion.MC1_13_R1, "n"), new Since(MinecraftVersion.MC1_14_R1, "removeTileEntity")), - - TILEENTITY_LOAD_LEGACY191(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTSERVER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_9_R1, MinecraftVersion.MC1_9_R1, new Since(MinecraftVersion.MC1_9_R1, "a")), //FIXME: No Spigot mapping! - TILEENTITY_LOAD_LEGACY183(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_9_R2, new Since(MinecraftVersion.MC1_8_R3, "c"), new Since(MinecraftVersion.MC1_9_R1, "a"), new Since(MinecraftVersion.MC1_9_R2, "c")), //FIXME: No Spigot mapping! - TILEENTITY_LOAD_LEGACY1121(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_WORLD.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_10_R1, MinecraftVersion.MC1_12_R1, new Since(MinecraftVersion.MC1_10_R1, "a"), new Since(MinecraftVersion.MC1_12_R1, "create")), - TILEENTITY_LOAD(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_12_R1, "create")), - - TILEENTITY_GET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "save")), - TILEENTITY_SET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_12_R1, "load")), - - CRAFT_ENTITY_GET_HANDLE(ClassWrapper.CRAFT_ENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getHandle")), - NMS_ENTITY_SET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "f")), //FIXME: No Spigot mapping! - NMS_ENTITY_GET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "e"), new Since(MinecraftVersion.MC1_12_R1, "save")), - NMS_ENTITY_GETSAVEID(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_14_R1,new Since(MinecraftVersion.MC1_14_R1, "getSaveID")), - - NBTFILE_READ(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS.getClazz(), new Class[]{InputStream.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping! - NBTFILE_WRITE(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), OutputStream.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping! - - - PARSE_NBT(ClassWrapper.NMS_MOJANGSONPARSER.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "parse")), - REGISTRY_KEYSET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "keySet")), - REGISTRY_GET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "get")), - REGISTRY_SET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class, Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "a")), //FIXME: No Spigot mapping! - REGISTRY_GET_INVERSE (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "b")), //FIXME: No Spigot mapping! - REGISTRYMATERIALS_KEYSET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "keySet")), - REGISTRYMATERIALS_GET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTKEY.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "get")), - - - ; - - private MinecraftVersion removedAfter; - private Since targetVersion; - private Method method; - private boolean loaded = false; - private boolean compatible = false; - private String methodName = null; - - ReflectionMethod(Class targetClass, Class[] args, MinecraftVersion addedSince, MinecraftVersion removedAfter, Since... methodnames){ - this.removedAfter = removedAfter; - MinecraftVersion server = MinecraftVersion.getVersion(); - if(server.compareTo(addedSince) < 0 || (this.removedAfter != null && server.getVersionId() > this.removedAfter.getVersionId()))return; - compatible = true; - Since target = methodnames[0]; - for(Since s : methodnames){ - if(s.version.getVersionId() <= server.getVersionId() && target.version.getVersionId() < s.version.getVersionId()) - target = s; - } - targetVersion = target; - try{ - method = targetClass.getMethod(targetVersion.name, args); - method.setAccessible(true); - loaded = true; - methodName = targetVersion.name; - }catch(NullPointerException | NoSuchMethodException | SecurityException ex){ - logger.log(Level.SEVERE, "Unable to find the method '" + targetVersion.name + "' in '" + targetClass.getSimpleName() + "'", ex); - } - } - - ReflectionMethod(Class targetClass, Class[] args, MinecraftVersion addedSince, Since... methodnames){ - this(targetClass, args, addedSince, null, methodnames); - } - - /** - * Runs the method on a given target object using the given args. - * - * @param target - * @param args - * @return Value returned by the method - */ - public Object run(Object target, Object... args){ - try{ - return method.invoke(target, args); - }catch(Exception ex){ - throw new NbtApiException("Error while calling the method '" + methodName + "', loaded: " + loaded + ".", ex); - } - } - - /** - * @return The MethodName, used in this Minecraft Version - */ - public String getMethodName() { - return methodName; - } - - /** - * @return Has this method been linked - */ - public boolean isLoaded() { - return loaded; - } - - /** - * @return Is this method available in this Minecraft Version - */ - public boolean isCompatible() { - return compatible; - } - - protected static class Since{ - public final MinecraftVersion version; - public final String name; - public Since(MinecraftVersion version, String name) { - this.version = version; - this.name = name; - } - } - -} +package de.tr7zw.changeme.nbtapi.utils.nmsmappings; + +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Method; +import java.util.logging.Level; + +import org.bukkit.inventory.ItemStack; + +import de.tr7zw.changeme.nbtapi.NbtApiException; +import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; +import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger; + +/** + * This class caches method reflections, keeps track of method name changes between versions and allows early checking for problems + * + * @author tr7zw + * + */ +@SuppressWarnings("javadoc") +public enum ReflectionMethod { + + COMPOUND_SET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, float.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setFloat")), + COMPOUND_SET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setString")), + COMPOUND_SET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setInt")), + COMPOUND_SET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByteArray")), + COMPOUND_SET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int[].class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setIntArray")), + COMPOUND_SET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, long.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setLong")), + COMPOUND_SET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, short.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setShort")), + COMPOUND_SET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, byte.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setByte")), + COMPOUND_SET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, double.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setDouble")), + COMPOUND_SET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, boolean.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setBoolean")), + COMPOUND_MERGE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping! + COMPOUND_SET(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "set")), + COMPOUND_GET(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get")), + COMPOUND_GET_LIST(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class, int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getList")), + + COMPOUND_GET_FLOAT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getFloat")), + COMPOUND_GET_STRING(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getString")), + COMPOUND_GET_INT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getInt")), + COMPOUND_GET_BYTEARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByteArray")), + COMPOUND_GET_INTARRAY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getIntArray")), + COMPOUND_GET_LONG(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getLong")), + COMPOUND_GET_SHORT(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getShort")), + COMPOUND_GET_BYTE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getByte")), + COMPOUND_GET_DOUBLE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getDouble")), + COMPOUND_GET_BOOLEAN(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getBoolean")), + COMPOUND_GET_COMPOUND(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getCompound")), + + NMSITEM_GETTAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTag")), + NMSITEM_SAVE(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "save")), + NMSITEM_CREATESTACK(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[] {ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_10_R1, new Since(MinecraftVersion.MC1_7_R4, "createStack")), + + COMPOUND_REMOVE_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "remove")), + COMPOUND_HAS_KEY(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "hasKey")), + COMPOUND_GET_TYPE(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "d")), //FIXME: No Spigot mapping! + COMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys")), + + LISTCOMPOUND_GET_KEYS(ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "c"), new Since(MinecraftVersion.MC1_13_R1, "getKeys")), + LIST_REMOVE_KEY(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_9_R1, "remove")), + LIST_SIZE(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "size")), + LIST_SET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a"), new Since(MinecraftVersion.MC1_13_R1, "set")), + LEGACY_LIST_ADD(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_7_R4, MinecraftVersion.MC1_13_R2, new Since(MinecraftVersion.MC1_7_R4, "add")), + LIST_ADD(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class, ClassWrapper.NMS_NBTBASE.getClazz()}, MinecraftVersion.MC1_14_R1, new Since(MinecraftVersion.MC1_14_R1, "add")), + LIST_GET_STRING(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getString")), + LIST_GET_COMPOUND(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "get")), + LIST_GET(ClassWrapper.NMS_NBTTAGLIST.getClazz(), new Class[]{int.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "g"), new Since(MinecraftVersion.MC1_9_R1, "h"), new Since(MinecraftVersion.MC1_12_R1, "i"), new Since(MinecraftVersion.MC1_13_R1, "get")), + + ITEMSTACK_SET_TAG(ClassWrapper.NMS_ITEMSTACK.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTag")), + ITEMSTACK_NMSCOPY(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), new Class[]{ItemStack.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asNMSCopy")), + ITEMSTACK_BUKKITMIRROR(ClassWrapper.CRAFT_ITEMSTACK.getClazz(), new Class[]{ClassWrapper.NMS_ITEMSTACK.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "asCraftMirror")), + + CRAFT_WORLD_GET_HANDLE(ClassWrapper.CRAFT_WORLD.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getHandle")), + NMS_WORLD_GET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getTileEntity")), + NMS_WORLD_SET_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz(), ClassWrapper.NMS_TILEENTITY.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "setTileEntity")), + NMS_WORLD_REMOVE_TILEENTITY(ClassWrapper.NMS_WORLDSERVER.getClazz(), new Class[]{ClassWrapper.NMS_BLOCKPOSITION.getClazz()}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "t"), new Since(MinecraftVersion.MC1_9_R1, "s"), new Since(MinecraftVersion.MC1_13_R1, "n"), new Since(MinecraftVersion.MC1_14_R1, "removeTileEntity")), + + TILEENTITY_LOAD_LEGACY191(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTSERVER.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_9_R1, MinecraftVersion.MC1_9_R1, new Since(MinecraftVersion.MC1_9_R1, "a")), //FIXME: No Spigot mapping! + TILEENTITY_LOAD_LEGACY183(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, MinecraftVersion.MC1_9_R2, new Since(MinecraftVersion.MC1_8_R3, "c"), new Since(MinecraftVersion.MC1_9_R1, "a"), new Since(MinecraftVersion.MC1_9_R2, "c")), //FIXME: No Spigot mapping! + TILEENTITY_LOAD_LEGACY1121(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_WORLD.getClazz(), ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_10_R1, MinecraftVersion.MC1_12_R1, new Since(MinecraftVersion.MC1_10_R1, "a"), new Since(MinecraftVersion.MC1_12_R1, "create")), + TILEENTITY_LOAD(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_12_R1, "create")), + + TILEENTITY_GET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "b"), new Since(MinecraftVersion.MC1_9_R1, "save")), + TILEENTITY_SET_NBT(ClassWrapper.NMS_TILEENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "a"), new Since(MinecraftVersion.MC1_12_R1, "load")), + + CRAFT_ENTITY_GET_HANDLE(ClassWrapper.CRAFT_ENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "getHandle")), + NMS_ENTITY_SET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "f")), //FIXME: No Spigot mapping! + NMS_ENTITY_GET_NBT(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz()}, MinecraftVersion.MC1_8_R3, new Since(MinecraftVersion.MC1_8_R3, "e"), new Since(MinecraftVersion.MC1_12_R1, "save")), + NMS_ENTITY_GETSAVEID(ClassWrapper.NMS_ENTITY.getClazz(), new Class[]{}, MinecraftVersion.MC1_14_R1,new Since(MinecraftVersion.MC1_14_R1, "getSaveID")), + + NBTFILE_READ(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS.getClazz(), new Class[]{InputStream.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping! + NBTFILE_WRITE(ClassWrapper.NMS_NBTCOMPRESSEDSTREAMTOOLS.getClazz(), new Class[]{ClassWrapper.NMS_NBTTAGCOMPOUND.getClazz(), OutputStream.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "a")), //FIXME: No Spigot mapping! + + + PARSE_NBT(ClassWrapper.NMS_MOJANGSONPARSER.getClazz(), new Class[]{String.class}, MinecraftVersion.MC1_7_R4, new Since(MinecraftVersion.MC1_7_R4, "parse")), + REGISTRY_KEYSET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "keySet")), + REGISTRY_GET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "get")), + REGISTRY_SET (ClassWrapper.NMS_REGISTRYSIMPLE.getClazz(), new Class[]{Object.class, Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "a")), //FIXME: No Spigot mapping! + REGISTRY_GET_INVERSE (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{Object.class}, MinecraftVersion.MC1_11_R1, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_11_R1, "b")), //FIXME: No Spigot mapping! + REGISTRYMATERIALS_KEYSET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "keySet")), + REGISTRYMATERIALS_GET (ClassWrapper.NMS_REGISTRYMATERIALS.getClazz(), new Class[]{ClassWrapper.NMS_MINECRAFTKEY.getClazz()}, MinecraftVersion.MC1_13_R1, new Since(MinecraftVersion.MC1_13_R1, "get")), + + + ; + + private MinecraftVersion removedAfter; + private Since targetVersion; + private Method method; + private boolean loaded = false; + private boolean compatible = false; + private String methodName = null; + + ReflectionMethod(Class targetClass, Class[] args, MinecraftVersion addedSince, MinecraftVersion removedAfter, Since... methodnames){ + this.removedAfter = removedAfter; + MinecraftVersion server = MinecraftVersion.getVersion(); + if(server.compareTo(addedSince) < 0 || (this.removedAfter != null && server.getVersionId() > this.removedAfter.getVersionId()))return; + compatible = true; + Since target = methodnames[0]; + for(Since s : methodnames){ + if(s.version.getVersionId() <= server.getVersionId() && target.version.getVersionId() < s.version.getVersionId()) + target = s; + } + targetVersion = target; + try{ + method = targetClass.getMethod(targetVersion.name, args); + method.setAccessible(true); + loaded = true; + methodName = targetVersion.name; + }catch(NullPointerException | NoSuchMethodException | SecurityException ex){ + System.out.println("[NBTAPI] Unable to find the method '" + targetVersion.name + "' in '" + targetClass.getSimpleName() + "'"); //NOSONAR This gets loaded before the logger is loaded + } + } + + ReflectionMethod(Class targetClass, Class[] args, MinecraftVersion addedSince, Since... methodnames){ + this(targetClass, args, addedSince, null, methodnames); + } + + /** + * Runs the method on a given target object using the given args. + * + * @param target + * @param args + * @return Value returned by the method + */ + public Object run(Object target, Object... args){ + try{ + return method.invoke(target, args); + }catch(Exception ex){ + throw new NbtApiException("Error while calling the method '" + methodName + "', loaded: " + loaded + ".", ex); + } + } + + /** + * @return The MethodName, used in this Minecraft Version + */ + public String getMethodName() { + return methodName; + } + + /** + * @return Has this method been linked + */ + public boolean isLoaded() { + return loaded; + } + + /** + * @return Is this method available in this Minecraft Version + */ + public boolean isCompatible() { + return compatible; + } + + protected static class Since{ + public final MinecraftVersion version; + public final String name; + public Since(MinecraftVersion version, String name) { + this.version = version; + this.name = name; + } + } + +} diff --git a/item-nbt-plugin/pom.xml b/item-nbt-plugin/pom.xml index a158cb900..e0f03c404 100644 --- a/item-nbt-plugin/pom.xml +++ b/item-nbt-plugin/pom.xml @@ -4,7 +4,7 @@ de.tr7zw item-nbt-parent - 2.0.0 + 2.1.0 item-nbt-api-plugin jar @@ -12,13 +12,13 @@ de.tr7zw item-nbt-api - 2.0.0 + 2.1.0 compile de.tr7zw nbt-injector - 2.0.0 + 2.1.0 compile @@ -73,11 +73,11 @@ - - 1.8.8-R0.1-SNAPSHOT-latest, 1.9.2-R0.1-SNAPSHOT-latest, 1.9.4-R0.1-SNAPSHOT-latest, 1.10.2-R0.1-SNAPSHOT-latest,1.11.2,1.12.2,1.13.2,1.14.1,1.14.2,1.14.3 + + 1.8.8-R0.1-SNAPSHOT-latest, 1.9.2-R0.1-SNAPSHOT-latest, 1.9.4-R0.1-SNAPSHOT-latest, 1.10.2-R0.1-SNAPSHOT-latest,1.11.2,1.12.2,1.13.2,1.14.1,1.14.2,1.14.3,1.14.4 Success! This version of NBT-API WARNING! This version of NBT-API - item-nbt-api-plugin-2.0.0.jar + item-nbt-api-plugin-2.1.0.jar item-nbt-plugin diff --git a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/NBTAPI.java b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/NBTAPI.java index 07e9a5005..9cef73daa 100644 --- a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/NBTAPI.java +++ b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/NBTAPI.java @@ -1,148 +1,153 @@ -package de.tr7zw.nbtapi.plugin; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; - -import org.bukkit.plugin.java.JavaPlugin; - -import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; -import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper; -import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod; -import de.tr7zw.nbtapi.plugin.tests.NBTFileTest; -import de.tr7zw.nbtapi.plugin.tests.compounds.GetterSetterTest; -import de.tr7zw.nbtapi.plugin.tests.compounds.ListTest; -import de.tr7zw.nbtapi.plugin.tests.compounds.MergeTest; -import de.tr7zw.nbtapi.plugin.tests.compounds.RemovingKeys; -import de.tr7zw.nbtapi.plugin.tests.compounds.SubCompoundsTest; -import de.tr7zw.nbtapi.plugin.tests.compounds.TypeTest; -import de.tr7zw.nbtapi.plugin.tests.entities.EntityCustomNbtTest; -import de.tr7zw.nbtapi.plugin.tests.entities.EntityTest; -import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest; -import de.tr7zw.nbtapi.plugin.tests.items.ItemConvertionTest; -import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTTest; -import de.tr7zw.nbtinjector.NBTInjector; - -public class NBTAPI extends JavaPlugin { - - private boolean compatible = true; - private ArrayList apiTests = new ArrayList<>(); - - private static NBTAPI instance; - - public static NBTAPI getInstance() { - return instance; - } - - @Override - public void onLoad() { - getLogger().info("Injecting custom NBT"); - try { - NBTInjector.inject(); - getLogger().info("Injected!"); - } catch (Throwable ex) { // NOSONAR - getLogger().log(Level.SEVERE, "Error while Injecting custom Tile/Entity classes!", ex); - compatible = false; - } - - // NBTCompounds - apiTests.add(new GetterSetterTest()); - apiTests.add(new TypeTest()); - apiTests.add(new RemovingKeys()); - apiTests.add(new ListTest()); - apiTests.add(new SubCompoundsTest()); - apiTests.add(new MergeTest()); - - // Items - apiTests.add(new ItemConvertionTest()); - apiTests.add(new EmptyItemTest()); - - // Entity - apiTests.add(new EntityTest()); - apiTests.add(new EntityCustomNbtTest()); - - // Tiles - apiTests.add(new TilesCustomNBTTest()); - - // Files - apiTests.add(new NBTFileTest()); - - } - - @Override - public void onEnable() { - instance = this; // NOSONAR - // new MetricsLite(this); The metrics moved into the API - - getLogger().info("Checking bindings..."); - MinecraftVersion.getVersion(); - getLogger().info("Gson:"); - MinecraftVersion.hasGsonSupport(); - getLogger().info("Classes:"); - boolean classUnlinked = false; - for (ClassWrapper c : ClassWrapper.values()) { - if (c.isEnabled() && c.getClazz() == null) { - getLogger().warning(c.name() + " did not find it's class!"); - compatible = false; - classUnlinked = true; - } - } - if (!classUnlinked) - getLogger().info("All Classes where able to link!"); - - getLogger().info("Methods:"); - boolean methodUnlinked = false; - for (ReflectionMethod method : ReflectionMethod.values()) { - if (method.isCompatible() && !method.isLoaded()) { - getLogger().warning(method.name() + " did not find the method!"); - compatible = false; - methodUnlinked = true; - } - } - if (!methodUnlinked) - getLogger().info("All Methods where able to link!"); - getLogger().info("Running NBT reflection test..."); - - Map results = new HashMap<>(); - for (de.tr7zw.nbtapi.plugin.tests.Test test : apiTests) { - try { - test.test(); - results.put(test, null); - } catch (Exception ex) { - results.put(test, ex); - getLogger().log(Level.WARNING, "Error during '" + test.getClass().getSimpleName() + "' test!", ex); - } catch (Throwable th) { // NOSONAR - getLogger().log(Level.SEVERE, "Servere error during '" + test.getClass().getSimpleName() + "' test!"); - getLogger().warning( - "WARNING! This version of Item-NBT-API seems to be broken with your Spigot version! Canceled the other tests!"); - throw th; - } - } - - for (Entry entry : results.entrySet()) { - if (entry.getValue() != null) - compatible = false; - getLogger().info(entry.getKey().getClass().getSimpleName() + ": " - + (entry.getValue() == null ? "Ok" : entry.getValue().getMessage())); - } - - String checkMessage = "Plugins that don't check properly may throw Exeptions, crash or have unexpected behaviors!"; - if (compatible) { - getLogger().info("Success! This version of NBT-API is compatible with your server."); - } else { - getLogger().warning( - "WARNING! This version of NBT-API seems to be broken with your Spigot version! " + checkMessage); - } - - } - - /** - * @return True if all selfchecks succeeded - */ - public boolean isCompatible() { - return compatible; - } - -} +package de.tr7zw.nbtapi.plugin; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.logging.Level; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; + +import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; +import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper; +import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod; +import de.tr7zw.nbtapi.plugin.tests.NBTFileTest; +import de.tr7zw.nbtapi.plugin.tests.compounds.GetterSetterTest; +import de.tr7zw.nbtapi.plugin.tests.compounds.ListTest; +import de.tr7zw.nbtapi.plugin.tests.compounds.MergeTest; +import de.tr7zw.nbtapi.plugin.tests.compounds.RemovingKeys; +import de.tr7zw.nbtapi.plugin.tests.compounds.SubCompoundsTest; +import de.tr7zw.nbtapi.plugin.tests.compounds.TypeTest; +import de.tr7zw.nbtapi.plugin.tests.entities.EntityCustomNbtTest; +import de.tr7zw.nbtapi.plugin.tests.entities.EntityTest; +import de.tr7zw.nbtapi.plugin.tests.items.EmptyItemTest; +import de.tr7zw.nbtapi.plugin.tests.items.ItemConvertionTest; +import de.tr7zw.nbtapi.plugin.tests.tiles.TilesCustomNBTTest; +import de.tr7zw.nbtinjector.NBTInjector; + +public class NBTAPI extends JavaPlugin { + + private boolean compatible = true; + private ArrayList apiTests = new ArrayList<>(); + + private static NBTAPI instance; + + public static NBTAPI getInstance() { + return instance; + } + + @Override + public void onLoad() { + + //Disabled by default since 2.1. Enable it yourself by calling NBTInjector.inject(); during onLoad. + /*getLogger().info("Injecting custom NBT"); + try { + NBTInjector.inject(); + getLogger().info("Injected!"); + } catch (Throwable ex) { // NOSONAR + getLogger().log(Level.SEVERE, "Error while Injecting custom Tile/Entity classes!", ex); + compatible = false; + }*/ + + // NBTCompounds + apiTests.add(new GetterSetterTest()); + apiTests.add(new TypeTest()); + apiTests.add(new RemovingKeys()); + apiTests.add(new ListTest()); + apiTests.add(new SubCompoundsTest()); + apiTests.add(new MergeTest()); + + // Items + apiTests.add(new ItemConvertionTest()); + apiTests.add(new EmptyItemTest()); + + // Entity + apiTests.add(new EntityTest()); + apiTests.add(new EntityCustomNbtTest()); + + // Tiles + apiTests.add(new TilesCustomNBTTest()); + + // Files + apiTests.add(new NBTFileTest()); + + } + + @Override + public void onEnable() { + instance = this; // NOSONAR + // new MetricsLite(this); The metrics moved into the API + + getLogger().info("Adding listeners..."); + Bukkit.getPluginManager().registerEvents(new ReloadListener(), this); + getLogger().info("Checking bindings..."); + MinecraftVersion.getVersion(); + getLogger().info("Gson:"); + MinecraftVersion.hasGsonSupport(); + getLogger().info("Classes:"); + boolean classUnlinked = false; + for (ClassWrapper c : ClassWrapper.values()) { + if (c.isEnabled() && c.getClazz() == null) { + getLogger().warning(c.name() + " did not find it's class!"); + compatible = false; + classUnlinked = true; + } + } + if (!classUnlinked) + getLogger().info("All Classes where able to link!"); + + getLogger().info("Methods:"); + boolean methodUnlinked = false; + for (ReflectionMethod method : ReflectionMethod.values()) { + if (method.isCompatible() && !method.isLoaded()) { + getLogger().warning(method.name() + " did not find the method!"); + compatible = false; + methodUnlinked = true; + } + } + if (!methodUnlinked) + getLogger().info("All Methods where able to link!"); + getLogger().info("Running NBT reflection test..."); + + Map results = new HashMap<>(); + for (de.tr7zw.nbtapi.plugin.tests.Test test : apiTests) { + try { + test.test(); + results.put(test, null); + } catch (Exception ex) { + results.put(test, ex); + getLogger().log(Level.WARNING, "Error during '" + test.getClass().getSimpleName() + "' test!", ex); + } catch (Throwable th) { // NOSONAR + getLogger().log(Level.SEVERE, "Servere error during '" + test.getClass().getSimpleName() + "' test!"); + getLogger().warning( + "WARNING! This version of Item-NBT-API seems to be broken with your Spigot version! Canceled the other tests!"); + throw th; + } + } + + for (Entry entry : results.entrySet()) { + if (entry.getValue() != null) + compatible = false; + getLogger().info(entry.getKey().getClass().getSimpleName() + ": " + + (entry.getValue() == null ? "Ok" : entry.getValue().getMessage())); + } + + String checkMessage = "Plugins that don't check properly may throw Exeptions, crash or have unexpected behaviors!"; + if (compatible) { + getLogger().info("Success! This version of NBT-API is compatible with your server."); + } else { + getLogger().warning( + "WARNING! This version of NBT-API seems to be broken with your Spigot version! " + checkMessage); + } + + } + + /** + * @return True if all selfchecks succeeded + */ + public boolean isCompatible() { + return compatible; + } + +} diff --git a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/ReloadListener.java b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/ReloadListener.java new file mode 100644 index 000000000..13f526084 --- /dev/null +++ b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/ReloadListener.java @@ -0,0 +1,42 @@ +package de.tr7zw.nbtapi.plugin; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +import de.tr7zw.nbtinjector.NBTInjector; + +/** + * This listener class tries to prevent people from reloading while the NBTInjector is enabled. + * + * @author tr7zw + * + */ +public class ReloadListener implements Listener{ + + /** + * Console handler + * + * @param event + */ + @EventHandler + public void onCommand(org.bukkit.event.server.ServerCommandEvent event) { + if(event.getCommand().toLowerCase().startsWith("reload") && NBTInjector.isInjected()) { + event.setCancelled(true); + event.getSender().sendMessage("[NBTAPI] The NBTInjector is currently enabled. Reloading will turn the server into an unstable state and data-loss may accure. Please do a clean restart. Canceled reload!"); + } + } + + /** + * Player handler + * + * @param event + */ + @EventHandler + public void onCommand(org.bukkit.event.player.PlayerCommandPreprocessEvent event) { + if(event.getMessage().toLowerCase().startsWith("/reload") && NBTInjector.isInjected()) { + event.setCancelled(true); + event.getPlayer().sendMessage("[NBTAPI] The NBTInjector is currently enabled. Reloading will turn the server into an unstable state and data-loss may accure. Please do a clean restart. Canceled reload!"); + } + } + +} diff --git a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/entities/EntityCustomNbtTest.java b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/entities/EntityCustomNbtTest.java index 915abff45..0e4231886 100644 --- a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/entities/EntityCustomNbtTest.java +++ b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/entities/EntityCustomNbtTest.java @@ -1,40 +1,41 @@ -package de.tr7zw.nbtapi.plugin.tests.entities; - -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.Animals; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Monster; - -import de.tr7zw.changeme.nbtapi.NBTCompound; -import de.tr7zw.changeme.nbtapi.NBTEntity; -import de.tr7zw.changeme.nbtapi.NbtApiException; -import de.tr7zw.nbtapi.plugin.tests.Test; -import de.tr7zw.nbtinjector.NBTInjector; - -public class EntityCustomNbtTest implements Test { - - @Override - public void test() throws Exception { - if (!Bukkit.getWorlds().isEmpty()) { - World world = Bukkit.getWorlds().get(0); - try { - if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) { - Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next(); - ent = NBTInjector.patchEntity(ent); - NBTCompound comp = NBTInjector.getNbtData(ent); - comp.setString("Hello", "World"); - NBTEntity nbtent = new NBTEntity(ent); - if (!nbtent.asNBTString().contains("__extraData:{Hello:\"World\"}")) { - throw new NbtApiException("Custom Data did not save to the Entity!"); - } - comp.removeKey("Hello"); - - } - } catch (Exception ex) { - throw new NbtApiException("Wasn't able to use NBTEntities!", ex); - } - } - } - -} +package de.tr7zw.nbtapi.plugin.tests.entities; + +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Monster; + +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTEntity; +import de.tr7zw.changeme.nbtapi.NbtApiException; +import de.tr7zw.nbtapi.plugin.tests.Test; +import de.tr7zw.nbtinjector.NBTInjector; + +public class EntityCustomNbtTest implements Test { + + @Override + public void test() throws Exception { + if(!NBTInjector.isInjected())return; + if (!Bukkit.getWorlds().isEmpty()) { + World world = Bukkit.getWorlds().get(0); + try { + if (!world.getEntitiesByClasses(Animals.class, Monster.class).isEmpty()) { + Entity ent = world.getEntitiesByClasses(Animals.class, Monster.class).iterator().next(); + ent = NBTInjector.patchEntity(ent); + NBTCompound comp = NBTInjector.getNbtData(ent); + comp.setString("Hello", "World"); + NBTEntity nbtent = new NBTEntity(ent); + if (!nbtent.asNBTString().contains("__extraData:{Hello:\"World\"}")) { + throw new NbtApiException("Custom Data did not save to the Entity!"); + } + comp.removeKey("Hello"); + + } + } catch (Exception ex) { + throw new NbtApiException("Wasn't able to use NBTEntities!", ex); + } + } + } + +} diff --git a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/tiles/TilesCustomNBTTest.java b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/tiles/TilesCustomNBTTest.java index 3c6ad68a3..fdd7b15c6 100644 --- a/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/tiles/TilesCustomNBTTest.java +++ b/item-nbt-plugin/src/main/java/de/tr7zw/nbtapi/plugin/tests/tiles/TilesCustomNBTTest.java @@ -1,39 +1,40 @@ -package de.tr7zw.nbtapi.plugin.tests.tiles; - -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; - -import de.tr7zw.changeme.nbtapi.NBTCompound; -import de.tr7zw.changeme.nbtapi.NBTTileEntity; -import de.tr7zw.changeme.nbtapi.NbtApiException; -import de.tr7zw.nbtapi.plugin.tests.Test; -import de.tr7zw.nbtinjector.NBTInjector; - -public class TilesCustomNBTTest implements Test { - - @Override - public void test() throws Exception { - if (!Bukkit.getWorlds().isEmpty()) { - World world = Bukkit.getWorlds().get(0); - try { - Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 255, - world.getSpawnLocation().getBlockZ()); - if (block.getType() == Material.AIR) { - block.setType(Material.CHEST); - NBTCompound comp = NBTInjector.getNbtData(block.getState()); - comp.setString("Foo", "Bar"); - if (!new NBTTileEntity(block.getState()).asNBTString().contains("__extraData:{Foo:\"Bar\"}")) { - block.setType(Material.AIR); - throw new NbtApiException("Custom Data did not save to the Tile!"); - } - block.setType(Material.AIR); - } - } catch (Exception ex) { - throw new NbtApiException("Wasn't able to use NBTTiles!", ex); - } - } - } - -} +package de.tr7zw.nbtapi.plugin.tests.tiles; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; + +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTTileEntity; +import de.tr7zw.changeme.nbtapi.NbtApiException; +import de.tr7zw.nbtapi.plugin.tests.Test; +import de.tr7zw.nbtinjector.NBTInjector; + +public class TilesCustomNBTTest implements Test { + + @Override + public void test() throws Exception { + if(!NBTInjector.isInjected())return; + if (!Bukkit.getWorlds().isEmpty()) { + World world = Bukkit.getWorlds().get(0); + try { + Block block = world.getBlockAt(world.getSpawnLocation().getBlockX(), 255, + world.getSpawnLocation().getBlockZ()); + if (block.getType() == Material.AIR) { + block.setType(Material.CHEST); + NBTCompound comp = NBTInjector.getNbtData(block.getState()); + comp.setString("Foo", "Bar"); + if (!new NBTTileEntity(block.getState()).asNBTString().contains("__extraData:{Foo:\"Bar\"}")) { + block.setType(Material.AIR); + throw new NbtApiException("Custom Data did not save to the Tile!"); + } + block.setType(Material.AIR); + } + } catch (Exception ex) { + throw new NbtApiException("Wasn't able to use NBTTiles!", ex); + } + } + } + +} diff --git a/nbt-injector/pom.xml b/nbt-injector/pom.xml index 53e066f14..cc9550cfe 100644 --- a/nbt-injector/pom.xml +++ b/nbt-injector/pom.xml @@ -4,7 +4,7 @@ de.tr7zw item-nbt-parent - 2.0.0 + 2.1.0 nbt-injector jar @@ -12,7 +12,7 @@ de.tr7zw item-nbt-api - 2.0.0 + 2.1.0 compile diff --git a/nbt-injector/src/main/java/de/tr7zw/nbtinjector/InternalInjectors.java b/nbt-injector/src/main/java/de/tr7zw/nbtinjector/InternalInjectors.java index d34120aeb..badcf8d19 100644 --- a/nbt-injector/src/main/java/de/tr7zw/nbtinjector/InternalInjectors.java +++ b/nbt-injector/src/main/java/de/tr7zw/nbtinjector/InternalInjectors.java @@ -1,277 +1,280 @@ -package de.tr7zw.nbtinjector; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.logging.Level; - -import org.bukkit.Bukkit; - -import de.tr7zw.changeme.nbtapi.NbtApiException; -import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; -import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper; -import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod; -import de.tr7zw.nbtinjector.NBTInjector.Entity; -import de.tr7zw.nbtinjector.NBTInjector.TileEntity; -import javassist.ClassPool; -import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger; - -/** - * Contains the internal methods for different Minecraft Versions of injecting - * the Entities/Tiles - * - * @author tr7zw - * - */ -@SuppressWarnings("unchecked") -public class InternalInjectors { - - private static final List skippingEntities = Arrays.asList("minecraft:player", "minecraft:fishing_bobber", - "minecraft:lightning_bolt"); // These are broken/won't work, used by 1.14+ - private static final Map classMappings = new HashMap<>(); - - static { - classMappings.put("minecraft:wandering_trader", "VillagerTrader"); - classMappings.put("minecraft:trader_llama", "LlamaTrader"); - classMappings.put("minecraft:area_effect_cloud", "AreaEffectCloud"); - classMappings.put("minecraft:donkey", "HorseDonkey"); - classMappings.put("minecraft:ender_dragon", "EnderDragon"); - classMappings.put("minecraft:skeleton_horse", "HorseSkeleton"); - classMappings.put("minecraft:fireball", "LargeFireball"); - classMappings.put("minecraft:mule", "HorseMule"); - classMappings.put("minecraft:zombie_horse", "HorseZombie"); - classMappings.put("minecraft:mooshroom", "MushroomCow"); - classMappings.put("minecraft:wither_skeleton", "SkeletonWither"); - classMappings.put("minecraft:snow_golem", "Snowman"); - classMappings.put("minecraft:polar_bear", "PolarBear"); - classMappings.put("minecraft:magma_cube", "MagmaCube"); - classMappings.put("minecraft:armor_stand", "ArmorStand"); - classMappings.put("minecraft:elder_guardian", "GuardianElder"); - classMappings.put("minecraft:zombie_pigman", "PigZombie"); - classMappings.put("minecraft:giant", "GiantZombie"); - classMappings.put("minecraft:zombie_villager", "ZombieVillager"); - classMappings.put("minecraft:husk", "ZombieHusk"); - classMappings.put("minecraft:iron_golem", "IronGolem"); - classMappings.put("minecraft:tropical_fish", "TropicalFish"); - classMappings.put("minecraft:stray", "SkeletonStray"); - classMappings.put("minecraft:illusioner", "IllagerIllusioner"); - classMappings.put("minecraft:pufferfish", "PufferFish"); - classMappings.put("minecraft:cave_spider", "CaveSpider"); - } - - /** - * Hidden constructor - */ - private InternalInjectors() { - - } - - protected static void entity1v10Below(ClassPool classPool) throws ReflectiveOperationException { - for (Map.Entry> entry : new HashSet<>(Entity.getCMap().entrySet())) { - try { - if (INBTWrapper.class.isAssignableFrom(entry.getValue())) { - continue; - } // Already injected - int entityId = Entity.getFMap().get(entry.getValue()); - - Class wrapped = ClassGenerator.wrapEntity(classPool, entry.getValue(), "__extraData"); - Entity.getCMap().put(entry.getKey(), wrapped); - Entity.getDMap().put(wrapped, entry.getKey()); - - Entity.getEMap().put(entityId, wrapped); - Entity.getFMap().put(wrapped, entityId); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + entry.getKey(), e); - } - } - } - - protected static void entity1v12Below(ClassPool classPool) throws ReflectiveOperationException { - Object registry = Entity.getRegistry(); - Map inverse = new HashMap<>(); - Set it = new HashSet<>((Set) ReflectionMethod.REGISTRY_KEYSET.run(registry)); - for (Object mckey : it) { - Class tileclass = (Class) ReflectionMethod.REGISTRY_GET.run(registry, mckey); - inverse.put(tileclass, mckey); - try { - if (INBTWrapper.class.isAssignableFrom(tileclass)) { - continue; - } // Already injected - Class wrapped = ClassGenerator.wrapEntity(classPool, tileclass, "__extraData"); - ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped); - inverse.put(wrapped, mckey); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + mckey, e); - } - } - Field inverseField = registry.getClass().getDeclaredField("b"); - NBTInjector.setFinal(registry, inverseField, inverse); - } - - protected static void entity1v13Below(ClassPool classPool) throws ReflectiveOperationException { - Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null); - Set registryentries = new HashSet<>((Set) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry)); - for (Object mckey : registryentries) { - Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey); - Field supplierField = entityTypesObj.getClass().getDeclaredField("aT"); - Field classField = entityTypesObj.getClass().getDeclaredField("aS"); - classField.setAccessible(true); - supplierField.setAccessible(true); - Function function = (Function) supplierField.get(entityTypesObj); - Class nmsclass = (Class) classField.get(entityTypesObj); - try { - if (INBTWrapper.class.isAssignableFrom(nmsclass)) { - continue; - } // Already injected - Class wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData"); - NBTInjector.setFinal(entityTypesObj, classField, wrapped); - NBTInjector.setFinal(entityTypesObj, supplierField, new Function() { - - @Override - public Object apply(Object t) { - try { - return wrapped.getConstructor(ClassWrapper.NMS_WORLD.getClazz()).newInstance(t); - } catch (Exception ex) { - logger.log(Level.SEVERE, "Error while creating custom entity instance! ", ex); - return function.apply(t);// Fallback to the original one - } - } - }); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + mckey, e); - } - } - } - - protected static void entity1v14(ClassPool classPool) throws ReflectiveOperationException { - Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null); - Set registryentries = new HashSet<>((Set) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry)); - for (Object mckey : registryentries) { - if (skippingEntities.contains(mckey.toString())) { - logger.info("Skipping, won't be able add NBT to '" + mckey + "' entities!"); - continue; - } - Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey); - Field creatorField = entityTypesObj.getClass().getDeclaredField("aZ"); - creatorField.setAccessible(true); - Object creator = creatorField.get(entityTypesObj); - Method createEntityMethod = creator.getClass().getMethod("create", ClassWrapper.NMS_ENTITYTYPES.getClazz(), - ClassWrapper.NMS_WORLD.getClazz()); - createEntityMethod.setAccessible(true); - Class nmsclass = null; - try { - nmsclass = createEntityMethod.invoke(creator, entityTypesObj, null).getClass(); - } catch (Exception ignore) { - // ignore - } - if (nmsclass == null) { - String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; - String name = mckey.toString().replace("minecraft:", ""); - name = name.substring(0, 1).toUpperCase() + name.substring(1); - name = "Entity" + name; - if (classMappings.containsKey(mckey.toString())) - name = "Entity" + classMappings.get(mckey.toString()); - try { - nmsclass = Class.forName("net.minecraft.server." + version + "." + name); - } catch (Exception ignore) { - logger.info("Not found: " + "net.minecraft.server." + version + "." + name); - // ignore - } - } - if (nmsclass == null) { - logger.info( - "Wasn't able to create an Entity instace, won't be able add NBT to '" + mckey + "' entities!"); - continue; - } - try { - if (INBTWrapper.class.isAssignableFrom(nmsclass)) { - continue; - } // Already injected - Class wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData"); - NBTInjector.setFinal(entityTypesObj, creatorField, - ClassGenerator.createEntityTypeWrapper(classPool, wrapped).newInstance()); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + mckey, e); - } - } - } - - protected static void tile1v10Below(ClassPool classPool) throws ReflectiveOperationException { - for (Map.Entry> entry : new HashSet<>(TileEntity.getFMap().entrySet())) { - try { - if (INBTWrapper.class.isAssignableFrom(entry.getValue())) { - continue; - } // Already injected - Class wrapped = ClassGenerator.wrapTileEntity(classPool, entry.getValue(), "__extraData"); - TileEntity.getFMap().put(entry.getKey(), wrapped); - TileEntity.getGMap().put(wrapped, entry.getKey()); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + entry.getKey(), e); - } - } - } - - protected static void tile1v12Below(ClassPool classPool) throws ReflectiveOperationException { - Object registry = TileEntity.getRegistry(); - Map inverse = new HashMap<>(); - Set it = new HashSet<>((Set) ReflectionMethod.REGISTRY_KEYSET.run(registry)); - for (Object mckey : it) { - Class tileclass = (Class) ReflectionMethod.REGISTRY_GET.run(registry, mckey); - inverse.put(tileclass, mckey); - try { - if (INBTWrapper.class.isAssignableFrom(tileclass)) { - continue; - } // Already injected - Class wrapped = ClassGenerator.wrapTileEntity(classPool, tileclass, "__extraData"); - ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped); - inverse.put(wrapped, mckey); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + mckey, e); - } - } - Field inverseField = registry.getClass().getDeclaredField("b"); - NBTInjector.setFinal(registry, inverseField, inverse); - } - - protected static void tile1v13(ClassPool classPool) throws ReflectiveOperationException { - Object tileRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("BLOCK_ENTITY_TYPE").get(null); - Set registryentries = new HashSet<>((Set) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(tileRegistry)); - for (Object mckey : registryentries) { - Object tileEntityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(tileRegistry, mckey); - String supplierFieldName = "A"; - if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId()) - supplierFieldName = "H"; - Field supplierField = tileEntityTypesObj.getClass().getDeclaredField(supplierFieldName); - supplierField.setAccessible(true); - Supplier supplier = (Supplier) supplierField.get(tileEntityTypesObj); - Class nmsclass = supplier.get().getClass(); - try { - if (INBTWrapper.class.isAssignableFrom(nmsclass)) { - continue; - } // Already injected - Class wrapped = ClassGenerator.wrapTileEntity(classPool, nmsclass, "__extraData"); - NBTInjector.setFinal(tileEntityTypesObj, supplierField, new Supplier() { - @Override - public Object get() { - try { - return wrapped.newInstance(); - } catch (InstantiationException | IllegalAccessException e) { - logger.log(Level.SEVERE, "Error while creating custom tile instance! ", e); - return supplier.get(); // Use the original one as fallback - } - } - }); - } catch (Exception e) { - throw new NbtApiException("Exception while injecting " + mckey, e); - } - } - } - -} +package de.tr7zw.nbtinjector; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.logging.Level; + +import org.bukkit.Bukkit; + +import de.tr7zw.changeme.nbtapi.NbtApiException; +import de.tr7zw.changeme.nbtapi.utils.MinecraftVersion; +import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ClassWrapper; +import de.tr7zw.changeme.nbtapi.utils.nmsmappings.ReflectionMethod; +import de.tr7zw.nbtinjector.NBTInjector.Entity; +import de.tr7zw.nbtinjector.NBTInjector.TileEntity; +import javassist.ClassPool; +import static de.tr7zw.changeme.nbtapi.utils.MinecraftVersion.logger; + +/** + * Contains the internal methods for different Minecraft Versions of injecting + * the Entities/Tiles + * + * @author tr7zw + * + */ +@SuppressWarnings("unchecked") +public class InternalInjectors { + + private static final List skippingEntities = Arrays.asList("minecraft:player", "minecraft:fishing_bobber", + "minecraft:lightning_bolt"); // These are broken/won't work, used by 1.14+ + private static final Map classMappings = new HashMap<>(); + + static { + classMappings.put("minecraft:wandering_trader", "VillagerTrader"); + classMappings.put("minecraft:trader_llama", "LlamaTrader"); + classMappings.put("minecraft:area_effect_cloud", "AreaEffectCloud"); + classMappings.put("minecraft:donkey", "HorseDonkey"); + classMappings.put("minecraft:ender_dragon", "EnderDragon"); + classMappings.put("minecraft:skeleton_horse", "HorseSkeleton"); + classMappings.put("minecraft:fireball", "LargeFireball"); + classMappings.put("minecraft:mule", "HorseMule"); + classMappings.put("minecraft:zombie_horse", "HorseZombie"); + classMappings.put("minecraft:mooshroom", "MushroomCow"); + classMappings.put("minecraft:wither_skeleton", "SkeletonWither"); + classMappings.put("minecraft:snow_golem", "Snowman"); + classMappings.put("minecraft:polar_bear", "PolarBear"); + classMappings.put("minecraft:magma_cube", "MagmaCube"); + classMappings.put("minecraft:armor_stand", "ArmorStand"); + classMappings.put("minecraft:elder_guardian", "GuardianElder"); + classMappings.put("minecraft:zombie_pigman", "PigZombie"); + classMappings.put("minecraft:giant", "GiantZombie"); + classMappings.put("minecraft:zombie_villager", "ZombieVillager"); + classMappings.put("minecraft:husk", "ZombieHusk"); + classMappings.put("minecraft:iron_golem", "IronGolem"); + classMappings.put("minecraft:tropical_fish", "TropicalFish"); + classMappings.put("minecraft:stray", "SkeletonStray"); + classMappings.put("minecraft:illusioner", "IllagerIllusioner"); + classMappings.put("minecraft:pufferfish", "PufferFish"); + classMappings.put("minecraft:cave_spider", "CaveSpider"); + } + + /** + * Hidden constructor + */ + private InternalInjectors() { + + } + + protected static void entity1v10Below(ClassPool classPool) throws ReflectiveOperationException { + for (Map.Entry> entry : new HashSet<>(Entity.getCMap().entrySet())) { + try { + if (INBTWrapper.class.isAssignableFrom(entry.getValue())) { + continue; + } // Already injected + int entityId = Entity.getFMap().get(entry.getValue()); + + Class wrapped = ClassGenerator.wrapEntity(classPool, entry.getValue(), "__extraData"); + Entity.getCMap().put(entry.getKey(), wrapped); + Entity.getDMap().put(wrapped, entry.getKey()); + + Entity.getEMap().put(entityId, wrapped); + Entity.getFMap().put(wrapped, entityId); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + entry.getKey(), e); + } + } + } + + protected static void entity1v12Below(ClassPool classPool) throws ReflectiveOperationException { + Object registry = Entity.getRegistry(); + Map inverse = new HashMap<>(); + Set it = new HashSet<>((Set) ReflectionMethod.REGISTRY_KEYSET.run(registry)); + Object registryId = Entity.getRegistryId(registry); + for (Object mckey : it) { + Class entclass = (Class) ReflectionMethod.REGISTRY_GET.run(registry, mckey); + inverse.put(entclass, mckey); + try { + if (INBTWrapper.class.isAssignableFrom(entclass)) { + continue; + } // Already injected + Class wrapped = ClassGenerator.wrapEntity(classPool, entclass, "__extraData"); + ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped); + inverse.put(wrapped, mckey); + int id = (int) registryId.getClass().getMethod("getId", new Class[] {Object.class}).invoke(registryId, entclass); + registryId.getClass().getMethod("a", new Class[] {Object.class, int.class}).invoke(registryId, wrapped, id); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + mckey, e); + } + } + Field inverseField = registry.getClass().getDeclaredField("b"); + NBTInjector.setFinal(registry, inverseField, inverse); + } + + protected static void entity1v13Below(ClassPool classPool) throws ReflectiveOperationException { + Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null); + Set registryentries = new HashSet<>((Set) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry)); + for (Object mckey : registryentries) { + Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey); + Field supplierField = entityTypesObj.getClass().getDeclaredField("aT"); + Field classField = entityTypesObj.getClass().getDeclaredField("aS"); + classField.setAccessible(true); + supplierField.setAccessible(true); + Function function = (Function) supplierField.get(entityTypesObj); + Class nmsclass = (Class) classField.get(entityTypesObj); + try { + if (INBTWrapper.class.isAssignableFrom(nmsclass)) { + continue; + } // Already injected + Class wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData"); + NBTInjector.setFinal(entityTypesObj, classField, wrapped); + NBTInjector.setFinal(entityTypesObj, supplierField, new Function() { + + @Override + public Object apply(Object t) { + try { + return wrapped.getConstructor(ClassWrapper.NMS_WORLD.getClazz()).newInstance(t); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Error while creating custom entity instance! ", ex); + return function.apply(t);// Fallback to the original one + } + } + }); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + mckey, e); + } + } + } + + protected static void entity1v14(ClassPool classPool) throws ReflectiveOperationException { + Object entityRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("ENTITY_TYPE").get(null); + Set registryentries = new HashSet<>((Set) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(entityRegistry)); + for (Object mckey : registryentries) { + if (skippingEntities.contains(mckey.toString())) { + logger.info("Skipping, won't be able add NBT to '" + mckey + "' entities!"); + continue; + } + Object entityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(entityRegistry, mckey); + Field creatorField = entityTypesObj.getClass().getDeclaredField("aZ"); + creatorField.setAccessible(true); + Object creator = creatorField.get(entityTypesObj); + Method createEntityMethod = creator.getClass().getMethod("create", ClassWrapper.NMS_ENTITYTYPES.getClazz(), + ClassWrapper.NMS_WORLD.getClazz()); + createEntityMethod.setAccessible(true); + Class nmsclass = null; + try { + nmsclass = createEntityMethod.invoke(creator, entityTypesObj, null).getClass(); + } catch (Exception ignore) { + // ignore + } + if (nmsclass == null) { + String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + String name = mckey.toString().replace("minecraft:", ""); + name = name.substring(0, 1).toUpperCase() + name.substring(1); + name = "Entity" + name; + if (classMappings.containsKey(mckey.toString())) + name = "Entity" + classMappings.get(mckey.toString()); + try { + nmsclass = Class.forName("net.minecraft.server." + version + "." + name); + } catch (Exception ignore) { + logger.info("Not found: " + "net.minecraft.server." + version + "." + name); + // ignore + } + } + if (nmsclass == null) { + logger.info( + "Wasn't able to create an Entity instace, won't be able add NBT to '" + mckey + "' entities!"); + continue; + } + try { + if (INBTWrapper.class.isAssignableFrom(nmsclass)) { + continue; + } // Already injected + Class wrapped = ClassGenerator.wrapEntity(classPool, nmsclass, "__extraData"); + NBTInjector.setFinal(entityTypesObj, creatorField, + ClassGenerator.createEntityTypeWrapper(classPool, wrapped).newInstance()); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + mckey, e); + } + } + } + + protected static void tile1v10Below(ClassPool classPool) throws ReflectiveOperationException { + for (Map.Entry> entry : new HashSet<>(TileEntity.getFMap().entrySet())) { + try { + if (INBTWrapper.class.isAssignableFrom(entry.getValue())) { + continue; + } // Already injected + Class wrapped = ClassGenerator.wrapTileEntity(classPool, entry.getValue(), "__extraData"); + TileEntity.getFMap().put(entry.getKey(), wrapped); + TileEntity.getGMap().put(wrapped, entry.getKey()); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + entry.getKey(), e); + } + } + } + + protected static void tile1v12Below(ClassPool classPool) throws ReflectiveOperationException { + Object registry = TileEntity.getRegistry(); + Map inverse = new HashMap<>(); + Set it = new HashSet<>((Set) ReflectionMethod.REGISTRY_KEYSET.run(registry)); + for (Object mckey : it) { + Class tileclass = (Class) ReflectionMethod.REGISTRY_GET.run(registry, mckey); + inverse.put(tileclass, mckey); + try { + if (INBTWrapper.class.isAssignableFrom(tileclass)) { + continue; + } // Already injected + Class wrapped = ClassGenerator.wrapTileEntity(classPool, tileclass, "__extraData"); + ReflectionMethod.REGISTRY_SET.run(registry, mckey, wrapped); + inverse.put(wrapped, mckey); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + mckey, e); + } + } + Field inverseField = registry.getClass().getDeclaredField("b"); + NBTInjector.setFinal(registry, inverseField, inverse); + } + + protected static void tile1v13(ClassPool classPool) throws ReflectiveOperationException { + Object tileRegistry = ClassWrapper.NMS_IREGISTRY.getClazz().getField("BLOCK_ENTITY_TYPE").get(null); + Set registryentries = new HashSet<>((Set) ReflectionMethod.REGISTRYMATERIALS_KEYSET.run(tileRegistry)); + for (Object mckey : registryentries) { + Object tileEntityTypesObj = ReflectionMethod.REGISTRYMATERIALS_GET.run(tileRegistry, mckey); + String supplierFieldName = "A"; + if (MinecraftVersion.getVersion().getVersionId() >= MinecraftVersion.MC1_14_R1.getVersionId()) + supplierFieldName = "H"; + Field supplierField = tileEntityTypesObj.getClass().getDeclaredField(supplierFieldName); + supplierField.setAccessible(true); + Supplier supplier = (Supplier) supplierField.get(tileEntityTypesObj); + Class nmsclass = supplier.get().getClass(); + try { + if (INBTWrapper.class.isAssignableFrom(nmsclass)) { + continue; + } // Already injected + Class wrapped = ClassGenerator.wrapTileEntity(classPool, nmsclass, "__extraData"); + NBTInjector.setFinal(tileEntityTypesObj, supplierField, new Supplier() { + @Override + public Object get() { + try { + return wrapped.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + logger.log(Level.SEVERE, "Error while creating custom tile instance! ", e); + return supplier.get(); // Use the original one as fallback + } + } + }); + } catch (Exception e) { + throw new NbtApiException("Exception while injecting " + mckey, e); + } + } + } + +} diff --git a/nbt-injector/src/main/java/de/tr7zw/nbtinjector/NBTInjector.java b/nbt-injector/src/main/java/de/tr7zw/nbtinjector/NBTInjector.java index ad03ab912..762b2ddc5 100644 --- a/nbt-injector/src/main/java/de/tr7zw/nbtinjector/NBTInjector.java +++ b/nbt-injector/src/main/java/de/tr7zw/nbtinjector/NBTInjector.java @@ -36,6 +36,7 @@ private NBTInjector() { } static Logger logger = Logger.getLogger("NBTInjector"); + private static boolean isInjected = false; /** * Replaces the vanilla classes with Wrapped classes that support custom NBT. @@ -44,6 +45,8 @@ private NBTInjector() { * this method so it's class gets Wrapped. */ public static void inject() { + if(isInjected)return; + isInjected = true; try { ClassPool classPool = ClassPool.getDefault(); logger.info("[NBTINJECTOR] Injecting Entity classes..."); @@ -70,6 +73,10 @@ public static void inject() { } } + public static boolean isInjected() { + return isInjected; + } + private static NBTCompound getNbtData(Object object) { if (object instanceof INBTWrapper) { return ((INBTWrapper) object).getNbtData(); @@ -109,7 +116,7 @@ public static org.bukkit.entity.Entity patchEntity(org.bukkit.entity.Entity enti String id = ""; if (MinecraftVersion.getVersion().getVersionId() <= MinecraftVersion.MC1_10_R1.getVersionId()) { id = Entity.getBackupMap().get(ent.getClass()); - } else if (MinecraftVersion.getVersion().getVersionId() <= MinecraftVersion.MC1_13_R1.getVersionId()) { + } else if (MinecraftVersion.getVersion().getVersionId() <= MinecraftVersion.MC1_13_R2.getVersionId()) { id = ReflectionMethod.REGISTRY_GET_INVERSE.run(Entity.getRegistry(), ent.getClass()).toString(); } else { id = (String) ReflectionMethod.NMS_ENTITY_GETSAVEID.run(ent); @@ -245,6 +252,10 @@ private Entity() { static Object getRegistry() throws ReflectiveOperationException { return getAccessable(ClassWrapper.NMS_ENTITYTYPES.getClazz().getDeclaredField("b")).get(null); } + + static Object getRegistryId(Object reg) throws ReflectiveOperationException { + return getAccessable(reg.getClass().getDeclaredField("a")).get(reg); + } static Map, String> getBackupMap() throws ReflectiveOperationException { return backupMap; diff --git a/pom.xml b/pom.xml index 8eaca74f0..7709df105 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 de.tr7zw item-nbt-parent - 2.0.0 + 2.1.0 pom item-nbt-api