Skip to content

Commit f60ef7e

Browse files
committed
Fix RecipeIterator error when not available for the MC version
1 parent 1735918 commit f60ef7e

3 files changed

Lines changed: 176 additions & 64 deletions

File tree

core/src/main/java/com/wolfyscript/utilities/bukkit/nms/fallback/FallbackRecipeUtilImpl.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,15 @@
2121
import me.wolfyscript.utilities.api.nms.NMSUtil;
2222
import me.wolfyscript.utilities.api.nms.inventory.RecipeType;
2323
import me.wolfyscript.utilities.util.NamespacedKey;
24-
import me.wolfyscript.utilities.util.Reflection;
2524
import org.bukkit.inventory.Inventory;
2625
import org.bukkit.inventory.InventoryView;
2726
import org.bukkit.inventory.Recipe;
2827
import org.jetbrains.annotations.NotNull;
2928

30-
import java.lang.reflect.Field;
31-
import java.lang.reflect.Method;
3229
import java.util.Iterator;
3330

34-
import static me.wolfyscript.utilities.util.Reflection.NMSMapping.of;
35-
3631
public class FallbackRecipeUtilImpl extends me.wolfyscript.utilities.api.nms.RecipeUtil {
3732

38-
static Class<?> MINECRAFT_SERVER_CLASS = Reflection.getNMS("server.MinecraftServer");
39-
static Class<?> RECIPE_HOLDER = Reflection.getNMS("world.item.crafting.RecipeHolder");
40-
static Class<?> RECIPE_MANAGER = Reflection.getNMS("world.item.crafting", of("CraftingManager").mojang("RecipeManager"));
41-
static Class<?> RECIPE_TYPE = Reflection.getNMS("world.item.crafting", of("Recipes").mojang("RecipeType"));
42-
static Class<?> BUILT_IN_REGISTRIES = Reflection.getNMS("core.registries.BuiltInRegistries");
43-
static Class<?> REGISTRY = Reflection.getNMS("core", of("IRegistry").mojang("Registry"));
44-
static Class<?> RESOURCE_LOCATION = Reflection.getNMS("resources", of("MinecraftKey").mojang("ResourceLocation"));
45-
46-
static Method GET_SERVER = Reflection.getDeclaredMethod(false, MINECRAFT_SERVER_CLASS, "getServer");
47-
static Method GET_RECIPE_MANAGER = Reflection.getDeclaredMethod(false, MINECRAFT_SERVER_CLASS, of("aJ").mojang("getRecipeManager").get());
48-
static Method GET_ALL_RECIPES_FOR = Reflection.getDeclaredMethod(false, RECIPE_MANAGER, of("a").mojang("getAllRecipesFor").get(), RECIPE_TYPE);
49-
static Method TO_BUKKIT_RECIPE = Reflection.getDeclaredMethod(false, RECIPE_HOLDER, "toBukkitRecipe");
50-
static Method GET_RECIPE_TYPE_FROM_REGISTRY = Reflection.getDeclaredMethod(false, REGISTRY, of("a").mojang("get").get(), RESOURCE_LOCATION);
51-
52-
static Field RECIPE_TYPE_REGISTRY = Reflection.getDeclaredField(BUILT_IN_REGISTRIES, of("q").mojang("RECIPE_TYPE").get());
53-
54-
static Method RESOURCE_LOCATION_CREATOR = Reflection.getDeclaredMethod(false, RESOURCE_LOCATION, of("a").mojang("of").get(), String.class, Character.TYPE);
55-
5633
protected FallbackRecipeUtilImpl(NMSUtil nmsUtil) {
5734
super(nmsUtil);
5835
}

core/src/main/java/com/wolfyscript/utilities/bukkit/nms/fallback/RecipeIterator.java

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,70 @@
1919
package com.wolfyscript.utilities.bukkit.nms.fallback;
2020

2121
import me.wolfyscript.utilities.api.nms.inventory.RecipeType;
22+
import me.wolfyscript.utilities.util.Reflection;
2223
import org.bukkit.inventory.Recipe;
2324

25+
import java.lang.reflect.Field;
2426
import java.lang.reflect.InvocationTargetException;
27+
import java.lang.reflect.Method;
2528
import java.util.Collections;
2629
import java.util.Iterator;
2730
import java.util.List;
31+
import java.util.NoSuchElementException;
32+
33+
import static me.wolfyscript.utilities.util.Reflection.NMSMapping.of;
2834

2935
public class RecipeIterator implements Iterator<org.bukkit.inventory.Recipe> {
3036

37+
static boolean failedToInitialize = false;
38+
39+
static Class<?> MINECRAFT_SERVER_CLASS;
40+
static Class<?> RECIPE_HOLDER;
41+
static Class<?> RECIPE_MANAGER;
42+
static Class<?> RECIPE_TYPE;
43+
static Class<?> BUILT_IN_REGISTRIES;
44+
static Class<?> REGISTRY;
45+
static Class<?> RESOURCE_LOCATION;
46+
static Method GET_SERVER;
47+
static Method GET_RECIPE_MANAGER;
48+
static Method GET_ALL_RECIPES_FOR;
49+
static Method TO_BUKKIT_RECIPE;
50+
static Method GET_RECIPE_TYPE_FROM_REGISTRY;
51+
static Field RECIPE_TYPE_REGISTRY;
52+
static Method RESOURCE_LOCATION_CREATOR;
53+
54+
static {
55+
try {
56+
MINECRAFT_SERVER_CLASS = Reflection.getNMSUnsafe("server.MinecraftServer");
57+
RECIPE_HOLDER = Reflection.getNMSUnsafe("world.item.crafting.RecipeHolder");
58+
RECIPE_MANAGER = Reflection.getNMSUnsafe("world.item.crafting", of("CraftingManager").mojang("RecipeManager"));
59+
RECIPE_TYPE = Reflection.getNMSUnsafe("world.item.crafting", of("Recipes").mojang("RecipeType"));
60+
BUILT_IN_REGISTRIES = Reflection.getNMSUnsafe("core.registries.BuiltInRegistries");
61+
REGISTRY = Reflection.getNMSUnsafe("core", of("IRegistry").mojang("Registry"));
62+
RESOURCE_LOCATION = Reflection.getNMSUnsafe("resources", of("MinecraftKey").mojang("ResourceLocation"));
63+
64+
GET_SERVER = Reflection.getDeclaredMethodUnsafe(MINECRAFT_SERVER_CLASS, "getServer");
65+
GET_RECIPE_MANAGER = Reflection.getDeclaredMethodUnsafe(MINECRAFT_SERVER_CLASS, of("aJ").mojang("getRecipeManager").get());
66+
GET_ALL_RECIPES_FOR = Reflection.getDeclaredMethodUnsafe(RECIPE_MANAGER, of("a").mojang("getAllRecipesFor").get(), RECIPE_TYPE);
67+
TO_BUKKIT_RECIPE = Reflection.getDeclaredMethodUnsafe(RECIPE_HOLDER, "toBukkitRecipe");
68+
GET_RECIPE_TYPE_FROM_REGISTRY = Reflection.getDeclaredMethodUnsafe(REGISTRY, of("a").mojang("get").get(), RESOURCE_LOCATION);
69+
70+
RECIPE_TYPE_REGISTRY = Reflection.getDeclaredFieldUnsafe(BUILT_IN_REGISTRIES, of("q").mojang("RECIPE_TYPE").get());
71+
72+
RESOURCE_LOCATION_CREATOR = Reflection.getDeclaredMethodUnsafe(RESOURCE_LOCATION, of("a").mojang("of").get(), String.class, Character.TYPE);
73+
} catch (Exception e) {
74+
// Fallback to empty iterator when it fails to find methods using reflection
75+
failedToInitialize = true;
76+
}
77+
}
78+
3179
private final Iterator<?> recipes; // List of RecipeHolder instances
3280

3381
public RecipeIterator(RecipeType recipeType) {
82+
if (failedToInitialize) {
83+
this.recipes = Collections.emptyIterator();
84+
return;
85+
}
3486
Iterator<?> iterator;
3587
try {
3688
iterator = getRecipesFor(recipeType).iterator();
@@ -42,14 +94,14 @@ public RecipeIterator(RecipeType recipeType) {
4294

4395
private List<?> getRecipesFor(RecipeType type) throws InvocationTargetException, IllegalAccessException, InstantiationException {
4496
// var recipeManager = MinecraftServer.getServer().getRecipeManager();
45-
var minecraftServer = FallbackRecipeUtilImpl.GET_SERVER.invoke(null);
46-
var recipeManager = FallbackRecipeUtilImpl.GET_RECIPE_MANAGER.invoke(minecraftServer);
97+
var minecraftServer = GET_SERVER.invoke(null);
98+
var recipeManager = GET_RECIPE_MANAGER.invoke(minecraftServer);
4799
// var type = BuiltInRegistries.RECIPE_TYPE.get(type.getId());
48-
var resourceLocation = FallbackRecipeUtilImpl.RESOURCE_LOCATION_CREATOR.invoke(null, type.getId(), ':');
49-
var registry = FallbackRecipeUtilImpl.RECIPE_TYPE_REGISTRY.get(null);
50-
var recipeType = FallbackRecipeUtilImpl.GET_RECIPE_TYPE_FROM_REGISTRY.invoke(registry, resourceLocation);
100+
var resourceLocation = RESOURCE_LOCATION_CREATOR.invoke(null, type.getId(), ':');
101+
var registry = RECIPE_TYPE_REGISTRY.get(null);
102+
var recipeType = GET_RECIPE_TYPE_FROM_REGISTRY.invoke(registry, resourceLocation);
51103
// List<? extends RecipeHolder<?>> recipes = recipeManager.getAllRecipesFor(type)
52-
var recipes = FallbackRecipeUtilImpl.GET_ALL_RECIPES_FOR.invoke(recipeManager, recipeType);
104+
var recipes = GET_ALL_RECIPES_FOR.invoke(recipeManager, recipeType);
53105
return (List<?>) recipes;
54106
}
55107

@@ -60,8 +112,11 @@ public boolean hasNext() {
60112

61113
@Override
62114
public org.bukkit.inventory.Recipe next() {
115+
if (failedToInitialize) {
116+
throw new NoSuchElementException();
117+
}
63118
try {
64-
return (Recipe) FallbackRecipeUtilImpl.TO_BUKKIT_RECIPE.invoke(this.recipes.next());
119+
return (Recipe) TO_BUKKIT_RECIPE.invoke(this.recipes.next());
65120
} catch (IllegalAccessException | InvocationTargetException e) {
66121
throw new RuntimeException(e);
67122
}

core/src/main/java/me/wolfyscript/utilities/util/Reflection.java

Lines changed: 114 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,16 @@ public class Reflection {
7474
private static final Map<Class<?>, Map<String, Field>> loadedDeclaredFields = new HashMap<>();
7575
private static final Map<Class<?>, Map<Class<?>, Field>> foundFields = new HashMap<>();
7676

77-
private Reflection() {}
77+
private Reflection() {
78+
}
7879

7980
/**
8081
* Gets the version from the version dependent CraftBukkit package. e.g. v1_17_R1
8182
*
8283
* @return The CraftBukkit version; empty when mojang mappings are used
8384
*/
8485
public static Optional<String> getVersion() {
85-
if(VERSION != null){
86+
if (VERSION != null) {
8687
return Optional.of(VERSION);
8788
}
8889
String[] packages = Bukkit.getServer().getClass().getPackage().getName().split("\\.");
@@ -117,6 +118,27 @@ public static synchronized Class<?> getOBC(String obcClassName) {
117118
return clazz;
118119
}
119120

121+
public static Class<?> getNMSUnsafe(String nmsClassName) throws ClassNotFoundException {
122+
if (loadedNMSClasses.containsKey(nmsClassName)) {
123+
return loadedNMSClasses.get(nmsClassName);
124+
}
125+
Class<?> clazz = Class.forName(NMS_PKG + nmsClassName);
126+
loadedNMSClasses.put(nmsClassName, clazz);
127+
return clazz;
128+
}
129+
130+
public static Class<?> getNMSUnsafe(NMSMapping mapping) throws ClassNotFoundException {
131+
return getNMSUnsafe(mapping.get());
132+
}
133+
134+
public static Class<?> getNMSUnsafe(String mojangPkg, String className) throws ClassNotFoundException {
135+
return getNMSUnsafe(mojangPkg + "." + className);
136+
}
137+
138+
public static Class<?> getNMSUnsafe(String mojangPkg, NMSMapping mapping) throws ClassNotFoundException {
139+
return getNMSUnsafe(mojangPkg, mapping.get());
140+
}
141+
120142
/**
121143
* Get an NMS Class
122144
*
@@ -127,16 +149,12 @@ public static Class<?> getNMS(String nmsClassName) {
127149
if (loadedNMSClasses.containsKey(nmsClassName)) {
128150
return loadedNMSClasses.get(nmsClassName);
129151
}
130-
String clazzName = NMS_PKG + nmsClassName;
131-
Class<?> clazz;
132152
try {
133-
clazz = Class.forName(clazzName);
153+
return getNMSUnsafe(nmsClassName);
134154
} catch (ClassNotFoundException e) {
135155
WolfyUtilCore.getInstance().getLogger().log(Level.SEVERE, "Could not get NMS Class!", e);
136156
return loadedNMSClasses.put(nmsClassName, null);
137157
}
138-
loadedNMSClasses.put(nmsClassName, clazz);
139-
return clazz;
140158
}
141159

142160
public static Class<?> getNMS(NMSMapping mapping) {
@@ -202,6 +220,25 @@ public static Constructor<?> getConstructor(@NotNull Class<?> clazz, Class<?>...
202220
}
203221
}
204222

223+
/**
224+
* Get a method from a class that has the specific parameters
225+
*
226+
* @param clazz The class we are searching
227+
* @param methodName The name of the method
228+
* @param params Any parameters that the method has
229+
* @return The method with appropriate parameters
230+
*/
231+
public static Method getMethodUnsafe(@NotNull Class<?> clazz, String methodName, Class<?>... params) throws NoSuchMethodException {
232+
Map<String, Method> methods = loadedMethods.computeIfAbsent(clazz, aClass -> new HashMap<>());
233+
if (methods.containsKey(methodName)) {
234+
return methods.get(methodName);
235+
}
236+
Method method = clazz.getMethod(methodName, params);
237+
methods.put(methodName, method);
238+
loadedMethods.put(clazz, methods);
239+
return method;
240+
}
241+
205242
/**
206243
* Get a method from a class that has the specific parameters
207244
*
@@ -223,26 +260,41 @@ public static Method getMethod(@NotNull Class<?> clazz, String methodName, Class
223260
* @return The method with appropriate parameters
224261
*/
225262
public static Method getMethod(boolean silent, @NotNull Class<?> clazz, String methodName, Class<?>... params) {
226-
loadedMethods.computeIfAbsent(clazz, aClass -> new HashMap<>());
227-
Map<String, Method> methods = loadedMethods.get(clazz);
228-
if (methods.containsKey(methodName)) {
229-
return methods.get(methodName);
230-
}
231263
try {
232-
Method method = clazz.getMethod(methodName, params);
233-
methods.put(methodName, method);
234-
loadedMethods.put(clazz, methods);
235-
return method;
264+
return getMethodUnsafe(clazz, methodName, params);
236265
} catch (Exception e) {
266+
Map<String, Method> methods = loadedMethods.get(clazz);
237267
if (!silent) {
238268
WolfyUtilCore.getInstance().getLogger().log(Level.SEVERE, "Could not find or invoke Method!", e);
239269
}
240270
methods.put(methodName, null);
271+
if (methods.containsKey(methodName)) {
272+
return methods.get(methodName);
273+
}
241274
loadedMethods.put(clazz, methods);
242275
return null;
243276
}
244277
}
245278

279+
/**
280+
* Get a declared method from a class that has the specific parameters
281+
*
282+
* @param clazz The class we are searching
283+
* @param methodName The name of the method
284+
* @param params Any parameters that the method has
285+
* @return The method with appropriate parameters
286+
*/
287+
public static Method getDeclaredMethodUnsafe(@NotNull Class<?> clazz, String methodName, Class<?>... params) throws NoSuchMethodException {
288+
Map<String, Method> methods = loadedDeclaredMethods.computeIfAbsent(clazz, aClass -> new HashMap<>());
289+
if (methods.containsKey(methodName)) {
290+
return methods.get(methodName);
291+
}
292+
Method method = clazz.getDeclaredMethod(methodName, params);
293+
methods.put(methodName, method);
294+
loadedDeclaredMethods.put(clazz, methods);
295+
return method;
296+
}
297+
246298
/**
247299
* Get a declared method from a class that has the specific parameters
248300
*
@@ -292,18 +344,50 @@ public static Method getDeclaredMethod(boolean silent, @NotNull Class<?> clazz,
292344
* @param fieldName The name of the field
293345
* @return The field object
294346
*/
295-
public static Field getField(@NotNull Class<?> clazz, String fieldName) {
296-
loadedFields.computeIfAbsent(clazz, aClass -> new HashMap<>());
297-
Map<String, Field> fields = loadedFields.get(clazz);
347+
public static Field getFieldUnsafe(@NotNull Class<?> clazz, String fieldName) throws NoSuchFieldException {
348+
Map<String, Field> fields = loadedFields.computeIfAbsent(clazz, aClass -> new HashMap<>());
349+
if (fields.containsKey(fieldName)) {
350+
return fields.get(fieldName);
351+
}
352+
Field field = clazz.getField(fieldName);
353+
fields.put(fieldName, field);
354+
loadedFields.put(clazz, fields);
355+
return field;
356+
}
357+
358+
/**
359+
* Get a declared field with a particular name from a class
360+
*
361+
* @param clazz The class
362+
* @param fieldName The name of the field
363+
* @return The field object
364+
*/
365+
public static Field getDeclaredFieldUnsafe(@NotNull Class<?> clazz, String fieldName) throws NoSuchFieldException {
366+
Map<String, Field> fields = loadedDeclaredFields.computeIfAbsent(clazz, aClass -> new HashMap<>());
298367
if (fields.containsKey(fieldName)) {
299368
return fields.get(fieldName);
300369
}
370+
Field field = clazz.getDeclaredField(fieldName);
371+
fields.put(fieldName, field);
372+
loadedDeclaredFields.put(clazz, fields);
373+
return field;
374+
}
375+
376+
/**
377+
* Get a field with a particular name from a class
378+
*
379+
* @param clazz The class
380+
* @param fieldName The name of the field
381+
* @return The field object
382+
*/
383+
public static Field getField(@NotNull Class<?> clazz, String fieldName) {
301384
try {
302-
Field field = clazz.getField(fieldName);
303-
fields.put(fieldName, field);
304-
loadedFields.put(clazz, fields);
305-
return field;
385+
return getFieldUnsafe(clazz, fieldName);
306386
} catch (Exception e) {
387+
Map<String, Field> fields = loadedFields.get(clazz);
388+
if (fields.containsKey(fieldName)) {
389+
return fields.get(fieldName);
390+
}
307391
WolfyUtilCore.getInstance().getLogger().log(Level.SEVERE, "Could not find or access field!", e);
308392
fields.put(fieldName, null);
309393
loadedFields.put(clazz, fields);
@@ -319,17 +403,13 @@ public static Field getField(@NotNull Class<?> clazz, String fieldName) {
319403
* @return The field object
320404
*/
321405
public static Field getDeclaredField(@NotNull Class<?> clazz, String fieldName) {
322-
loadedDeclaredFields.computeIfAbsent(clazz, aClass -> new HashMap<>());
323-
Map<String, Field> fields = loadedDeclaredFields.get(clazz);
324-
if (fields.containsKey(fieldName)) {
325-
return fields.get(fieldName);
326-
}
327406
try {
328-
Field field = clazz.getDeclaredField(fieldName);
329-
fields.put(fieldName, field);
330-
loadedDeclaredFields.put(clazz, fields);
331-
return field;
407+
return getDeclaredFieldUnsafe(clazz, fieldName);
332408
} catch (Exception e) {
409+
Map<String, Field> fields = loadedDeclaredFields.get(clazz);
410+
if (fields.containsKey(fieldName)) {
411+
return fields.get(fieldName);
412+
}
333413
WolfyUtilCore.getInstance().getLogger().log(Level.SEVERE, "Could not find or access field!", e);
334414
fields.put(fieldName, null);
335415
loadedDeclaredFields.put(clazz, fields);
@@ -354,8 +434,8 @@ public static Field findField(@NotNull Class<?> clazz, Class<?> type) {
354434
List<Field> allFields = new ArrayList<>();
355435
allFields.addAll(Arrays.asList(clazz.getFields()));
356436
allFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
357-
for(Field f : allFields){
358-
if(type.equals(f.getType())){
437+
for (Field f : allFields) {
438+
if (type.equals(f.getType())) {
359439
fields.put(type, f);
360440
foundFields.put(clazz, fields);
361441
return f;

0 commit comments

Comments
 (0)