Skip to content

Instantly share code, notes, and snippets.

@nahkd123
Created August 5, 2024 18:22
Show Gist options
  • Save nahkd123/963ed9c332cde836996d01a8dcbdbb68 to your computer and use it in GitHub Desktop.
Save nahkd123/963ed9c332cde836996d01a8dcbdbb68 to your computer and use it in GitHub Desktop.
Item NBT manipulation with NMS for Bukkit 1.12.2. PersistentDataContainer should be used whenever possible. Only use this if you really need to store custom data to item on legacy versions. Alternatively, you can use latest version.
/*
* Licensed under MIT license.
*/
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.UUID;
import java.lang.invoke.MethodHandles.Lookup;
import org.bukkit.inventory.ItemStack;
// Torture.
// Please use 1.16+.
public final class LegacyNMS {
private static final String CRAFTBUKKIT = "org.bukkit.craftbukkit.v1_12_R1";
private static final String NMS = "net.minecraft.server.v1_12_R1";
private static boolean initialized = false;
private static Class<?> CraftItemStack;
private static Class<?> NMS$ItemStack;
private static Class<?> NMS$NBTBase;
private static Class<?> NMS$NBTTagString;
private static Class<?> NMS$NBTTagCompound;
private static Class<?> NMS$NBTTagList;
private static MethodHandle CraftItemStack$asNMSCopy;
private static MethodHandle CraftItemStack$asBukkitCopy;
private static MethodHandle NMS$ItemStack$hasTag;
private static MethodHandle NMS$ItemStack$getTag;
private static MethodHandle NMS$ItemStack$setTag;
private static MethodHandle NMS$NBTTagString$NBTTagString;
private static MethodHandle NMS$NBTTagString$getContent;
private static MethodHandle NMS$NBTTagCompound$NBTTagCompound;
private static MethodHandle NMS$NBTTagCompound$set;
private static MethodHandle NMS$NBTTagCompound$setByte;
private static MethodHandle NMS$NBTTagCompound$setShort;
private static MethodHandle NMS$NBTTagCompound$setInt;
private static MethodHandle NMS$NBTTagCompound$setLong;
private static MethodHandle NMS$NBTTagCompound$setFloat;
private static MethodHandle NMS$NBTTagCompound$setDouble;
private static MethodHandle NMS$NBTTagCompound$setUUID;
private static MethodHandle NMS$NBTTagCompound$setString;
private static MethodHandle NMS$NBTTagCompound$get;
private static MethodHandle NMS$NBTTagCompound$getByte;
private static MethodHandle NMS$NBTTagCompound$getShort;
private static MethodHandle NMS$NBTTagCompound$getInt;
private static MethodHandle NMS$NBTTagCompound$getLong;
private static MethodHandle NMS$NBTTagCompound$getFloat;
private static MethodHandle NMS$NBTTagCompound$getDouble;
private static MethodHandle NMS$NBTTagCompound$getUUID;
private static MethodHandle NMS$NBTTagCompound$getString;
private static MethodHandle NMS$NBTTagCompound$hasKey;
private static MethodHandle NMS$NBTTagCompound$remove;
private static MethodHandle NMS$NBTTagList$NBTTagList;
private static MethodHandle NMS$NBTTagList$add;
private static MethodHandle NMS$NBTTagList$size;
private static MethodHandle NMS$NBTTagList$remove;
private static MethodHandle NMS$NBTTagList$get;
private static MethodHandle NMS$NBTTagList$set;
public static void initialize() {
if (initialized) return;
try {
Lookup lookup = MethodHandles.publicLookup();
CraftItemStack = Class.forName(CRAFTBUKKIT + ".inventory.CraftItemStack");
NMS$ItemStack = Class.forName(NMS + ".ItemStack");
NMS$NBTBase = Class.forName(NMS + ".NBTBase");
NMS$NBTTagString = Class.forName(NMS + ".NBTTagString");
NMS$NBTTagCompound = Class.forName(NMS + ".NBTTagCompound");
NMS$NBTTagList = Class.forName(NMS + ".NBTTagList");
CraftItemStack$asNMSCopy = lookup.findStatic(CraftItemStack, "asNMSCopy", MethodType.methodType(NMS$ItemStack, ItemStack.class));
CraftItemStack$asBukkitCopy = lookup.findStatic(CraftItemStack, "asBukkitCopy", MethodType.methodType(ItemStack.class, NMS$ItemStack));
NMS$ItemStack$hasTag = lookup.findVirtual(NMS$ItemStack, "hasTag", MethodType.methodType(boolean.class));
NMS$ItemStack$getTag = lookup.findVirtual(NMS$ItemStack, "getTag", MethodType.methodType(NMS$NBTTagCompound));
NMS$ItemStack$setTag = lookup.findVirtual(NMS$ItemStack, "setTag", MethodType.methodType(void.class, NMS$NBTTagCompound));
NMS$NBTTagString$NBTTagString = lookup.findConstructor(NMS$NBTTagString, MethodType.methodType(void.class, String.class));
NMS$NBTTagString$getContent = lookup.findVirtual(NMS$NBTTagString, "c_", MethodType.methodType(String.class));
NMS$NBTTagCompound$NBTTagCompound = lookup.findConstructor(NMS$NBTTagCompound, MethodType.methodType(void.class));
NMS$NBTTagCompound$set = lookup.findVirtual(NMS$NBTTagCompound, "set", MethodType.methodType(void.class, String.class, NMS$NBTBase));
NMS$NBTTagCompound$setByte = lookup.findVirtual(NMS$NBTTagCompound, "setByte", MethodType.methodType(void.class, String.class, byte.class));
NMS$NBTTagCompound$setShort = lookup.findVirtual(NMS$NBTTagCompound, "setShort", MethodType.methodType(void.class, String.class, short.class));
NMS$NBTTagCompound$setInt = lookup.findVirtual(NMS$NBTTagCompound, "setInt", MethodType.methodType(void.class, String.class, int.class));
NMS$NBTTagCompound$setLong = lookup.findVirtual(NMS$NBTTagCompound, "setLong", MethodType.methodType(void.class, String.class, long.class));
NMS$NBTTagCompound$setFloat = lookup.findVirtual(NMS$NBTTagCompound, "setFloat", MethodType.methodType(void.class, String.class, float.class));
NMS$NBTTagCompound$setDouble = lookup.findVirtual(NMS$NBTTagCompound, "setDouble", MethodType.methodType(void.class, String.class, double.class));
NMS$NBTTagCompound$setUUID = lookup.findVirtual(NMS$NBTTagCompound, "setUUID", MethodType.methodType(void.class, String.class, UUID.class));
NMS$NBTTagCompound$setString = lookup.findVirtual(NMS$NBTTagCompound, "setString", MethodType.methodType(void.class, String.class, String.class));
NMS$NBTTagCompound$get = lookup.findVirtual(NMS$NBTTagCompound, "get", MethodType.methodType(NMS$NBTBase, String.class));
NMS$NBTTagCompound$getByte = lookup.findVirtual(NMS$NBTTagCompound, "getByte", MethodType.methodType(byte.class, String.class));
NMS$NBTTagCompound$getShort = lookup.findVirtual(NMS$NBTTagCompound, "getShort", MethodType.methodType(short.class, String.class));
NMS$NBTTagCompound$getInt = lookup.findVirtual(NMS$NBTTagCompound, "getInt", MethodType.methodType(int.class, String.class));
NMS$NBTTagCompound$getLong = lookup.findVirtual(NMS$NBTTagCompound, "getLong", MethodType.methodType(long.class, String.class));
NMS$NBTTagCompound$getFloat = lookup.findVirtual(NMS$NBTTagCompound, "getFloat", MethodType.methodType(float.class, String.class));
NMS$NBTTagCompound$getDouble = lookup.findVirtual(NMS$NBTTagCompound, "getDouble", MethodType.methodType(double.class, String.class));
NMS$NBTTagCompound$getUUID = lookup.findVirtual(NMS$NBTTagCompound, "getUUID", MethodType.methodType(UUID.class, String.class));
NMS$NBTTagCompound$getString = lookup.findVirtual(NMS$NBTTagCompound, "getString", MethodType.methodType(String.class, String.class));
NMS$NBTTagCompound$hasKey = lookup.findVirtual(NMS$NBTTagCompound, "hasKey", MethodType.methodType(boolean.class, String.class));
NMS$NBTTagCompound$remove = lookup.findVirtual(NMS$NBTTagCompound, "remove", MethodType.methodType(void.class, String.class));
NMS$NBTTagList$NBTTagList = lookup.findConstructor(NMS$NBTTagList, MethodType.methodType(void.class));
NMS$NBTTagList$add = lookup.findVirtual(NMS$NBTTagList, "add", MethodType.methodType(void.class, NMS$NBTBase));
NMS$NBTTagList$size = lookup.findVirtual(NMS$NBTTagList, "size", MethodType.methodType(int.class));
NMS$NBTTagList$remove = lookup.findVirtual(NMS$NBTTagList, "remove", MethodType.methodType(NMS$NBTBase, int.class));
NMS$NBTTagList$get = lookup.findVirtual(NMS$NBTTagList, "i", MethodType.methodType(NMS$NBTBase, int.class));
NMS$NBTTagList$set = lookup.findVirtual(NMS$NBTTagList, "a", MethodType.methodType(void.class, int.class, NMS$NBTBase));
initialized = true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static NMSItemStack asNMSCopy(ItemStack bukkit) {
try {
initialize();
return new NMSItemStack(CraftItemStack$asNMSCopy.invoke(bukkit));
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
public static final class NMSItemStack {
private Object nms;
private NMSItemStack(Object nms) { this.nms = nms; }
public boolean hasTag() { try { return (boolean) NMS$ItemStack$hasTag.bindTo(nms).invoke(); } catch (Throwable e) { throw new RuntimeException(e); } }
public NBTTagCompound getTag() { try { return new NBTTagCompound(NMS$ItemStack$getTag.bindTo(nms).invoke()); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setTag(NBTTagCompound tag) { try { NMS$ItemStack$setTag.bindTo(nms).invoke(tag.nms); } catch (Throwable e) { throw new RuntimeException(e); } }
public ItemStack asBukkitCopy() { try { return (ItemStack) CraftItemStack$asBukkitCopy.invoke(nms); } catch (Throwable e) { throw new RuntimeException(e); } }
}
public static interface NBTBase {
Object nms();
}
private static NBTBase wrapNMS(Object nms) {
if (nms == null) return null;
if (nms.getClass() == NMS$NBTTagString) return new NBTTagString(nms);
if (nms.getClass() == NMS$NBTTagCompound) return new NBTTagCompound(nms);
if (nms.getClass() == NMS$NBTTagList) return new NBTTagList(nms);
throw new RuntimeException("Not implemented: " + nms.getClass());
}
public static final class NBTTagString implements NBTBase {
private Object nms;
private NBTTagString(Object nms) { this.nms = nms; }
public NBTTagString(String content) { try { initialize(); this.nms = NMS$NBTTagString$NBTTagString.invoke(content); } catch (Throwable e) { throw new RuntimeException(e); } }
@Override
public Object nms() { return nms; }
public String getContent() { try { return (String) NMS$NBTTagString$getContent.bindTo(nms).invoke(); } catch (Throwable e) { throw new RuntimeException(e); } }
}
public static final class NBTTagCompound implements NBTBase {
private Object nms;
private NBTTagCompound(Object nms) { this.nms = nms; }
public NBTTagCompound() { try { initialize(); this.nms = NMS$NBTTagCompound$NBTTagCompound.invoke(); } catch (Throwable e) { throw new RuntimeException(e); } }
@Override
public Object nms() { return nms; }
public void set(String key, NBTBase value) { try { NMS$NBTTagCompound$set.bindTo(nms).invoke(key, value.nms()); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setByte(String key, byte value) { try { NMS$NBTTagCompound$setByte.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setShort(String key, short value) { try { NMS$NBTTagCompound$setShort.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setInt(String key, int value) { try { NMS$NBTTagCompound$setInt.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setLong(String key, long value) { try { NMS$NBTTagCompound$setLong.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setFloat(String key, float value) { try { NMS$NBTTagCompound$setFloat.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setDouble(String key, double value) { try { NMS$NBTTagCompound$setDouble.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setUUID(String key, UUID value) { try { NMS$NBTTagCompound$setUUID.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setString(String key, String value) { try { NMS$NBTTagCompound$setString.bindTo(nms).invoke(key, value); } catch (Throwable e) { throw new RuntimeException(e); } }
public void setCompound(String key, NBTTagCompound value) { try { NMS$NBTTagCompound$set.bindTo(nms).invoke(key, value.nms); } catch (Throwable e) { throw new RuntimeException(e); } }
public NBTBase get(String key) { try { return wrapNMS(NMS$NBTTagCompound$get.bindTo(nms).invoke(key)); } catch (Throwable e) { throw new RuntimeException(e); } }
public byte getByte(String key) { try { return (byte) NMS$NBTTagCompound$getByte.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public short getShort(String key) { try { return (short) NMS$NBTTagCompound$getShort.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public int getInt(String key) { try { return (int) NMS$NBTTagCompound$getInt.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public long getLong(String key) { try { return (long) NMS$NBTTagCompound$getLong.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public float getFloat(String key) { try { return (float) NMS$NBTTagCompound$getFloat.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public double getDouble(String key) { try { return (double) NMS$NBTTagCompound$getDouble.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public UUID getUUID(String key) { try { return (UUID) NMS$NBTTagCompound$getUUID.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public String getString(String key) { try { return (String) NMS$NBTTagCompound$getString.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public NBTTagCompound getCompound(String key) { try { return has(key) ? new NBTTagCompound(NMS$NBTTagCompound$get.bindTo(nms).invoke(key)) : null; } catch (Throwable e) { throw new RuntimeException(e); } }
public boolean has(String key) { try { return (boolean) NMS$NBTTagCompound$hasKey.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
public void remove(String key) { try { NMS$NBTTagCompound$remove.bindTo(nms).invoke(key); } catch (Throwable e) { throw new RuntimeException(e); } }
}
public static final class NBTTagList implements NBTBase {
private Object nms;
private NBTTagList(Object nms) { this.nms = nms; }
public NBTTagList() { try { initialize(); this.nms = NMS$NBTTagList$NBTTagList.invoke(); } catch (Throwable e) { throw new RuntimeException(e); } }
@Override
public Object nms() { return nms; }
public void add(NBTBase value) { try { NMS$NBTTagList$add.bindTo(nms).invoke(value.nms()); } catch (Throwable e) { throw new RuntimeException(e); } }
public int size() { try { return (int) NMS$NBTTagList$size.bindTo(nms).invoke(); } catch (Throwable e) { throw new RuntimeException(e); } }
public NBTBase remove(int index) { try { return wrapNMS(NMS$NBTTagList$remove.bindTo(nms).invoke(index)); } catch (Throwable e) { throw new RuntimeException(e); } }
public NBTBase get(int index) { try { return wrapNMS(NMS$NBTTagList$get.bindTo(nms).invoke(index)); } catch (Throwable e) { throw new RuntimeException(e); } }
public void set(int index, NBTBase value) { try { NMS$NBTTagList$set.bindTo(nms).invoke(index, value.nms()); } catch (Throwable e) { throw new RuntimeException(e); } }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment