From f9607dc9943f873c239b14a2a58d6bead20f978b Mon Sep 17 00:00:00 2001 From: Gugle Date: Mon, 10 Jun 2024 21:18:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E4=BA=9B=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/recipe/AnvilRecipeManager.java | 76 ++-- .../data/recipe/anvil/AnvilRecipe.java | 345 +++++++----------- .../data/recipe/anvil/predicate/HasItem.java | 19 + .../anvil/predicate/HasItemIngredient.java | 9 +- .../mixin/IngredientValueAccessor.java | 27 ++ .../resources/anvilcraft-common.mixins.json | 2 + 6 files changed, 222 insertions(+), 256 deletions(-) create mode 100644 common/src/main/java/dev/dubhe/anvilcraft/mixin/IngredientValueAccessor.java diff --git a/common/src/main/java/dev/dubhe/anvilcraft/api/recipe/AnvilRecipeManager.java b/common/src/main/java/dev/dubhe/anvilcraft/api/recipe/AnvilRecipeManager.java index ef6666dda..946c2ca8a 100644 --- a/common/src/main/java/dev/dubhe/anvilcraft/api/recipe/AnvilRecipeManager.java +++ b/common/src/main/java/dev/dubhe/anvilcraft/api/recipe/AnvilRecipeManager.java @@ -2,58 +2,62 @@ import dev.dubhe.anvilcraft.data.recipe.anvil.AnvilRecipe; import dev.dubhe.anvilcraft.init.ModRecipeTypes; +import lombok.Getter; import net.minecraft.server.MinecraftServer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.CampfireCookingRecipe; +import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.SmeltingRecipe; +import net.minecraft.world.item.crafting.SmokingRecipe; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.List; public class AnvilRecipeManager { - private static List ANVIL_RECIPE_SET = List.of(); + @Getter + private static List anvilRecipeList = List.of(); /** * 更新配方 * * @param server 服务器实例 */ - public static void updateRecipes(MinecraftServer server) { + public static void updateRecipes(@NotNull MinecraftServer server) { RecipeManager manager = server.getRecipeManager(); ArrayList anvilRecipes = new ArrayList<>(manager.getAllRecipesFor(ModRecipeTypes.ANVIL_RECIPE)); - ArrayList smokingRecipes = new ArrayList<>(); - ArrayList smeltingRecipes = new ArrayList<>(); - manager.getAllRecipesFor(RecipeType.SMOKING).forEach( - smokingRecipe -> smokingRecipes.addAll(AnvilRecipe.of(smokingRecipe, server.registryAccess()))); - manager.getAllRecipesFor(RecipeType.CAMPFIRE_COOKING).forEach( - campfireCookingRecipe -> - anvilRecipes.addAll(AnvilRecipe.of(campfireCookingRecipe, server.registryAccess()))); - manager.getAllRecipesFor(RecipeType.BLASTING).forEach( - blastingRecipe -> - anvilRecipes.addAll(AnvilRecipe.of(blastingRecipe, server.registryAccess()))); - manager.getAllRecipesFor(RecipeType.SMELTING).forEach( - smeltingRecipe -> { - List anvilRecipe = - AnvilRecipe.of(smeltingRecipe, server.registryAccess()); - if (!anvilRecipe.isEmpty() - && smokingRecipes.stream().noneMatch((smokingRecipe) -> - anvilRecipe.get(0).getResultItem(server.registryAccess()) - .is(smokingRecipe.getResultItem(server.registryAccess()).getItem()))) - smeltingRecipes.addAll(anvilRecipe); - }); - manager.getAllRecipesFor(RecipeType.CRAFTING).forEach( - craftingRecipe -> - anvilRecipes.addAll(AnvilRecipe.of(craftingRecipe, server.registryAccess()))); - anvilRecipes.addAll(smokingRecipes); - anvilRecipes.addAll(smeltingRecipes); - - ANVIL_RECIPE_SET = anvilRecipes - .stream() - .sorted(Comparator.comparing(AnvilRecipe::getWeightCoefficient).reversed()) - .toList(); - } - - public static List getAnvilRecipeList() { - return ANVIL_RECIPE_SET; + List needFilter = new ArrayList<>(); + for (CampfireCookingRecipe recipe : manager.getAllRecipesFor(RecipeType.CAMPFIRE_COOKING)) { + AnvilRecipe anvilRecipe = AnvilRecipe.of(recipe, server.registryAccess()); + if (anvilRecipe != null) anvilRecipes.add(anvilRecipe); + } + for (SmokingRecipe recipe : manager.getAllRecipesFor(RecipeType.SMOKING)) { + needFilter.add(recipe.getResultItem(server.registryAccess())); + AnvilRecipe anvilRecipe = AnvilRecipe.of(recipe, server.registryAccess()); + if (anvilRecipe != null) anvilRecipes.add(anvilRecipe); + } + for (BlastingRecipe recipe : manager.getAllRecipesFor(RecipeType.BLASTING)) { + needFilter.add(recipe.getResultItem(server.registryAccess())); + AnvilRecipe anvilRecipe = AnvilRecipe.of(recipe, server.registryAccess()); + if (anvilRecipe != null) anvilRecipes.add(anvilRecipe); + } + for (SmeltingRecipe recipe : manager.getAllRecipesFor(RecipeType.SMELTING)) { + ItemStack item = recipe.getResultItem(server.registryAccess()); + if (needFilter.stream().anyMatch(stack -> item.is(stack.getItem()))) continue; + AnvilRecipe anvilRecipe = AnvilRecipe.of(recipe, server.registryAccess()); + if (anvilRecipe != null) anvilRecipes.add(anvilRecipe); + } + for (CraftingRecipe recipe : manager.getAllRecipesFor(RecipeType.CRAFTING)) { + AnvilRecipe anvilRecipe = AnvilRecipe.of(recipe, server.registryAccess()); + if (anvilRecipe != null) anvilRecipes.add(anvilRecipe); + } + anvilRecipeList = Collections.synchronizedList( + anvilRecipes.stream().sorted(Comparator.comparing(AnvilRecipe::getWeightCoefficient).reversed()).toList() + ); } } diff --git a/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/AnvilRecipe.java b/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/AnvilRecipe.java index c2223e132..f80ac0f27 100644 --- a/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/AnvilRecipe.java +++ b/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/AnvilRecipe.java @@ -21,10 +21,8 @@ import dev.dubhe.anvilcraft.data.recipe.anvil.predicate.NotHasBlock; import dev.dubhe.anvilcraft.init.ModBlocks; import dev.dubhe.anvilcraft.init.ModItemTags; -import dev.dubhe.anvilcraft.inventory.SimpleCraftingContainer; import dev.dubhe.anvilcraft.util.IItemStackUtil; import lombok.Getter; -import lombok.Setter; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementRewards; import net.minecraft.advancements.CriterionTriggerInstance; @@ -62,6 +60,7 @@ import net.minecraft.world.level.block.CampfireBlock; import net.minecraft.world.level.block.TrapDoorBlock; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Half; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; @@ -85,7 +84,6 @@ public class AnvilRecipe implements Recipe { private final List outcomes = new ArrayList<>(); private final ItemStack icon; private final Map data = new HashMap<>(); - @Setter @Getter private AnvilRecipeType anvilRecipeType = AnvilRecipeType.GENERIC; @@ -108,6 +106,11 @@ public int getWeightCoefficient() { return weight; } + public AnvilRecipe setAnvilRecipeType(AnvilRecipeType anvilRecipeType) { + this.anvilRecipeType = anvilRecipeType; + return this; + } + @SuppressWarnings("UnusedReturnValue") public AnvilRecipe addPredicates(RecipePredicate... predicates) { this.predicates.addAll(Arrays.stream(predicates).toList()); @@ -196,7 +199,7 @@ public enum Serializer implements RecipeSerializer { AnvilRecipe recipe = new AnvilRecipe(recipeId, icon); recipe.setAnvilRecipeType( AnvilRecipeType.of( - serializedRecipe.getAsJsonPrimitive("anvil_recipe_type").getAsString()) + serializedRecipe.getAsJsonPrimitive("anvil_recipe_type").getAsString()) ); JsonArray predicates = GsonHelper.getAsJsonArray(serializedRecipe, "predicates"); for (JsonElement predicate : predicates) { @@ -776,7 +779,6 @@ public void save(@NotNull Consumer finishedRecipeConsumer, @NotN ); } - @SuppressWarnings("LombokGetterMayBeUsed") static class Result implements FinishedRecipe { @Getter private final ResourceLocation id; @@ -866,262 +868,173 @@ public static void init() { RecipeOutcome.register("select_one", SelectOne::new, SelectOne::new); } - /** - * 深度复制 - */ - public AnvilRecipe copy() { - AnvilRecipe anvilRecipe = new AnvilRecipe(id, icon); - anvilRecipe.setAnvilRecipeType(this.getAnvilRecipeType()); - outcomes.forEach(anvilRecipe::addOutcomes); - predicates.forEach(anvilRecipe::addPredicates); - return anvilRecipe; - } - /** * 将熔炉配方转换至铁砧工艺配方 */ - public static List of(SmeltingRecipe blastingRecipe, RegistryAccess registryAccess) { - List anvilRecipes = new ArrayList<>(); - AnvilRecipe anvilRecipe = new AnvilRecipe( - AnvilCraft.of(blastingRecipe.getId().getPath() + "_translate_from_smelting_recipe"), - blastingRecipe.getResultItem(registryAccess) - ); - anvilRecipe.setAnvilRecipeType(AnvilRecipeType.SUPER_HEATING); - anvilRecipe - .addPredicates( + public static @Nullable AnvilRecipe of(@NotNull SmeltingRecipe recipe, RegistryAccess registryAccess) { + if (recipe.getIngredients().isEmpty()) return null; + return new AnvilRecipe( + AnvilCraft.of(recipe.getId().getPath() + "_translate_from_smelting_recipe"), + recipe.getResultItem(registryAccess) + ) + .setAnvilRecipeType(AnvilRecipeType.SUPER_HEATING) + .addPredicates( new HasBlock( - new Vec3(0, -2, 0), - new HasBlock.ModBlockPredicate().block(ModBlocks.HEATER.get()) - .property(Map.entry(OVERLOAD, false)) + new Vec3(0, -2, 0), + new HasBlock.ModBlockPredicate().block(ModBlocks.HEATER.get()).property(Map.entry(OVERLOAD, false)) ), - new HasBlock( - new Vec3(0, -1, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) - ); - NonNullList ingredients = blastingRecipe.getIngredients(); - for (Ingredient ingredient : ingredients) { - for (ItemStack itemStack : ingredient.getItems()) { - AnvilRecipe anvilRecipe1 = anvilRecipe - .copy() - .addPredicates(new HasItemIngredient(new Vec3(0, -1, 0), - HasItem.ModItemPredicate - .of(itemStack.getItem()) - .withCount(MinMaxBounds.Ints.atLeast(itemStack.getCount())))); - ItemStack resultItem = blastingRecipe.getResultItem(registryAccess); - resultItem.setCount( - itemStack.is(ModItemTags.RAW_ORES) - || itemStack.is(ModItemTags.FORGE_RAW_ORES) - || itemStack.is(ModItemTags.ORES) - || itemStack.is(ModItemTags.FORGE_ORES) - ? blastingRecipe.getResultItem(registryAccess).getCount() * 2 - : blastingRecipe.getResultItem(registryAccess).getCount() - ); - anvilRecipe1.addOutcomes(new SpawnItem(new Vec3(0, -1, 0), 1, resultItem)); - anvilRecipes.add(anvilRecipe1); - } - } - return anvilRecipes; + new HasBlock(new Vec3(0, -1, 0), new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) + ) + .addOutcomes(new SpawnItem(new Vec3(0, -1, 0), 1, recipe.getResultItem(registryAccess))) + .addPredicates(HasItemIngredient.of(new Vec3(0, -1, 0), recipe.getIngredients().get(0))); } - /** * 将高炉配方转换至铁砧工艺配方 */ - public static List of(BlastingRecipe blastingRecipe, RegistryAccess registryAccess) { + public static @Nullable AnvilRecipe of(@NotNull BlastingRecipe recipe, RegistryAccess registryAccess) { + if (recipe.getIngredients().isEmpty()) return null; List anvilRecipes = new ArrayList<>(); + Ingredient ingredient = recipe.getIngredients().get(0); AnvilRecipe anvilRecipe = new AnvilRecipe( - AnvilCraft.of(blastingRecipe.getId().getPath() + "_translate_from_blasting_recipe"), - blastingRecipe.getResultItem(registryAccess) - ); - anvilRecipe.setAnvilRecipeType(AnvilRecipeType.SUPER_HEATING); - anvilRecipe.addPredicates( + AnvilCraft.of(recipe.getId().getPath() + "_translate_from_blasting_recipe"), + recipe.getResultItem(registryAccess) + ) + .setAnvilRecipeType(AnvilRecipeType.SUPER_HEATING) + .addPredicates( new HasBlock( - new Vec3(0, -1, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON) + new Vec3(0, -2, 0), + new HasBlock.ModBlockPredicate().block(ModBlocks.HEATER.get()).property(Map.entry(OVERLOAD, false)) ), - new HasBlock( - new Vec3(0, -2, 0), - new HasBlock.ModBlockPredicate().block(ModBlocks.HEATER.get()) - .property(Map.entry(OVERLOAD, false)) - ) - ); - NonNullList ingredients = blastingRecipe.getIngredients(); - for (Ingredient ingredient : ingredients) { - for (ItemStack itemStack : ingredient.getItems()) { - AnvilRecipe anvilRecipe1 = anvilRecipe - .copy() - .addPredicates(new HasItemIngredient(new Vec3(0, -1, 0), - HasItem.ModItemPredicate - .of(itemStack.getItem()) - .withCount(MinMaxBounds.Ints.atLeast(itemStack.getCount())))); - ItemStack resultItem = blastingRecipe.getResultItem(registryAccess); - resultItem.setCount( - itemStack.is(ModItemTags.RAW_ORES) - || itemStack.is(ModItemTags.FORGE_RAW_ORES) - || itemStack.is(ModItemTags.ORES) - || itemStack.is(ModItemTags.FORGE_ORES) - ? blastingRecipe.getResultItem(registryAccess).getCount() * 2 - : blastingRecipe.getResultItem(registryAccess).getCount() - ); - anvilRecipe1.addOutcomes(new SpawnItem(new Vec3(0, -1, 0), 1, resultItem)); - anvilRecipes.add(anvilRecipe1); - } - } - return anvilRecipes; + new HasBlock(new Vec3(0, -1, 0), new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) + ) + .addPredicates(HasItemIngredient.of(new Vec3(0, -1, 0), ingredient)); + ItemStack resultItem = recipe.getResultItem(registryAccess); + for (ItemStack item : ingredient.getItems()) { + if (item.is(ModItemTags.RAW_ORES) + || item.is(ModItemTags.FORGE_RAW_ORES) + || item.is(ModItemTags.ORES) + || item.is(ModItemTags.FORGE_ORES)) { + resultItem.setCount(recipe.getResultItem(registryAccess).getCount() * 2); + break; + } else resultItem.setCount(recipe.getResultItem(registryAccess).getCount()); + } + anvilRecipe.addOutcomes(new SpawnItem(new Vec3(0, -1, 0), 1, resultItem)); + return anvilRecipe; } - /** * 将烟熏配方转换至铁砧工艺配方 */ - public static List of(SmokingRecipe smokingRecipe, RegistryAccess registryAccess) { - final List anvilRecipes = new ArrayList<>(); - AnvilRecipe anvilRecipe = new AnvilRecipe( - AnvilCraft.of(smokingRecipe.getId().getPath() + "_translate_from_smoking_recipe"), - smokingRecipe.getResultItem(registryAccess) - ); - anvilRecipe.setAnvilRecipeType(AnvilRecipeType.COOKING); - anvilRecipe.addPredicates( + public static @Nullable AnvilRecipe of(@NotNull SmokingRecipe recipe, RegistryAccess registryAccess) { + if (recipe.getIngredients().isEmpty()) return null; + return new AnvilRecipe( + AnvilCraft.of(recipe.getId().getPath() + "_translate_from_smoking_recipe"), + recipe.getResultItem(registryAccess) + ) + .setAnvilRecipeType(AnvilRecipeType.COOKING) + .addPredicates( new HasBlock( - new Vec3(0, -2, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAMPFIRE) - .property(CampfireBlock.LIT, true) + new Vec3(0, -2, 0), + new HasBlock.ModBlockPredicate().block(Blocks.CAMPFIRE).property(CampfireBlock.LIT, true) ), - new HasBlock( - new Vec3(0, -1, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) - ); - anvilRecipe.addOutcomes( - new SpawnItem( - new Vec3(0, -1, 0), - 1, - smokingRecipe.getResultItem(registryAccess) - ) - ); - NonNullList ingredients = smokingRecipe.getIngredients(); - for (Ingredient ingredient : ingredients) { - for (ItemStack itemStack : ingredient.getItems()) { - anvilRecipes.add(anvilRecipe.copy().addPredicates(new HasItemIngredient(new Vec3(0, -1, 0), - HasItem.ModItemPredicate - .of(itemStack.getItem()) - .withCount(MinMaxBounds.Ints.atLeast(itemStack.getCount()))))); - } - } - return anvilRecipes; + new HasBlock(new Vec3(0, -1, 0), new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) + ) + .addOutcomes(new SpawnItem(new Vec3(0, -1, 0), 1, recipe.getResultItem(registryAccess))) + .addPredicates(HasItemIngredient.of(new Vec3(0, -1, 0), recipe.getIngredients().get(0))); } /** * 将篝火配方转换至铁砧工艺配方 */ - public static List of(CampfireCookingRecipe campfireCookingRecipe, RegistryAccess registryAccess) { - final List anvilRecipes = new ArrayList<>(); - AnvilRecipe anvilRecipe = new AnvilRecipe( - AnvilCraft.of(campfireCookingRecipe.getId().getPath() + "_translate_from_campfire_recipe"), - campfireCookingRecipe.getResultItem(registryAccess) - ); - anvilRecipe.setAnvilRecipeType(AnvilRecipeType.COOKING); - anvilRecipe.addPredicates( + public static @Nullable AnvilRecipe of(@NotNull CampfireCookingRecipe recipe, RegistryAccess registryAccess) { + if (recipe.getIngredients().isEmpty()) return null; + return new AnvilRecipe( + AnvilCraft.of(recipe.getId().getPath() + "_translate_from_campfire_recipe"), + recipe.getResultItem(registryAccess) + ) + .setAnvilRecipeType(AnvilRecipeType.COOKING) + .addPredicates( new HasBlock( - new Vec3(0, -2, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAMPFIRE) - .property(CampfireBlock.LIT, true) + new Vec3(0, -2, 0), + new HasBlock.ModBlockPredicate().block(Blocks.CAMPFIRE).property(CampfireBlock.LIT, true) ), new HasBlock( - new Vec3(0, -1, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) - ); - anvilRecipe.addOutcomes( - new SpawnItem( - new Vec3(0, -1, 0), - 1, - campfireCookingRecipe.getResultItem(registryAccess) - ) - ); - NonNullList ingredients = campfireCookingRecipe.getIngredients(); - for (Ingredient ingredient : ingredients) { - for (ItemStack itemStack : ingredient.getItems()) { - anvilRecipes.add(anvilRecipe.copy().addPredicates(new HasItemIngredient(new Vec3(0, -1, 0), - HasItem.ModItemPredicate - .of(itemStack.getItem()) - .withCount(MinMaxBounds.Ints.atLeast(itemStack.getCount()))))); - } - } - return anvilRecipes; + new Vec3(0, -1, 0), + new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) + ) + .addOutcomes(new SpawnItem(new Vec3(0, -1, 0), 1, recipe.getResultItem(registryAccess))) + .addPredicates(HasItemIngredient.of(new Vec3(0, -1, 0), recipe.getIngredients().get(0))); } /** * 将工作台配方转换至铁砧工艺配方 */ - public static List of(CraftingRecipe craftingRecipe, RegistryAccess registryAccess) { - List anvilRecipes = new ArrayList<>(); + public static @Nullable AnvilRecipe of(@NotNull CraftingRecipe recipe, RegistryAccess registryAccess) { + if (recipe.getIngredients().isEmpty()) return null; + ItemStack resultItem = recipe.getResultItem(registryAccess); AnvilRecipe anvilRecipe = new AnvilRecipe( - AnvilCraft.of(craftingRecipe.getId().getPath() + "_translate_from_crafting_recipe"), - craftingRecipe.getResultItem(registryAccess) - ); - if (craftingRecipe instanceof ShapedRecipe shapedRecipe - && (shapedRecipe.getIngredients().size() == 4 || shapedRecipe.getIngredients().size() == 9)) { - ItemStack[] itemStacks = shapedRecipe.getIngredients().get(0).getItems(); - for (Ingredient ingredient : shapedRecipe.getIngredients()) { - if (Arrays.stream(itemStacks).noneMatch(ingredient)) return anvilRecipes; - itemStacks = ingredient.getItems(); - } + AnvilCraft.of(recipe.getId().getPath() + "_translate_from_crafting_recipe"), + recipe.getResultItem(registryAccess) + ).addOutcomes(new SpawnItem(new Vec3(0.0, -1.0, 0.0), 1.0, resultItem)); + if (recipe instanceof ShapedRecipe shapedRecipe) { + NonNullList ingredients = shapedRecipe.getIngredients(); + List list = ingredients.stream() + .map(ingredient -> HasItemIngredient.of(new Vec3(0.0, -1.0, 0.0), ingredient)) + .toList(); + if (list.stream().anyMatch(i -> !i.getMatchItem().sameItemsOrTag(list.get(0).getMatchItem()))) return null; + int size = shapedRecipe.getIngredients().size(); + if (size != 4 && size != 9 || shapedRecipe.getWidth() != shapedRecipe.getHeight()) return null; + if (resultItem.is(Items.IRON_TRAPDOOR)) return null; anvilRecipe.setAnvilRecipeType(AnvilRecipeType.COMPRESS); anvilRecipe.addPredicates( - new HasBlock( - new Vec3(0, -1, 0), - new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) - ); - anvilRecipe.addOutcomes( - new SpawnItem( - new Vec3(0, -1, 0), - 1, - craftingRecipe.getResultItem(registryAccess) - ) + new HasBlock( + new Vec3(0, -1, 0), + new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) ); - for (ItemStack itemStack : itemStacks) { - anvilRecipes.add(anvilRecipe.copy().addPredicates(new HasItemIngredient( - new Vec3(0, -1, 0), - HasItem.ModItemPredicate - .of(itemStack.getItem()) - .withCount(MinMaxBounds.Ints.atLeast(shapedRecipe.getIngredients().size()))))); + for (HasItemIngredient ingredient : list) { + anvilRecipe.addPredicates(ingredient); } - } - if (craftingRecipe instanceof ShapelessRecipe shapelessRecipe - && shapelessRecipe.getResultItem(registryAccess).getCount() > 1) { + return anvilRecipe; + } else if ( + recipe instanceof ShapelessRecipe shapelessRecipe + && shapelessRecipe.getIngredients().size() == 1 + ) { + NonNullList ingredients = shapelessRecipe.getIngredients(); anvilRecipe.setAnvilRecipeType(AnvilRecipeType.ITEM_SMASH); anvilRecipe.addPredicates( - new HasBlock( - new Vec3(0, -1, 0), - new HasBlock.ModBlockPredicate().block(Blocks.IRON_TRAPDOOR) - .property(Map.entry(TrapDoorBlock.OPEN, false))) - ); - anvilRecipe.addOutcomes( - new SpawnItem( - new Vec3(0, -1, 0), - 1, - craftingRecipe.getResultItem(registryAccess) - ) + new HasBlock( + new Vec3(0, -1, 0), + new HasBlock.ModBlockPredicate().block(Blocks.IRON_TRAPDOOR) + .property( + Map.entry(TrapDoorBlock.OPEN, false), + Map.entry(TrapDoorBlock.HALF, Half.TOP) + )) ); - craftingRecipe.getRemainingItems(new SimpleCraftingContainer()).forEach(itemStack -> { - if (!itemStack.isEmpty()) - anvilRecipe.addOutcomes( - new SpawnItem( - new Vec3(0, -1, 0), - 1, - itemStack - )); - }); - NonNullList ingredients = craftingRecipe.getIngredients(); for (Ingredient ingredient : ingredients) { - for (ItemStack itemStack : ingredient.getItems()) { - anvilRecipes.add(anvilRecipe.copy().addPredicates(new HasItemIngredient(Vec3.ZERO, - HasItem.ModItemPredicate - .of(itemStack.getItem()) - .withCount(MinMaxBounds.Ints.atLeast(itemStack.getCount()))))); - } + anvilRecipe.addPredicates(HasItemIngredient.of(new Vec3(0.0, 0.0, 0.0), ingredient)); + } + return anvilRecipe; + } else if ( + recipe instanceof ShapelessRecipe shapelessRecipe + ) { + NonNullList ingredients = shapelessRecipe.getIngredients(); + List list = ingredients.stream() + .map(ingredient -> HasItemIngredient.of(new Vec3(0.0, -1.0, 0.0), ingredient)) + .toList(); + if (list.stream().anyMatch(i -> !i.getMatchItem().sameItemsOrTag(list.get(0).getMatchItem()))) return null; + anvilRecipe.setAnvilRecipeType(AnvilRecipeType.COMPRESS); + anvilRecipe.addPredicates( + new HasBlock( + new Vec3(0, -1, 0), + new HasBlock.ModBlockPredicate().block(Blocks.CAULDRON)) + ); + for (HasItemIngredient ingredient : list) { + anvilRecipe.addPredicates(ingredient); } + return anvilRecipe; } - return anvilRecipes; + return null; } } diff --git a/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItem.java b/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItem.java index 6103a13d7..f8c593dda 100644 --- a/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItem.java +++ b/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItem.java @@ -222,6 +222,25 @@ public static class ModItemPredicate { private ModItemPredicate() { } + /** + * 是否具有相同的物品/标签 + */ + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean sameItemsOrTag(ModItemPredicate predicate) { + if (this == predicate) return true; + if ( + this.tag != null && predicate.tag != null + && !this.tag.location().equals(predicate.tag.location()) + ) { + return false; + } + if (this.items.size() != predicate.items.size()) return false; + for (Item item : items) { + if (!predicate.items.contains(item)) return false; + } + return true; + } + /** * ModItemPredicate */ diff --git a/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItemIngredient.java b/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItemIngredient.java index b043092bc..c92788750 100644 --- a/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItemIngredient.java +++ b/common/src/main/java/dev/dubhe/anvilcraft/data/recipe/anvil/predicate/HasItemIngredient.java @@ -3,6 +3,7 @@ import com.google.common.base.Predicates; import com.google.gson.JsonObject; import dev.dubhe.anvilcraft.data.recipe.anvil.AnvilCraftingContainer; +import dev.dubhe.anvilcraft.mixin.IngredientValueAccessor; import lombok.Getter; import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.core.BlockPos; @@ -53,10 +54,10 @@ public HasItemIngredient(@NotNull FriendlyByteBuf buffer) { ModItemPredicate item = ModItemPredicate.of().withCount(MinMaxBounds.Ints.atLeast(count)); List items = new ArrayList<>(); for (Ingredient.Value value : ingredient.values) { - if (value instanceof Ingredient.TagValue tagValue) - item.withTag(tagValue.tag); - if (value instanceof Ingredient.ItemValue itemValue) - items.add(itemValue.item.getItem()); + if (value instanceof IngredientValueAccessor.Tag tagValue) + item.withTag(tagValue.getTag()); + if (value instanceof IngredientValueAccessor.Item itemValue) + items.add(itemValue.getItem().getItem()); } item.add(items.toArray(ItemLike[]::new)); return new HasItemIngredient(offset, item); diff --git a/common/src/main/java/dev/dubhe/anvilcraft/mixin/IngredientValueAccessor.java b/common/src/main/java/dev/dubhe/anvilcraft/mixin/IngredientValueAccessor.java new file mode 100644 index 000000000..9bc9b9380 --- /dev/null +++ b/common/src/main/java/dev/dubhe/anvilcraft/mixin/IngredientValueAccessor.java @@ -0,0 +1,27 @@ +package dev.dubhe.anvilcraft.mixin; + +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +public class IngredientValueAccessor { + /** + * Mixin + */ + @Mixin(Ingredient.ItemValue.class) + public interface Item { + @Accessor + ItemStack getItem(); + } + + /** + * Mixin + */ + @Mixin(Ingredient.TagValue.class) + public interface Tag { + @Accessor + TagKey getTag(); + } +} diff --git a/common/src/main/resources/anvilcraft-common.mixins.json b/common/src/main/resources/anvilcraft-common.mixins.json index 4092a72db..fe9c44735 100644 --- a/common/src/main/resources/anvilcraft-common.mixins.json +++ b/common/src/main/resources/anvilcraft-common.mixins.json @@ -18,6 +18,8 @@ "FallingBlockEntityMixin", "FlyingHitEntityMixin", "HoeItemMixin", + "IngredientValueAccessor$Item", + "IngredientValueAccessor$Tag", "ItemEntityMixin", "LivingEntityMixin", "PistonBaseBlockMixin",