Custom Crafting Processors
Create a custom Crafting Processor when a recipe needs a rule or result that the built-in processors cannot express. Start with one visible change, such as requiring a crafting level for Brew Health Potion or assigning a runtime Quality value to the crafted Health Potion.
The built-in Simple Crafting Processor handles standard Item, Item Definition, and Item Category ingredients. Simple Crafting Processor With Currency adds Currency requirements. Keep one of those processors when changing the recipe data is enough.
Choose the smallest extension
| Desired result | Recommended approach |
|---|---|
| Change the required ingredients or output amounts | Edit the Crafting Recipe; no custom processor is needed. |
| Apply one level requirement to every recipe in a Crafting Category | Map recipe.Category to a level in a custom processor. |
| Give each recipe its own level requirement | Add a field to a custom Crafting Recipe type and read it from a custom processor. |
| Set an Item attribute from a character stat or minigame result | Override the output-creation step and set the mutable Item attribute before adding the result to the Inventory. |
| Replace ingredient selection, removal, and output creation together | Override the full crafting transaction only when the narrower extension points are insufficient. |
Prefer the narrowest option. It keeps the built-in validation, ingredient removal, quantity handling, and crafting events intact.
Prepare the Health Potion test
Use one known recipe so a processor change has an unambiguous result:
- Brew Health Potion belongs to Consumable Recipes.
- It requires 2 Herb and 1 Water from the player’s Bag.
- It normally produces 1 Health Potion.
- The Crafter includes Consumable Recipes and the Crafting Menu references that Crafter and Inventory.
Confirm that this recipe works with a built-in processor before adding a custom rule. That separates a processor problem from a recipe, Inventory, or UI setup problem.
Require a crafting level
Use a custom Recipe Type when the required level varies by recipe. The complete Version 1 example is in Developer reference.
- Add the
LevelCraftingRecipeandLevelCraftingProcessorclasses to the project and allow Unity to compile. - Open Tools > Opsive > Ultimate Inventory System > Main Manager and select Crafting Categories.
- Select Consumable Recipes and set Recipe Type to Level Crafting Recipe. If only some consumable recipes need this data, create a separate concrete category for them instead.
- Select Crafting Recipes, open Brew Health Potion, and set Required Level in the Other tab.
- Select the GameObject with the Crafter component and change Processor to Level Crafting Processor.
- Set Test Crafting Level while proving the workflow. Replace the example getter with the project’s character-level source before shipping.
The expected outcome is simple: below the Required Level, the craft is rejected and the Bag does not change. At or above the Required Level, the same recipe consumes its ingredients and adds the Health Potion.
All direct recipes in one Crafting Category share its Recipe Type. Changing that type converts the existing recipes and can discard fields that are not present on the new type, so make the change in version control and review every recipe afterward.
Set runtime output quality
Use a mutable Item attribute when the output remains a Health Potion but one runtime value depends on a character stat, tool, or minigame result. The example processor overrides only output creation; the Simple Crafting Processor still validates and removes the ingredients.
- Add an integer Quality Item attribute to the Item Category used by Health Potion and make it mutable.
- Add the
QualityCraftingProcessorclass from Developer reference and allow Unity to compile. - Select the Crafter and change Processor to Quality Crafting Processor.
- Set Test Crafting Quality to a recognizable value, such as 3.
- Keep Brew Health Potion’s normal ingredient and output lists unchanged.
- After the test works, replace the example quality getter with the project’s character-stat or minigame provider.
On a successful craft, the processor creates the Health Potion, sets its Item-level Quality, and then adds it to the Inventory. The recipe still controls the Item Definition and amount; the external source controls only the runtime value.
Connect a processor safely
The Crafter Inspector labels the type selector Processor. Selecting another type opens Change Crafting Processor Type? because the action cannot be undone and some values may be lost.
After confirming the change, review every processor field. In particular, retain the intended Externally Remove Ingredients and Ingredient Item Collections behavior inherited from Simple Crafting Processor. Leave external removal disabled unless another system handles the removal callback and reports success.
Editor checkpoint
Before entering Play Mode, confirm that:
- the custom processor class compiles and appears in the Crafter’s Processor selector;
- the Crafter still includes Consumable Recipes;
- Ingredient Item Collections still points to Bag when the project limits ingredient searches to that collection;
- Externally Remove Ingredients has the intended value;
- a level-gated recipe uses the custom Recipe Type and shows Required Level in Other; and
- a quality-based output has a mutable integer Quality Item attribute.
Verify in Play Mode
Test one variable at a time:
- Give the Bag exactly 2 Herb and 1 Water.
- For the level processor, set Test Crafting Level below Required Level and attempt Brew Health Potion. Confirm that neither ingredient is removed and no Health Potion is added.
- Raise Test Crafting Level to the requirement and craft again. Confirm that 2 Herb and 1 Water are removed and 1 Health Potion is added.
- For the quality processor, set Test Crafting Quality to 3 and craft once. Inspect the resulting Health Potion or show its Quality through an Attribute View, and confirm that the value is 3.
- Craft a quantity greater than 1 when the menu permits it. Confirm that ingredient and output amounts scale with quantity while every produced Item receives the same tested Quality.
Troubleshooting
- The custom processor is absent from Processor: Check that the class compiles, inherits from Crafting Processor or one of its subclasses, and is not abstract; then reselect the Crafter.
- Processor settings disappeared: Changing the Processor type can lose unsupported fields. Restore the previous version if needed, select the intended type again, and re-enter every custom and inherited setting.
- Required Level is absent from the recipe: Check that the recipe’s Crafting Category uses the custom Recipe Type, then open the recipe’s Other tab.
- Every level-gated craft fails: Check that the processor and recipe types are paired, the test or character level source returns the expected value, and the base processor can find the ingredients.
- Ingredients disappear even though the level is too low: Apply the level test in
CanCraftInternaland returnfalsebefore the craft begins; do not remove Items in the level getter. - Quality stays at its default: Check that Health Potion has an integer Quality Item attribute, that the attribute is mutable, and that the name and type match the code exactly.
- Crafting succeeds but the wrong collection changes: Check Ingredient Item Collections, the Inventory’s Main Item Collection, and any external-removal handler.
Related pages
- Crafting concepts, processors, and Crafter
- Crafting Category editor
- Crafting Recipe editor
- Attribute editor
- Attribute View
- Crafting Menu
Developer reference
These examples match the released Ultimate Inventory System Version 1 signatures. In the protected methods, selectedIngredients comes before quantity.
| Extension point | Use it for |
|---|---|
CanCraftInternal(recipe, inventory, selectedIngredients, quantity) |
Add a rule while retaining the built-in ingredient and Inventory checks. |
CreateCraftingOutput(recipe, inventory, quantity) |
Create or modify runtime output while retaining built-in validation and ingredient removal. |
RemoveIngredients(inventory, selectedIngredients) |
Replace removal only when the built-in or external-removal paths cannot support the design. |
CraftInternal(recipe, inventory, selectedIngredients, quantity) |
Replace the complete transaction. Reproduce validation, removal, output creation, Inventory updates, and failure handling deliberately. |
Gate a recipe by level
The test field keeps the sample self-contained. Replace GetCraftingLevel with the project’s real level provider.
using Opsive.Shared.Utility;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;
using Opsive.UltimateInventorySystem.Crafting;
using Opsive.UltimateInventorySystem.Crafting.Processors;
using System;
using UnityEngine;
public class LevelCraftingRecipe : CraftingRecipe
{
[SerializeField] protected int m_RequiredLevel = 1;
public int RequiredLevel => m_RequiredLevel;
}
[Serializable]
public class LevelCraftingProcessor : SimpleCraftingProcessor
{
[SerializeField] protected int m_TestCraftingLevel = 1;
protected override bool CanCraftInternal(
CraftingRecipe recipe,
IInventory inventory,
ListSlice<ItemInfo> selectedIngredients,
int quantity)
{
var levelRecipe = recipe as LevelCraftingRecipe;
if (levelRecipe == null) { return false; }
if (GetCraftingLevel(inventory) < levelRecipe.RequiredLevel) {
return false;
}
return base.CanCraftInternal(
recipe, inventory, selectedIngredients, quantity);
}
protected virtual int GetCraftingLevel(IInventory inventory)
{
// Replace this test value with the project's character-level source.
return m_TestCraftingLevel;
}
}
Set a mutable output attribute
This example preserves the Simple Crafting Processor’s validation and removal path while creating the output with a runtime Quality value.
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core.InventoryCollections;
using Opsive.UltimateInventorySystem.Crafting;
using Opsive.UltimateInventorySystem.Crafting.Processors;
using System;
using UnityEngine;
[Serializable]
public class QualityCraftingProcessor : SimpleCraftingProcessor
{
[SerializeField] protected int m_TestCraftingQuality = 1;
protected override CraftingOutput CreateCraftingOutput(
CraftingRecipe recipe, IInventory inventory, int quantity)
{
var sourceAmounts = recipe.DefaultOutput.ItemAmounts;
var resultAmounts = new ItemAmount[sourceAmounts.Count];
var craftingQuality = GetCraftingQuality(inventory);
for (int i = 0; i < resultAmounts.Length; i++) {
var sourceAmount = sourceAmounts[i];
var craftedItem = InventorySystemManager.CreateItem(sourceAmount.Item);
var quality = craftedItem.GetAttribute<
Opsive.UltimateInventorySystem.Core.AttributeSystem.Attribute<int>>(
"Quality");
if (quality != null) {
quality.SetOverrideValue(craftingQuality);
}
var resultAmount = new ItemAmount(
craftedItem, sourceAmount.Amount * quantity);
resultAmounts[i] = resultAmount;
inventory.AddItem((ItemInfo)resultAmount);
}
return new CraftingOutput(resultAmounts);
}
protected virtual int GetCraftingQuality(IInventory inventory)
{
// Replace this test value with the project's stat or minigame source.
return m_TestCraftingQuality;
}
}