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<AnvilRecipe> ANVIL_RECIPE_SET = List.of();
+    @Getter
+    private static List<AnvilRecipe> anvilRecipeList = List.of();
 
     /**
      * 更新配方
      *
      * @param server 服务器实例
      */
-    public static void updateRecipes(MinecraftServer server) {
+    public static void updateRecipes(@NotNull MinecraftServer server) {
         RecipeManager manager = server.getRecipeManager();
         ArrayList<AnvilRecipe> anvilRecipes = new ArrayList<>(manager.getAllRecipesFor(ModRecipeTypes.ANVIL_RECIPE));
-        ArrayList<AnvilRecipe> smokingRecipes = new ArrayList<>();
-        ArrayList<AnvilRecipe> 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 =
-                            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<AnvilRecipe> getAnvilRecipeList() {
-        return ANVIL_RECIPE_SET;
+        List<ItemStack> 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<AnvilCraftingContainer> {
     private final List<RecipeOutcome> outcomes = new ArrayList<>();
     private final ItemStack icon;
     private final Map<String, CompoundTag> 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> {
             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<FinishedRecipe> 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<AnvilRecipe> of(SmeltingRecipe blastingRecipe, RegistryAccess registryAccess) {
-        List<AnvilRecipe> 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<Ingredient> 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<AnvilRecipe> of(BlastingRecipe blastingRecipe, RegistryAccess registryAccess) {
+    public static @Nullable AnvilRecipe of(@NotNull BlastingRecipe recipe, RegistryAccess registryAccess) {
+        if (recipe.getIngredients().isEmpty()) return null;
         List<AnvilRecipe> 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<Ingredient> 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<AnvilRecipe> of(SmokingRecipe smokingRecipe, RegistryAccess registryAccess) {
-        final List<AnvilRecipe> 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<Ingredient> 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<AnvilRecipe> of(CampfireCookingRecipe campfireCookingRecipe, RegistryAccess registryAccess) {
-        final List<AnvilRecipe> 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<Ingredient> 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<AnvilRecipe> of(CraftingRecipe craftingRecipe, RegistryAccess registryAccess) {
-        List<AnvilRecipe> 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<Ingredient> ingredients = shapedRecipe.getIngredients();
+            List<HasItemIngredient> 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<Ingredient> 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<Ingredient> 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<Ingredient> ingredients = shapelessRecipe.getIngredients();
+            List<HasItemIngredient> 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<Item> 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<net.minecraft.world.item.Item> 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",