minecraft-src/net/minecraft/data/recipes/RecipeProvider.java
2025-07-04 03:45:38 +03:00

719 lines
31 KiB
Java

package net.minecraft.data.recipes;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.advancements.Criterion;
import net.minecraft.advancements.critereon.InventoryChangeTrigger;
import net.minecraft.advancements.critereon.ItemPredicate;
import net.minecraft.advancements.critereon.MinMaxBounds;
import net.minecraft.advancements.critereon.EnterBlockTrigger.TriggerInstance;
import net.minecraft.advancements.critereon.InventoryChangeTrigger.TriggerInstance.Slots;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Holder.Reference;
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.data.BlockFamily.Variant;
import net.minecraft.data.PackOutput.PathProvider;
import net.minecraft.data.recipes.RecipeProvider.Runner.1;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
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.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.crafting.AbstractCookingRecipe;
import net.minecraft.world.item.crafting.BlastingRecipe;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.SmeltingRecipe;
import net.minecraft.world.item.crafting.AbstractCookingRecipe.Factory;
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.jetbrains.annotations.Nullable;
public abstract class RecipeProvider {
protected final HolderLookup.Provider registries;
private final HolderGetter<Item> items;
protected final RecipeOutput output;
private static final Map<Variant, RecipeProvider.FamilyRecipeProvider> SHAPE_BUILDERS = ImmutableMap.<Variant, RecipeProvider.FamilyRecipeProvider>builder()
.put(Variant.BUTTON, (recipeProvider, itemLike, itemLike2) -> recipeProvider.buttonBuilder(itemLike, Ingredient.of(itemLike2)))
.put(
Variant.CHISELED,
(recipeProvider, itemLike, itemLike2) -> recipeProvider.chiseledBuilder(RecipeCategory.BUILDING_BLOCKS, itemLike, Ingredient.of(itemLike2))
)
.put(Variant.CUT, (recipeProvider, itemLike, itemLike2) -> recipeProvider.cutBuilder(RecipeCategory.BUILDING_BLOCKS, itemLike, Ingredient.of(itemLike2)))
.put(Variant.DOOR, (recipeProvider, itemLike, itemLike2) -> recipeProvider.doorBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.CUSTOM_FENCE, (recipeProvider, itemLike, itemLike2) -> recipeProvider.fenceBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.FENCE, (recipeProvider, itemLike, itemLike2) -> recipeProvider.fenceBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.CUSTOM_FENCE_GATE, (recipeProvider, itemLike, itemLike2) -> recipeProvider.fenceGateBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.FENCE_GATE, (recipeProvider, itemLike, itemLike2) -> recipeProvider.fenceGateBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.SIGN, (recipeProvider, itemLike, itemLike2) -> recipeProvider.signBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.SLAB, (recipeProvider, itemLike, itemLike2) -> recipeProvider.slabBuilder(RecipeCategory.BUILDING_BLOCKS, itemLike, Ingredient.of(itemLike2)))
.put(Variant.STAIRS, (recipeProvider, itemLike, itemLike2) -> recipeProvider.stairBuilder(itemLike, Ingredient.of(itemLike2)))
.put(
Variant.PRESSURE_PLATE,
(recipeProvider, itemLike, itemLike2) -> recipeProvider.pressurePlateBuilder(RecipeCategory.REDSTONE, itemLike, Ingredient.of(itemLike2))
)
.put(
Variant.POLISHED,
(recipeProvider, itemLike, itemLike2) -> recipeProvider.polishedBuilder(RecipeCategory.BUILDING_BLOCKS, itemLike, Ingredient.of(itemLike2))
)
.put(Variant.TRAPDOOR, (recipeProvider, itemLike, itemLike2) -> recipeProvider.trapdoorBuilder(itemLike, Ingredient.of(itemLike2)))
.put(Variant.WALL, (recipeProvider, itemLike, itemLike2) -> recipeProvider.wallBuilder(RecipeCategory.DECORATIONS, itemLike, Ingredient.of(itemLike2)))
.build();
protected RecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
this.registries = registries;
this.items = registries.lookupOrThrow(Registries.ITEM);
this.output = output;
}
protected abstract void buildRecipes();
protected void generateForEnabledBlockFamilies(FeatureFlagSet enabledFeatures) {
BlockFamilies.getAllFamilies().filter(BlockFamily::shouldGenerateRecipe).forEach(blockFamily -> this.generateRecipes(blockFamily, enabledFeatures));
}
protected void oneToOneConversionRecipe(ItemLike result, ItemLike ingredient, @Nullable String group) {
this.oneToOneConversionRecipe(result, ingredient, group, 1);
}
protected void oneToOneConversionRecipe(ItemLike result, ItemLike ingredient, @Nullable String group, int resultCount) {
this.shapeless(RecipeCategory.MISC, result, resultCount)
.requires(ingredient)
.group(group)
.unlockedBy(getHasName(ingredient), this.has(ingredient))
.save(this.output, getConversionRecipeName(result, ingredient));
}
protected void oreSmelting(List<ItemLike> ingredients, RecipeCategory category, ItemLike result, float experience, int cookingTime, String group) {
this.oreCooking(RecipeSerializer.SMELTING_RECIPE, SmeltingRecipe::new, ingredients, category, result, experience, cookingTime, group, "_from_smelting");
}
protected void oreBlasting(List<ItemLike> ingredients, RecipeCategory category, ItemLike result, float experience, int cookingTime, String group) {
this.oreCooking(RecipeSerializer.BLASTING_RECIPE, BlastingRecipe::new, ingredients, category, result, experience, cookingTime, group, "_from_blasting");
}
private <T extends AbstractCookingRecipe> void oreCooking(
RecipeSerializer<T> serializer,
Factory<T> recipeFactory,
List<ItemLike> ingredients,
RecipeCategory category,
ItemLike result,
float experience,
int cookingTime,
String group,
String suffix
) {
for (ItemLike itemLike : ingredients) {
SimpleCookingRecipeBuilder.generic(Ingredient.of(itemLike), category, result, experience, cookingTime, serializer, recipeFactory)
.group(group)
.unlockedBy(getHasName(itemLike), this.has(itemLike))
.save(this.output, getItemName(result) + suffix + "_" + getItemName(itemLike));
}
}
protected void netheriteSmithing(Item ingredientItem, RecipeCategory category, Item resultItem) {
SmithingTransformRecipeBuilder.smithing(
Ingredient.of(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE), Ingredient.of(ingredientItem), this.tag(ItemTags.NETHERITE_TOOL_MATERIALS), category, resultItem
)
.unlocks("has_netherite_ingot", this.has(ItemTags.NETHERITE_TOOL_MATERIALS))
.save(this.output, getItemName(resultItem) + "_smithing");
}
protected void trimSmithing(Item template, ResourceKey<TrimPattern> pattern, ResourceKey<Recipe<?>> recipe) {
Reference<TrimPattern> reference = this.registries.lookupOrThrow(Registries.TRIM_PATTERN).getOrThrow(pattern);
SmithingTrimRecipeBuilder.smithingTrim(
Ingredient.of(template), this.tag(ItemTags.TRIMMABLE_ARMOR), this.tag(ItemTags.TRIM_MATERIALS), reference, RecipeCategory.MISC
)
.unlocks("has_smithing_trim_template", this.has(template))
.save(this.output, recipe);
}
protected void twoByTwoPacker(RecipeCategory category, ItemLike packed, ItemLike unpacked) {
this.shaped(category, packed, 1).define('#', unpacked).pattern("##").pattern("##").unlockedBy(getHasName(unpacked), this.has(unpacked)).save(this.output);
}
protected void threeByThreePacker(RecipeCategory category, ItemLike packed, ItemLike unpacked, String criterionName) {
this.shapeless(category, packed).requires(unpacked, 9).unlockedBy(criterionName, this.has(unpacked)).save(this.output);
}
protected void threeByThreePacker(RecipeCategory category, ItemLike packed, ItemLike unpacked) {
this.threeByThreePacker(category, packed, unpacked, getHasName(unpacked));
}
protected void planksFromLog(ItemLike planks, TagKey<Item> logs, int resultCount) {
this.shapeless(RecipeCategory.BUILDING_BLOCKS, planks, resultCount).requires(logs).group("planks").unlockedBy("has_log", this.has(logs)).save(this.output);
}
protected void planksFromLogs(ItemLike planks, TagKey<Item> logs, int result) {
this.shapeless(RecipeCategory.BUILDING_BLOCKS, planks, result).requires(logs).group("planks").unlockedBy("has_logs", this.has(logs)).save(this.output);
}
protected void woodFromLogs(ItemLike wood, ItemLike log) {
this.shaped(RecipeCategory.BUILDING_BLOCKS, wood, 3)
.define('#', log)
.pattern("##")
.pattern("##")
.group("bark")
.unlockedBy("has_log", this.has(log))
.save(this.output);
}
protected void woodenBoat(ItemLike boat, ItemLike material) {
this.shaped(RecipeCategory.TRANSPORTATION, boat)
.define('#', material)
.pattern("# #")
.pattern("###")
.group("boat")
.unlockedBy("in_water", insideOf(Blocks.WATER))
.save(this.output);
}
protected void chestBoat(ItemLike boat, ItemLike material) {
this.shapeless(RecipeCategory.TRANSPORTATION, boat)
.requires(Blocks.CHEST)
.requires(material)
.group("chest_boat")
.unlockedBy("has_boat", this.has(ItemTags.BOATS))
.save(this.output);
}
private RecipeBuilder buttonBuilder(ItemLike button, Ingredient material) {
return this.shapeless(RecipeCategory.REDSTONE, button).requires(material);
}
protected RecipeBuilder doorBuilder(ItemLike door, Ingredient material) {
return this.shaped(RecipeCategory.REDSTONE, door, 3).define('#', material).pattern("##").pattern("##").pattern("##");
}
private RecipeBuilder fenceBuilder(ItemLike fence, Ingredient material) {
int i = fence == Blocks.NETHER_BRICK_FENCE ? 6 : 3;
Item item = fence == Blocks.NETHER_BRICK_FENCE ? Items.NETHER_BRICK : Items.STICK;
return this.shaped(RecipeCategory.DECORATIONS, fence, i).define('W', material).define('#', item).pattern("W#W").pattern("W#W");
}
private RecipeBuilder fenceGateBuilder(ItemLike fenceGate, Ingredient material) {
return this.shaped(RecipeCategory.REDSTONE, fenceGate).define('#', Items.STICK).define('W', material).pattern("#W#").pattern("#W#");
}
protected void pressurePlate(ItemLike pressurePlate, ItemLike material) {
this.pressurePlateBuilder(RecipeCategory.REDSTONE, pressurePlate, Ingredient.of(material))
.unlockedBy(getHasName(material), this.has(material))
.save(this.output);
}
private RecipeBuilder pressurePlateBuilder(RecipeCategory category, ItemLike pressurePlate, Ingredient material) {
return this.shaped(category, pressurePlate).define('#', material).pattern("##");
}
protected void slab(RecipeCategory category, ItemLike slab, ItemLike material) {
this.slabBuilder(category, slab, Ingredient.of(material)).unlockedBy(getHasName(material), this.has(material)).save(this.output);
}
protected RecipeBuilder slabBuilder(RecipeCategory category, ItemLike slab, Ingredient material) {
return this.shaped(category, slab, 6).define('#', material).pattern("###");
}
protected RecipeBuilder stairBuilder(ItemLike stairs, Ingredient material) {
return this.shaped(RecipeCategory.BUILDING_BLOCKS, stairs, 4).define('#', material).pattern("# ").pattern("## ").pattern("###");
}
protected RecipeBuilder trapdoorBuilder(ItemLike trapdoor, Ingredient material) {
return this.shaped(RecipeCategory.REDSTONE, trapdoor, 2).define('#', material).pattern("###").pattern("###");
}
private RecipeBuilder signBuilder(ItemLike sign, Ingredient material) {
return this.shaped(RecipeCategory.DECORATIONS, sign, 3)
.group("sign")
.define('#', material)
.define('X', Items.STICK)
.pattern("###")
.pattern("###")
.pattern(" X ");
}
protected void hangingSign(ItemLike sign, ItemLike material) {
this.shaped(RecipeCategory.DECORATIONS, sign, 6)
.group("hanging_sign")
.define('#', material)
.define('X', Items.CHAIN)
.pattern("X X")
.pattern("###")
.pattern("###")
.unlockedBy("has_stripped_logs", this.has(material))
.save(this.output);
}
protected void colorBlockWithDye(List<Item> dyes, List<Item> dyeableItems, String group) {
this.colorWithDye(dyes, dyeableItems, null, group, RecipeCategory.BUILDING_BLOCKS);
}
protected void colorWithDye(List<Item> dyes, List<Item> dyeableItems, @Nullable Item dye, String group, RecipeCategory category) {
for (int i = 0; i < dyes.size(); i++) {
Item item = (Item)dyes.get(i);
Item item2 = (Item)dyeableItems.get(i);
Stream<Item> stream = dyeableItems.stream().filter(item2x -> !item2x.equals(item2));
if (dye != null) {
stream = Stream.concat(stream, Stream.of(dye));
}
this.shapeless(category, item2)
.requires(item)
.requires(Ingredient.of(stream))
.group(group)
.unlockedBy("has_needed_dye", this.has(item))
.save(this.output, "dye_" + getItemName(item2));
}
}
protected void carpet(ItemLike carpet, ItemLike material) {
this.shaped(RecipeCategory.DECORATIONS, carpet, 3)
.define('#', material)
.pattern("##")
.group("carpet")
.unlockedBy(getHasName(material), this.has(material))
.save(this.output);
}
protected void bedFromPlanksAndWool(ItemLike bed, ItemLike wool) {
this.shaped(RecipeCategory.DECORATIONS, bed)
.define('#', wool)
.define('X', ItemTags.PLANKS)
.pattern("###")
.pattern("XXX")
.group("bed")
.unlockedBy(getHasName(wool), this.has(wool))
.save(this.output);
}
protected void banner(ItemLike banner, ItemLike material) {
this.shaped(RecipeCategory.DECORATIONS, banner)
.define('#', material)
.define('|', Items.STICK)
.pattern("###")
.pattern("###")
.pattern(" | ")
.group("banner")
.unlockedBy(getHasName(material), this.has(material))
.save(this.output);
}
protected void stainedGlassFromGlassAndDye(ItemLike stainedGlass, ItemLike dye) {
this.shaped(RecipeCategory.BUILDING_BLOCKS, stainedGlass, 8)
.define('#', Blocks.GLASS)
.define('X', dye)
.pattern("###")
.pattern("#X#")
.pattern("###")
.group("stained_glass")
.unlockedBy("has_glass", this.has(Blocks.GLASS))
.save(this.output);
}
protected void stainedGlassPaneFromStainedGlass(ItemLike stainedGlassPane, ItemLike stainedGlass) {
this.shaped(RecipeCategory.DECORATIONS, stainedGlassPane, 16)
.define('#', stainedGlass)
.pattern("###")
.pattern("###")
.group("stained_glass_pane")
.unlockedBy("has_glass", this.has(stainedGlass))
.save(this.output);
}
protected void stainedGlassPaneFromGlassPaneAndDye(ItemLike stainedGlassPane, ItemLike dye) {
this.shaped(RecipeCategory.DECORATIONS, stainedGlassPane, 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(stainedGlassPane, Blocks.GLASS_PANE));
}
protected void coloredTerracottaFromTerracottaAndDye(ItemLike terracotta, ItemLike dye) {
this.shaped(RecipeCategory.BUILDING_BLOCKS, terracotta, 8)
.define('#', Blocks.TERRACOTTA)
.define('X', dye)
.pattern("###")
.pattern("#X#")
.pattern("###")
.group("stained_terracotta")
.unlockedBy("has_terracotta", this.has(Blocks.TERRACOTTA))
.save(this.output);
}
protected void concretePowder(ItemLike concretePowder, ItemLike dye) {
this.shapeless(RecipeCategory.BUILDING_BLOCKS, concretePowder, 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);
}
protected void candle(ItemLike candle, ItemLike dye) {
this.shapeless(RecipeCategory.DECORATIONS, candle)
.requires(Blocks.CANDLE)
.requires(dye)
.group("dyed_candle")
.unlockedBy(getHasName(dye), this.has(dye))
.save(this.output);
}
protected void wall(RecipeCategory category, ItemLike wall, ItemLike material) {
this.wallBuilder(category, wall, Ingredient.of(material)).unlockedBy(getHasName(material), this.has(material)).save(this.output);
}
private RecipeBuilder wallBuilder(RecipeCategory category, ItemLike wall, Ingredient material) {
return this.shaped(category, wall, 6).define('#', material).pattern("###").pattern("###");
}
protected void polished(RecipeCategory category, ItemLike result, ItemLike material) {
this.polishedBuilder(category, result, Ingredient.of(material)).unlockedBy(getHasName(material), this.has(material)).save(this.output);
}
private RecipeBuilder polishedBuilder(RecipeCategory category, ItemLike result, Ingredient material) {
return this.shaped(category, result, 4).define('S', material).pattern("SS").pattern("SS");
}
protected void cut(RecipeCategory category, ItemLike cutResult, ItemLike material) {
this.cutBuilder(category, cutResult, Ingredient.of(material)).unlockedBy(getHasName(material), this.has(material)).save(this.output);
}
private ShapedRecipeBuilder cutBuilder(RecipeCategory category, ItemLike cutResult, Ingredient material) {
return this.shaped(category, cutResult, 4).define('#', material).pattern("##").pattern("##");
}
protected void chiseled(RecipeCategory category, ItemLike chiseledResult, ItemLike material) {
this.chiseledBuilder(category, chiseledResult, Ingredient.of(material)).unlockedBy(getHasName(material), this.has(material)).save(this.output);
}
protected void mosaicBuilder(RecipeCategory category, ItemLike result, ItemLike material) {
this.shaped(category, result).define('#', material).pattern("#").pattern("#").unlockedBy(getHasName(material), this.has(material)).save(this.output);
}
protected ShapedRecipeBuilder chiseledBuilder(RecipeCategory category, ItemLike chiseledResult, Ingredient material) {
return this.shaped(category, chiseledResult).define('#', material).pattern("#").pattern("#");
}
protected void stonecutterResultFromBase(RecipeCategory category, ItemLike result, ItemLike material) {
this.stonecutterResultFromBase(category, result, material, 1);
}
protected void stonecutterResultFromBase(RecipeCategory category, ItemLike result, ItemLike material, int resultCount) {
SingleItemRecipeBuilder.stonecutting(Ingredient.of(material), category, result, resultCount)
.unlockedBy(getHasName(material), this.has(material))
.save(this.output, getConversionRecipeName(result, material) + "_stonecutting");
}
private void smeltingResultFromBase(ItemLike result, ItemLike ingredient) {
SimpleCookingRecipeBuilder.smelting(Ingredient.of(ingredient), RecipeCategory.BUILDING_BLOCKS, result, 0.1F, 200)
.unlockedBy(getHasName(ingredient), this.has(ingredient))
.save(this.output);
}
protected void nineBlockStorageRecipes(RecipeCategory unpackedCategory, ItemLike unpacked, RecipeCategory packedCategory, ItemLike packed) {
this.nineBlockStorageRecipes(unpackedCategory, unpacked, packedCategory, packed, getSimpleRecipeName(packed), null, getSimpleRecipeName(unpacked), null);
}
protected void nineBlockStorageRecipesWithCustomPacking(
RecipeCategory unpackedCategory, ItemLike unpacked, RecipeCategory packedCategory, ItemLike packed, String packedName, String packedGroup
) {
this.nineBlockStorageRecipes(unpackedCategory, unpacked, packedCategory, packed, packedName, packedGroup, getSimpleRecipeName(unpacked), null);
}
protected void nineBlockStorageRecipesRecipesWithCustomUnpacking(
RecipeCategory unpackedCategory, ItemLike unpacked, RecipeCategory packedCategory, ItemLike packed, String unpackedName, String unpackedGroup
) {
this.nineBlockStorageRecipes(unpackedCategory, unpacked, packedCategory, packed, getSimpleRecipeName(packed), null, unpackedName, unpackedGroup);
}
private void nineBlockStorageRecipes(
RecipeCategory unpackedCategory,
ItemLike unpacked,
RecipeCategory packedCategory,
ItemLike packed,
String packedName,
@Nullable String packedGroup,
String unpackedName,
@Nullable String unpackedGroup
) {
this.shapeless(unpackedCategory, unpacked, 9)
.requires(packed)
.group(unpackedGroup)
.unlockedBy(getHasName(packed), this.has(packed))
.save(this.output, ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(unpackedName)));
this.shaped(packedCategory, packed)
.define('#', unpacked)
.pattern("###")
.pattern("###")
.pattern("###")
.group(packedGroup)
.unlockedBy(getHasName(unpacked), this.has(unpacked))
.save(this.output, ResourceKey.create(Registries.RECIPE, ResourceLocation.parse(packedName)));
}
protected void copySmithingTemplate(ItemLike template, ItemLike baseItem) {
this.shaped(RecipeCategory.MISC, template, 2)
.define('#', Items.DIAMOND)
.define('C', baseItem)
.define('S', template)
.pattern("#S#")
.pattern("#C#")
.pattern("###")
.unlockedBy(getHasName(template), this.has(template))
.save(this.output);
}
protected void copySmithingTemplate(ItemLike template, Ingredient baseItem) {
this.shaped(RecipeCategory.MISC, template, 2)
.define('#', Items.DIAMOND)
.define('C', baseItem)
.define('S', template)
.pattern("#S#")
.pattern("#C#")
.pattern("###")
.unlockedBy(getHasName(template), this.has(template))
.save(this.output);
}
protected <T extends AbstractCookingRecipe> void cookRecipes(
String cookingMethod, RecipeSerializer<T> cookingSerializer, Factory<T> recipeFactory, int cookingTime
) {
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.BEEF, Items.COOKED_BEEF, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.CHICKEN, Items.COOKED_CHICKEN, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.COD, Items.COOKED_COD, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.KELP, Items.DRIED_KELP, 0.1F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.SALMON, Items.COOKED_SALMON, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.MUTTON, Items.COOKED_MUTTON, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.PORKCHOP, Items.COOKED_PORKCHOP, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.POTATO, Items.BAKED_POTATO, 0.35F);
this.simpleCookingRecipe(cookingMethod, cookingSerializer, recipeFactory, cookingTime, Items.RABBIT, Items.COOKED_RABBIT, 0.35F);
}
private <T extends AbstractCookingRecipe> void simpleCookingRecipe(
String cookingMethod, RecipeSerializer<T> cookingSerializer, Factory<T> recipeFactory, int cookingTime, ItemLike material, ItemLike result, float experience
) {
SimpleCookingRecipeBuilder.generic(Ingredient.of(material), RecipeCategory.FOOD, result, experience, cookingTime, cookingSerializer, recipeFactory)
.unlockedBy(getHasName(material), this.has(material))
.save(this.output, getItemName(result) + "_from_" + cookingMethod);
}
protected void waxRecipes(FeatureFlagSet requiredFeatures) {
((BiMap)HoneycombItem.WAXABLES.get())
.forEach(
(block, block2) -> {
if (block2.requiredFeatures().isSubsetOf(requiredFeatures)) {
this.shapeless(RecipeCategory.BUILDING_BLOCKS, block2)
.requires(block)
.requires(Items.HONEYCOMB)
.group(getItemName(block2))
.unlockedBy(getHasName(block), this.has(block))
.save(this.output, getConversionRecipeName(block2, Items.HONEYCOMB));
}
}
);
}
protected void grate(Block grateBlock, Block material) {
this.shaped(RecipeCategory.BUILDING_BLOCKS, grateBlock, 4)
.define('M', material)
.pattern(" M ")
.pattern("M M")
.pattern(" M ")
.unlockedBy(getHasName(material), this.has(material))
.save(this.output);
}
protected void copperBulb(Block bulbBlock, Block material) {
this.shaped(RecipeCategory.REDSTONE, bulbBlock, 4)
.define('C', material)
.define('R', Items.REDSTONE)
.define('B', Items.BLAZE_ROD)
.pattern(" C ")
.pattern("CBC")
.pattern(" R ")
.unlockedBy(getHasName(material), this.has(material))
.save(this.output);
}
protected void suspiciousStew(Item flowerItem, SuspiciousEffectHolder effect) {
ItemStack itemStack = new ItemStack(
Items.SUSPICIOUS_STEW.builtInRegistryHolder(),
1,
DataComponentPatch.builder().set(DataComponents.SUSPICIOUS_STEW_EFFECTS, effect.getSuspiciousEffects()).build()
);
this.shapeless(RecipeCategory.FOOD, itemStack)
.requires(Items.BOWL)
.requires(Items.BROWN_MUSHROOM)
.requires(Items.RED_MUSHROOM)
.requires(flowerItem)
.group("suspicious_stew")
.unlockedBy(getHasName(flowerItem), this.has(flowerItem))
.save(this.output, getItemName(itemStack.getItem()) + "_from_" + getItemName(flowerItem));
}
protected void generateRecipes(BlockFamily blockFamily, FeatureFlagSet requiredFeatures) {
blockFamily.getVariants().forEach((variant, block) -> {
if (block.requiredFeatures().isSubsetOf(requiredFeatures)) {
RecipeProvider.FamilyRecipeProvider familyRecipeProvider = (RecipeProvider.FamilyRecipeProvider)SHAPE_BUILDERS.get(variant);
ItemLike itemLike = this.getBaseBlock(blockFamily, variant);
if (familyRecipeProvider != null) {
RecipeBuilder recipeBuilder = familyRecipeProvider.create(this, block, itemLike);
blockFamily.getRecipeGroupPrefix().ifPresent(string -> recipeBuilder.group(string + (variant == Variant.CUT ? "" : "_" + variant.getRecipeGroup())));
recipeBuilder.unlockedBy((String)blockFamily.getRecipeUnlockedBy().orElseGet(() -> getHasName(itemLike)), this.has(itemLike));
recipeBuilder.save(this.output);
}
if (variant == Variant.CRACKED) {
this.smeltingResultFromBase(block, itemLike);
}
}
});
}
private Block getBaseBlock(BlockFamily family, Variant variant) {
if (variant == Variant.CHISELED) {
if (!family.getVariants().containsKey(Variant.SLAB)) {
throw new IllegalStateException("Slab is not defined for the family.");
} else {
return family.get(Variant.SLAB);
}
} else {
return family.getBaseBlock();
}
}
private static Criterion<TriggerInstance> insideOf(Block block) {
return CriteriaTriggers.ENTER_BLOCK.createCriterion(new TriggerInstance(Optional.empty(), Optional.of(block.builtInRegistryHolder()), Optional.empty()));
}
private Criterion<InventoryChangeTrigger.TriggerInstance> has(MinMaxBounds.Ints count, ItemLike item) {
return inventoryTrigger(ItemPredicate.Builder.item().of(this.items, item).withCount(count));
}
protected Criterion<InventoryChangeTrigger.TriggerInstance> has(ItemLike itemLike) {
return inventoryTrigger(ItemPredicate.Builder.item().of(this.items, itemLike));
}
protected Criterion<InventoryChangeTrigger.TriggerInstance> has(TagKey<Item> tag) {
return inventoryTrigger(ItemPredicate.Builder.item().of(this.items, tag));
}
private static Criterion<InventoryChangeTrigger.TriggerInstance> inventoryTrigger(ItemPredicate.Builder... items) {
return inventoryTrigger((ItemPredicate[])Arrays.stream(items).map(ItemPredicate.Builder::build).toArray(ItemPredicate[]::new));
}
private static Criterion<InventoryChangeTrigger.TriggerInstance> inventoryTrigger(ItemPredicate... predicates) {
return CriteriaTriggers.INVENTORY_CHANGED.createCriterion(new InventoryChangeTrigger.TriggerInstance(Optional.empty(), Slots.ANY, List.of(predicates)));
}
protected static String getHasName(ItemLike itemLike) {
return "has_" + getItemName(itemLike);
}
protected static String getItemName(ItemLike itemLike) {
return BuiltInRegistries.ITEM.getKey(itemLike.asItem()).getPath();
}
protected static String getSimpleRecipeName(ItemLike itemLike) {
return getItemName(itemLike);
}
protected static String getConversionRecipeName(ItemLike result, ItemLike ingredient) {
return getItemName(result) + "_from_" + getItemName(ingredient);
}
protected static String getSmeltingRecipeName(ItemLike itemLike) {
return getItemName(itemLike) + "_from_smelting";
}
protected static String getBlastingRecipeName(ItemLike itemLike) {
return getItemName(itemLike) + "_from_blasting";
}
protected Ingredient tag(TagKey<Item> tag) {
return Ingredient.of(this.items.getOrThrow(tag));
}
protected ShapedRecipeBuilder shaped(RecipeCategory category, ItemLike result) {
return ShapedRecipeBuilder.shaped(this.items, category, result);
}
protected ShapedRecipeBuilder shaped(RecipeCategory category, ItemLike result, int count) {
return ShapedRecipeBuilder.shaped(this.items, category, result, count);
}
protected ShapelessRecipeBuilder shapeless(RecipeCategory category, ItemStack result) {
return ShapelessRecipeBuilder.shapeless(this.items, category, result);
}
protected ShapelessRecipeBuilder shapeless(RecipeCategory category, ItemLike result) {
return ShapelessRecipeBuilder.shapeless(this.items, category, result);
}
protected ShapelessRecipeBuilder shapeless(RecipeCategory category, ItemLike result, int count) {
return ShapelessRecipeBuilder.shapeless(this.items, category, result, count);
}
@FunctionalInterface
interface FamilyRecipeProvider {
RecipeBuilder create(RecipeProvider recipeProvider, ItemLike itemLike, ItemLike itemLike2);
}
protected abstract static class Runner implements DataProvider {
private final PackOutput packOutput;
private final CompletableFuture<HolderLookup.Provider> registries;
protected Runner(PackOutput packOutput, CompletableFuture<HolderLookup.Provider> registries) {
this.packOutput = packOutput;
this.registries = registries;
}
@Override
public final CompletableFuture<?> run(CachedOutput output) {
return this.registries.thenCompose(provider -> {
PathProvider pathProvider = this.packOutput.createRegistryElementsPathProvider(Registries.RECIPE);
PathProvider pathProvider2 = this.packOutput.createRegistryElementsPathProvider(Registries.ADVANCEMENT);
Set<ResourceKey<Recipe<?>>> set = Sets.<ResourceKey<Recipe<?>>>newHashSet();
List<CompletableFuture<?>> list = new ArrayList();
RecipeOutput recipeOutput = new 1(this, set, list, output, provider, pathProvider, pathProvider2);
this.createRecipeProvider(provider, recipeOutput).buildRecipes();
return CompletableFuture.allOf((CompletableFuture[])list.toArray(CompletableFuture[]::new));
});
}
protected abstract RecipeProvider createRecipeProvider(HolderLookup.Provider registries, RecipeOutput output);
}
}