Complete JSON Field Reference
This page consolidates fields from the previous wiki and fields verified against the 1.20.1 source.
Controllers
Path:
config/mm/controllers/<file>.json
Example:
{
"type": "mm:machine",
"id": "coke_oven",
"name": "Coke Oven",
"parallelProcessingDefault": false,
"maxParallelRecipes": -1,
"recipeSelectionMode": "default"
}
| Field | Type | Required | Notes |
|---|---|---|---|
type |
resource location | yes | Currently mm:machine. |
id |
string | yes | Base controller id. coke_oven generates the controller block/item id mm:coke_oven. |
name |
string | yes | Display name. |
parallelProcessingDefault |
boolean | no | Defaults to false. Used by recipes unless overridden. |
maxParallelRecipes |
integer | no | Controller override. -1 means unspecified/fallback. Non-negative values clamp up to 100. Global common config is separate and is ranged 1..100. |
recipeSelectionMode |
string | no | Recipe scheduling mode. Supported values: default, avoid_same_recipe, round_robin_input_item. Unknown values fall back to default. |
Controller recipe selection modes
recipeSelectionMode changes which runnable recipe a formed controller prefers to start. It does not change recipe validity, inputs, outputs, timings, or parallel-processing caps.
| Value | Behavior |
|---|---|
default |
Normal rotating recipe scan order. |
avoid_same_recipe |
Prefer another runnable recipe instead of starting the exact same recipe as last time. Falls back if only the same recipe can run. |
round_robin_input_item |
Prefer the least-recently-used consumed item input among all currently runnable recipes. Falls back if only one input item type can run. |
round_robin_input_item is intended for sieve/washer/recycler-style machines where several input items share one input port and should be processed fairly.
Ports
Path:
config/mm/ports/<file>.json
Every port JSON is expanded into input and output variants.
Common fields:
{
"id": "item_port",
"controllerIds": ["mm:coke_oven"],
"name": "Item Port",
"type": "mm:item",
"config": {}
}
| Field | Type | Required | Notes |
|---|---|---|---|
id |
string | yes | Base port id. item_port generates mm:item_port_input and mm:item_port_output. |
controllerIds |
resource location or array | yes | One controller id or a list of ids. |
name |
string | yes | Display name. |
type |
resource location | yes | See supported port types below. |
config |
object | yes | Type-specific storage config. |
Port config fields
| Port type | Config fields | Recipe ingredient fields |
|---|---|---|
mm:item |
rows, columns, optional autoPush, optional slotCapacity, optional tierRank |
item or tag, count, optional nbt, optional nbt_snbt, optional nbt_match |
mm:fluid |
rows, columns, slotCapacity, optional autoPush, optional tierRank |
fluid, amount |
mm:energy |
capacity, maxReceive, maxExtract, optional autoPush, optional tierRank |
amount |
mm:create/kinetic |
stress |
speed |
mm:botania/mana |
capacity |
mana |
mm:pneumaticcraft/air |
volume, danger, critical |
air, optional pressure |
mm:mekanism/gas |
capacity |
gas, amount |
mm:mekanism/slurry |
capacity |
slurry, amount |
mm:mekanism/pigment |
capacity |
pigment, amount |
mm:mekanism/infuse |
capacity |
infuse, amount |
Item NBT matching
Item ingredients support two ways to specify NBT:
{
"type": "mm:item",
"item": "minecraft:potion",
"count": 1,
"nbt": { "Potion": "minecraft:water" },
"nbt_match": "weak"
}
or:
{
"type": "mm:item",
"item": "minecraft:potion",
"count": 1,
"nbt_snbt": "{Potion:\"minecraft:water\"}",
"nbt_match": "strong"
}
weak/default matching treats the provided NBT as a subset. strong requires a stricter match.
Extra blocks
Path:
config/mm/extras/<file>.json
Example:
{
"id": "basic_circuit",
"name": "Basic Circuit",
"type": "mm:circuit"
}
Supported types:
mm:circuitmm:gearboxmm:vent
Structures
Path:
data/<namespace>/mm/structures/<path>.json
Example:
{
"name": "Coke Oven",
"controllerIds": "mm:coke_oven",
"portsAnywhere": false,
"maxParallelRecipes": -1,
"layout": [
["AAA", "ACA", "AAA"]
],
"key": {
"A": { "block": "minecraft:bricks" },
"C": { "block": "mm:coke_oven" }
}
}
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | Display name. |
controllerIds |
resource location or array | yes | Controller ids allowed to form this structure. |
layout |
array of layers | yes | Layers are arrays of strings. Each character maps to key. |
key |
object | yes | Character-to-piece definitions. |
portsAnywhere |
boolean | no | Lets normal port and portType pieces match any of the candidate port positions in the layout. |
maxParallelRecipes |
integer | no | Per-structure override. -1 means unspecified/fallback; non-negative values clamp up to 100. Global common config is separate and is ranged 1..100. |
stateLists |
object | no | Defines named lists of block states used by stateList pieces. |
Structure key piece types
A key entry is identified by the field it contains:
"A": { "block": "minecraft:bricks" }
| Field | Meaning |
|---|---|
block |
Require one exact block. |
tag |
Require any block in a block tag. |
port |
Require a specific port id. Optional input: true/false. Optional anywhere: true. |
portType |
Require any port of a type. Optional input, minTier, maxTier, anywhere. |
stateList |
Require one of the named block states from stateLists. Optional nameTranslationKey. |
properties |
Modifier array for blockstate properties, used together with a base piece. |
For exact port matching, use the base port id plus the input flag:
"I": { "port": "mm:item_port", "input": true }
"O": { "port": "mm:item_port", "input": false }
Do not use port: "mm:item_port_input" as the normal structure form. Generated block ids include _input and _output, but the structure port requirement is intended to reference the base port id.
Port type matching with tiers
Example:
"I": {
"portType": "mm:item",
"input": true,
"minTier": 2,
"maxTier": 4
}
This matches any input item port whose storage config tierRank is between 2 and 4. If a port config has no meaningful tier, it behaves like tier 1 for matching.
KubeJS generated-id rules
For startup-generated config-backed content, event.create(...) takes a bare MM base id/path, not a namespaced id:
MMEvents.registerControllers(event => {
event.create('coke_oven')
.type('mm:machine')
.name('Coke Oven')
})
MMEvents.registerExtraBlocks(event => {
event.create('basic_circuit')
.type('mm:circuit')
.name('Basic Circuit')
})
MMEvents.registerPorts(event => {
event.create('item_port')
.name('Item Port')
.controllerId('mm:coke_oven')
.config('mm:item', c => {
c.rows(1).columns(3).slotCapacity(64).tierRank(1)
})
})
Wrong:
event.create('mm:coke_oven')
event.create('mm:basic_circuit')
event.create('mm:item_port')
Structures and process recipes are different: those are datapack/resource ids and should be namespaced:
MMEvents.createStructures(event => {
event.create('expert:coke_oven')
.controllerId('mm:coke_oven')
})
MMEvents.createProcesses(event => {
event.create('expert:coke_oven/charcoal')
.structureId('expert:coke_oven')
})
Process recipes
Path:
data/<namespace>/mm/processes/<path>.json
Example:
{
"structureId": "mypack:coke_oven",
"ticks": 200,
"parallelProcessing": false,
"inputs": [
{
"type": "mm:input/consume",
"ingredient": {
"type": "mm:item",
"item": "minecraft:oak_log",
"count": 1
}
}
],
"outputs": [
{
"type": "mm:output/simple",
"ingredient": {
"type": "mm:item",
"item": "minecraft:charcoal",
"count": 1
}
}
],
"conditions": []
}
| Field | Type | Required | Notes |
|---|---|---|---|
structureId |
resource location | yes | Structure that can run the recipe. |
ticks |
integer | yes | Runtime in game ticks. 20 ticks = 1 second. |
inputs |
array | yes | Input entries. |
outputs |
array | yes | Output entries. |
conditions |
array | no | Extra requirements. |
parallelProcessing |
boolean | no | Overrides global/controller defaults. |
Input entries
{
"type": "mm:input/consume",
"ingredient": { "type": "mm:item", "item": "minecraft:iron_ingot", "count": 1 },
"chance": 1.0,
"per_tick": false
}
| Field | Type | Required | Notes |
|---|---|---|---|
type |
resource location | yes | Currently mm:input/consume. |
ingredient |
object | yes | Port ingredient object. |
chance |
number | no | Defaults to 1.0. Chance is checked as a probability. |
per_tick |
boolean | no | If true, input is consumed every recipe tick rather than once on completion. |
Output entries
{
"type": "mm:output/simple",
"ingredient": { "type": "mm:energy", "amount": 1000 },
"chance": 1.0,
"per_tick": false
}
Output entries use the same optional chance and per_tick fields. For item outputs, the source also accepts shorthand fields such as item, count, and NBT fields directly on the output entry, but the full ingredient object is clearer and recommended.
Conditions
Supported condition types:
{ "type": "mm:dimension", "dimension": "minecraft:the_nether" }
{ "type": "mm:weather", "weather": "clear" }
Weather values are parsed as enum names. Use lowercase or uppercase variants equivalent to the enum names: clear, rain, or thunder.