Repository navigation
API Recipe Matching
Lua API / Recipe matching
On this page
Matches a supplied input snapshot. Required type (name/handle); optional ingredients role map and context values validated against the type.
Returns a match snapshot, or nil when no recipe matches. Supports custom recipe types and native smelting. The tile-bound variant provides inventory application methods.
local match = betamoon.recipes:match {
type = "smelting",
ingredients = { input = betamoon.stack(15) }
}Single-item roles take a stack, pools a dense list of stacks, and grids a dense matrix with the schema's exact width and height. Omitted roles supply empty inputs; an empty pool table supplies an empty pool.
Tile-context matching. Required type and slots = { ingredients = ..., outputs = ... }; optional validated context. Returns nil or a match bound to this tile inventory.
Every role, including optional roles, requires a physical binding. Item roles bind a slot-name string. Pool/output-pool roles bind a pool handle/list; grid roles bind a grid handle/matrix. Unknown slots and overlapping physical bindings are errors.
local match = ctx.recipes:match {
type = "smelting",
slots = {
ingredients = { input = "input" },
outputs = { output = "output" }
}
}Discovery can return a match whose outputs are blocked. Check canApply before advancing a machine. Custom candidates are enabled recipes ordered by descending priority, then by earlier registration for equal priorities.
| Field | Meaning |
|---|---|
recipe |
Selected recipe reference. |
type |
Custom qualified type name or smelting. |
signature |
Opaque recipe/allocation/binding identity for comparing work-in-progress; do not parse it. |
data |
Recipe data snapshot. |
output |
Primary output stack. |
outputs |
All output role values. |
ingredients |
Selected single-role stacks with consume flags; pool/grid roles expose allocations. |
allocations |
Per-role allocation lists with slot, count, selected stack; requirement and row/column when relevant. |
remainders |
List of byproducts with ingredient role, source slot, stack, and optional output role. |
Grid allocation views may also report transformation and placement row/column. Views are descriptive; changing them does not rewrite the processing plan.
Bound matches only. Returns true if inputs, recipe revision, conditions, outputs and remainders are still valid; otherwise false, reason. No inventory mutation.
Optional options = { context = ... }. Recipes with conditions require a fresh context snapshot at application checks; omitting it is an error.
local ready, reason = match:canApply { context = { heat = 400, powered = true } }Bound matches only. Revalidates and atomically consumes required inputs, retains catalysts, and inserts all outputs/remainders. Returns true on commit or false, reason on rejection. Options follow canApply.
A successful plan cannot be applied twice. Do not also manually consume inputs or insert outputs.
local applied, reason = match:apply()| Reason | Meaning |
|---|---|
| already_applied | This match already committed. |
| invalid_inventory | Bound tile inventory is no longer valid. |
| reentrant_apply | Inventory is already inside an incompatible commit/callback operation. |
| stale_recipe | Recipe/type/matcher revision changed or registration disappeared. |
| conditions_changed | Fresh context no longer satisfies recipe conditions. |
| inputs_changed | Current allocation no longer matches the discovered plan. |
| output_full | Output insertion cannot fit completely. |
| remainder_blocked | Remainder placement cannot complete. |
Commit can also reject an inventory changed during revalidation. Invalid arguments/schema values raise Lua errors rather than returning a normal mismatch reason.
Creates a reusable slot-name pool. Accepts a nonempty unique list of names or { prefix = ..., count = ... }. Count range 1–4096; generated names are prefix1, prefix2, etc.
local pool = betamoon.recipeBindings:pool { prefix = "input_", count = 4 }Returns a pool handle with kind = "item_pool", count, and numeric indexed names.
Returns a detached list of names.
local names = pool:toTable()Creates a reusable slot-name grid from a nonempty rectangular matrix, or { prefix, width, height }. Dimensions 1–16. Generated names are prefix followed by row_column, with row/column starting at 1. Names must be unique.
local grid = betamoon.recipeBindings:grid { prefix = "work_", width = 3, height = 3 }Returns a grid handle exposing kind = "item_grid", width, height, and indexed row views.
Returns a detached matrix of slot names.
local names = grid:toTable()Registers a custom allocation strategy for the current script generation. Required name and match function. Returns a matcher handle; duplicate names raise an error. Type schemas reference it through their matcher field.
local matcher = betamoon.recipeMatchers:add {
name = "mymod:recipe_matcher/first_slot",
match = function(recipe, inputs, context, plan)
if not inputs.input.stack then return false end
plan:use { role = "input", slot = inputs.input.slot }
return true
end
}This minimal strategy assumes a single item role named input. A valid plan must still satisfy all required counts and item constraints.
Receives detached normalized recipe data (including type/key), detached input cells, copied context values, and a plan builder. Return truthy to validate the proposed allocation; false/nil means no match.
An input cell has index (one-based position within its binding), slot (name), and stack (nil if empty). Grid cells additionally have row/column; pools are cell lists, grids are matrices, single items are one cell.
Mutating snapshots does not mutate inventory. Errors or invalid plans disable the matcher until re-registration. Recursive invocation of the same matcher does not match. Validate contents before proposing uses.
Adds a proposed allocation and returns the plan builder.
plan:use { role = "materials", slot = 1, requirement = 1, count = 4 }| Field | Meaning |
|---|---|
role |
Required ingredient role name. |
slot |
Required bound slot name or one-based flattened binding index. |
requirement |
Omit for item roles; pool requirement index for pools; recipe character for grids. |
count |
Optional positive count; defaults to that ingredient requirement's count. |
Allocation must reference the role's slots, satisfy item/damage constraints, avoid over-allocation, meet exact required counts, and respect empty/extra-slot rules. It cannot invent outputs or bypass retained ingredient rules. Using a finalized plan raises an error.
Returns the registered matcher handle or nil. Accepts name or matcher handle. Handle properties are documented below.
local matcher = betamoon.recipeMatchers:get("mymod:recipe_matcher/first_slot")Properties: name (qualified matcher name), owner (script filename), and exists (true while this registration is current and enabled). Registration is scoped to its owner generation; reload removes owned matchers and invalidates affected recipe plans.
Examples: Context revalidation, advanced matching, custom matcher.
- Installation
- Install scripts
- Getting started
- VS Code and LuaLS
- Examples
- Reload and compatibility
- Troubleshooting
- Changelog
Scripts and shared values
- Script lifecycle
- Packaged Lua mods
- Modules
- References and stacks
- Queries
- Overrides
- Minecraft constants
- Chat and positions
- Structured data
- Script configuration
- Particles
Blocks and items
- Multiblocks
- Blocks
- Block state and placement
- Block shapes and rendering
- Block callbacks
- Block ticks and redstone
- Items
- Fluids
- Item callbacks
- Tools and armor
- Materials
- Textures
Entities
- Entities
- Entity access and movement
- Entity lifecycle and data
- Entity health and loot
- Entity inventories and relationships
- Projectiles and pickups
- Entity presentation and sounds
- Living entities and AI
- Entity parts and sensors
Assets and audio
- Assets
- Models and animations
- Built-in Minecraft models
- Model appearances
- Blockbench workflow
- Audio
- Texture-pack overrides
Events and world actions
World generation
World systems
Inventories and screens
Recipes