From 30588d86eb4d92a1d6ebb67bd99f123b1d2a1186 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 4 Apr 2025 03:21:35 +0800 Subject: [PATCH] refactor recipes --- .../src/main/resources/translations/en.yml | 3 +- .../api/event/CraftEngineReloadEvent.java | 1 + .../item/recipe/BukkitRecipeConvertor.java | 10 + .../item/recipe/BukkitRecipeManager.java | 1115 +++++++---------- .../item/recipe/CrafterEventListener.java | 4 +- .../item/recipe/RecipeEventListener.java | 20 +- .../bukkit/plugin/BukkitCraftEngine.java | 32 +- .../plugin/command/feature/ReloadCommand.java | 49 +- .../feature/SearchRecipeAdminCommand.java | 2 +- .../feature/SearchRecipePlayerCommand.java | 2 +- .../feature/SearchUsageAdminCommand.java | 2 +- .../feature/SearchUsagePlayerCommand.java | 2 +- .../plugin/injector/BukkitInjector.java | 46 +- .../bukkit/util/InteractUtils.java | 4 +- .../core/font/AbstractFontManager.java | 2 +- .../item/recipe/AbstractRecipeManager.java | 183 +++ .../core/item/recipe/RecipeManager.java | 28 +- .../craftengine/core/plugin/CraftEngine.java | 93 +- .../gui/category/ItemBrowserManagerImpl.java | 50 +- 19 files changed, 828 insertions(+), 820 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java diff --git a/bukkit/loader/src/main/resources/translations/en.yml b/bukkit/loader/src/main/resources/translations/en.yml index 8d5ad85c2..851f3889d 100644 --- a/bukkit/loader/src/main/resources/translations/en.yml +++ b/bukkit/loader/src/main/resources/translations/en.yml @@ -63,4 +63,5 @@ warning.config.image.invalid_font_name: "Issue found in file - T warning.config.image.lack_char: "Issue found in file - The image '' is missing the required 'char' argument." warning.config.image.codepoint_in_use: "Issue found in file - The image '' is using a character[()] in font that has been used by another image ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grind." -warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." \ No newline at end of file +warning.config.image.file_not_exist: "Issue found in file - PNG file not found for image ''." +warning.config.recipe.duplicated: "Issue found in file - Duplicated recipe ''." \ No newline at end of file diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java index 58d5dea02..e56d98aa1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/event/CraftEngineReloadEvent.java @@ -10,6 +10,7 @@ public class CraftEngineReloadEvent extends Event { private final BukkitCraftEngine plugin; public CraftEngineReloadEvent(BukkitCraftEngine plugin) { + super(true); this.plugin = plugin; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java new file mode 100644 index 000000000..c899ca4df --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeConvertor.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.bukkit.item.recipe; + +import net.momirealms.craftengine.core.item.recipe.Recipe; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.inventory.ItemStack; + +public interface BukkitRecipeConvertor> { + + Runnable convert(Key id, T recipe); +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 6501e49aa..fc0fe0577 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -14,19 +14,13 @@ import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; -import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.vanilla.*; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5; -import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2; -import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.HeptaFunction; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.PentaFunction; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -35,247 +29,249 @@ import org.bukkit.event.HandlerList; import org.bukkit.inventory.*; import org.bukkit.inventory.recipe.CookingBookCategory; import org.bukkit.inventory.recipe.CraftingBookCategory; -import org.jetbrains.annotations.Nullable; import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Path; import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; import java.util.function.Consumer; -public class BukkitRecipeManager implements RecipeManager { - private static final Map>> BUKKIT_RECIPE_FACTORIES = new HashMap<>(); - private static Object minecraftRecipeManager; - private static final List injectedIngredients = new ArrayList<>(); - private static final IdentityHashMap, Object> recipeToMcRecipeHolder = new IdentityHashMap<>(); +public class BukkitRecipeManager extends AbstractRecipeManager { private static BukkitRecipeManager instance; + // 将自定义配方转为“广义”配方,接受更加宽容的输入 + // 部分过程借助bukkit完成,部分直接通过nms方法注册 + private static final Map>> MIXED_RECIPE_CONVERTORS = new HashMap<>(); + private static Object nmsRecipeManager; + private static final List injectedIngredients = new ArrayList<>(); + private static final IdentityHashMap, Object> recipeToMcRecipeHolder = new IdentityHashMap<>(); + + private static void registerNMSSmithingRecipe(Object recipe) { + try { + Reflections.method$RecipeManager$addRecipe.invoke(nmsRecipeManager(), recipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register smithing recipe", e); + } + } + + private static void registerBukkitShapedRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register shaped recipe", e); + } + } + + private static void registerBukkitShapelessRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register shapeless recipe", e); + } + } + + private static void registerBukkitSmeltingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftFurnaceRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register smelting recipe", e); + } + } + + private static void registerBukkitSmokingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftSmokingRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register smoking recipe", e); + } + } + + private static void registerBukkitBlastingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftBlastingRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register blasting recipe", e); + } + } + + private static void registerBukkitCampfireRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftCampfireRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register campfire recipe", e); + } + } + + private static void registerBukkitStoneCuttingRecipe(Object recipe) { + try { + Object craftRecipe = Reflections.method$CraftStonecuttingRecipe$fromBukkitRecipe.invoke(null, recipe); + Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); + } catch (IllegalAccessException | InvocationTargetException e) { + CraftEngine.instance().logger().warn("Failed to register stonecutting recipe", e); + } + } + static { - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMITHING_TRANSFORM, (key, recipe) -> { - CustomSmithingTransformRecipe ceRecipe = (CustomSmithingTransformRecipe) recipe; - ceRecipe.addition(); - // bukkit api doesn't allow empty material choices, that's why we do this + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMITHING_TRANSFORM, (BukkitRecipeConvertor>) (id, recipe) -> { try { - Object smithingRecipe = createMinecraftSmithingTransformRecipe(ceRecipe); + Object nmsRecipe = createMinecraftSmithingTransformRecipe(recipe); if (VersionHelper.isVersionNewerThan1_21_2()) { - smithingRecipe = Reflections.constructor$RecipeHolder.newInstance(Reflections.method$CraftRecipe$toMinecraft.invoke(null, key), smithingRecipe); + nmsRecipe = Reflections.constructor$RecipeHolder.newInstance( + Reflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())), nmsRecipe); } else if (VersionHelper.isVersionNewerThan1_20_2()) { - smithingRecipe = Reflections.constructor$RecipeHolder.newInstance(Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, key.namespace(), key.value()), smithingRecipe); + nmsRecipe = Reflections.constructor$RecipeHolder.newInstance( + Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, id.namespace(), id.value()), nmsRecipe); + } else { + return () -> {}; } - Reflections.method$RecipeManager$addRecipe.invoke(minecraftRecipeManager(), smithingRecipe); + Object finalNmsRecipe = nmsRecipe; + return () -> registerNMSSmithingRecipe(finalNmsRecipe); } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert transform recipe", e); + CraftEngine.instance().logger().warn("Failed to convert smithing transform recipe", e); + return null; } }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SHAPED, (key, recipe) -> { - CustomShapedRecipe ceRecipe = (CustomShapedRecipe) recipe; - ShapedRecipe shapedRecipe = new ShapedRecipe(key, ceRecipe.result(ItemBuildContext.EMPTY)); - if (ceRecipe.group() != null) { - shapedRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - shapedRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - shapedRecipe.shape(ceRecipe.pattern().pattern()); - for (Map.Entry> entry : ceRecipe.pattern().ingredients().entrySet()) { + // TODO DO NOT USE BUKKIT RECIPE AS BRIDGE IN FUTURE VERSIONS, WE SHOULD DIRECTLY CONSTRUCT THOSE NMS RECIPES + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPED, (BukkitRecipeConvertor>) (id, recipe) -> { + ShapedRecipe shapedRecipe = new ShapedRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); + if (recipe.group() != null) shapedRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) shapedRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + shapedRecipe.shape(recipe.pattern().pattern()); + for (Map.Entry> entry : recipe.pattern().ingredients().entrySet()) { shapedRecipe.setIngredient(entry.getKey(), ingredientToBukkitRecipeChoice(entry.getValue())); } - try { - Object craftRecipe = Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, shapedRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectShapedRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shaped recipe", e); - } + return () -> { + registerBukkitShapedRecipe(shapedRecipe); + injectShapedRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SHAPELESS, (key, recipe) -> { - CustomShapelessRecipe ceRecipe = (CustomShapelessRecipe) recipe; - ShapelessRecipe shapelessRecipe = new ShapelessRecipe(key, ceRecipe.result(ItemBuildContext.EMPTY)); - if (ceRecipe.group() != null) { - shapelessRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - for (Ingredient ingredient : ceRecipe.ingredientsInUse()) { + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SHAPELESS, (BukkitRecipeConvertor>) (id, recipe) -> { + ShapelessRecipe shapelessRecipe = new ShapelessRecipe(new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY)); + if (recipe.group() != null) shapelessRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) shapelessRecipe.setCategory(CraftingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + for (Ingredient ingredient : recipe.ingredientsInUse()) { shapelessRecipe.addIngredient(ingredientToBukkitRecipeChoice(ingredient)); } - try { - Object craftRecipe = Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, shapelessRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectShapelessRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shapeless recipe", e); - } + return () -> { + registerBukkitShapelessRecipe(shapelessRecipe); + injectShapelessRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMELTING, (key, recipe) -> { - CustomSmeltingRecipe ceRecipe = (CustomSmeltingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMELTING, (BukkitRecipeConvertor>) (id, recipe) -> { FurnaceRecipe furnaceRecipe = new FurnaceRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - furnaceRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - furnaceRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftFurnaceRecipe$fromBukkitRecipe.invoke(null, furnaceRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smelting recipe", e); - } + if (recipe.group() != null) furnaceRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) furnaceRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitSmeltingRecipe(furnaceRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.SMOKING, (key, recipe) -> { - CustomSmokingRecipe ceRecipe = (CustomSmokingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.SMOKING, (BukkitRecipeConvertor>) (id, recipe) -> { SmokingRecipe smokingRecipe = new SmokingRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - smokingRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - smokingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftSmokingRecipe$fromBukkitRecipe.invoke(null, smokingRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smoking recipe", e); - } + if (recipe.group() != null) smokingRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) smokingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitSmokingRecipe(smokingRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.BLASTING, (key, recipe) -> { - CustomBlastingRecipe ceRecipe = (CustomBlastingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.BLASTING, (BukkitRecipeConvertor>) (id, recipe) -> { BlastingRecipe blastingRecipe = new BlastingRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - blastingRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - blastingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftBlastingRecipe$fromBukkitRecipe.invoke(null, blastingRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert blasting recipe", e); - } + if (recipe.group() != null) blastingRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) blastingRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitBlastingRecipe(blastingRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.CAMPFIRE_COOKING, (key, recipe) -> { - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.CAMPFIRE_COOKING, (BukkitRecipeConvertor>) (id, recipe) -> { CampfireRecipe campfireRecipe = new CampfireRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), - ingredientToBukkitRecipeChoice(ceRecipe.ingredient()), - ceRecipe.experience(), ceRecipe.cookingTime() + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), + ingredientToBukkitRecipeChoice(recipe.ingredient()), + recipe.experience(), recipe.cookingTime() ); - if (ceRecipe.group() != null) { - campfireRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - if (ceRecipe.category() != null) { - campfireRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(ceRecipe.category()).name())); - } - try { - Object craftRecipe = Reflections.method$CraftCampfireRecipe$fromBukkitRecipe.invoke(null, campfireRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - injectCookingRecipe(new Key(key.namespace(), key.value()), ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert campfire recipe", e); - } + if (recipe.group() != null) campfireRecipe.setGroup(Objects.requireNonNull(recipe.group())); + if (recipe.category() != null) campfireRecipe.setCategory(CookingBookCategory.valueOf(Objects.requireNonNull(recipe.category()).name())); + return () -> { + registerBukkitCampfireRecipe(campfireRecipe); + injectCookingRecipe(id, recipe); + }; }); - BUKKIT_RECIPE_FACTORIES.put(RecipeTypes.STONECUTTING, (key, recipe) -> { - CustomStoneCuttingRecipe ceRecipe = (CustomStoneCuttingRecipe) recipe; + MIXED_RECIPE_CONVERTORS.put(RecipeTypes.STONECUTTING, (BukkitRecipeConvertor>) (id, recipe) -> { List itemStacks = new ArrayList<>(); - for (Holder item : ceRecipe.ingredient().items()) { + for (Holder item : recipe.ingredient().items()) { itemStacks.add(BukkitItemManager.instance().buildItemStack(item.value(), null)); } StonecuttingRecipe stonecuttingRecipe = new StonecuttingRecipe( - key, ceRecipe.result(ItemBuildContext.EMPTY), + new NamespacedKey(id.namespace(), id.value()), recipe.result(ItemBuildContext.EMPTY), new RecipeChoice.ExactChoice(itemStacks) ); - if (ceRecipe.group() != null) { - stonecuttingRecipe.setGroup(Objects.requireNonNull(ceRecipe.group())); - } - try { - Object craftRecipe = Reflections.method$CraftStonecuttingRecipe$fromBukkitRecipe.invoke(null, stonecuttingRecipe); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(craftRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert stone cutting recipe", e); - } + if (recipe.group() != null) stonecuttingRecipe.setGroup(Objects.requireNonNull(recipe.group())); + return () -> { + registerBukkitStoneCuttingRecipe(stonecuttingRecipe); + }; }); } + /* + * 注册全过程: + * + * 0.准备阶段偷取flag以减少注册的性能开销 + * 1.先读取用户配置自定义配方 + * 2.延迟加载中为自定义配方生成转换为nms配方的任务 + * 3.读取全部的数据包配方并转换为自定义配方,对必要的含有tag配方添加先移除后注册nms配方的任务 + * 4.主线程完成剩余任务 + * 5.归还flag + */ + private final BukkitCraftEngine plugin; private final RecipeEventListener recipeEventListener; private final CrafterEventListener crafterEventListener; - private final Map>> byType; - private final Map> byId; - private final Map>> byResult; - private final Map>> byIngredient; - private final VanillaRecipeReader recipeReader; - private final List injectedDataPackRecipes; - private final List registeredCustomRecipes; - // data pack recipe resource locations [minecraft:xxx] - private final Set dataPackRecipes; - + // To optimize recipes loading, will return the flag later private Object stolenFeatureFlagSet; + // Some delayed tasks on main thread + private final List delayedTasksOnMainThread = new ArrayList<>(); public BukkitRecipeManager(BukkitCraftEngine plugin) { instance = this; this.plugin = plugin; - this.byType = new HashMap<>(); - this.byId = new HashMap<>(); - this.byIngredient = new HashMap<>(); - this.byResult = new HashMap<>(); - this.injectedDataPackRecipes = new ArrayList<>(); - this.registeredCustomRecipes = new ArrayList<>(); - this.dataPackRecipes = new HashSet<>(); this.recipeEventListener = new RecipeEventListener(plugin, this, plugin.itemManager()); - if (VersionHelper.isVersionNewerThan1_21()) { - this.crafterEventListener = new CrafterEventListener(plugin, this, plugin.itemManager()); - } else { - this.crafterEventListener = null; - } - if (VersionHelper.isVersionNewerThan1_21_2()) { - this.recipeReader = new VanillaRecipeReader1_21_2(); - } else if (VersionHelper.isVersionNewerThan1_20_5()) { - this.recipeReader = new VanillaRecipeReader1_20_5(); - } else { - this.recipeReader = new VanillaRecipeReader1_20(); - } + this.crafterEventListener = VersionHelper.isVersionNewerThan1_21() ? new CrafterEventListener(plugin, this, plugin.itemManager()) : null; try { - minecraftRecipeManager = Reflections.method$MinecraftServer$getRecipeManager.invoke(Reflections.method$MinecraftServer$getServer.invoke(null)); + nmsRecipeManager = Reflections.method$MinecraftServer$getRecipeManager.invoke(Reflections.method$MinecraftServer$getServer.invoke(null)); } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to get minecraft recipe manager", e); } } - @Override - public boolean isDataPackRecipe(Key key) { - return this.dataPackRecipes.contains(key); + public Object nmsRecipeHolderByRecipe(Recipe recipe) { + return recipeToMcRecipeHolder.get(recipe); } - @Override - public boolean isCustomRecipe(Key key) { - return this.byId.containsKey(key); + public static Object nmsRecipeManager() { + return nmsRecipeManager; } - @Override - public Optional> getRecipeById(Key key) { - return Optional.ofNullable(this.byId.get(key)); + public static BukkitRecipeManager instance() { + return instance; } @Override @@ -291,8 +287,8 @@ public class BukkitRecipeManager implements RecipeManager { if (!ConfigManager.enableRecipeSystem()) return; if (VersionHelper.isVersionNewerThan1_21_2()) { try { - this.stolenFeatureFlagSet = Reflections.field$RecipeManager$featureflagset.get(minecraftRecipeManager); - Reflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager, null); + this.stolenFeatureFlagSet = Reflections.field$RecipeManager$featureflagset.get(nmsRecipeManager); + Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, null); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to steal featureflagset", e); } @@ -301,370 +297,235 @@ public class BukkitRecipeManager implements RecipeManager { @Override public void unload() { - this.byType.clear(); - this.byId.clear(); - this.byResult.clear(); - this.byIngredient.clear(); - this.dataPackRecipes.clear(); - + super.unload(); try { - // do not unregister them -// for (NamespacedKey key : this.injectedDataPackRecipes) { -// unregisterRecipe(key); -// } - for (NamespacedKey key : this.registeredCustomRecipes) { - unregisterRecipe(key); - } if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager); + Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager); } } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to unregister recipes", e); + this.plugin.logger().warn("Failed to unregister recipes", e); } - - this.registeredCustomRecipes.clear(); - this.injectedDataPackRecipes.clear(); - recipeToMcRecipeHolder.clear(); } + @Override + public void delayedLoad() { + this.injectDataPackRecipes(); + } + @Override public void disable() { + unload(); HandlerList.unregisterAll(this.recipeEventListener); if (this.crafterEventListener != null) { HandlerList.unregisterAll(this.crafterEventListener); } - unload(); - } - - private void unregisterRecipe(NamespacedKey key) throws ReflectiveOperationException { - if (VersionHelper.isVersionNewerThan1_21_2()) { - Object recipeMap = Reflections.field$RecipeManager$recipes.get(minecraftRecipeManager); - Reflections.method$RecipeMap$removeRecipe.invoke(recipeMap, Reflections.method$CraftRecipe$toMinecraft.invoke(null, key)); - } else { - Bukkit.removeRecipe(key); - } } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { - if (!ConfigManager.enableRecipeSystem()) return; - if (this.byId.containsKey(id)) { - this.plugin.logger().warn(path, "Duplicated recipe " + id); - return; - } - Recipe recipe = RecipeTypes.fromMap(id, section); - NamespacedKey key = NamespacedKey.fromString(id.toString()); - BUKKIT_RECIPE_FACTORIES.get(recipe.type()).accept(key, recipe); + protected void unregisterPlatformRecipe(Key key) { + unregisterNMSRecipe(new NamespacedKey(key.namespace(), key.value())); + } + + @Override + protected void registerPlatformRecipe(Key id, Recipe recipe) { try { - this.registeredCustomRecipes.add(key); - addInternalRecipe(id, recipe); + Runnable converted = findNMSRecipeConvertor(recipe).convert(id, recipe); + if (converted != null) { + this.delayedTasksOnMainThread.add(converted); + } } catch (Exception e) { - plugin.logger().warn("Failed to add custom recipe " + id, e); + this.plugin.logger().warn("Failed to convert recipe " + id, e); } } - @Override - public List> getRecipes(Key type) { - return this.byType.getOrDefault(type, List.of()); - } - - @Override - public List> getRecipeByResult(Key result) { - return this.byResult.getOrDefault(result, List.of()); - } - - @Override - public List> getRecipeByIngredient(Key ingredient) { - return this.byIngredient.getOrDefault(ingredient, List.of()); - } - - private void addInternalRecipe(Key id, Recipe recipe) { - this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); - this.byId.put(id, recipe); - this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe); - HashSet usedKeys = new HashSet<>(); - for (Ingredient ingredient : recipe.ingredientsInUse()) { - for (Holder holder : ingredient.items()) { - Key key = holder.value(); - if (usedKeys.add(key)) { - this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); - } - } - } - } - - @Nullable - @Override - public Recipe getRecipe(Key type, RecipeInput input) { - List> recipes = this.byType.get(type); - if (recipes == null) return null; - for (Recipe recipe : recipes) { - if (recipe.matches(input)) { - return recipe; - } - } - return null; - } - - @Nullable - @Override - public Recipe getRecipe(Key type, RecipeInput input, Key lastRecipe) { - if (lastRecipe != null) { - Recipe last = byId.get(lastRecipe); - if (last != null && last.matches(input)) { - return last; - } - } - return getRecipe(type, input); - } - - @Override - public CompletableFuture asyncDelayedLoad() { - if (!ConfigManager.enableRecipeSystem()) return CompletableFuture.completedFuture(null); - return this.processVanillaRecipes().thenRun(() -> { - try { - // give flags back on 1.21.2+ - if (VersionHelper.isVersionNewerThan1_21_2() && this.stolenFeatureFlagSet != null) { - Reflections.field$RecipeManager$featureflagset.set(minecraftRecipeManager, this.stolenFeatureFlagSet); - this.stolenFeatureFlagSet = false; - } - - // refresh recipes - if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(minecraftRecipeManager); - } - - // send to players - Reflections.method$DedicatedPlayerList$reloadRecipes.invoke(Reflections.field$CraftServer$playerList.get(Bukkit.getServer())); - - // now we need to remove the fake `exact` - if (VersionHelper.isVersionNewerThan1_21_4()) { - for (Object ingredient : injectedIngredients) { - Reflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); - } - } else if (VersionHelper.isVersionNewerThan1_21_2()) { - for (Object ingredient : injectedIngredients) { - Reflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); - } - } - - // clear cache - injectedIngredients.clear(); - } catch (Exception e) { - this.plugin.logger().warn("Failed to run delayed recipe tasks", e); - } - }); - } - @SuppressWarnings("unchecked") - private CompletableFuture processVanillaRecipes() { - CompletableFuture future = new CompletableFuture<>(); + private > BukkitRecipeConvertor findNMSRecipeConvertor(T recipe) { + return (BukkitRecipeConvertor) MIXED_RECIPE_CONVERTORS.get(recipe.type()); + } + + private void unregisterNMSRecipe(NamespacedKey key) { try { - List injectLogics = new ArrayList<>(); - plugin.scheduler().async().execute(() -> { - try { - Object fileToIdConverter = Reflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isVersionNewerThan1_21() ? "recipe" : "recipes"); - Object minecraftServer = Reflections.method$MinecraftServer$getServer.invoke(null); - Object packRepository = Reflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); - List selected = (List) Reflections.field$PackRepository$selected.get(packRepository); - List packResources = new ArrayList<>(); - for (Object pack : selected) { - packResources.add(Reflections.method$Pack$open.invoke(pack)); - } - try (AutoCloseable resourceManager = (AutoCloseable) Reflections.constructor$MultiPackResourceManager.newInstance(Reflections.instance$PackType$SERVER_DATA, packResources)) { - Map scannedResources = (Map) Reflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); - for (Map.Entry entry : scannedResources.entrySet()) { - Key id = extractKeyFromResourceLocation(entry.getKey().toString()); - this.dataPackRecipes.add(id); - // Maybe it's unregistered by other plugins - if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { - continue; - } - Reader reader = (Reader) Reflections.method$Resource$openAsReader.invoke(entry.getValue()); - JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); - String type = jsonObject.get("type").getAsString(); - switch (type) { - case "minecraft:crafting_shaped" -> { - VanillaShapedRecipe recipe = this.recipeReader.readShaped(jsonObject); - handleDataPackShapedRecipe(id, recipe, (injectLogics::add)); - } - case "minecraft:crafting_shapeless" -> { - VanillaShapelessRecipe recipe = this.recipeReader.readShapeless(jsonObject); - handleDataPackShapelessRecipe(id, recipe, (injectLogics::add)); - } - case "minecraft:smelting" -> { - VanillaSmeltingRecipe recipe = this.recipeReader.readSmelting(jsonObject); - handleDataPackCookingRecipe(id, recipe, FurnaceRecipe::new, CustomSmeltingRecipe::new, Reflections.method$CraftFurnaceRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:blasting" -> { - VanillaBlastingRecipe recipe = this.recipeReader.readBlasting(jsonObject); - handleDataPackCookingRecipe(id, recipe, BlastingRecipe::new, CustomBlastingRecipe::new, Reflections.method$CraftBlastingRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:smoking" -> { - VanillaSmokingRecipe recipe = this.recipeReader.readSmoking(jsonObject); - handleDataPackCookingRecipe(id, recipe, SmokingRecipe::new, CustomSmokingRecipe::new, Reflections.method$CraftSmokingRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:campfire_cooking" -> { - VanillaCampfireRecipe recipe = this.recipeReader.readCampfire(jsonObject); - handleDataPackCookingRecipe(id, recipe, CampfireRecipe::new, CustomCampfireRecipe::new, Reflections.method$CraftCampfireRecipe$fromBukkitRecipe, (injectLogics::add)); - } - case "minecraft:stonecutting" -> { - VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); - handleDataPackStoneCuttingRecipe(id, recipe); - } - case "minecraft:smithing_transform" -> { - VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); - handleDataPackSmithingTransform(id, recipe, (injectLogics::add)); - } - } - } - } - } catch (Exception e) { - plugin.logger().warn("Failed to read data pack recipes", e); - } finally { - plugin.scheduler().sync().run(() -> { - try { - for (Runnable runnable : injectLogics) { - runnable.run(); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to register recipes", e); - } finally { - future.complete(null); - } - }); - } - }); - } catch (Exception e) { - this.plugin.logger().warn("Failed to inject vanilla recipes", e); - } - return future; - } - - private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer materialConsumer, Consumer> holderConsumer) { - for (String item : ingredients) { - if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - for (Material material : tagToMaterials(tag)) { - materialConsumer.accept(material); - } - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; - } - } - for (Holder holder : plugin.itemManager().tagToItems(tag)) { - holderConsumer.accept(holder); - } + if (VersionHelper.isVersionNewerThan1_21_2()) { + Object recipeMap = Reflections.field$RecipeManager$recipes.get(nmsRecipeManager); + Reflections.method$RecipeMap$removeRecipe.invoke(recipeMap, Reflections.method$CraftRecipe$toMinecraft.invoke(null, key)); } else { - materialConsumer.accept(MaterialUtils.getMaterial(item)); - holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + Bukkit.removeRecipe(key); } + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to unregister nms recipes", e); } - return hasCustomItemInTag; } - private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { - NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); - ItemStack result = createResultStack(recipe.result()); - ShapelessRecipe shapelessRecipe = new ShapelessRecipe(key, result); - if (recipe.group() != null) { - shapelessRecipe.setGroup(recipe.group()); - } - if (recipe.category() != null) { - shapelessRecipe.setCategory(CraftingBookCategory.valueOf(recipe.category().name())); - } - - boolean hasCustomItemInTag = false; - List> ingredientList = new ArrayList<>(); - for (List list : recipe.ingredients()) { - Set materials = new HashSet<>(); - Set> holders = new HashSet<>(); - for (String item : list) { - if (item.charAt(0) == '#') { - Key tag = Key.of(item.substring(1)); - materials.addAll(tagToMaterials(tag)); - if (!hasCustomItemInTag) { - if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { - hasCustomItemInTag = true; + @SuppressWarnings("unchecked") + private void injectDataPackRecipes() { + try { + Object fileToIdConverter = Reflections.method$FileToIdConverter$json.invoke(null, VersionHelper.isVersionNewerThan1_21() ? "recipe" : "recipes"); + Object minecraftServer = Reflections.method$MinecraftServer$getServer.invoke(null); + Object packRepository = Reflections.method$MinecraftServer$getPackRepository.invoke(minecraftServer); + List selected = (List) Reflections.field$PackRepository$selected.get(packRepository); + List packResources = new ArrayList<>(); + for (Object pack : selected) { + packResources.add(Reflections.method$Pack$open.invoke(pack)); + } + try (AutoCloseable resourceManager = (AutoCloseable) Reflections.constructor$MultiPackResourceManager.newInstance(Reflections.instance$PackType$SERVER_DATA, packResources)) { + Map scannedResources = (Map) Reflections.method$FileToIdConverter$listMatchingResources.invoke(fileToIdConverter, resourceManager); + for (Map.Entry entry : scannedResources.entrySet()) { + Key id = extractKeyFromResourceLocation(entry.getKey().toString()); + // Maybe it's unregistered by other plugins + if (Bukkit.getRecipe(new NamespacedKey(id.namespace(), id.value())) == null) { + continue; + } + markAsDataPackRecipe(id); + Reader reader = (Reader) Reflections.method$Resource$openAsReader.invoke(entry.getValue()); + JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); + String type = jsonObject.get("type").getAsString(); + switch (type) { + case "minecraft:crafting_shaped" -> { + VanillaShapedRecipe recipe = this.recipeReader.readShaped(jsonObject); + handleDataPackShapedRecipe(id, recipe, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:crafting_shapeless" -> { + VanillaShapelessRecipe recipe = this.recipeReader.readShapeless(jsonObject); + handleDataPackShapelessRecipe(id, recipe, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:smelting" -> { + VanillaSmeltingRecipe recipe = this.recipeReader.readSmelting(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomSmeltingRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:blasting" -> { + VanillaBlastingRecipe recipe = this.recipeReader.readBlasting(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomBlastingRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:smoking" -> { + VanillaSmokingRecipe recipe = this.recipeReader.readSmoking(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomSmokingRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:campfire_cooking" -> { + VanillaCampfireRecipe recipe = this.recipeReader.readCampfire(jsonObject); + handleDataPackCookingRecipe(id, recipe, CustomCampfireRecipe::new, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:smithing_transform" -> { + VanillaSmithingTransformRecipe recipe = this.recipeReader.readSmithingTransform(jsonObject); + handleDataPackSmithingTransform(id, recipe, (this.delayedTasksOnMainThread::add)); + } + case "minecraft:stonecutting" -> { + VanillaStoneCuttingRecipe recipe = this.recipeReader.readStoneCutting(jsonObject); + handleDataPackStoneCuttingRecipe(id, recipe); } } - holders.addAll(plugin.itemManager().tagToItems(tag)); - } else { - materials.add(MaterialUtils.getMaterial(item)); - holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - shapelessRecipe.addIngredient(new RecipeChoice.MaterialChoice(new ArrayList<>(materials))); - ingredientList.add(Ingredient.of(holders)); + } catch (Exception e) { + plugin.logger().warn("Failed to read data pack recipes", e); } + } - CustomShapelessRecipe ceRecipe = new CustomShapelessRecipe<>( - id, - recipe.category(), - recipe.group(), - ingredientList, - new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) - ); - if (hasCustomItemInTag) { - callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftShapelessRecipe$fromBukkitRecipe.invoke(null, shapelessRecipe)); - injectShapelessRecipe(id, ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shapeless recipe", e); + @Override + public void runSyncTasks() { + try { + // run delayed tasks + for (Runnable r : this.delayedTasksOnMainThread) { + r.run(); + } + this.delayedTasksOnMainThread.clear(); + + // give flags back on 1.21.2+ + if (VersionHelper.isVersionNewerThan1_21_2() && this.stolenFeatureFlagSet != null) { + Reflections.field$RecipeManager$featureflagset.set(nmsRecipeManager, this.stolenFeatureFlagSet); + this.stolenFeatureFlagSet = false; + } + + // refresh recipes + if (VersionHelper.isVersionNewerThan1_21_2()) { + Reflections.method$RecipeManager$finalizeRecipeLoading.invoke(nmsRecipeManager); + } + + // send to players + Reflections.method$DedicatedPlayerList$reloadRecipes.invoke(Reflections.field$CraftServer$playerList.get(Bukkit.getServer())); + + // now we need to remove the fake `exact` + if (VersionHelper.isVersionNewerThan1_21_4()) { + for (Object ingredient : injectedIngredients) { + Reflections.field$Ingredient$itemStacks1_21_4.set(ingredient, null); } - }); - this.injectedDataPackRecipes.add(key); + } else if (VersionHelper.isVersionNewerThan1_21_2()) { + for (Object ingredient : injectedIngredients) { + Reflections.field$Ingredient$itemStacks1_21_2.set(ingredient, null); + } + } + + // clear cache + injectedIngredients.clear(); + } catch (Exception e) { + this.plugin.logger().warn("Failed to run delayed recipe tasks", e); } - this.addInternalRecipe(id, ceRecipe); } private void handleDataPackStoneCuttingRecipe(Key id, VanillaStoneCuttingRecipe recipe) { ItemStack result = createResultStack(recipe.result()); Set> holders = new HashSet<>(); - for (String item : recipe.ingredient()) { if (item.charAt(0) == '#') { Key tag = Key.from(item.substring(1)); - holders.addAll(plugin.itemManager().tagToItems(tag)); + holders.addAll(this.plugin.itemManager().tagToItems(tag)); } else { holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - CustomStoneCuttingRecipe ceRecipe = new CustomStoneCuttingRecipe<>( - id, - recipe.group(), - Ingredient.of(holders), + id, recipe.group(), Ingredient.of(holders), new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) ); - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } - private void handleDataPackShapedRecipe(Key id, VanillaShapedRecipe recipe, Consumer callback) { + private void handleDataPackShapelessRecipe(Key id, VanillaShapelessRecipe recipe, Consumer callback) { NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createResultStack(recipe.result()); - ShapedRecipe shapedRecipe = new ShapedRecipe(key, result); - if (recipe.group() != null) { - shapedRecipe.setGroup(recipe.group()); - } - if (recipe.category() != null) { - shapedRecipe.setCategory(CraftingBookCategory.valueOf(recipe.category().name())); - } - shapedRecipe.shape(recipe.pattern()); - boolean hasCustomItemInTag = false; - Map> ingredients = new HashMap<>(); - for (Map.Entry> entry : recipe.ingredients().entrySet()) { - Set materials = new HashSet<>(); + List> ingredientList = new ArrayList<>(); + for (List list : recipe.ingredients()) { Set> holders = new HashSet<>(); - for (String item : entry.getValue()) { + for (String item : list) { if (item.charAt(0) == '#') { - Key tag = Key.from(item.substring(1)); - materials.addAll(tagToMaterials(tag)); + Key tag = Key.of(item.substring(1)); + if (!hasCustomItemInTag) { + if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { + hasCustomItemInTag = true; + } + } + holders.addAll(plugin.itemManager().tagToItems(tag)); + } else { + holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); + } + } + ingredientList.add(Ingredient.of(holders)); + } + CustomShapelessRecipe ceRecipe = new CustomShapelessRecipe<>( + id, recipe.category(), recipe.group(), ingredientList, + new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) + ); + if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); + callback.accept(() -> { + unregisterNMSRecipe(key); + converted.run(); + }); + } + this.registerInternalRecipe(id, ceRecipe); + } + + private void handleDataPackShapedRecipe(Key id, VanillaShapedRecipe recipe, Consumer callback) { + NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); + ItemStack result = createResultStack(recipe.result()); + boolean hasCustomItemInTag = false; + Map> ingredients = new HashMap<>(); + for (Map.Entry> entry : recipe.ingredients().entrySet()) { + Set> holders = new HashSet<>(); + for (String item : entry.getValue()) { + if (item.charAt(0) == '#') { + Key tag = Key.from(item.substring(1)); if (!hasCustomItemInTag) { if (!plugin.itemManager().tagToCustomItems(tag).isEmpty()) { hasCustomItemInTag = true; @@ -672,79 +533,48 @@ public class BukkitRecipeManager implements RecipeManager { } holders.addAll(plugin.itemManager().tagToItems(tag)); } else { - materials.add(MaterialUtils.getMaterial(item)); holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - shapedRecipe.setIngredient(entry.getKey(), new RecipeChoice.MaterialChoice(new ArrayList<>(materials))); ingredients.put(entry.getKey(), Ingredient.of(holders)); } - CustomShapedRecipe ceRecipe = new CustomShapedRecipe<>( - id, - recipe.category(), - recipe.group(), + id, recipe.category(), recipe.group(), new CustomShapedRecipe.Pattern<>(recipe.pattern(), ingredients), new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) ); if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftShapedRecipe$fromBukkitRecipe.invoke(null, shapedRecipe)); - injectShapedRecipe(id, ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert shaped recipe", e); - } + unregisterNMSRecipe(key); + converted.run(); }); - this.injectedDataPackRecipes.add(key); } - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } private void handleDataPackCookingRecipe(Key id, VanillaCookingRecipe recipe, - PentaFunction> constructor1, HeptaFunction, Integer, Float, CustomRecipeResult, CustomCookingRecipe> constructor2, - Method fromBukkitRecipeMethod, Consumer callback) { NamespacedKey key = new NamespacedKey(id.namespace(), id.value()); ItemStack result = createResultStack(recipe.result()); - - Set materials = new HashSet<>(); Set> holders = new HashSet<>(); - - boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), materials::add, holders::add); - org.bukkit.inventory.CookingRecipe cookingRecipe = constructor1.apply(key, result, new RecipeChoice.MaterialChoice(new ArrayList<>(materials)), recipe.experience(), recipe.cookingTime()); - if (recipe.group() != null) { - cookingRecipe.setGroup(recipe.group()); - } - if (recipe.category() != null) { - cookingRecipe.setCategory(CookingBookCategory.valueOf(recipe.category().name())); - } - + boolean hasCustomItemInTag = readVanillaIngredients(false, recipe.ingredient(), holders::add); CustomCookingRecipe ceRecipe = constructor2.apply( - id, - recipe.category(), - recipe.group(), + id, recipe.category(), recipe.group(), Ingredient.of(holders), - recipe.cookingTime(), - recipe.experience(), + recipe.cookingTime(), recipe.experience(), new CustomRecipeResult<>(new CloneableConstantItem(recipe.result().isCustom() ? Key.of("!internal:custom") : Key.of(recipe.result().id()), result), recipe.result().count()) ); if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(fromBukkitRecipeMethod.invoke(null, cookingRecipe)); - injectCookingRecipe(id, ceRecipe); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert smelting recipe", e); - } + unregisterNMSRecipe(key); + converted.run(); }); - this.injectedDataPackRecipes.add(key); } - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } private void handleDataPackSmithingTransform(Key id, VanillaSmithingTransformRecipe recipe, Consumer callback) { @@ -752,17 +582,12 @@ public class BukkitRecipeManager implements RecipeManager { ItemStack result = createResultStack(recipe.result()); boolean hasCustomItemInTag; - Set additionMaterials = new HashSet<>(); Set> additionHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionMaterials::add, additionHolders::add); - - Set templateMaterials = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(false, recipe.addition(), additionHolders::add); Set> templateHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateMaterials::add, templateHolders::add); - - Set baseMaterials = new HashSet<>(); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.template(), templateHolders::add); Set> baseHolders = new HashSet<>(); - hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseMaterials::add, baseHolders::add); + hasCustomItemInTag = readVanillaIngredients(hasCustomItemInTag, recipe.base(), baseHolders::add); CustomSmithingTransformRecipe ceRecipe = new CustomSmithingTransformRecipe<>( id, @@ -774,43 +599,33 @@ public class BukkitRecipeManager implements RecipeManager { List.of() ); - SmithingTransformRecipe transformRecipe = new SmithingTransformRecipe(key, result, - new RecipeChoice.MaterialChoice(new ArrayList<>(templateMaterials)), - new RecipeChoice.MaterialChoice(new ArrayList<>(baseMaterials)), - new RecipeChoice.MaterialChoice(new ArrayList<>(additionMaterials)) - ); - if (hasCustomItemInTag) { + Runnable converted = findNMSRecipeConvertor(ceRecipe).convert(id, ceRecipe); callback.accept(() -> { - try { - unregisterRecipe(key); - Reflections.method$CraftRecipe$addToCraftingManager.invoke(Reflections.method$CraftSmithingTransformRecipe$fromBukkitRecipe.invoke(null, transformRecipe)); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to convert transform recipe", e); - } + unregisterNMSRecipe(key); + converted.run(); }); - this.injectedDataPackRecipes.add(key); } - this.addInternalRecipe(id, ceRecipe); + this.registerInternalRecipe(id, ceRecipe); } - private List tagToMaterials(Key tag) { - Set materials = new HashSet<>(); - List> holders = this.plugin.itemManager().tagToVanillaItems(tag); - if (holders != null) { - for (Holder holder : holders) { - materials.add(MaterialUtils.getMaterial(holder.value())); + private boolean readVanillaIngredients(boolean hasCustomItemInTag, List ingredients, Consumer> holderConsumer) { + for (String item : ingredients) { + if (item.charAt(0) == '#') { + Key tag = Key.from(item.substring(1)); + if (!hasCustomItemInTag) { + if (!this.plugin.itemManager().tagToCustomItems(tag).isEmpty()) { + hasCustomItemInTag = true; + } + } + for (Holder holder : this.plugin.itemManager().tagToItems(tag)) { + holderConsumer.accept(holder); + } + } else { + holderConsumer.accept(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.from(item)).orElseThrow()); } } - List> customItems = this.plugin.itemManager().tagToCustomItems(tag); - if (customItems != null) { - for (Holder holder : customItems) { - this.plugin.itemManager().getCustomItem(holder.value()).ifPresent(it -> { - materials.add(MaterialUtils.getMaterial(it.material())); - }); - } - } - return new ArrayList<>(materials); + return hasCustomItemInTag; } private ItemStack createResultStack(RecipeResult result) { @@ -870,66 +685,81 @@ public class BukkitRecipeManager implements RecipeManager { return itemStacks; } - private static void injectShapedRecipe(Key id, CustomShapedRecipe recipe) throws ReflectiveOperationException { - List> actualIngredients = recipe.parsedPattern().ingredients() - .stream() - .filter(Optional::isPresent) - .map(Optional::get) - .toList(); + // 无论是什么注入什么配方类型的方法,其本质都是注入ingredient + private static void injectShapedRecipe(Key id, CustomShapedRecipe recipe) { + try { + List> actualIngredients = recipe.parsedPattern().ingredients() + .stream() + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); - Object shapedRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, shapedRecipe); - if (VersionHelper.isVersionNewerThan1_20_2()) { - shapedRecipe = Reflections.field$RecipeHolder$recipe.get(shapedRecipe); - } + Object shapedRecipe = getNMSRecipe(id); + recipeToMcRecipeHolder.put(recipe, shapedRecipe); + if (VersionHelper.isVersionNewerThan1_20_2()) { + shapedRecipe = Reflections.field$RecipeHolder$recipe.get(shapedRecipe); + } - if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); + if (VersionHelper.isVersionNewerThan1_21_2()) { + Reflections.field$ShapedRecipe$placementInfo.set(shapedRecipe, null); + } + + List ingredients = RecipeUtils.getIngredientsFromShapedRecipe(shapedRecipe); + injectIngredients(ingredients, actualIngredients); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject shaped recipe", e); } - List ingredients = RecipeUtils.getIngredientsFromShapedRecipe(shapedRecipe); - injectIngredients(ingredients, actualIngredients); } - @SuppressWarnings("unchecked") - private static void injectShapelessRecipe(Key id, CustomShapelessRecipe recipe) throws ReflectiveOperationException { - List> actualIngredients = recipe.ingredientsInUse(); + private static void injectShapelessRecipe(Key id, CustomShapelessRecipe recipe) { + try { + List> actualIngredients = recipe.ingredientsInUse(); - Object shapelessRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, shapelessRecipe); - if (VersionHelper.isVersionNewerThan1_20_2()) { - shapelessRecipe = Reflections.field$RecipeHolder$recipe.get(shapelessRecipe); - } + Object shapelessRecipe = getNMSRecipe(id); + recipeToMcRecipeHolder.put(recipe, shapelessRecipe); + if (VersionHelper.isVersionNewerThan1_20_2()) { + shapelessRecipe = Reflections.field$RecipeHolder$recipe.get(shapelessRecipe); + } - if (VersionHelper.isVersionNewerThan1_21_2()) { - Reflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); + if (VersionHelper.isVersionNewerThan1_21_2()) { + Reflections.field$ShapelessRecipe$placementInfo.set(shapelessRecipe, null); + } + @SuppressWarnings("unchecked") + List ingredients = (List) Reflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); + injectIngredients(ingredients, actualIngredients); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject shapeless recipe", e); } - List ingredients = (List) Reflections.field$ShapelessRecipe$ingredients.get(shapelessRecipe); - injectIngredients(ingredients, actualIngredients); } - private static void injectCookingRecipe(Key id, CustomCookingRecipe recipe) throws ReflectiveOperationException { - Ingredient actualIngredient = recipe.ingredient(); - Object smeltingRecipe = getNMSRecipe(id); - recipeToMcRecipeHolder.put(recipe, smeltingRecipe); - if (VersionHelper.isVersionNewerThan1_20_2()) { - smeltingRecipe = Reflections.field$RecipeHolder$recipe.get(smeltingRecipe); - } + private static void injectCookingRecipe(Key id, CustomCookingRecipe recipe) { + try { + Ingredient actualIngredient = recipe.ingredient(); + Object smeltingRecipe = getNMSRecipe(id); + recipeToMcRecipeHolder.put(recipe, smeltingRecipe); + if (VersionHelper.isVersionNewerThan1_20_2()) { + smeltingRecipe = Reflections.field$RecipeHolder$recipe.get(smeltingRecipe); + } - Object ingredient; - if (VersionHelper.isVersionNewerThan1_21_2()) { - ingredient = Reflections.field$SingleItemRecipe$input.get(smeltingRecipe); - } else { - ingredient = Reflections.field$AbstractCookingRecipe$input.get(smeltingRecipe); + Object ingredient; + if (VersionHelper.isVersionNewerThan1_21_2()) { + ingredient = Reflections.field$SingleItemRecipe$input.get(smeltingRecipe); + } else { + ingredient = Reflections.field$AbstractCookingRecipe$input.get(smeltingRecipe); + } + injectIngredients(List.of(ingredient), List.of(actualIngredient)); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to inject cooking recipe", e); } - injectIngredients(List.of(ingredient), List.of(actualIngredient)); } + // 获取nms配方,请注意1.20.1获取配方本身,而1.20.2+获取的是配方的holder // recipe on 1.20.1 and holder on 1.20.2+ private static Object getNMSRecipe(Key id) throws ReflectiveOperationException { if (VersionHelper.isVersionNewerThan1_21_2()) { Object resourceKey = Reflections.method$CraftRecipe$toMinecraft.invoke(null, new NamespacedKey(id.namespace(), id.value())); @SuppressWarnings("unchecked") - Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(minecraftRecipeManager, resourceKey); + Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceKey); if (optional.isEmpty()) { throw new IllegalArgumentException("Recipe " + id + " not found"); } @@ -937,7 +767,7 @@ public class BukkitRecipeManager implements RecipeManager { } else { Object resourceLocation = Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, id.namespace(), id.value()); @SuppressWarnings("unchecked") - Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(minecraftRecipeManager, resourceLocation); + Optional optional = (Optional) Reflections.method$RecipeManager$byKey.invoke(nmsRecipeManager, resourceLocation); if (optional.isEmpty()) { throw new IllegalArgumentException("Recipe " + id + " not found"); } @@ -945,12 +775,14 @@ public class BukkitRecipeManager implements RecipeManager { } } - private static void injectIngredients(List ingredients, List> actualIngredients) throws ReflectiveOperationException { - if (ingredients.size() != actualIngredients.size()) { + // 注入原料,这个方法受不同服务端fork和版本影响极大,需要每个版本测试 + // 此过程是为了避免自己处理“广义”配方与客户端的注册通讯 + private static void injectIngredients(List fakeIngredients, List> actualIngredients) throws ReflectiveOperationException { + if (fakeIngredients.size() != actualIngredients.size()) { throw new IllegalArgumentException("Ingredient count mismatch"); } - for (int i = 0; i < ingredients.size(); i++) { - Object ingredient = ingredients.get(i); + for (int i = 0; i < fakeIngredients.size(); i++) { + Object ingredient = fakeIngredients.get(i); Ingredient actualIngredient = actualIngredients.get(i); List items = getIngredientLooks(actualIngredient.items()); if (VersionHelper.isVersionNewerThan1_21_4()) { @@ -996,48 +828,37 @@ public class BukkitRecipeManager implements RecipeManager { return Reflections.constructor$TransmuteResult.newInstance(nmsItem); } - private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe ceRecipe) throws ReflectiveOperationException { + // create nms smithing recipe for different versions + private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe recipe) throws ReflectiveOperationException { if (VersionHelper.isVersionNewerThan1_21_5()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( - toOptionalMinecraftIngredient(ceRecipe.template()), - toMinecraftIngredient(ceRecipe.base()), - toOptionalMinecraftIngredient(ceRecipe.addition()), - toTransmuteResult(ceRecipe.result(ItemBuildContext.EMPTY)) + toOptionalMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toOptionalMinecraftIngredient(recipe.addition()), + toTransmuteResult(recipe.result(ItemBuildContext.EMPTY)) ); } else if (VersionHelper.isVersionNewerThan1_21_2()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( - toOptionalMinecraftIngredient(ceRecipe.template()), - toOptionalMinecraftIngredient(ceRecipe.base()), - toOptionalMinecraftIngredient(ceRecipe.addition()), - Reflections.method$CraftItemStack$asNMSCopy.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + toOptionalMinecraftIngredient(recipe.template()), + toOptionalMinecraftIngredient(recipe.base()), + toOptionalMinecraftIngredient(recipe.addition()), + Reflections.method$CraftItemStack$asNMSCopy.invoke(null, recipe.result(ItemBuildContext.EMPTY)) ); } else if (VersionHelper.isVersionNewerThan1_20_2()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( - toMinecraftIngredient(ceRecipe.template()), - toMinecraftIngredient(ceRecipe.base()), - toMinecraftIngredient(ceRecipe.addition()), - Reflections.method$CraftItemStack$asNMSCopy.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()), + Reflections.method$CraftItemStack$asNMSCopy.invoke(null, recipe.result(ItemBuildContext.EMPTY)) ); } else { return Reflections.constructor$SmithingTransformRecipe.newInstance( - Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, ceRecipe.id().namespace(), ceRecipe.id().value()), - toMinecraftIngredient(ceRecipe.template()), - toMinecraftIngredient(ceRecipe.base()), - toMinecraftIngredient(ceRecipe.addition()), - Reflections.method$CraftItemStack$asNMSCopy.invoke(null, ceRecipe.result(ItemBuildContext.EMPTY)) + Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, recipe.id().namespace(), recipe.id().value()), + toMinecraftIngredient(recipe.template()), + toMinecraftIngredient(recipe.base()), + toMinecraftIngredient(recipe.addition()), + Reflections.method$CraftItemStack$asNMSCopy.invoke(null, recipe.result(ItemBuildContext.EMPTY)) ); } } - - public Object getRecipeHolderByRecipe(Recipe recipe) { - return recipeToMcRecipeHolder.get(recipe); - } - - public static Object minecraftRecipeManager() { - return minecraftRecipeManager; - } - - public static BukkitRecipeManager instance() { - return instance; - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java index d24bdec79..8d51b8b04 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/CrafterEventListener.java @@ -82,12 +82,12 @@ public class CrafterEventListener implements Listener { return; } - Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPELESS, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input); if (ceRecipe != null) { event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); return; } - ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPED, input); + ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input); if (ceRecipe != null) { event.setResult(ceRecipe.result(ItemBuildContext.EMPTY)); return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 2a2f64bc8..de3dc7564 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -85,7 +85,7 @@ public class RecipeEventListener implements Listener { recipeType = RecipeTypes.SMOKING; } - Recipe ceRecipe = recipeManager.getRecipe(recipeType, input); + Recipe ceRecipe = recipeManager.recipeByInput(recipeType, input); // The item is an ingredient, we should never consider it as fuel firstly if (ceRecipe != null) return; @@ -345,7 +345,7 @@ public class RecipeEventListener implements Listener { try { @SuppressWarnings("unchecked") Optional optionalMCRecipe = (Optional) Reflections.method$RecipeManager$getRecipeFor1.invoke( - BukkitRecipeManager.minecraftRecipeManager(), + BukkitRecipeManager.nmsRecipeManager(), Reflections.instance$RecipeType$CAMPFIRE_COOKING, Reflections.constructor$SingleRecipeInput.newInstance(Reflections.method$CraftItemStack$asNMSCopy.invoke(null, itemStack)), FastNMS.INSTANCE.field$CraftWorld$ServerLevel(event.getPlayer().getWorld()), @@ -360,7 +360,7 @@ public class RecipeEventListener implements Listener { return; } SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); } @@ -392,7 +392,7 @@ public class RecipeEventListener implements Listener { } SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setTotalCookTime(Integer.MAX_VALUE); return; @@ -427,7 +427,7 @@ public class RecipeEventListener implements Listener { } SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); - CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); + CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); return; @@ -802,14 +802,14 @@ public class RecipeEventListener implements Listener { BukkitServerPlayer serverPlayer = this.plugin.adapt(player); Key lastRecipe = serverPlayer.lastUsedRecipe(); - Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPELESS, input, lastRecipe); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPELESS, input, lastRecipe); if (ceRecipe != null) { inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); correctCraftingRecipeUsed(inventory, ceRecipe); return; } - ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SHAPED, input, lastRecipe); + ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SHAPED, input, lastRecipe); if (ceRecipe != null) { inventory.setResult(ceRecipe.result(new ItemBuildContext(serverPlayer, ContextHolder.EMPTY))); serverPlayer.setLastUsedRecipe(ceRecipe.id()); @@ -821,7 +821,7 @@ public class RecipeEventListener implements Listener { } private void correctCraftingRecipeUsed(CraftingInventory inventory, Recipe recipe) { - Object holderOrRecipe = recipeManager.getRecipeHolderByRecipe(recipe); + Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { // it's a vanilla recipe but not injected return; @@ -857,7 +857,7 @@ public class RecipeEventListener implements Listener { getOptimizedIDItem(addition) ); - Recipe ceRecipe = this.recipeManager.getRecipe(RecipeTypes.SMITHING_TRANSFORM, input); + Recipe ceRecipe = this.recipeManager.recipeByInput(RecipeTypes.SMITHING_TRANSFORM, input); if (ceRecipe == null) { event.setResult(null); return; @@ -878,7 +878,7 @@ public class RecipeEventListener implements Listener { } private void correctSmithingRecipeUsed(SmithingInventory inventory, Recipe recipe) { - Object holderOrRecipe = recipeManager.getRecipeHolderByRecipe(recipe); + Object holderOrRecipe = recipeManager.nmsRecipeHolderByRecipe(recipe); if (holderOrRecipe == null) { // it's a vanilla recipe but not injected return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 9b755b212..e42e271d5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -200,8 +200,10 @@ public class BukkitCraftEngine extends CraftEngine { @Override public void reload() { super.reload(); - CraftEngineReloadEvent event = new CraftEngineReloadEvent(this); - EventUtils.fireAndForget(event); + scheduler.async().execute(() -> { + CraftEngineReloadEvent event = new CraftEngineReloadEvent(this); + EventUtils.fireAndForget(event); + }); } @Override @@ -211,32 +213,6 @@ public class BukkitCraftEngine extends CraftEngine { } } - @Override - protected void registerParsers() { - // register template parser - this.packManager.registerConfigSectionParser(this.templateManager); - // register font parser - this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); - // register item parser - this.packManager.registerConfigSectionParser(this.itemManager); - // register furniture parser - this.packManager.registerConfigSectionParser(this.furnitureManager); - // register block parser - this.packManager.registerConfigSectionParser(this.blockManager); - // register recipe parser - this.packManager.registerConfigSectionParser(this.recipeManager); - // register category parser - this.packManager.registerConfigSectionParser(this.itemBrowserManager); - // register translation parser - this.packManager.registerConfigSectionParser(this.translationManager); - this.packManager.registerConfigSectionParser(this.translationManager.clientLangManager()); - // register sound parser - this.packManager.registerConfigSectionParser(this.soundManager); - this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); - // register vanilla loot parser - this.packManager.registerConfigSectionParser(this.vanillaLootManager); - } - @Override public InputStream resourceStream(String filePath) { return bootstrap.getResource(filePath.replace("\\", "/")); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java index cab37225a..e6fff1b0b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/ReloadCommand.java @@ -34,16 +34,18 @@ public class ReloadCommand extends BukkitCommandFeature { argument = optional.get(); } if (argument == ReloadArgument.CONFIG) { - try { - RELOAD_PACK_FLAG = true; - long time1 = System.currentTimeMillis(); - plugin().reload(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); - plugin().logger().warn("Failed to reload config", e); - } + plugin().scheduler().executeAsync(() -> { + try { + RELOAD_PACK_FLAG = true; + long time1 = System.currentTimeMillis(); + plugin().reload(); + long time2 = System.currentTimeMillis(); + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_SUCCESS, Component.text(time2 - time1)); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_CONFIG_FAILURE); + plugin().logger().warn("Failed to reload config", e); + } + }); } else if (argument == ReloadArgument.PACK) { plugin().scheduler().executeAsync(() -> { try { @@ -57,23 +59,18 @@ public class ReloadCommand extends BukkitCommandFeature { } }); } else if (argument == ReloadArgument.ALL) { - long time1 = System.currentTimeMillis(); - try { + plugin().scheduler().executeAsync(() -> { + long time1 = System.currentTimeMillis(); plugin().reload(); - plugin().scheduler().executeAsync(() -> { - try { - plugin().packManager().generateResourcePack(); - long time2 = System.currentTimeMillis(); - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(time2 - time1)); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to generate resource pack", e); - } - }); - } catch (Exception e) { - handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); - plugin().logger().warn("Failed to reload config", e); - } + try { + plugin().packManager().generateResourcePack(); + long time2 = System.currentTimeMillis(); + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_SUCCESS, Component.text(time2 - time1)); + } catch (Exception e) { + handleFeedback(context, MessageConstants.COMMAND_RELOAD_ALL_FAILURE); + plugin().logger().warn("Failed to generate resource pack", e); + } + }); } }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java index 5c4dfee42..c5c7847f5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java @@ -47,7 +47,7 @@ public class SearchRecipeAdminCommand extends BukkitCommandFeature> inRecipes = plugin().recipeManager().getRecipeByResult(itemId); + List> inRecipes = plugin().recipeManager().recipeByResult(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java index 82fc61cff..1082e366a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipePlayerCommand.java @@ -35,7 +35,7 @@ public class SearchRecipePlayerCommand extends BukkitCommandFeature> inRecipes = plugin().recipeManager().getRecipeByResult(itemId); + List> inRecipes = plugin().recipeManager().recipeByResult(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java index 313fbe932..034be222d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java @@ -47,7 +47,7 @@ public class SearchUsageAdminCommand extends BukkitCommandFeature for (Player player : players) { BukkitServerPlayer serverPlayer = plugin().adapt(player); Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); - List> inRecipes = plugin().recipeManager().getRecipeByIngredient(itemId); + List> inRecipes = plugin().recipeManager().recipeByIngredient(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java index 3494cfd3e..26e28808b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsagePlayerCommand.java @@ -35,7 +35,7 @@ public class SearchUsagePlayerCommand extends BukkitCommandFeature> inRecipes = plugin().recipeManager().getRecipeByIngredient(itemId); + List> inRecipes = plugin().recipeManager().recipeByIngredient(itemId); if (!inRecipes.isEmpty()) { plugin().itemBrowserManager().openRecipePage(serverPlayer, null, inRecipes, 0, 0, false); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 5be2a0711..74794df67 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -357,7 +357,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -394,13 +394,13 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -412,7 +412,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(resourceLocation); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond())); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(pair.getSecond())); } else { return Optional.empty(); } @@ -425,7 +425,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -462,13 +462,13 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -480,7 +480,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); } @@ -493,7 +493,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -522,13 +522,13 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$CAMPFIRE_COOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.CAMPFIRE_COOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -540,7 +540,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); } @@ -553,7 +553,7 @@ public class BukkitInjector { @SuppressWarnings("unchecked") @RuntimeType public Object intercept(@This Object thisObj, @AllArguments Object[] args) throws Exception { - Object mcRecipeManager = BukkitRecipeManager.minecraftRecipeManager(); + Object mcRecipeManager = BukkitRecipeManager.nmsRecipeManager(); InjectedCacheCheck injectedCacheCheck = (InjectedCacheCheck) thisObj; Object type = injectedCacheCheck.recipeType(); Object lastRecipe = injectedCacheCheck.lastRecipe(); @@ -583,11 +583,11 @@ public class BukkitInjector { CustomCookingRecipe ceRecipe; Key lastCustomRecipe = injectedCacheCheck.lastCustomRecipe(); if (type == Reflections.instance$RecipeType$SMELTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMELTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMELTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$BLASTING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.BLASTING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.BLASTING, input, lastCustomRecipe); } else if (type == Reflections.instance$RecipeType$SMOKING) { - ceRecipe = (CustomCookingRecipe) recipeManager.getRecipe(RecipeTypes.SMOKING, input, lastCustomRecipe); + ceRecipe = (CustomCookingRecipe) recipeManager.recipeByInput(RecipeTypes.SMOKING, input, lastCustomRecipe); } else { return Optional.empty(); } @@ -599,7 +599,7 @@ public class BukkitInjector { injectedCacheCheck.lastCustomRecipe(ceRecipe.id()); // It doesn't matter at all injectedCacheCheck.lastRecipe(id); - return Optional.of(Optional.ofNullable(recipeManager.getRecipeHolderByRecipe(ceRecipe)).orElse(holder)); + return Optional.of(Optional.ofNullable(recipeManager.nmsRecipeHolderByRecipe(ceRecipe)).orElse(holder)); } else { return Optional.empty(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index f41f5437a..eeed1b749 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -79,14 +79,14 @@ public class InteractUtils { register(BlockKeys.SOUL_CAMPFIRE, (player, item, blockState, result) -> { if (!ConfigManager.enableRecipeSystem()) return false; Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); - return optional.filter(keyReference -> BukkitRecipeManager.instance().getRecipe(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( + return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() ))) != null).isPresent(); }); register(BlockKeys.CAMPFIRE, (player, item, blockState, result) -> { if (!ConfigManager.enableRecipeSystem()) return false; Optional> optional = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(item.id()); - return optional.filter(keyReference -> BukkitRecipeManager.instance().getRecipe(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( + return optional.filter(keyReference -> BukkitRecipeManager.instance().recipeByInput(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() ))) != null).isPresent(); }); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index fdd4f93a5..2f51310ce 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -68,7 +68,7 @@ public abstract class AbstractFontManager implements FontManager { @Override public Collection fonts() { - return new ArrayList<>(this.fonts.values()); + return Collections.unmodifiableCollection(this.fonts.values()); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java new file mode 100644 index 000000000..627900416 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeManager.java @@ -0,0 +1,183 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.vanilla.VanillaRecipeReader; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20_5; +import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_21_2; +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.ConfigManager; +import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.jetbrains.annotations.Nullable; + +import java.nio.file.Path; +import java.util.*; + +public abstract class AbstractRecipeManager implements RecipeManager { + protected final VanillaRecipeReader recipeReader; + protected final Map>> byType = new HashMap<>(); + protected final Map> byId = new HashMap<>(); + protected final Map>> byResult = new HashMap<>(); + protected final Map>> byIngredient = new HashMap<>(); + protected final Set dataPackRecipes = new HashSet<>(); + protected final Set customRecipes = new HashSet<>(); + private final RecipeParser recipeParser; + + public AbstractRecipeManager() { + this.recipeReader = initVanillaRecipeReader(); + this.recipeParser = new RecipeParser(); + } + + @Override + public ConfigSectionParser parser() { + return this.recipeParser; + } + + private VanillaRecipeReader initVanillaRecipeReader() { + if (VersionHelper.isVersionNewerThan1_21_2()) { + return new VanillaRecipeReader1_21_2(); + } else if (VersionHelper.isVersionNewerThan1_20_5()) { + return new VanillaRecipeReader1_20_5(); + } else { + return new VanillaRecipeReader1_20(); + } + } + + @Override + public void unload() { + this.dataPackRecipes.clear(); + this.byType.clear(); + this.byId.clear(); + this.byResult.clear(); + this.byIngredient.clear(); + for (Key key : this.customRecipes) { + unregisterPlatformRecipe(key); + } + this.customRecipes.clear(); + } + + protected void markAsDataPackRecipe(Key key) { + this.dataPackRecipes.add(key); + } + + protected void markAsCustomRecipe(Key key) { + this.customRecipes.add(key); + } + + @Override + public boolean isDataPackRecipe(Key key) { + return this.dataPackRecipes.contains(key); + } + + @Override + public boolean isCustomRecipe(Key key) { + return this.byId.containsKey(key); + } + + @Override + public Optional> recipeById(Key key) { + return Optional.ofNullable(this.byId.get(key)); + } + + @Override + public List> recipesByType(Key type) { + return this.byType.getOrDefault(type, List.of()); + } + + @Override + public List> recipeByResult(Key result) { + return this.byResult.getOrDefault(result, List.of()); + } + + @Override + public List> recipeByIngredient(Key ingredient) { + return this.byIngredient.getOrDefault(ingredient, List.of()); + } + + @Nullable + @Override + public Recipe recipeByInput(Key type, RecipeInput input) { + List> recipes = this.byType.get(type); + if (recipes == null) return null; + for (Recipe recipe : recipes) { + if (recipe.matches(input)) { + return recipe; + } + } + return null; + } + + @Nullable + @Override + public Recipe recipeByInput(Key type, RecipeInput input, Key lastRecipe) { + if (lastRecipe != null) { + Recipe last = byId.get(lastRecipe); + if (last != null && last.matches(input)) { + return last; + } + } + return recipeByInput(type, input); + } + + protected void registerInternalRecipe(Key id, Recipe recipe) { + this.byType.computeIfAbsent(recipe.type(), k -> new ArrayList<>()).add(recipe); + this.byId.put(id, recipe); + this.byResult.computeIfAbsent(recipe.result().item().id(), k -> new ArrayList<>()).add(recipe); + HashSet usedKeys = new HashSet<>(); + for (Ingredient ingredient : recipe.ingredientsInUse()) { + for (Holder holder : ingredient.items()) { + Key key = holder.value(); + if (usedKeys.add(key)) { + this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); + } + } + } + } + + public class RecipeParser implements ConfigSectionParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; + + @Override + public int loadingSequence() { + return LoadingSequence.RECIPE; + } + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public void parseSection(Pack pack, Path path, Key id, Map section) { + if (!ConfigManager.enableRecipeSystem()) return; + if (AbstractRecipeManager.this.byId.containsKey(id)) { + TranslationManager.instance().log("warning.config.recipe.duplicated", path.toString(), id.toString()); + return; + } + Recipe recipe; + try { + recipe = RecipeTypes.fromMap(id, section); + } catch (Exception e) { + CraftEngine.instance().logger().warn(path, "Failed to create recipe: " + id, e); + return; + } + try { + markAsCustomRecipe(id); + registerInternalRecipe(id, recipe); + registerPlatformRecipe(id, recipe); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to register custom recipe " + id, e); + } + } + } + + protected abstract void unregisterPlatformRecipe(Key key); + + protected abstract void registerPlatformRecipe(Key key, Recipe recipe); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java index 55556118f..3573ec789 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeManager.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; -import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; import net.momirealms.craftengine.core.util.Key; @@ -9,35 +8,28 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Optional; -import java.util.concurrent.CompletableFuture; -public interface RecipeManager extends Reloadable, ConfigSectionParser { - String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; +public interface RecipeManager extends Reloadable { - default String[] sectionId() { - return CONFIG_SECTION_NAME; - } + ConfigSectionParser parser(); boolean isDataPackRecipe(Key key); boolean isCustomRecipe(Key key); - Optional> getRecipeById(Key id); + Optional> recipeById(Key id); - List> getRecipes(Key type); + List> recipesByType(Key type); - List> getRecipeByResult(Key result); + List> recipeByResult(Key result); - List> getRecipeByIngredient(Key ingredient); + List> recipeByIngredient(Key ingredient); @Nullable - Recipe getRecipe(Key type, RecipeInput input); + Recipe recipeByInput(Key type, RecipeInput input); - @Nullable Recipe getRecipe(Key type, RecipeInput input, @Nullable Key lastRecipe); + @Nullable + Recipe recipeByInput(Key type, RecipeInput input, @Nullable Key lastRecipe); - CompletableFuture asyncDelayedLoad(); - - default int loadingSequence() { - return LoadingSequence.RECIPE; - } + void runSyncTasks(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index 1f9d9826c..767a9edc0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -101,39 +101,43 @@ public abstract class CraftEngine implements Plugin { public void reload() { if (this.isReloading) return; this.isReloading = true; - try { - this.configManager.reload(); - this.translationManager.reload(); - this.templateManager.reload(); - this.furnitureManager.reload(); - this.fontManager.reload(); - this.itemManager.reload(); - this.soundManager.reload(); - this.recipeManager.reload(); - this.itemBrowserManager.reload(); - this.blockManager.reload(); - this.worldManager.reload(); - this.vanillaLootManager.reload(); - // load configs here - this.packManager.reload(); - // load at last - this.guiManager.reload(); - // delayed load - this.translationManager.delayedLoad(); - this.blockManager.delayedLoad(); - this.furnitureManager.delayedLoad(); - this.itemBrowserManager.delayedLoad(); - this.soundManager.delayedLoad(); - this.fontManager.delayedLoad(); - // reset debugger - if (ConfigManager.debug()) { - this.debugger = (s) -> logger.info("[Debug] " + s.get()); - } else { - this.debugger = (s) -> {}; - } - } finally { - this.recipeManager.asyncDelayedLoad().thenRun(() -> this.isReloading = false); + this.configManager.reload(); + this.translationManager.reload(); + this.templateManager.reload(); + this.furnitureManager.reload(); + this.fontManager.reload(); + this.itemManager.reload(); + this.soundManager.reload(); + this.recipeManager.reload(); + this.itemBrowserManager.reload(); + this.blockManager.reload(); + this.worldManager.reload(); + this.vanillaLootManager.reload(); + // load configs here + this.packManager.reload(); + // load at last + this.guiManager.reload(); + // delayed load + this.translationManager.delayedLoad(); + this.blockManager.delayedLoad(); + this.furnitureManager.delayedLoad(); + this.itemBrowserManager.delayedLoad(); + this.soundManager.delayedLoad(); + this.fontManager.delayedLoad(); + this.recipeManager.delayedLoad(); + // reset debugger + if (ConfigManager.debug()) { + this.debugger = (s) -> logger.info("[Debug] " + s.get()); + } else { + this.debugger = (s) -> {}; } + scheduler().sync().run(() -> { + try { + this.recipeManager.runSyncTasks(); + } finally { + this.isReloading = false; + } + }); } @Override @@ -181,7 +185,30 @@ public abstract class CraftEngine implements Plugin { ResourcePackHost.instance().disable(); } - protected abstract void registerParsers(); + protected void registerParsers() { + // register template parser + this.packManager.registerConfigSectionParser(this.templateManager); + // register font parser + this.packManager.registerConfigSectionParsers(this.fontManager.parsers()); + // register item parser + this.packManager.registerConfigSectionParser(this.itemManager); + // register furniture parser + this.packManager.registerConfigSectionParser(this.furnitureManager); + // register block parser + this.packManager.registerConfigSectionParser(this.blockManager); + // register recipe parser + this.packManager.registerConfigSectionParser(this.recipeManager.parser()); + // register category parser + this.packManager.registerConfigSectionParser(this.itemBrowserManager); + // register translation parser + this.packManager.registerConfigSectionParser(this.translationManager); + this.packManager.registerConfigSectionParser(this.translationManager.clientLangManager()); + // register sound parser + this.packManager.registerConfigSectionParser(this.soundManager); + this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager()); + // register vanilla loot parser + this.packManager.registerConfigSectionParser(this.vanillaLootManager); + } protected abstract void delayedEnable(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index cc496f346..4368de433 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -239,7 +239,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(itemId); + List> inRecipes = this.plugin.recipeManager().recipeByResult(itemId); player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); @@ -247,7 +247,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, itemId, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(itemId); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(itemId); player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { openRecipePage(c.clicker(), e.gui(), inRecipes, 0, 0, canOpenNoRecipePage); @@ -288,7 +288,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { item.count(item.maxStackSize()); c.setItemOnCursor(item); } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { openRecipePage(c.clicker(), e.gui(), inRecipes, 0, depth + 1, true); @@ -377,7 +377,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -386,7 +386,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -460,7 +460,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -469,7 +469,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -493,7 +493,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -502,7 +502,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -526,7 +526,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -535,7 +535,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -584,7 +584,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -593,7 +593,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -620,7 +620,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -629,7 +629,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -717,7 +717,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -726,7 +726,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -759,7 +759,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -768,7 +768,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -862,7 +862,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(result); + List> inRecipes = this.plugin.recipeManager().recipeByResult(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -871,7 +871,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, result, e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(result); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(result); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -954,7 +954,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -963,7 +963,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -997,7 +997,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return; } if (LEFT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByResult(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByResult(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) { @@ -1006,7 +1006,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { openNoRecipePage(player, e.item().id(), e.gui(), 0); } } else if (RIGHT_CLICK.contains(c.type())) { - List> inRecipes = this.plugin.recipeManager().getRecipeByIngredient(e.item().id()); + List> inRecipes = this.plugin.recipeManager().recipeByIngredient(e.item().id()); if (inRecipes == recipes) return; player.playSound(Constants.SOUND_CLICK_BUTTON); if (!inRecipes.isEmpty()) {