Skip to content

Commit 78ac27d

Browse files
Add NBT for menu item
Add NBT for menu item checking and safer (if not any) menu item execution
1 parent 01fee2e commit 78ac27d

File tree

3 files changed

+429
-0
lines changed

3 files changed

+429
-0
lines changed
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
package me.flame.menus.components.nbt;
2+
3+
import org.bukkit.Bukkit;
4+
import org.bukkit.Material;
5+
import org.bukkit.inventory.ItemStack;
6+
import org.jetbrains.annotations.NotNull;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
import java.lang.reflect.Constructor;
10+
import java.lang.reflect.InvocationTargetException;
11+
import java.lang.reflect.Method;
12+
import java.util.Objects;
13+
14+
/**
15+
* Class to set / get NBT tags from items.
16+
* I hate this class.
17+
*/
18+
public final class LegacyNbt implements NbtWrapper {
19+
20+
public static final String PACKAGE_NAME = Bukkit.getServer().getClass().getPackage().getName();
21+
public static final String NMS_VERSION = PACKAGE_NAME.substring(PACKAGE_NAME.lastIndexOf(46) + 1);
22+
23+
private static Method getStringMethod;
24+
private static Method setStringMethod;
25+
private static Method setBooleanMethod;
26+
private static Method hasTagMethod;
27+
private static Method getTagMethod;
28+
private static Method setTagMethod;
29+
private static Method removeTagMethod;
30+
private static Method asNMSCopyMethod;
31+
private static Method asBukkitCopyMethod;
32+
33+
private static final Material AIR = Material.AIR;
34+
35+
private static Constructor<?> nbtCompoundConstructor;
36+
37+
static {
38+
try {
39+
getStringMethod = Objects.requireNonNull(getNMSClass("NBTTagCompound")).getMethod("getString", String.class);
40+
removeTagMethod = Objects.requireNonNull(getNMSClass("NBTTagCompound")).getMethod("remove", String.class);
41+
setStringMethod = Objects.requireNonNull(getNMSClass("NBTTagCompound")).getMethod("setString", String.class, String.class);
42+
setBooleanMethod = Objects.requireNonNull(getNMSClass("NBTTagCompound")).getMethod("setBoolean", String.class, boolean.class);
43+
hasTagMethod = Objects.requireNonNull(getNMSClass("ItemStack")).getMethod("hasTag");
44+
getTagMethod = Objects.requireNonNull(getNMSClass("ItemStack")).getMethod("getTag");
45+
setTagMethod = Objects.requireNonNull(getNMSClass("ItemStack")).getMethod("setTag", getNMSClass("NBTTagCompound"));
46+
nbtCompoundConstructor = Objects.requireNonNull(getNMSClass("NBTTagCompound")).getDeclaredConstructor();
47+
asNMSCopyMethod = Objects.requireNonNull(getCraftItemStackClass()).getMethod("asNMSCopy", ItemStack.class);
48+
asBukkitCopyMethod = Objects.requireNonNull(getCraftItemStackClass()).getMethod("asBukkitCopy", getNMSClass("ItemStack"));
49+
} catch (NoSuchMethodException e) {
50+
e.printStackTrace();
51+
}
52+
}
53+
54+
/**
55+
* Sets an NBT tag to the an {@link ItemStack}.
56+
*
57+
* @param itemStack The current {@link ItemStack} to be set.
58+
* @param key The NBT key to use.
59+
* @param value The tag value to set.
60+
* @return An {@link ItemStack} that has NBT set.
61+
*/
62+
@Override
63+
public ItemStack setString(@NotNull final ItemStack itemStack, final String key, final String value) {
64+
if (itemStack.getType() == AIR) return itemStack;
65+
66+
Object nmsItemStack = asNMSCopy(itemStack);
67+
Object itemCompound = hasTag(nmsItemStack) ? getTag(nmsItemStack) : newNBTTagCompound();
68+
69+
setString(itemCompound, key, value);
70+
setTag(nmsItemStack, itemCompound);
71+
72+
return asBukkitCopy(nmsItemStack);
73+
}
74+
75+
/**
76+
* Removes a tag from an {@link ItemStack}.
77+
*
78+
* @param itemStack The current {@link ItemStack} to be removed.
79+
* @param key The NBT key to remove.
80+
* @return An {@link ItemStack} that has the tag removed.
81+
*/
82+
@Override
83+
public ItemStack removeTag(@NotNull final ItemStack itemStack, final String key) {
84+
if (itemStack.getType() == AIR) return itemStack;
85+
86+
Object nmsItemStack = asNMSCopy(itemStack);
87+
Object itemCompound = hasTag(nmsItemStack) ? getTag(nmsItemStack) : newNBTTagCompound();
88+
89+
remove(itemCompound, key);
90+
setTag(nmsItemStack, itemCompound);
91+
92+
return asBukkitCopy(nmsItemStack);
93+
}
94+
95+
/**
96+
* Sets a boolean to the {@link ItemStack}.
97+
* Mainly used for setting an item to be unbreakable on older versions.
98+
*
99+
* @param itemStack The {@link ItemStack} to set the boolean to.
100+
* @param key The key to use.
101+
* @param value The boolean value.
102+
* @return An {@link ItemStack} with a boolean value set.
103+
*/
104+
@Override
105+
public ItemStack setBoolean(@NotNull final ItemStack itemStack, final String key, final boolean value) {
106+
if (itemStack.getType() == AIR) return itemStack;
107+
108+
Object nmsItemStack = asNMSCopy(itemStack);
109+
Object itemCompound = hasTag(nmsItemStack) ? getTag(nmsItemStack) : newNBTTagCompound();
110+
111+
setBoolean(itemCompound, key, value);
112+
setTag(nmsItemStack, itemCompound);
113+
114+
return asBukkitCopy(nmsItemStack);
115+
}
116+
117+
/**
118+
* Gets the NBT tag based on a given key.
119+
*
120+
* @param itemStack The {@link ItemStack} to get from.
121+
* @param key The key to look for.
122+
* @return The tag that was stored in the {@link ItemStack}.
123+
*/
124+
@Nullable
125+
@Override
126+
public String getString(@NotNull final ItemStack itemStack, final String key) {
127+
if (itemStack.getType() == AIR) return null;
128+
129+
Object nmsItemStack = asNMSCopy(itemStack);
130+
Object itemCompound = hasTag(nmsItemStack) ? getTag(nmsItemStack) : newNBTTagCompound();
131+
132+
return getString(itemCompound, key);
133+
}
134+
135+
/**
136+
* Mimics the itemCompound#setString method.
137+
*
138+
* @param itemCompound The ItemCompound.
139+
* @param key The key to add.
140+
* @param value The value to add.
141+
*/
142+
private static void setString(final Object itemCompound, final String key, final String value) {
143+
try {
144+
setStringMethod.invoke(itemCompound, key, value);
145+
} catch (IllegalAccessException | InvocationTargetException ignored) {
146+
}
147+
}
148+
149+
private static void setBoolean(final Object itemCompound, final String key, final boolean value) {
150+
try {
151+
setBooleanMethod.invoke(itemCompound, key, value);
152+
} catch (IllegalAccessException | InvocationTargetException ignored) {
153+
}
154+
}
155+
156+
/**
157+
* Mimics the itemCompound#remove method.
158+
*
159+
* @param itemCompound The ItemCompound.
160+
* @param key The key to remove.
161+
*/
162+
private static void remove(final Object itemCompound, final String key) {
163+
try {
164+
removeTagMethod.invoke(itemCompound, key);
165+
} catch (IllegalAccessException | InvocationTargetException ignored) {
166+
}
167+
}
168+
169+
/**
170+
* Mimics the itemCompound#getString method.
171+
*
172+
* @param itemCompound The ItemCompound.
173+
* @param key The key to get from.
174+
* @return A string with the value from the key.
175+
*/
176+
private static String getString(final Object itemCompound, final String key) {
177+
try {
178+
return (String) getStringMethod.invoke(itemCompound, key);
179+
} catch (IllegalAccessException | InvocationTargetException e) {
180+
return null;
181+
}
182+
}
183+
184+
/**
185+
* Mimics the nmsItemStack#hasTag method.
186+
*
187+
* @param nmsItemStack the NMS ItemStack to check from.
188+
* @return True or false depending on if it has tag or not.
189+
*/
190+
private static boolean hasTag(final Object nmsItemStack) {
191+
try {
192+
return (boolean) hasTagMethod.invoke(nmsItemStack);
193+
} catch (IllegalAccessException | InvocationTargetException e) {
194+
return false;
195+
}
196+
}
197+
198+
/**
199+
* Mimics the nmsItemStack#getTag method.
200+
*
201+
* @param nmsItemStack The NMS ItemStack to get from.
202+
* @return The tag compound.
203+
*/
204+
public static Object getTag(final Object nmsItemStack) {
205+
try {
206+
return getTagMethod.invoke(nmsItemStack);
207+
} catch (IllegalAccessException | InvocationTargetException e) {
208+
return null;
209+
}
210+
}
211+
212+
/**
213+
* Mimics the nmsItemStack#setTag method.
214+
*
215+
* @param nmsItemStack the NMS ItemStack to set the tag to.
216+
* @param itemCompound The item compound to set.
217+
*/
218+
private static void setTag(final Object nmsItemStack, final Object itemCompound) {
219+
try {
220+
setTagMethod.invoke(nmsItemStack, itemCompound);
221+
} catch (IllegalAccessException | InvocationTargetException ignored) {
222+
}
223+
}
224+
225+
/**
226+
* Mimics the new NBTTagCompound instantiation.
227+
*
228+
* @return The new NBTTagCompound.
229+
*/
230+
private static Object newNBTTagCompound() {
231+
try {
232+
return nbtCompoundConstructor.newInstance();
233+
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
234+
return null;
235+
}
236+
}
237+
238+
/**
239+
* Mimics the CraftItemStack#asNMSCopy method.
240+
*
241+
* @param itemStack The ItemStack to make NMS copy.
242+
* @return An NMS copy of the ItemStack.
243+
*/
244+
public static Object asNMSCopy(final ItemStack itemStack) {
245+
try {
246+
return asNMSCopyMethod.invoke(null, itemStack);
247+
} catch (IllegalAccessException | InvocationTargetException e) {
248+
return null;
249+
}
250+
}
251+
252+
/**
253+
* Mimics the CraftItemStack#asBukkitCopy method.
254+
*
255+
* @param nmsItemStack The NMS ItemStack to turn into {@link ItemStack}.
256+
* @return The new {@link ItemStack}.
257+
*/
258+
public static ItemStack asBukkitCopy(final Object nmsItemStack) {
259+
try {
260+
return (ItemStack) asBukkitCopyMethod.invoke(null, nmsItemStack);
261+
} catch (IllegalAccessException | InvocationTargetException e) {
262+
return null;
263+
}
264+
}
265+
266+
/**
267+
* Gets the NMS class from class name.
268+
*
269+
* @return The NMS class.
270+
*/
271+
private static Class<?> getNMSClass(final String className) {
272+
try {
273+
return Class.forName("net.minecraft.server." + NMS_VERSION + "." + className);
274+
} catch (ClassNotFoundException e) {
275+
return null;
276+
}
277+
}
278+
279+
/**
280+
* Gets the NMS craft {@link ItemStack} class from class name.
281+
*
282+
* @return The NMS craft {@link ItemStack} class.
283+
*/
284+
private static Class<?> getCraftItemStackClass() {
285+
try {
286+
return Class.forName("org.bukkit.craftbukkit." + NMS_VERSION + ".inventory.CraftItemStack");
287+
} catch (ClassNotFoundException e) {
288+
return null;
289+
}
290+
}
291+
292+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package me.flame.menus.components.nbt;
2+
3+
import org.bukkit.inventory.ItemStack;
4+
import org.jetbrains.annotations.NotNull;
5+
import org.jetbrains.annotations.Nullable;
6+
7+
public interface NbtWrapper {
8+
9+
/**
10+
* Sets an String NBT tag to the an {@link ItemStack}.
11+
*
12+
* @param itemStack The current {@link ItemStack} to be set.
13+
* @param key The NBT key to use.
14+
* @param value The tag value to set.
15+
* @return An {@link ItemStack} that has NBT set.
16+
*/
17+
ItemStack setString(@NotNull final ItemStack itemStack, final String key, final String value);
18+
19+
/**
20+
* Removes a tag from an {@link ItemStack}.
21+
*
22+
* @param itemStack The current {@link ItemStack} to be remove.
23+
* @param key The NBT key to remove.
24+
* @return An {@link ItemStack} that has the tag removed.
25+
*/
26+
ItemStack removeTag(@NotNull final ItemStack itemStack, final String key);
27+
28+
/**
29+
* Sets a boolean to the {@link ItemStack}.
30+
* Mainly used for setting an item to be unbreakable on older versions.
31+
*
32+
* @param itemStack The {@link ItemStack} to set the boolean to.
33+
* @param key The key to use.
34+
* @param value The boolean value.
35+
* @return An {@link ItemStack} with a boolean value set.
36+
*/
37+
ItemStack setBoolean(@NotNull final ItemStack itemStack, final String key, final boolean value);
38+
39+
/**
40+
* Gets the NBT tag based on a given key.
41+
*
42+
* @param itemStack The {@link ItemStack} to get from.
43+
* @param key The key to look for.
44+
* @return The tag that was stored in the {@link ItemStack}.
45+
*/
46+
@Nullable
47+
String getString(@NotNull final ItemStack itemStack, final String key);
48+
49+
}

0 commit comments

Comments
 (0)