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 2f32d2fc7..38e8d36ac 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 @@ -179,6 +179,26 @@ public class BukkitRecipeManager implements RecipeManager { CraftEngine.instance().logger().warn("Failed to convert campfire recipe", e); } }); + BUKKIT_RECIPE_REGISTER.put(RecipeTypes.STONE_CUTTING, (key, recipe) -> { + CustomStoneCuttingRecipe ceRecipe = (CustomStoneCuttingRecipe) recipe; + List itemStacks = new ArrayList<>(); + for (Holder item : ceRecipe.ingredient().items()) { + itemStacks.add(BukkitItemManager.instance().buildItemStack(item.value(), null)); + } + StonecuttingRecipe stonecuttingRecipe = new StonecuttingRecipe( + key, ceRecipe.getResult(null), + 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); + } + }); } private final BukkitCraftEngine plugin; 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 e829548ae..188800a79 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 @@ -12,7 +12,7 @@ import net.momirealms.craftengine.core.item.recipe.CustomCampfireRecipe; import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; -import net.momirealms.craftengine.core.item.recipe.input.CookingInput; +import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; @@ -64,7 +64,7 @@ public class RecipeEventListener implements Listener { Optional> idHolder = BuiltInRegistries.OPTIMIZED_ITEM_ID.get(wrappedItem.id()); if (idHolder.isEmpty()) return; - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), item)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), item)); Key recipeType; if (furnaceInventory.getType() == InventoryType.FURNACE) { recipeType = RecipeTypes.SMELTING; @@ -344,7 +344,7 @@ public class RecipeEventListener implements Listener { if (idHolder.isEmpty()) { return; } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); @@ -374,7 +374,7 @@ public class RecipeEventListener implements Listener { return; } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setTotalCookTime(Integer.MAX_VALUE); @@ -406,7 +406,7 @@ public class RecipeEventListener implements Listener { return; } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); CustomCampfireRecipe ceRecipe = (CustomCampfireRecipe) this.recipeManager.getRecipe(RecipeTypes.CAMPFIRE_COOKING, input); if (ceRecipe == null) { event.setCancelled(true); 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 8a9d84c72..fd8d5cdf5 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 @@ -25,7 +25,7 @@ import net.momirealms.craftengine.core.block.StatePredicate; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; -import net.momirealms.craftengine.core.item.recipe.input.CookingInput; +import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -351,7 +351,7 @@ public class BukkitInjector { return Optional.empty(); } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); net.momirealms.craftengine.core.item.recipe.CookingRecipe ceRecipe; Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); if (type == Reflections.instance$RecipeType$SMELTING) { @@ -418,7 +418,7 @@ public class BukkitInjector { return Optional.empty(); } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); net.momirealms.craftengine.core.item.recipe.CookingRecipe ceRecipe; Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); if (type == Reflections.instance$RecipeType$SMELTING) { @@ -477,7 +477,7 @@ public class BukkitInjector { return Optional.empty(); } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); net.momirealms.craftengine.core.item.recipe.CookingRecipe ceRecipe; Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); if (type == Reflections.instance$RecipeType$SMELTING) { @@ -537,7 +537,7 @@ public class BukkitInjector { return Optional.empty(); } - CookingInput input = new CookingInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); + SingleItemInput input = new SingleItemInput<>(new OptimizedIDItem<>(idHolder.get(), itemStack)); net.momirealms.craftengine.core.item.recipe.CookingRecipe ceRecipe; Key lastCustomRecipe = (Key) field$InjectedCacheChecker$lastCustomRecipe.get(thisObj); if (type == Reflections.instance$RecipeType$SMELTING) { 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 80af3421f..f41f5437a 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 @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.block.BlockKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; import net.momirealms.craftengine.core.item.recipe.RecipeTypes; -import net.momirealms.craftengine.core.item.recipe.input.CookingInput; +import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.registry.BuiltInRegistries; @@ -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 CookingInput<>(new OptimizedIDItem<>( + return optional.filter(keyReference -> BukkitRecipeManager.instance().getRecipe(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 CookingInput<>(new OptimizedIDItem<>( + return optional.filter(keyReference -> BukkitRecipeManager.instance().getRecipe(RecipeTypes.CAMPFIRE_COOKING, new SingleItemInput<>(new OptimizedIDItem<>( keyReference, item.getItem() ))) != null).isPresent(); }); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 2caa015d4..11bbdca80 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -4341,6 +4341,18 @@ public class Reflections { ) ); + public static final Class clazz$CraftStonecuttingRecipe = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleCBClass("inventory.CraftStonecuttingRecipe") + ) + ); + + public static final Method method$CraftStonecuttingRecipe$fromBukkitRecipe = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$CraftStonecuttingRecipe, clazz$CraftStonecuttingRecipe, StonecuttingRecipe.class + ) + ); + public static final Field field$AbstractFurnaceBlockEntity$recipeType = requireNonNull( ReflectionUtils.getDeclaredField( clazz$AbstractFurnaceBlockEntity, clazz$RecipeType, 0 diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipe.java index 47bf1e00e..a01b66624 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CookingRecipe.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.item.recipe; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.recipe.input.CookingInput; +import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.util.Key; @@ -30,7 +30,7 @@ public abstract class CookingRecipe extends AbstractRecipe { @SuppressWarnings("unchecked") @Override public boolean matches(RecipeInput input) { - return this.ingredient.test(((CookingInput) input).input()); + return this.ingredient.test(((SingleItemInput) input).input()); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java new file mode 100644 index 000000000..47bda2e9f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomStoneCuttingRecipe.java @@ -0,0 +1,73 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; +import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.registry.BuiltInRegistries; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class CustomStoneCuttingRecipe extends AbstractRecipe { + public static final Factory FACTORY = new Factory<>(); + protected final Ingredient ingredient; + protected final CustomRecipeResult result; + + protected CustomStoneCuttingRecipe(Key id, String group, Ingredient ingredient, CustomRecipeResult result) { + super(id, group); + this.ingredient = ingredient; + this.result = result; + } + + @SuppressWarnings("unchecked") + @Override + public boolean matches(RecipeInput input) { + return this.ingredient.test(((SingleItemInput) input).input()); + } + + @Override + public T getResult(Player player) { + return result.buildItemStack(player); + } + + @Override + public @NotNull Key type() { + return RecipeTypes.STONE_CUTTING; + } + + public Ingredient ingredient() { + return ingredient; + } + + public CustomRecipeResult result() { + return result; + } + + public static class Factory implements RecipeFactory { + + @SuppressWarnings({"DuplicatedCode"}) + @Override + public Recipe create(Key id, Map arguments) { + String group = arguments.containsKey("group") ? arguments.get("group").toString() : null; + List items = MiscUtils.getAsStringList(arguments.get("ingredient")); + Set> holders = new HashSet<>(); + for (String item : items) { + if (item.charAt(0) == '#') { + holders.addAll(CraftEngine.instance().itemManager().tagToItems(Key.of(item.substring(1)))); + } else { + holders.add(BuiltInRegistries.OPTIMIZED_ITEM_ID.get(Key.of(item)).orElseThrow(() -> new IllegalArgumentException("Invalid vanilla/custom item: " + item))); + } + } + return new CustomStoneCuttingRecipe<>( + id, + group, + Ingredient.of(holders), + parseResult(arguments) + ); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java index a2bc1c164..e350f5111 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/RecipeTypes.java @@ -16,6 +16,7 @@ public class RecipeTypes { public static final Key BLASTING = Key.of("minecraft:blasting"); public static final Key SMOKING = Key.of("minecraft:smoking"); public static final Key CAMPFIRE_COOKING = Key.of("minecraft:campfire_cooking"); + public static final Key STONE_CUTTING = Key.of("minecraft:stone_cutting"); static { register(SHAPED, CustomShapedRecipe.FACTORY); @@ -24,6 +25,7 @@ public class RecipeTypes { register(SMOKING, CustomSmokingRecipe.FACTORY); register(BLASTING, CustomBlastingRecipe.FACTORY); register(CAMPFIRE_COOKING, CustomCampfireRecipe.FACTORY); + register(STONE_CUTTING, CustomStoneCuttingRecipe.FACTORY); } public static void register(Key key, RecipeFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CookingInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CookingInput.java deleted file mode 100644 index c5291e077..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/CookingInput.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.momirealms.craftengine.core.item.recipe.input; - -import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; - -public class CookingInput implements RecipeInput { - private final OptimizedIDItem input; - - public CookingInput(OptimizedIDItem input) { - this.input = input; - } - - public OptimizedIDItem input() { - return input; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java new file mode 100644 index 000000000..c706c38d0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/input/SingleItemInput.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.item.recipe.input; + +import net.momirealms.craftengine.core.item.recipe.OptimizedIDItem; + +public record SingleItemInput(OptimizedIDItem input) implements RecipeInput { +}