Controllers
Controllers are the machine brains. A placed controller checks the blocks around itself, forms a matching structure, and runs process recipes for that structure.
How controllers work
- The controller uses its world position as the origin.
- It scans known structures that reference that controller ID.
- If the blocks around it match a structure layout, the controller becomes formed.
- Once formed, it checks matching process recipes.
- A recipe can run when all inputs exist, all outputs have room, and all conditions pass.
The controller GUI reports whether a structure is formed and which structure was detected.
Creating a controller
Create JSON files in:
config/mm/controllers/
Minimal example:
{
"type": "mm:machine",
"id": "my_controller",
"name": "My Controller"
}
| Field | Meaning |
|---|---|
type |
Controller type. For normal machines use mm:machine. |
id |
Unique controller path. my_controller becomes the generated controller block/item id mm:my_controller. |
name |
Default English display name. Translation key: block.mm.<id>. |
Parallel-processing fields
Controllers can define default parallel-processing behaviour:
{
"type": "mm:machine",
"id": "my_controller",
"name": "My Controller",
"parallelProcessingDefault": false,
"maxParallelRecipes": -1,
"recipeSelectionMode": "default"
}
| Field | Default | Meaning |
|---|---|---|
parallelProcessingDefault |
false |
Whether recipes for this controller run in parallel by default. |
maxParallelRecipes |
-1 |
Controller-level parallel cap. -1 means use the global config value. Non-negative values are capped internally at 100. |
recipeSelectionMode |
default |
Recipe scheduling mode used when multiple recipes are runnable. See below. |
Recipe selection mode
Controllers normally scan matching recipes in their existing order. For machines with many recipes that share one port, such as sieves, a fairer selection mode can stop one input type from dominating the machine.
{
"type": "mm:machine",
"id": "big_sieve",
"name": "Big Sieve",
"recipeSelectionMode": "round_robin_input_item"
}
| Mode | Meaning |
|---|---|
default |
Current/default behavior. Recipes are checked in the normal rotating scan order. |
avoid_same_recipe |
Prefer not to start the exact same recipe twice in a row when another runnable recipe exists. |
round_robin_input_item |
Prefer the least-recently-used consumed item input among currently runnable recipes. Useful for machines where gravel/sand/dust-style inputs should be kept balanced. |
round_robin_input_item falls back to any runnable recipe if only one input type is available, so it should not stall a machine just because the next preferred input is missing.
ID usage
The generated controller block id is exactly mm:<id>. For example, id: "my_controller" generates mm:my_controller, not mm:my_controller_controller.
When another file references this controller, use the full ID:
"controllerIds": "mm:my_controller"
or:
"controllerIds": ["mm:my_controller", "mm:another_controller"]