package net.minecraft.data.recipes; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.mojang.datafixers.util.Pair; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.advancements.predicates.ItemPredicate; import net.minecraft.advancements.predicates.MinMaxBounds; import net.minecraft.advancements.triggers.BredAnimalsTrigger; import net.minecraft.advancements.triggers.CriteriaTriggers; import net.minecraft.advancements.triggers.Criterion; import net.minecraft.advancements.triggers.EnterBlockTrigger; import net.minecraft.advancements.triggers.ImpossibleTrigger; import net.minecraft.advancements.triggers.InventoryChangeTrigger; import net.minecraft.core.Holder; import net.minecraft.core.HolderGetter; import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.data.BlockFamilies; import net.minecraft.data.BlockFamily; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.tags.ItemTags; import net.minecraft.tags.TagKey; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.item.HoneycombItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStackTemplate; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.AbstractCookingRecipe; import net.minecraft.world.item.crafting.BannerDuplicateRecipe; import net.minecraft.world.item.crafting.BlastingRecipe; import net.minecraft.world.item.crafting.CookingBookCategory; import net.minecraft.world.item.crafting.DyeRecipe; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.SmeltingRecipe; import net.minecraft.world.item.equipment.trim.TrimPattern; import net.minecraft.world.level.ItemLike; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SuspiciousEffectHolder; import org.jspecify.annotations.Nullable; /** * Access widened by fabric-data-generation-api-v1 to accessible */ public abstract class RecipeProvider { protected final HolderLookup.Provider registries; private final HolderGetter items; protected final RecipeOutput output; private static final Map SHAPE_BUILDERS = ImmutableMap.builder() .put(BlockFamily.Variant.BUTTON, (context, result, base) -> context.buttonBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.CHISELED, (context, result, base) -> context.chiseledBuilder(RecipeCategory.BUILDING_BLOCKS, result, Ingredient.of(base))) .put(BlockFamily.Variant.CUT, (context, result, base) -> context.cutBuilder(RecipeCategory.BUILDING_BLOCKS, result, Ingredient.of(base))) .put(BlockFamily.Variant.DOOR, (context, result, base) -> context.doorBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.CUSTOM_FENCE, (context, result, base) -> context.fenceBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.FENCE, (context, result, base) -> context.fenceBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.CUSTOM_FENCE_GATE, (context, result, base) -> context.fenceGateBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.FENCE_GATE, (context, result, base) -> context.fenceGateBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.SIGN, (context, result, base) -> context.signBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.SLAB, (context, result, base) -> context.slabBuilder(RecipeCategory.BUILDING_BLOCKS, result, Ingredient.of(base))) .put(BlockFamily.Variant.STAIRS, (context, result, base) -> context.stairBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.PRESSURE_PLATE, (context, result, base) -> context.pressurePlateBuilder(RecipeCategory.REDSTONE, result, Ingredient.of(base))) .put(BlockFamily.Variant.POLISHED, (context, result, base) -> context.polishedBuilder(RecipeCategory.BUILDING_BLOCKS, result, Ingredient.of(base))) .put(BlockFamily.Variant.TRAPDOOR, (context, result, base) -> context.trapdoorBuilder(result, Ingredient.of(base))) .put(BlockFamily.Variant.WALL, (context, result, base) -> context.wallBuilder(RecipeCategory.DECORATIONS, result, Ingredient.of(base))) .put(BlockFamily.Variant.BRICKS, (context, result, base) -> context.bricksBuilder(RecipeCategory.BUILDING_BLOCKS, result, Ingredient.of(base))) .put(BlockFamily.Variant.TILES, (context, result, base) -> context.tilesBuilder(RecipeCategory.BUILDING_BLOCKS, result, Ingredient.of(base))) .build(); private static final Map STONECUTTER_RECIPE_BUILDERS = ImmutableMap.builder() .put(BlockFamily.Variant.SLAB, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 2)) .put(BlockFamily.Variant.STAIRS, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .put(BlockFamily.Variant.BRICKS, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .put(BlockFamily.Variant.WALL, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.DECORATIONS, result, base, 1)) .put(BlockFamily.Variant.CHISELED, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .put(BlockFamily.Variant.POLISHED, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .put(BlockFamily.Variant.CUT, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .put(BlockFamily.Variant.TILES, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .put(BlockFamily.Variant.COBBLED, (context, result, base) -> context.stonecutterResultFromBase(RecipeCategory.BUILDING_BLOCKS, result, base, 1)) .build(); protected RecipeProvider(final HolderLookup.Provider registries, final RecipeOutput output) { this.registries = registries; this.items = registries.lookupOrThrow(Registries.ITEM); this.output = output; } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public abstract void buildRecipes(); /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void generateForEnabledBlockFamilies(final FeatureFlagSet flagSet) { BlockFamilies.getAllFamilies().forEach(family -> this.generateRecipes(family, flagSet)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void oneToOneConversionRecipe(final ItemLike product, final ItemLike resource, @Nullable final String group) { this.oneToOneConversionRecipe(product, resource, group, 1); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void oneToOneConversionRecipe(final ItemLike product, final ItemLike resource, @Nullable final String group, final int productCount) { this.shapeless(RecipeCategory.MISC, product, productCount) .requires(resource) .group(group) .unlockedBy(getHasName(resource), this.has(resource)) .save(this.output, getConversionRecipeName(product, resource)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void oreSmelting( final List smeltables, final RecipeCategory craftingCategory, final CookingBookCategory cookingCategory, final ItemLike result, final float experience, final int cookingTime, final String group ) { this.oreCooking(SmeltingRecipe::new, smeltables, craftingCategory, cookingCategory, result, experience, cookingTime, group, "_from_smelting"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void oreBlasting( final List smeltables, final RecipeCategory craftingCategory, final CookingBookCategory cookingCategory, final ItemLike result, final float experience, final int cookingTime, final String group ) { this.oreCooking(BlastingRecipe::new, smeltables, craftingCategory, cookingCategory, result, experience, cookingTime, group, "_from_blasting"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final void oreCooking( final AbstractCookingRecipe.Factory factory, final List smeltables, final RecipeCategory craftingCategory, final CookingBookCategory cookingCategory, final ItemLike result, final float experience, final int cookingTime, final String group, final String fromDesc ) { for (ItemLike item : smeltables) { SimpleCookingRecipeBuilder.generic(Ingredient.of(item), craftingCategory, cookingCategory, result, experience, cookingTime, factory) .group(group) .unlockedBy(getHasName(item), this.has(item)) .save(this.output, getItemName(result) + fromDesc + "_" + getItemName(item)); } } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void netheriteSmithing(final Item base, final RecipeCategory category, final Item result) { SmithingTransformRecipeBuilder.smithing( Ingredient.of(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE), Ingredient.of(base), this.tag(ItemTags.NETHERITE_TOOL_MATERIALS), category, result ) .unlocks("has_netherite_ingot", this.has(ItemTags.NETHERITE_TOOL_MATERIALS)) .save(this.output, getItemName(result) + "_smithing"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void trimSmithing(final Item trimTemplate, final ResourceKey patternId, final ResourceKey> id) { Holder.Reference pattern = this.registries.lookupOrThrow(Registries.TRIM_PATTERN).getOrThrow(patternId); SmithingTrimRecipeBuilder.smithingTrim( Ingredient.of(trimTemplate), this.tag(ItemTags.TRIMMABLE_ARMOR), this.tag(ItemTags.TRIM_MATERIALS), pattern, RecipeCategory.MISC ) .unlocks("has_smithing_trim_template", this.has(trimTemplate)) .save(this.output, id); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void twoByTwoPacker(final RecipeCategory category, final ItemLike result, final ItemLike ingredient) { this.shaped(category, result, 1) .define('#', ingredient) .pattern("##") .pattern("##") .unlockedBy(getHasName(ingredient), this.has(ingredient)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void threeByThreePacker(final RecipeCategory category, final ItemLike result, final ItemLike ingredient, final String unlockedBy) { this.shapeless(category, result).requires(ingredient, 9).unlockedBy(unlockedBy, this.has(ingredient)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void threeByThreePacker(final RecipeCategory category, final ItemLike result, final ItemLike ingredient) { this.threeByThreePacker(category, result, ingredient, getHasName(ingredient)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void planksFromLog(final ItemLike result, final TagKey logs, final int count) { this.shapeless(RecipeCategory.BUILDING_BLOCKS, result, count).requires(logs).group("planks").unlockedBy("has_log", this.has(logs)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void planksFromLogs(final ItemLike result, final TagKey logs, final int count) { this.shapeless(RecipeCategory.BUILDING_BLOCKS, result, count).requires(logs).group("planks").unlockedBy("has_logs", this.has(logs)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void woodFromLogs(final ItemLike result, final ItemLike log) { this.shaped(RecipeCategory.BUILDING_BLOCKS, result, 3) .define('#', log) .pattern("##") .pattern("##") .group("bark") .unlockedBy("has_log", this.has(log)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void woodenBoat(final ItemLike result, final ItemLike planks) { this.shaped(RecipeCategory.TRANSPORTATION, result) .define('#', planks) .pattern("# #") .pattern("###") .group("boat") .unlockedBy("in_water", insideOf(Blocks.WATER)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void chestBoat(final ItemLike chestBoat, final ItemLike boat) { this.shapeless(RecipeCategory.TRANSPORTATION, chestBoat) .requires(Blocks.CHEST) .requires(boat) .group("chest_boat") .unlockedBy("has_boat", this.has(ItemTags.BOATS)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder buttonBuilder(final ItemLike result, final Ingredient base) { return this.shapeless(RecipeCategory.REDSTONE, result).requires(base); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public RecipeBuilder doorBuilder(final ItemLike result, final Ingredient base) { return this.shaped(RecipeCategory.REDSTONE, result, 3).define('#', base).pattern("##").pattern("##").pattern("##"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder fenceBuilder(final ItemLike result, final Ingredient base) { int count = result == Blocks.NETHER_BRICK_FENCE ? 6 : 3; Item base2 = result == Blocks.NETHER_BRICK_FENCE ? Items.NETHER_BRICK : Items.STICK; return this.shaped(RecipeCategory.DECORATIONS, result, count).define('W', base).define('#', base2).pattern("W#W").pattern("W#W"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder fenceGateBuilder(final ItemLike result, final Ingredient planks) { return this.shaped(RecipeCategory.REDSTONE, result).define('#', Items.STICK).define('W', planks).pattern("#W#").pattern("#W#"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void pressurePlate(final ItemLike result, final ItemLike base) { this.pressurePlateBuilder(RecipeCategory.REDSTONE, result, Ingredient.of(base)).unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder pressurePlateBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result).define('#', base).pattern("##"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void slab(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.slabBuilder(category, result, Ingredient.of(base)).unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void shelf(final ItemLike result, final ItemLike strippedLogs) { this.shaped(RecipeCategory.DECORATIONS, result, 6) .define('#', strippedLogs) .pattern("###") .pattern(" ") .pattern("###") .group("shelf") .unlockedBy(getHasName(strippedLogs), this.has(strippedLogs)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public RecipeBuilder slabBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result, 6).define('#', base).pattern("###"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public RecipeBuilder stairBuilder(final ItemLike result, final Ingredient base) { return this.shaped(RecipeCategory.BUILDING_BLOCKS, result, 4).define('#', base).pattern("# ").pattern("## ").pattern("###"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public RecipeBuilder trapdoorBuilder(final ItemLike result, final Ingredient base) { return this.shaped(RecipeCategory.REDSTONE, result, 2).define('#', base).pattern("###").pattern("###"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder signBuilder(final ItemLike result, final Ingredient planks) { return this.shaped(RecipeCategory.DECORATIONS, result, 3) .group("sign") .define('#', planks) .define('X', Items.STICK) .pattern("###") .pattern("###") .pattern(" X "); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void hangingSign(final ItemLike result, final ItemLike ingredient) { this.shaped(RecipeCategory.DECORATIONS, result, 6) .group("hanging_sign") .define('#', ingredient) .define('X', Items.IRON_CHAIN) .pattern("X X") .pattern("###") .pattern("###") .unlockedBy("has_stripped_logs", this.has(ingredient)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void colorItemWithDye(final List dyes, final List items, final String groupName, final RecipeCategory category) { this.colorWithDye(dyes, items, null, groupName, category); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void colorWithDye( final List dyes, final List dyedItems, @Nullable final Item uncoloredItem, final String groupName, final RecipeCategory category ) { for (int dyeIndex = 0; dyeIndex < dyes.size(); dyeIndex++) { Item dye = (Item)dyes.get(dyeIndex); Item dyedItem = (Item)dyedItems.get(dyeIndex); Stream sourceItems = dyedItems.stream().filter(b -> !b.equals(dyedItem)); if (uncoloredItem != null) { sourceItems = Stream.concat(sourceItems, Stream.of(uncoloredItem)); } this.shapeless(category, dyedItem) .requires(dye) .requires(Ingredient.of(sourceItems)) .group(groupName) .unlockedBy("has_needed_dye", this.has(dye)) .save(this.output, "dye_" + getItemName(dyedItem)); } } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void carpet(final ItemLike result, final ItemLike sourceItem) { this.shaped(RecipeCategory.DECORATIONS, result, 3) .define('#', sourceItem) .pattern("##") .group("carpet") .unlockedBy(getHasName(sourceItem), this.has(sourceItem)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void bedFromPlanksAndWool(final ItemLike result, final ItemLike wool) { this.shaped(RecipeCategory.DECORATIONS, result) .define('#', wool) .define('X', ItemTags.PLANKS) .pattern("###") .pattern("XXX") .group("bed") .unlockedBy(getHasName(wool), this.has(wool)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void banner(final ItemLike result, final ItemLike wool) { this.shaped(RecipeCategory.DECORATIONS, result) .define('#', wool) .define('|', Items.STICK) .pattern("###") .pattern("###") .pattern(" | ") .group("banner") .unlockedBy(getHasName(wool), this.has(wool)) .save(this.output); SpecialRecipeBuilder.special(() -> new BannerDuplicateRecipe(Ingredient.of(result), new ItemStackTemplate(result.asItem()))) .save(this.output, getItemName(result) + "_duplicate"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void stainedGlassFromGlassAndDye(final ItemLike result, final ItemLike dye) { this.shaped(RecipeCategory.BUILDING_BLOCKS, result, 8) .define('#', Blocks.GLASS) .define('X', dye) .pattern("###") .pattern("#X#") .pattern("###") .group("stained_glass") .unlockedBy("has_glass", this.has(Blocks.GLASS)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void dryGhast(final ItemLike result) { this.shaped(RecipeCategory.BUILDING_BLOCKS, result, 1) .define('#', Items.GHAST_TEAR) .define('X', Items.SOUL_SAND) .pattern("###") .pattern("#X#") .pattern("###") .group("dry_ghast") .unlockedBy(getHasName(Items.GHAST_TEAR), this.has(Items.GHAST_TEAR)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void harness(final ItemLike result, final ItemLike wool) { this.shaped(RecipeCategory.COMBAT, result) .define('#', wool) .define('G', Items.GLASS) .define('L', Items.LEATHER) .pattern("LLL") .pattern("G#G") .group("harness") .unlockedBy("has_dried_ghast", this.has(Blocks.DRIED_GHAST)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void stainedGlassPaneFromStainedGlass(final ItemLike result, final ItemLike stainedGlass) { this.shaped(RecipeCategory.DECORATIONS, result, 16) .define('#', stainedGlass) .pattern("###") .pattern("###") .group("stained_glass_pane") .unlockedBy("has_glass", this.has(stainedGlass)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void stainedGlassPaneFromGlassPaneAndDye(final ItemLike result, final ItemLike dye) { this.shaped(RecipeCategory.DECORATIONS, result, 8) .define('#', Blocks.GLASS_PANE) .define('$', dye) .pattern("###") .pattern("#$#") .pattern("###") .group("stained_glass_pane") .unlockedBy("has_glass_pane", this.has(Blocks.GLASS_PANE)) .unlockedBy(getHasName(dye), this.has(dye)) .save(this.output, getConversionRecipeName(result, Blocks.GLASS_PANE)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void coloredTerracottaFromTerracottaAndDye(final ItemLike result, final ItemLike dye) { this.shaped(RecipeCategory.BUILDING_BLOCKS, result, 8) .define('#', Blocks.TERRACOTTA) .define('X', dye) .pattern("###") .pattern("#X#") .pattern("###") .group("stained_terracotta") .unlockedBy("has_terracotta", this.has(Blocks.TERRACOTTA)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void concretePowder(final ItemLike result, final ItemLike dye) { this.shapeless(RecipeCategory.BUILDING_BLOCKS, result, 8) .requires(dye) .requires(Blocks.SAND, 4) .requires(Blocks.GRAVEL, 4) .group("concrete_powder") .unlockedBy("has_sand", this.has(Blocks.SAND)) .unlockedBy("has_gravel", this.has(Blocks.GRAVEL)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void candle(final ItemLike result, final ItemLike dye) { this.shapeless(RecipeCategory.DECORATIONS, result) .requires(Blocks.CANDLE) .requires(dye) .group("dyed_candle") .unlockedBy(getHasName(dye), this.has(dye)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void wall(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.wallBuilder(category, result, Ingredient.of(base)).unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder wallBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result, 6).define('#', base).pattern("###").pattern("###"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder bricksBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result, 4).define('#', base).pattern("##").pattern("##"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder tilesBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result, 4).define('#', base).pattern("##").pattern("##"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void polished(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.polishedBuilder(category, result, Ingredient.of(base)).unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final RecipeBuilder polishedBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result, 4).define('S', base).pattern("SS").pattern("SS"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void cut(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.cutBuilder(category, result, Ingredient.of(base)).unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final ShapedRecipeBuilder cutBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result, 4).define('#', base).pattern("##").pattern("##"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void chiseled(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.chiseledBuilder(category, result, Ingredient.of(base)).unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void mosaicBuilder(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.shaped(category, result).define('#', base).pattern("#").pattern("#").unlockedBy(getHasName(base), this.has(base)).save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public ShapedRecipeBuilder chiseledBuilder(final RecipeCategory category, final ItemLike result, final Ingredient base) { return this.shaped(category, result).define('#', base).pattern("#").pattern("#"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void stonecutterResultFromBase(final RecipeCategory category, final ItemLike result, final ItemLike base) { this.stonecutterResultFromBase(category, result, base, 1); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void stonecutterResultFromBase(final RecipeCategory category, final ItemLike result, final ItemLike base, final int count) { SingleItemRecipeBuilder.stonecutting(Ingredient.of(base), category, result, count) .unlockedBy(getHasName(base), this.has(base)) .save(this.output, getConversionRecipeName(result, base) + "_stonecutting"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final void smeltingResultFromBase(final ItemLike result, final ItemLike base) { SimpleCookingRecipeBuilder.smelting(Ingredient.of(base), RecipeCategory.BUILDING_BLOCKS, CookingBookCategory.BLOCKS, result, 0.1F, 200) .unlockedBy(getHasName(base), this.has(base)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void nineBlockStorageRecipes( final RecipeCategory unpackedFormCategory, final ItemLike unpackedForm, final RecipeCategory packedFormCategory, final ItemLike packedForm ) { this.nineBlockStorageRecipes( unpackedFormCategory, unpackedForm, packedFormCategory, packedForm, getSimpleRecipeName(packedForm), null, getSimpleRecipeName(unpackedForm), null ); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void nineBlockStorageRecipesWithCustomPacking( final RecipeCategory unpackedFormCategory, final ItemLike unpackedForm, final RecipeCategory packedFormCategory, final ItemLike packedForm, final String packingRecipeId, final String packingRecipeGroup ) { this.nineBlockStorageRecipes( unpackedFormCategory, unpackedForm, packedFormCategory, packedForm, packingRecipeId, packingRecipeGroup, getSimpleRecipeName(unpackedForm), null ); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void nineBlockStorageRecipesRecipesWithCustomUnpacking( final RecipeCategory unpackedFormCategory, final ItemLike unpackedForm, final RecipeCategory packedFormCategory, final ItemLike packedForm, final String unpackingRecipeId, final String unpackingRecipeGroup ) { this.nineBlockStorageRecipes( unpackedFormCategory, unpackedForm, packedFormCategory, packedForm, getSimpleRecipeName(packedForm), null, unpackingRecipeId, unpackingRecipeGroup ); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final void nineBlockStorageRecipes( final RecipeCategory unpackedFormCategory, final ItemLike unpackedForm, final RecipeCategory packedFormCategory, final ItemLike packedForm, final String packingRecipeId, @Nullable final String packingRecipeGroup, final String unpackingRecipeId, @Nullable final String unpackingRecipeGroup ) { this.shapeless(unpackedFormCategory, unpackedForm, 9) .requires(packedForm) .group(unpackingRecipeGroup) .unlockedBy(getHasName(packedForm), this.has(packedForm)) .save(this.output, ResourceKey.create(Registries.RECIPE, Identifier.parse(unpackingRecipeId))); this.shaped(packedFormCategory, packedForm) .define('#', unpackedForm) .pattern("###") .pattern("###") .pattern("###") .group(packingRecipeGroup) .unlockedBy(getHasName(unpackedForm), this.has(unpackedForm)) .save(this.output, ResourceKey.create(Registries.RECIPE, Identifier.parse(packingRecipeId))); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void copySmithingTemplate(final ItemLike smithingTemplate, final ItemLike baseMaterial) { this.shaped(RecipeCategory.MISC, smithingTemplate, 2) .define('#', Items.DIAMOND) .define('C', baseMaterial) .define('S', smithingTemplate) .pattern("#S#") .pattern("#C#") .pattern("###") .unlockedBy(getHasName(smithingTemplate), this.has(smithingTemplate)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void copySmithingTemplate(final ItemLike smithingTemplate, final Ingredient baseMaterials) { this.shaped(RecipeCategory.MISC, smithingTemplate, 2) .define('#', Items.DIAMOND) .define('C', baseMaterials) .define('S', smithingTemplate) .pattern("#S#") .pattern("#C#") .pattern("###") .unlockedBy(getHasName(smithingTemplate), this.has(smithingTemplate)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void cookRecipes(final String source, final AbstractCookingRecipe.Factory factory, final int cookingTime) { this.simpleCookingRecipe(source, factory, cookingTime, Items.BEEF, Items.COOKED_BEEF, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.CHICKEN, Items.COOKED_CHICKEN, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.COD, Items.COOKED_COD, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.KELP, Items.DRIED_KELP, 0.1F); this.simpleCookingRecipe(source, factory, cookingTime, Items.SALMON, Items.COOKED_SALMON, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.MUTTON, Items.COOKED_MUTTON, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.PORKCHOP, Items.COOKED_PORKCHOP, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.POTATO, Items.BAKED_POTATO, 0.35F); this.simpleCookingRecipe(source, factory, cookingTime, Items.RABBIT, Items.COOKED_RABBIT, 0.35F); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final void simpleCookingRecipe( final String source, final AbstractCookingRecipe.Factory factory, final int cookingTime, final ItemLike base, final ItemLike result, final float experience ) { SimpleCookingRecipeBuilder.generic(Ingredient.of(base), RecipeCategory.FOOD, CookingBookCategory.FOOD, result, experience, cookingTime, factory) .unlockedBy(getHasName(base), this.has(base)) .save(this.output, getItemName(result) + "_from_" + source); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void waxRecipes(final FeatureFlagSet flagSet) { ((BiMap)HoneycombItem.WAXABLES.get()) .forEach( (block, waxedBlock) -> { if (waxedBlock.requiredFeatures().isSubsetOf(flagSet)) { Pair pair = HoneycombItem.WAXED_RECIPES .getOrDefault(waxedBlock, Pair.of(RecipeCategory.BUILDING_BLOCKS, getItemName(waxedBlock))); RecipeCategory recipeCategory = pair.getFirst(); String group = pair.getSecond(); this.shapeless(recipeCategory, waxedBlock) .requires(block) .requires(Items.HONEYCOMB) .group(group) .unlockedBy(getHasName(block), this.has(block)) .save(this.output, getConversionRecipeName(waxedBlock, Items.HONEYCOMB)); } } ); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void grate(final Block grateBlock, final Block material) { this.shaped(RecipeCategory.BUILDING_BLOCKS, grateBlock, 4) .define('M', material) .pattern(" M ") .pattern("M M") .pattern(" M ") .group(getItemName(grateBlock)) .unlockedBy(getHasName(material), this.has(material)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void copperBulb(final Block copperBulb, final Block copperMaterial) { this.shaped(RecipeCategory.REDSTONE, copperBulb, 4) .define('C', copperMaterial) .define('R', Items.REDSTONE) .define('B', Items.BLAZE_ROD) .pattern(" C ") .pattern("CBC") .pattern(" R ") .unlockedBy(getHasName(copperMaterial), this.has(copperMaterial)) .group(getItemName(copperBulb)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void waxedChiseled(final Block result, final Block material) { this.shaped(RecipeCategory.BUILDING_BLOCKS, result) .define('M', material) .pattern(" M ") .pattern(" M ") .group(getItemName(result)) .unlockedBy(getHasName(material), this.has(material)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void suspiciousStew(final Item item, final SuspiciousEffectHolder effectHolder) { ItemStackTemplate stew = new ItemStackTemplate( Items.SUSPICIOUS_STEW, DataComponentPatch.builder().set(DataComponents.SUSPICIOUS_STEW_EFFECTS, effectHolder.getSuspiciousEffects()).build() ); this.shapeless(RecipeCategory.FOOD, stew) .requires(Items.BOWL) .requires(Items.BROWN_MUSHROOM) .requires(Items.RED_MUSHROOM) .requires(item) .group("suspicious_stew") .unlockedBy(getHasName(item), this.has(item)) .save(this.output, getItemName(stew.item().value()) + "_from_" + getItemName(item)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void dyedItem(final Item target, final String group) { CustomCraftingRecipeBuilder.customCrafting( RecipeCategory.MISC, (commonInfo, bookInfo) -> new DyeRecipe(commonInfo, bookInfo, Ingredient.of(target), this.tag(ItemTags.DYES), new ItemStackTemplate(target)) ) .unlockedBy(getHasName(target), this.has(target)) .group(group) .save(this.output, getItemName(target) + "_dyed"); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void dyedShulkerBoxRecipe(final Item dye, final Item dyedResult) { TransmuteRecipeBuilder.transmute(RecipeCategory.DECORATIONS, this.tag(ItemTags.SHULKER_BOXES), Ingredient.of(dye), dyedResult) .group("shulker_box_dye") .unlockedBy("has_shulker_box", this.has(ItemTags.SHULKER_BOXES)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void dyedBundleRecipe(final Item dye, final Item dyedResult) { TransmuteRecipeBuilder.transmute(RecipeCategory.TOOLS, this.tag(ItemTags.BUNDLES), Ingredient.of(dye), dyedResult) .group("bundle_dye") .unlockedBy(getHasName(dye), this.has(dye)) .save(this.output); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public void generateRecipes(final BlockFamily family, final FeatureFlagSet flagSet) { family.getVariants().forEach((variant, result) -> { if (result.requiredFeatures().isSubsetOf(flagSet)) { if (family.shouldGenerateCraftingRecipe()) { ItemLike base = this.getBaseBlockForCrafting(family, variant); this.generateCraftingRecipe(family, variant, result, base); if (variant == BlockFamily.Variant.CRACKED) { this.smeltingResultFromBase(result, base); } } if (family.shouldGenerateStonecutterRecipe()) { Block base = family.getBaseBlock(); this.generateStonecutterRecipe(family, variant, base); } } }); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final void generateCraftingRecipe(final BlockFamily family, final BlockFamily.Variant variant, final Block result, final ItemLike base) { RecipeProvider.FamilyCraftingRecipeProvider recipeFunction = (RecipeProvider.FamilyCraftingRecipeProvider)SHAPE_BUILDERS.get(variant); if (recipeFunction != null) { RecipeBuilder builder = recipeFunction.create(this, result, base); family.getRecipeGroupPrefix().ifPresent(prefix -> builder.group(prefix + (variant == BlockFamily.Variant.CUT ? "" : "_" + variant.getRecipeGroup()))); builder.unlockedBy((String)family.getRecipeUnlockedBy().orElseGet(() -> getHasName(base)), this.has(base)); builder.save(this.output); } } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final void generateStonecutterRecipe(final BlockFamily family, final BlockFamily.Variant variant, final Block base) { RecipeProvider.FamilyStonecutterRecipeProvider recipeFunction = (RecipeProvider.FamilyStonecutterRecipeProvider)STONECUTTER_RECIPE_BUILDERS.get(variant); if (recipeFunction != null) { recipeFunction.create(this, family.get(variant), base); } if (variant == BlockFamily.Variant.POLISHED || variant == BlockFamily.Variant.CUT || variant == BlockFamily.Variant.BRICKS || variant == BlockFamily.Variant.TILES || variant == BlockFamily.Variant.COBBLED) { BlockFamily childVariantFamily = BlockFamilies.getFamily(family.get(variant)); if (childVariantFamily != null) { childVariantFamily.getVariants().forEach((childVariant, r) -> this.generateStonecutterRecipe(childVariantFamily, childVariant, base)); } } } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final Block getBaseBlockForCrafting(final BlockFamily family, final BlockFamily.Variant variant) { if (variant == BlockFamily.Variant.CHISELED) { if (!family.getVariants().containsKey(BlockFamily.Variant.SLAB)) { throw new IllegalStateException("Slab is not defined for the family."); } else { return family.get(BlockFamily.Variant.SLAB); } } else { return family.getBaseBlock(); } } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static Criterion insideOf(final Block block) { return CriteriaTriggers.ENTER_BLOCK .createCriterion(new EnterBlockTrigger.TriggerInstance(Optional.empty(), Optional.of(block.builtInRegistryHolder()), Optional.empty())); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public Criterion bredAnimal() { return CriteriaTriggers.BRED_ANIMALS .createCriterion(new BredAnimalsTrigger.TriggerInstance(Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty())); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public final Criterion has(final MinMaxBounds.Ints count, final ItemLike item) { return inventoryTrigger(ItemPredicate.Builder.item().of(this.items, item).withCount(count)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public Criterion has(final ItemLike item) { return inventoryTrigger(ItemPredicate.Builder.item().of(this.items, item)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public Criterion has(final TagKey tag) { return inventoryTrigger(ItemPredicate.Builder.item().of(this.items, tag)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static Criterion inventoryTrigger(final ItemPredicate.Builder... predicates) { return inventoryTrigger((ItemPredicate[])Arrays.stream(predicates).map(ItemPredicate.Builder::build).toArray(ItemPredicate[]::new)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static Criterion inventoryTrigger(final ItemPredicate... predicates) { return CriteriaTriggers.INVENTORY_CHANGED .createCriterion(new InventoryChangeTrigger.TriggerInstance(Optional.empty(), InventoryChangeTrigger.TriggerInstance.Slots.ANY, List.of(predicates))); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static String getHasName(final ItemLike baseBlock) { return "has_" + getItemName(baseBlock); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static String getItemName(final ItemLike itemLike) { return BuiltInRegistries.ITEM.getKey(itemLike.asItem()).getPath(); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static String getSimpleRecipeName(final ItemLike itemLike) { return getItemName(itemLike); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static String getConversionRecipeName(final ItemLike product, final ItemLike material) { return getItemName(product) + "_from_" + getItemName(material); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static String getSmeltingRecipeName(final ItemLike product) { return getItemName(product) + "_from_smelting"; } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public static String getBlastingRecipeName(final ItemLike product) { return getItemName(product) + "_from_blasting"; } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public Ingredient tag(final TagKey id) { return Ingredient.of(this.items.getOrThrow(id)); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public ShapedRecipeBuilder shaped(final RecipeCategory category, final ItemLike item) { return ShapedRecipeBuilder.shaped(this.items, category, item); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public ShapedRecipeBuilder shaped(final RecipeCategory category, final ItemLike item, final int count) { return ShapedRecipeBuilder.shaped(this.items, category, item, count); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public ShapelessRecipeBuilder shapeless(final RecipeCategory category, final ItemStackTemplate result) { return ShapelessRecipeBuilder.shapeless(this.items, category, result); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public ShapelessRecipeBuilder shapeless(final RecipeCategory category, final ItemLike item) { return ShapelessRecipeBuilder.shapeless(this.items, category, item); } /** * Access widened by fabric-data-generation-api-v1 to accessible */ public ShapelessRecipeBuilder shapeless(final RecipeCategory category, final ItemLike item, final int count) { return ShapelessRecipeBuilder.shapeless(this.items, category, item, count); } @FunctionalInterface private interface FamilyCraftingRecipeProvider { RecipeBuilder create(RecipeProvider context, ItemLike result, ItemLike base); } @FunctionalInterface private interface FamilyStonecutterRecipeProvider { void create(RecipeProvider context, ItemLike result, ItemLike base); } /** * Access widened by fabric-data-generation-api-v1 to extendable */ public abstract static class Runner implements DataProvider { private final PackOutput packOutput; private final CompletableFuture registries; protected Runner(final PackOutput packOutput, final CompletableFuture registries) { this.packOutput = packOutput; this.registries = registries; } /** * Access widened by fabric-data-generation-api-v1 to extendable */ @Override public CompletableFuture run(final CachedOutput cache) { return this.registries .thenCompose( registries -> { final PackOutput.PathProvider recipePathProvider = this.packOutput.createRegistryElementsPathProvider(Registries.RECIPE); final PackOutput.PathProvider advancementPathProvider = this.packOutput.createRegistryElementsPathProvider(Registries.ADVANCEMENT); final Set>> allRecipes = Sets.>>newHashSet(); final List> tasks = new ArrayList(); RecipeOutput recipeOutput = new RecipeOutput() { { Objects.requireNonNull(Runner.this); } @Override public void accept(final ResourceKey> id, final Recipe recipe, @Nullable final AdvancementHolder advancementHolder) { if (!allRecipes.add(id)) { throw new IllegalStateException("Duplicate recipe " + id.identifier()); } else { this.saveRecipe(id, recipe); if (advancementHolder != null) { this.saveAdvancement(advancementHolder); } } } @Override public Advancement.Builder advancement() { return Advancement.Builder.recipeAdvancement().parent(RecipeBuilder.ROOT_RECIPE_ADVANCEMENT); } @Override public void includeRootAdvancement() { AdvancementHolder root = Advancement.Builder.recipeAdvancement() .addCriterion("impossible", CriteriaTriggers.IMPOSSIBLE.createCriterion(new ImpossibleTrigger.TriggerInstance())) .build(RecipeBuilder.ROOT_RECIPE_ADVANCEMENT); this.saveAdvancement(root); } private void saveRecipe(final ResourceKey> id, final Recipe recipe) { tasks.add(DataProvider.saveStable(cache, registries, Recipe.CODEC, recipe, recipePathProvider.json(id.identifier()))); } private void saveAdvancement(final AdvancementHolder advancementHolder) { tasks.add( DataProvider.saveStable(cache, registries, Advancement.CODEC, advancementHolder.value(), advancementPathProvider.json(advancementHolder.id())) ); } }; this.createRecipeProvider(registries, recipeOutput).buildRecipes(); return CompletableFuture.allOf((CompletableFuture[])tasks.toArray(CompletableFuture[]::new)); } ); } protected abstract RecipeProvider createRecipeProvider(HolderLookup.Provider registries, RecipeOutput output); } }