IConfigurableRecipe

The IConfigurableRecipe is an Interface implementation. It allows you to make your Recipe an Overridable Recipe to allow either:

  • Other Modders
  • Server Owners

To customize your Recipes for your items.

Not only that, you can use them to allow items from other mods to be used in your recipes allowing for greater extensions and mod connections. More Info on that in the IRecipeOverride Documentation

The implementation of the IConfigurableRecipe can be used with both RecipeFamily and Recipe depending on the situation.

Below is the Implementation of the IConfigurableRecipe in both cases:


Implementation


The implementation uses a specific data structure and is setup in a specific way for it to be able to work.

Working with the implementation will be confusing to start with as it is not a normal implementation of the recipe setup.

static RecipeDefaultModel Defaults => new()
  {
    // Defaults required to create recipes, but not overridable
    ModelType = typeof(MyRecipe).Name,
    Assembly = typeof(MyRecipe).AssemblyQualifiedName,
    HiddenName = "My Item Recipe",
    LocalizableName = Localizer.DoStr("My Item Recipe"),
    RequiredSkillType = typeof(SomeSkill),
    RequiredSkillLevel = 0,
    SpeedImprovementTalents = new Type[] { 
    typeof(SomeFocusedSpeedTalent), 
    typeof(SomeParallelSpeedTalent) },

    // RecipeModel (Will be overrideable)
    IngredientList = new()
    {
      new EMIngredient("PlasticItem", false, 15),
      new EMIngredient("GoldBarItem", false, 8),
      new EMIngredient("Lumber", true, 7)
    },
    ProductList = new()
    {
      new EMCraftable("MyItem"),
    },
    BaseExperienceOnCraft = 1,
    BaseLabor = 250,
    LaborIsStatic = false,
    BaseCraftTime = 1,
    CraftTimeIsStatic = false,
    CraftingStation = "CraftingTableItem",
    };

Here is each component broken down and explained:


ModelType:

The Model type refers to the recipe itself *Required


Assembly:

The Assembly Refers to the assembly its located in *Required


HiddenName:

The Hidden Name is the Internal Referencing Name Used


LocalizableName:

Is the display name used to display in the tables ( Also used for translations )


RequiredSkillType:

Required Skill for crafting


RequiredSkillLevel:

Required Skill level for crafting


SpeedImprovementTalents:

Craft Time Modifiers


IngredientList:

The list of ingredients used to make the item,

  • Param 1 is the Item as a string! This is important!!
  • Param 2 is "Is this a tag or not" false = not a tag, true = is a tag.
  • Param 3 is How many of this item is needed
  • Param 4 Is "Should the required amount change with modifiers"

ProductList:

The List of all items for the output

  • Param 1 is the Item for output as a string! This is Important!!
  • Param 2 is how many items to give back, Default is 1 and does not need to be included unless you wish to give more then 1 item

BaseExperienceOnCraft:

The Experience Modifier on top of their total skill value ( 1 is default )


BaseLabor:

The Base amount of labor required


LaborIsStatic:

Labor can be affected by skill level, use true if you are not using a skill


BaseCraftTime:

How long it takes to make this item


CraftTimeIsStatic:

Can the timer be altered by the talents, false = yes, true = no


CraftingStation:

Crafting Station it is to be made at, MUST be a string and MUST be the Item not the Object!

  • If it is the object IE: WorkbenchObject it will throw errors
  • Must be WorkbenchItem in order to function

Using RecipeFamily


These are the values that are required when using this on the RecipeFamily Recipe.

Anything Marked with an Asterixis (//*) is Required

    [RequiresSkill(typeof(Skill), level)] //*
    public class Recipe : RecipeFamily, IConfigurableRecipe
    {
        static RecipeDefaultModel Defaults => new()
        {
            ModelType = typeof(Recipe).Name, //*
            Assembly = typeof(Recipe).AssemblyQualifiedName, //*
            HiddenName = "Item Name", //*
            LocalizableName = Localizer.DoStr("Item Name"), //*
            IngredientList = new()
            {
                new EMIngredient("Item", false, 8) //*
            },
            ProductList = new()
            {
                new EMCraftable("Item", 3), //*
            },
            BaseExperienceOnCraft = 1,
            BaseLabor = 50, //*
            LaborIsStatic = false, //*
            BaseCraftTime = 1, //*
            CraftTimeIsStatic = false, //*
            CraftingStation = "Item", //*
            RequiredSkillType = typeof(Skill),
            RequiredSkillLevel = 4,
            IngredientImprovementTalents = typeof(LavishResourcesTalent),
            SpeedImprovementTalents = new Type[] { typeof(ParallelSpeedTalent), typeof(FocusedSpeedTalent) },
        };

        static Recipe() { EMRecipeResolver.AddDefaults(Defaults); } //*

        public Recipe()
        {
            this.Recipes = EMRecipeResolver.Obj.ResolveRecipe(this); //*
            this.LaborInCalories = EMRecipeResolver.Obj.ResolveLabor(this); //*
            this.CraftMinutes = EMRecipeResolver.Obj.ResolveCraftMinutes(this); //*
            this.ExperienceOnCraft = EMRecipeResolver.Obj.ResolveExperience(this); //*
            this.Initialize(Defaults.LocalizableName, GetType()); //*
            CraftingComponent.AddRecipe(EMRecipeResolver.Obj.ResolveStation(this), this); //*
        }
    }

Now here you will see some new things:

  • The Static Constructer
  • The Constructor

The static constructor adds the defaults to the Recipe Resolver ready to be read

The Constructor Initalizes everything ready to be used in game

Both Must be setup the way you see above


Using Recipe


Recipe is used for Variants, it is implemented the same way but the constructors are different

Here is an example:

    [RequiresSkill(typeof(Skill), 1)]
    public partial class Recipe : Recipe, IConfigurableRecipe
    {
        static RecipeDefaultModel Defaults => new()
        {
            ModelType = typeof(Recipe).Name,
            Assembly = typeof(Recipe).AssemblyQualifiedName,
            HiddenName = "Display Name",
            LocalizableName = Localizer.DoStr("Display Name"),
            IngredientList = new()
            {
                new EMIngredient("Item", false, 6, true),
            },
            ProductList = new()
            {
                new EMCraftable("Item", 6),
            },
            CraftingStation = "Item",
        };

        static Recipe() { EMRecipeResolver.AddDefaults(Defaults); }

        public Recipe()
        {
            CraftingComponent.AddTagProduct(EMRecipeResolver.Obj.ResolveStation(this), typeof(ParentRecipe), EMRecipeResolver.Obj.ResolveRecipe(this).First());
        }
    }

If you know how to make Recipe Variants this will be somewhat familiar.

In the Public Constructer we use the recipe resolver to attach to the correct table, then we reference the parent recipe, then we attach our recipe.

Recipe Variants don't override the craft time or skills so that is not needed as it inherits it from the parent recipe.


EMIngredient


The EMIngredient is our Version of the IngredientElement()

This uses this setup:

EMIngredient(string item: "", bool isTag: false, int amount: 1, bool isStatic: false)

We have to use strings here because this is how we find the Items before anything is initialized in order to override the Recipes or make them be able to be overridden.

We use true or false for the isTag to check if we should be looking for a tag or an item.

The other 2 are pretty standard.

Amount is how many of this item is required to make the end product ( in whole numbers only )

IsStatic is should the amount of items required be affected by modules, skill modifiers or talent modifiers:

  • false ( which is default ) means yes it can be affected by modifiers.
  • true means it can not be affected by modifiers.

EMProduct


The EMProduct is pretty much the same as CraftingElement<>()

This uses this setup:

EMProduct(string item: "", int amount: 1)

However here we use a string as well because we are looking for things before they are initialized

We use the amount to say how many we are giving when the recipe has finished crafting