Recipe interface

- Add IRecipeTypeInfo to replace AllRecipeTypes method calls in most
cases to allow for better addon support
- Tweak some visibility modifiers
This commit is contained in:
PepperBell 2021-07-22 13:40:40 -07:00
parent 2cea2e1c0f
commit c3f87ec347
11 changed files with 105 additions and 90 deletions

View file

@ -21,6 +21,7 @@ import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuild
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer;
import com.simibubi.create.content.curiosities.tools.SandPaperPolishingRecipe; import com.simibubi.create.content.curiosities.tools.SandPaperPolishingRecipe;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipe;
@ -32,7 +33,7 @@ import net.minecraft.util.registry.Registry;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent;
public enum AllRecipeTypes { public enum AllRecipeTypes implements IRecipeTypeInfo {
MECHANICAL_CRAFTING(MechanicalCraftingRecipe.Serializer::new), MECHANICAL_CRAFTING(MechanicalCraftingRecipe.Serializer::new),
CONVERSION(ConversionRecipe::new), CONVERSION(ConversionRecipe::new),
@ -78,16 +79,19 @@ public enum AllRecipeTypes {
this(processingSerializer(processingFactory)); this(processingSerializer(processingFactory));
} }
@Override
public ResourceLocation getId() { public ResourceLocation getId() {
return id; return id;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override
public <T extends IRecipeSerializer<?>> T getSerializer() { public <T extends IRecipeSerializer<?>> T getSerializer() {
return (T) serializer; return (T) serializer;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override
public <T extends IRecipeType<?>> T getType() { public <T extends IRecipeType<?>> T getType() {
return (T) type; return (T) type;
} }

View file

@ -51,6 +51,7 @@ import com.simibubi.create.content.schematics.block.SchematicannonScreen;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.CRecipes; import com.simibubi.create.foundation.config.CRecipes;
import com.simibubi.create.foundation.config.ConfigBase.ConfigBool; import com.simibubi.create.foundation.config.ConfigBase.ConfigBool;
import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import mezz.jei.api.IModPlugin; import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin; import mezz.jei.api.JeiPlugin;
@ -79,12 +80,6 @@ public class CreateJEI implements IModPlugin {
private static final ResourceLocation ID = new ResourceLocation(Create.ID, "jei_plugin"); private static final ResourceLocation ID = new ResourceLocation(Create.ID, "jei_plugin");
@Override
@Nonnull
public ResourceLocation getPluginUid() {
return ID;
}
public IIngredientManager ingredientManager; public IIngredientManager ingredientManager;
private final List<CreateRecipeCategory<?>> allCategories = new ArrayList<>(); private final List<CreateRecipeCategory<?>> allCategories = new ArrayList<>();
private final CreateRecipeCategory<?> private final CreateRecipeCategory<?>
@ -221,6 +216,12 @@ public class CreateJEI implements IModPlugin {
return new CategoryBuilder<T>(name, supplier); return new CategoryBuilder<T>(name, supplier);
} }
@Override
@Nonnull
public ResourceLocation getPluginUid() {
return ID;
}
@Override @Override
public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) { public void registerRecipeTransferHandlers(IRecipeTransferRegistration registration) {
registration.addRecipeTransferHandler(new BlueprintTransferHandler(), VanillaRecipeCategoryUid.CRAFTING); registration.addRecipeTransferHandler(new BlueprintTransferHandler(), VanillaRecipeCategoryUid.CRAFTING);
@ -269,7 +270,7 @@ public class CreateJEI implements IModPlugin {
pred = Predicates.alwaysTrue(); pred = Predicates.alwaysTrue();
} }
public CategoryBuilder<T> recipes(AllRecipeTypes recipeTypeEntry) { public CategoryBuilder<T> recipes(IRecipeTypeInfo recipeTypeEntry) {
return recipes(recipeTypeEntry::getType); return recipes(recipeTypeEntry::getType);
} }

View file

@ -1,14 +1,14 @@
package com.simibubi.create.content.contraptions.components.crusher; package com.simibubi.create.content.contraptions.components.crusher;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import net.minecraftforge.items.wrapper.RecipeWrapper; import net.minecraftforge.items.wrapper.RecipeWrapper;
public abstract class AbstractCrushingRecipe extends ProcessingRecipe<RecipeWrapper> { public abstract class AbstractCrushingRecipe extends ProcessingRecipe<RecipeWrapper> {
public AbstractCrushingRecipe(AllRecipeTypes recipeType, ProcessingRecipeParams params) { public AbstractCrushingRecipe(IRecipeTypeInfo recipeType, ProcessingRecipeParams params) {
super(recipeType, params); super(recipeType, params);
} }

View file

@ -22,7 +22,7 @@ public class CrushingRecipe extends AbstractCrushingRecipe {
return ingredients.get(0) return ingredients.get(0)
.test(inv.getItem(0)); .test(inv.getItem(0));
} }
@Override @Override
protected int getMaxOutputCount() { protected int getMaxOutputCount() {
return 7; return 7;

View file

@ -36,14 +36,14 @@ import net.minecraftforge.items.wrapper.RecipeWrapper;
public class SequencedAssemblyRecipe implements IRecipe<RecipeWrapper> { public class SequencedAssemblyRecipe implements IRecipe<RecipeWrapper> {
ResourceLocation id; protected ResourceLocation id;
SequencedAssemblyRecipeSerializer serializer; protected SequencedAssemblyRecipeSerializer serializer;
Ingredient ingredient; protected Ingredient ingredient;
List<SequencedRecipe<?>> sequence; protected List<SequencedRecipe<?>> sequence;
int loops; protected int loops;
ProcessingOutput transitionalItem; protected ProcessingOutput transitionalItem;
List<ProcessingOutput> resultPool; protected List<ProcessingOutput> resultPool;
public SequencedAssemblyRecipe(ResourceLocation recipeId, SequencedAssemblyRecipeSerializer serializer) { public SequencedAssemblyRecipe(ResourceLocation recipeId, SequencedAssemblyRecipeSerializer serializer) {
this.id = recipeId; this.id = recipeId;

View file

@ -8,12 +8,10 @@ import java.util.function.UnaryOperator;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.simibubi.create.AllRecipeTypes; import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.processing.ProcessingOutput; import com.simibubi.create.content.contraptions.processing.ProcessingOutput;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeFactory; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeFactory;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.data.IFinishedRecipe; import net.minecraft.data.IFinishedRecipe;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@ -92,16 +90,17 @@ public class SequencedAssemblyRecipeBuilder {
public static class DataGenResult implements IFinishedRecipe { public static class DataGenResult implements IFinishedRecipe {
private List<ICondition> recipeConditions;
private SequencedAssemblyRecipeSerializer serializer;
private ResourceLocation id;
private SequencedAssemblyRecipe recipe; private SequencedAssemblyRecipe recipe;
private List<ICondition> recipeConditions;
private ResourceLocation id;
private SequencedAssemblyRecipeSerializer serializer;
public DataGenResult(SequencedAssemblyRecipe recipe, List<ICondition> recipeConditions) { public DataGenResult(SequencedAssemblyRecipe recipe, List<ICondition> recipeConditions) {
this.recipeConditions = recipeConditions; this.recipeConditions = recipeConditions;
this.recipe = recipe; this.recipe = recipe;
this.id = Create.asResource(Lang.asId(AllRecipeTypes.SEQUENCED_ASSEMBLY.name()) + "/" + recipe.getId() recipe.getId();
.getPath()); this.id = new ResourceLocation(recipe.getId().getNamespace(),
AllRecipeTypes.SEQUENCED_ASSEMBLY.getId().getPath() + "/" + recipe.getId().getPath());
this.serializer = (SequencedAssemblyRecipeSerializer) recipe.getSerializer(); this.serializer = (SequencedAssemblyRecipeSerializer) recipe.getSerializer();
} }

View file

@ -10,11 +10,10 @@ import javax.annotation.ParametersAreNonnullByDefault;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder.ProcessingRecipeParams;
import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.fluid.FluidIngredient;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import mcp.MethodsReturnNonnullByDefault; import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
@ -42,24 +41,23 @@ public abstract class ProcessingRecipe<T extends IInventory> implements IRecipe<
private IRecipeType<?> type; private IRecipeType<?> type;
private IRecipeSerializer<?> serializer; private IRecipeSerializer<?> serializer;
private AllRecipeTypes enumType; private IRecipeTypeInfo typeInfo;
private Supplier<ItemStack> forcedResult; private Supplier<ItemStack> forcedResult;
public ProcessingRecipe(AllRecipeTypes recipeType, ProcessingRecipeParams params) { public ProcessingRecipe(IRecipeTypeInfo typeInfo, ProcessingRecipeParams params) {
this.forcedResult = null; this.forcedResult = null;
this.enumType = recipeType; this.typeInfo = typeInfo;
this.processingDuration = params.processingDuration; this.processingDuration = params.processingDuration;
this.fluidIngredients = params.fluidIngredients; this.fluidIngredients = params.fluidIngredients;
this.fluidResults = params.fluidResults; this.fluidResults = params.fluidResults;
this.serializer = recipeType.getSerializer(); this.serializer = typeInfo.getSerializer();
this.requiredHeat = params.requiredHeat; this.requiredHeat = params.requiredHeat;
this.ingredients = params.ingredients; this.ingredients = params.ingredients;
this.type = recipeType.getType(); this.type = typeInfo.getType();
this.results = params.results; this.results = params.results;
this.id = params.id; this.id = params.id;
validate(Lang.asId(recipeType.name())); validate(typeInfo.getId());
} }
// Recipe type options: // Recipe type options:
@ -86,8 +84,8 @@ public abstract class ProcessingRecipe<T extends IInventory> implements IRecipe<
// //
private void validate(String recipeTypeName) { private void validate(ResourceLocation recipeTypeId) {
String messageHeader = "Your custom " + recipeTypeName + " recipe (" + id.toString() + ")"; String messageHeader = "Your custom " + recipeTypeId + " recipe (" + id.toString() + ")";
Logger logger = Create.LOGGER; Logger logger = Create.LOGGER;
int ingredientCount = ingredients.size(); int ingredientCount = ingredients.size();
int outputCount = results.size(); int outputCount = results.size();
@ -185,32 +183,36 @@ public abstract class ProcessingRecipe<T extends IInventory> implements IRecipe<
.getStack(); .getStack();
} }
@Override
public ResourceLocation getId() {
return id;
}
@Override @Override
public boolean isSpecial() { public boolean isSpecial() {
return true; return true;
} }
@Override
public IRecipeSerializer<?> getSerializer() {
return serializer;
}
// Processing recipes do not show up in the recipe book // Processing recipes do not show up in the recipe book
@Override @Override
public String getGroup() { public String getGroup() {
return "processing"; return "processing";
} }
@Override
public ResourceLocation getId() {
return id;
}
@Override
public IRecipeSerializer<?> getSerializer() {
return serializer;
}
@Override @Override
public IRecipeType<?> getType() { public IRecipeType<?> getType() {
return type; return type;
} }
public IRecipeTypeInfo getTypeInfo() {
return typeInfo;
}
// Additional Data added by subtypes // Additional Data added by subtypes
public void readAdditional(JsonObject json) {} public void readAdditional(JsonObject json) {}
@ -221,8 +223,4 @@ public abstract class ProcessingRecipe<T extends IInventory> implements IRecipe<
public void writeAdditional(PacketBuffer buffer) {} public void writeAdditional(PacketBuffer buffer) {}
public AllRecipeTypes getEnumType() {
return enumType;
}
} }

View file

@ -6,11 +6,10 @@ import java.util.function.Consumer;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.foundation.fluid.FluidHelper; import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.fluid.FluidIngredient; import com.simibubi.create.foundation.fluid.FluidIngredient;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import net.minecraft.data.IFinishedRecipe; import net.minecraft.data.IFinishedRecipe;
import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluid;
@ -221,16 +220,16 @@ public class ProcessingRecipeBuilder<T extends ProcessingRecipe<?>> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public DataGenResult(S recipe, List<ICondition> recipeConditions) { public DataGenResult(S recipe, List<ICondition> recipeConditions) {
this.recipeConditions = recipeConditions;
AllRecipeTypes recipeType = recipe.getEnumType();
String typeName = Lang.asId(recipeType.name());
this.recipe = recipe; this.recipe = recipe;
this.recipeConditions = recipeConditions;
IRecipeTypeInfo recipeType = this.recipe.getTypeInfo();
ResourceLocation typeId = recipeType.getId();
if (!(recipeType.getSerializer() instanceof ProcessingRecipeSerializer)) if (!(recipeType.getSerializer() instanceof ProcessingRecipeSerializer))
throw new IllegalStateException("Cannot datagen ProcessingRecipe of type: " + typeName); throw new IllegalStateException("Cannot datagen ProcessingRecipe of type: " + typeId);
this.id = new ResourceLocation(recipe.getId().getNamespace(), this.id = new ResourceLocation(recipe.getId().getNamespace(),
typeName + "/" + recipe.getId().getPath()); typeId.getPath() + "/" + recipe.getId().getPath());
this.serializer = (ProcessingRecipeSerializer<S>) recipe.getSerializer(); this.serializer = (ProcessingRecipeSerializer<S>) recipe.getSerializer();
} }

View file

@ -20,10 +20,10 @@ import net.minecraftforge.common.Tags;
public abstract class CreateRecipeProvider extends RecipeProvider { public abstract class CreateRecipeProvider extends RecipeProvider {
final List<GeneratedRecipe> all = new ArrayList<>(); protected final List<GeneratedRecipe> all = new ArrayList<>();
public CreateRecipeProvider(DataGenerator p_i48262_1_) { public CreateRecipeProvider(DataGenerator generator) {
super(p_i48262_1_); super(generator);
} }
@Override @Override
@ -32,16 +32,16 @@ public abstract class CreateRecipeProvider extends RecipeProvider {
Create.LOGGER.info(getName() + " registered " + all.size() + " recipe" + (all.size() == 1 ? "" : "s")); Create.LOGGER.info(getName() + " registered " + all.size() + " recipe" + (all.size() == 1 ? "" : "s"));
} }
@FunctionalInterface
public interface GeneratedRecipe {
void register(Consumer<IFinishedRecipe> consumer);
}
protected GeneratedRecipe register(GeneratedRecipe recipe) { protected GeneratedRecipe register(GeneratedRecipe recipe) {
all.add(recipe); all.add(recipe);
return recipe; return recipe;
} }
@FunctionalInterface
public interface GeneratedRecipe {
void register(Consumer<IFinishedRecipe> consumer);
}
protected static class Marker { protected static class Marker {
} }

View file

@ -6,11 +6,11 @@ import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import com.simibubi.create.AllRecipeTypes;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipe; import com.simibubi.create.content.contraptions.processing.ProcessingRecipe;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeBuilder;
import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer; import com.simibubi.create.content.contraptions.processing.ProcessingRecipeSerializer;
import com.simibubi.create.foundation.utility.recipe.IRecipeTypeInfo;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
import net.minecraft.data.DirectoryCache; import net.minecraft.data.DirectoryCache;
@ -22,22 +22,22 @@ import net.minecraftforge.fluids.FluidAttributes;
public abstract class ProcessingRecipeGen extends CreateRecipeProvider { public abstract class ProcessingRecipeGen extends CreateRecipeProvider {
protected static List<ProcessingRecipeGen> generators = new ArrayList<>(); protected static final List<ProcessingRecipeGen> GENERATORS = new ArrayList<>();
protected static final int BUCKET = FluidAttributes.BUCKET_VOLUME; protected static final int BUCKET = FluidAttributes.BUCKET_VOLUME;
protected static final int BOTTLE = 250; protected static final int BOTTLE = 250;
public static void registerAll(DataGenerator gen) { public static void registerAll(DataGenerator gen) {
generators.add(new CrushingRecipeGen(gen)); GENERATORS.add(new CrushingRecipeGen(gen));
generators.add(new MillingRecipeGen(gen)); GENERATORS.add(new MillingRecipeGen(gen));
generators.add(new CuttingRecipeGen(gen)); GENERATORS.add(new CuttingRecipeGen(gen));
generators.add(new WashingRecipeGen(gen)); GENERATORS.add(new WashingRecipeGen(gen));
generators.add(new PolishingRecipeGen(gen)); GENERATORS.add(new PolishingRecipeGen(gen));
generators.add(new DeployingRecipeGen(gen)); GENERATORS.add(new DeployingRecipeGen(gen));
generators.add(new MixingRecipeGen(gen)); GENERATORS.add(new MixingRecipeGen(gen));
generators.add(new CompactingRecipeGen(gen)); GENERATORS.add(new CompactingRecipeGen(gen));
generators.add(new PressingRecipeGen(gen)); GENERATORS.add(new PressingRecipeGen(gen));
generators.add(new FillingRecipeGen(gen)); GENERATORS.add(new FillingRecipeGen(gen));
generators.add(new EmptyingRecipeGen(gen)); GENERATORS.add(new EmptyingRecipeGen(gen));
gen.addProvider(new IDataProvider() { gen.addProvider(new IDataProvider() {
@ -48,7 +48,7 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider {
@Override @Override
public void run(DirectoryCache dc) throws IOException { public void run(DirectoryCache dc) throws IOException {
generators.forEach(g -> { GENERATORS.forEach(g -> {
try { try {
g.run(dc); g.run(dc);
} catch (IOException e) { } catch (IOException e) {
@ -59,8 +59,8 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider {
}); });
} }
public ProcessingRecipeGen(DataGenerator p_i48262_1_) { public ProcessingRecipeGen(DataGenerator generator) {
super(p_i48262_1_); super(generator);
} }
/** /**
@ -86,7 +86,7 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider {
* Create a processing recipe with a single itemstack ingredient, using its id * Create a processing recipe with a single itemstack ingredient, using its id
* as the name of the recipe * as the name of the recipe
*/ */
protected <T extends ProcessingRecipe<?>> GeneratedRecipe create(Supplier<IItemProvider> singleIngredient, <T extends ProcessingRecipe<?>> GeneratedRecipe create(Supplier<IItemProvider> singleIngredient,
UnaryOperator<ProcessingRecipeBuilder<T>> transform) { UnaryOperator<ProcessingRecipeBuilder<T>> transform) {
return create(Create.ID, singleIngredient, transform); return create(Create.ID, singleIngredient, transform);
} }
@ -109,21 +109,20 @@ public abstract class ProcessingRecipeGen extends CreateRecipeProvider {
* Create a new processing recipe, with recipe definitions provided by the * Create a new processing recipe, with recipe definitions provided by the
* function * function
*/ */
protected <T extends ProcessingRecipe<?>> GeneratedRecipe create(String name, <T extends ProcessingRecipe<?>> GeneratedRecipe create(String name,
UnaryOperator<ProcessingRecipeBuilder<T>> transform) { UnaryOperator<ProcessingRecipeBuilder<T>> transform) {
return create(Create.asResource(name), transform); return create(Create.asResource(name), transform);
} }
protected <T extends ProcessingRecipe<?>> ProcessingRecipeSerializer<T> getSerializer() { protected abstract IRecipeTypeInfo getRecipeType();
ProcessingRecipeSerializer<T> serializer = getRecipeType().getSerializer();
return serializer; protected <T extends ProcessingRecipe<?>> ProcessingRecipeSerializer<T> getSerializer() {
return getRecipeType().getSerializer();
} }
@Override @Override
public final String getName() { public String getName() {
return "Create's Processing Recipes: " + getRecipeType(); return "Create's Processing Recipes: " + getRecipeType().getId().getPath();
} }
protected abstract AllRecipeTypes getRecipeType();
} }

View file

@ -0,0 +1,15 @@
package com.simibubi.create.foundation.utility.recipe;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.util.ResourceLocation;
public interface IRecipeTypeInfo {
ResourceLocation getId();
<T extends IRecipeSerializer<?>> T getSerializer();
<T extends IRecipeType<?>> T getType();
}