Skip to content

Stations ​

The seven Cooking stations are explained below: where each station's block source, interaction, progress state, ingredient cache, fuel, fluid, and stage data are configured, and how to troubleshoot them. A station is the block you cook with. It carries recipe interaction, progress state, ingredient cache, fuel, fluid, stage data, and output handling; one station can map to a block, a GUI, or a custom interaction entity. When troubleshooting, confirm the block source first, then the station state and recipe matching

Station types ​

StationMain stateBest for
Chopping BoardInput item, accumulated amount, and cut countSlicing and preprocessing
GrinderInput item and remaining timeGrinding powders or herbs
SteamerInput item, fuel, moisture, and steam progressSteamed food and cooked intermediates
WokIngredients, heat, stir count, mistakesTiming-based cooking gameplay
OvenInput, burn time, heat, and baking stageBaking with heat control and stage resolution
JuicerInput, press count, fluid id, and fluid amountJuice and drinks bottled by serving capacity
Fermentation BarrelMultiple inputs, progress, completion flag, and stageWine, vinegar, and fermented intermediates

Configuration order ​

  1. Confirm the station block source and interactions in config.yml first
  2. Then write the matching recipes under recipes/<station>/
  3. If the station has a GUI, adjust gui/*.yml afterwards
  4. Use /ec inspect hand to check materials, tools, containers, and block sources
  5. Use /ec debug to troubleshoot station listeners, display entities, and persistence

Common config fields ​

These fields are available under every stations.<station>; each station's extra fields are listed in its own section below

FieldTypeRequiredDefaultRangeDescription
block_item_sourceslist<string>YesOne entry per station type as shipped (see each station section)CoreLib item source shorthand, e.g. minecraft-oak_logBlock sources bound to the station; any match identifies it. Does not support matcher, see below
interactions.<operation>stringNoBuilt-in default per station (see "Default interactions" below)left_click, right_click, shift_left_click, shift_right_click (case-insensitive; - and _ are equivalent)Click mapping per operation. A missing or invalid value falls back to the built-in default; operations the station does not support have no default
drop_resultbooleanNotruetrue / falseWhether results are dropped directly in the world instead of going to the player's inventory
only_recipe_itemsbooleanNoInherits input_rules.only_recipe_items (default true)true / falseWhether only items that can match the station's recipes may enter the input
disabled_worldslist<string>No[] (no world disabled)World name, case-insensitivePer-station disabled worlds. In a listed world the plugin does not take over that station's events and vanilla block behavior is preserved
actions.<operation>list<string>NoShipped sample actions for some operationsCoreLib action stringsFeedback actions run when the operation triggers; the operation names match the interactions keys

Default interactions ​

Operations omitted from interactions use the built-in defaults below. The built-in defaults only cover the interactions the station actually supports

StationDefault interactions
Chopping Boardplace_input = shift_left_click, process = shift_left_click, return_input = right_click
Wokadd_ingredient, stir, serve, return_ingredient = shift_left_click, inspect = shift_right_click
Grinderstart = shift_left_click
Steameropen = shift_right_click, fuel, moisture = right_click
Ovenopen = shift_right_click, fuel, inspect = shift_left_click
Juiceropen = shift_right_click, process, serve = shift_left_click, inspect = right_click
Fermentation Barrelopen = shift_right_click, start, serve = shift_left_click, inspect = right_click

Matchers for tools and containers ​

Tool, spatula, and container detection each live in their own child node holding a standard item_sources + matcher pair:

NodeFieldsLegacy flat key still read
tooltool.item_sources, tool.matchertool_matcher, tool_item_sources
spatulaspatula.item_sources, spatula.matcherspatula_matcher, spatula_item_sources
containercontainer.item_sources, container.matchercontainer_matcher, container_item_sources

TIP

item_sources and matcher are siblings and both must hold (AND). item_sources carries only the allowed item sources; matcher carries only non-item-source conditions such as component, PDC, or lore. Either may be omitted; omitting both is what makes the role never match

The nested child node wins. As soon as the nested key is present (such as tool), parsing uses the child node only and the legacy flat keys no longer take part — an empty child node does not fall back to the flat keys either

Item source conditions must not be written inside matcher — type: item_source and its aliases are rejected at load time with a warning and never match

The old flat keys (tool_matcher, spatula_matcher, container_matcher) are still read for compatibility (with a load-time warning), so existing configs keep working. Write the nested form in new configs, or migrate with /ec convert-legacy. Recipe inputs follow exactly the same item_sources + matcher rule, see Recipes

yaml
stations:
  chopping_board:
    block_item_sources:
      - minecraft-oak_log
    # Two sibling fields: an iron axe that also has Efficiency
    tool:
      item_sources:
        - minecraft-iron_axe
      matcher:
        type: component
        component: enchantments
        path: efficiency
        operator: '>='
        value: 1

DANGER

block_item_sources does not support matchers. It answers which block counts as the station — block-side detection, not item input matching. A matcher there has no effect

The same applies to the recipe output side (result.<branch>.outputs). See Only input-matching fields support matcher

Full syntax is in Item Matcher

World blacklist ​

Station interaction can be disabled per world at two levels, both defaulting to an empty list (nothing disabled):

yaml
# Global: applies to every station
station:
  disabled_worlds:
    - world_nether

stations:
  chopping_board:
    # Per station: applies to this station only
    disabled_worlds:
      - world_the_end

In a blacklisted world the plugin does not take over the related events and the block keeps vanilla behavior, so you can use this to preserve vanilla interaction in resource or instance worlds

State storage and IO optimization ​

EmakiCooking chooses the station-state backend from the actual anchor block. If the block state implements Bukkit TileState, station state is written to that block entity's PersistentDataContainer (BLOCK_PDC). If the anchor is a normal block, the module falls back to YAML files under data/stations/ (YAML_FALLBACK)

Runtime boundary

The backend selection, the backup path after successful legacy-YAML migration, and fermentation-barrel legacy identity migration are established only by source inspection and local JVM tests in this cycle. They were not verified on a live Paper or Folia server, and arbitrary old YAML or persisted saves are not claimed to be live-tested. Back up and sample-test on the target server before upgrading

This can further improve server IO-process performance:

  • When many stations use block entities, state follows the chunk/block-entity save path instead of creating and rewriting one standalone YAML file per station
  • data/stations/index/<world>.idx stores only coordinates, station type, source, and backend so ChunkLoad recovery can locate stations by chunk without a full directory scan
  • Legacy YAML states are moved to data/stations-legacy-backup/ after a successful migration to block-entity PDC, keeping them available for investigation without leaving them on the hot path
  • Non-block-entity anchors still use YAML fallback; for large or performance-sensitive servers, prefer block-entity blocks as station anchors

PDC keys ​

Station state written to block-entity PDC uses the keys below, under the plugin-name namespace emakicooking (so the full key looks like emakicooking:station_state). Read these keys when investigating with third-party NBT tools:

KeyDescription
station_stateThe serialized station state itself
station_typeStation type
station_sourceStation block source
station_saved_at_msTimestamp of the last write, in milliseconds
station_state_versionState version used for concurrency and stale-write checks
station_tombstoneTombstone marker meaning the station at this position was removed

Items carry one more PDC key, cooking_history: a comma-separated list of the recipe ids an item has passed through. Chained steamer recipes rely on it to resolve requires_previous_step

Diagnostics:

  • /ec inspect block: checks the targeted block's block_state, tile_state, storage_backend, pdc_state, indexed, and legacy_yaml values
  • /ec station reindex: rebuilds the station coordinate index from legacy YAML and currently loaded PDC stations

Minecraft block entity list (good station anchors) ​

The list below groups common vanilla block entities that Paper/Bukkit can expose as TileState. Availability still depends on the server version and the inspected block showing tile_state=yes. Wood, color, and variant families are merged

TypeCommon blocks
ContainersChest, trapped chest, barrel, shulker box, ender chest, hopper, dispenser, dropper, jukebox, lectern, chiseled bookshelf
Processing / craftingFurnace, smoker, blast furnace, brewing stand, campfire, soul campfire, crafter
Display / decorationBanner, bed, sign, hanging sign, player head, decorated pot, bee nest, beehive
Redstone / utilityComparator, daylight detector, command block, structure block, jigsaw block, moving piston
World / specialBeacon, enchanting table, bell, conduit, spawner, trial spawner, vault, end gateway
Sculk / archaeologySculk sensor, calibrated sculk sensor, sculk catalyst, sculk shrieker, suspicious sand, suspicious gravel
Newer API-exposed blocksCopper golem statue, shelf, test block, test instance block

Chopping board example ​

yaml
stations:
  chopping_board:
    block_item_sources:
      - minecraft-oak_log
    only_recipe_items: true
    interactions:
      place_input: shift_left_click
      process: shift_left_click
      return_input: right_click
    drop_result: true
    interaction_delay_ms: 1000
    tool:
      item_sources:
        - minecraft-iron_axe
FieldTypeRequiredDefaultRangeDescription
space_restrictionbooleanNofalsetrue / falseWhether a space restriction is checked
interaction_delay_msintNo1000≥ 0 (milliseconds)Minimum delay between interactions; values below 0 are treated as 0
toolobjectNoNo child node written (so no item counts as a knife)Holds item_sources / matcherKnife detection; the two sibling fields are ANDed
tool_item_sources / tool_matcher—No——Legacy flat form of tool, read only when no tool child node exists
cut_damage.enabledbooleanNotruetrue / falseWhether cutting can damage the tool
cut_damage.chanceintNo10≥ 0 (percent)Chance per cut to consume durability
cut_damage.valueintNo2≥ 0Durability removed when the chance hits
actions.cut / actions.complete / actions.placelist<string>NoSample actions shippedCoreLib action stringsFeedback actions for cutting, completion, and placing

The recipe-level damage_override.chance / damage_override.value can override the cut_damage values above; see Recipes

The chopping board input interaction takes the whole main-hand stack and accumulates it in station state; the item display entity still shows only one input item. In recipes, input.amount is the amount required and consumed for each completed cut cycle, and cutting cannot start until the accumulated amount is high enough. With cuts_required: 1, players can continuously process an already placed batch without re-placing one ingredient at a time

Wok example ​

yaml
stations:
  wok:
    block_item_sources:
      - minecraft-iron_block
    interactions:
      add_ingredient: shift_left_click
      stir: shift_left_click
      serve: shift_left_click
      return_ingredient: shift_left_click
      inspect: shift_right_click
    drop_result: true
    need_bowl: true
    stir_delay_ms: 5000
    timeout_ms: 30000
    spatula:
      item_sources:
        - minecraft-iron_shovel
    heat_levels:
      - item_sources:
          - minecraft-campfire
        level: 1
      - item_sources:
          - minecraft-magma_block
        level: 2
      - item_sources:
          - minecraft-lava
        level: 3

Wok config fields ​

FieldTypeRequiredDefaultRangeDescription
need_bowlbooleanNotruetrue / falseWhether a bowl is required to serve
stir_delay_msintNo5000≥ 0 (milliseconds)Minimum delay between two stirs
timeout_msintNo30000≥ 0 (milliseconds)Treat the wok as overcooked after this timeout
ignite_heat_sourcebooleanNotruetrue / falseWhether adding ingredients lights the heat source appearance; the wok tries to extinguish it once emptied
invalid_result_item_sourceslist<string>No[minecraft-stone]Item source shorthandDefault result source when no recipe matches or the result is invalid; the first entry is used
spatulaobjectNoNo child node written (so no item counts as a spatula)Holds item_sources / matcherSpatula detection; the two sibling fields are ANDed
spatula_item_sources / spatula_matcher—No——Legacy flat form of spatula, read only when no spatula child node exists
heat_levels[].item_sourcesstringNo—Item source shorthandMatched block source below the wok; an entry without it is skipped
heat_levels[].lit_item_sourcesstringNoNone (no lit appearance swap)Item source shorthandSource substituted when that heat block is lit
heat_levels[].unlit_item_sourcesstringNoFalls back to the sibling item_sourcesItem source shorthandSource substituted when that heat block is unlit
heat_levels[].levelintNo0≥ 0Heat level produced; values below 0 are treated as 0
stir_animation.enabledbooleanNotruetrue / falseWhether the stir animation plays
stir_animation.duration_ticksintNo10≥ 2 (ticks)Total animation length; values below 2 are treated as 2. The shipped config.yml explicitly writes 20
stir_animation.heightdoubleNo0.4≥ 0 (blocks)Ingredient toss height; the shipped config.yml explicitly writes 1.0
stir_animation.rotation_axisstringNoxx / y / zRotation axis; invalid values fall back to x
stir_animation.rotation_degreesdoubleNo360.0— (not validated)Rotation angle in degrees
scald_damage.enabledbooleanNotruetrue / falseWhether scald damage is enabled
scald_damage.valueintNo2≥ 0Scald damage value
failure.enabledbooleanNotruetrue / falseWhether stir failure output is enabled
failure.chanceintNo5≥ 0 (percent)Chance for a stir to fail
failure.item_sourcesstringNo[minecraft-bone_meal]Item source shorthandFailed result source; the first entry is used
actions.stir / actions.add_ingredient / actions.servelist<string>NoSample actions shippedCoreLib action stringsFeedback actions for stirring, adding ingredients, and serving

The wok runtime records the ingredient list, heat, stir count, and mistake count. ignite_heat_source only affects the heat block's swapped appearance and does not change recipe matching

Grinder example ​

yaml
stations:
  grinder:
    block_item_sources:
      - minecraft-grindstone
    interactions:
      start: shift_left_click
    drop_result: true
    check_delay_ticks: 20
FieldTypeRequiredDefaultRangeDescription
check_delay_ticksintNo20≥ 1 (ticks)Background check interval. The grinder starts automatically after input and checks progress at this interval
actions.start / actions.running / actions.completelist<string>NoSample actions shippedCoreLib action stringsFeedback actions for start, running, and completion

The grinder is the simplest station — place an input item, it starts grinding automatically, and produces a result when the recipe time is reached. No fuel, moisture, or manual stirring required

Steamer example ​

yaml
stations:
  steamer:
    block_item_sources:
      - minecraft-barrel
    interactions:
      open: shift_right_click
      fuel: right_click
      moisture: right_click
    drop_result: true
    heat_item_sources:
      - minecraft-furnace
      - minecraft-smoker
      - minecraft-blast_furnace
    ignite_heat_source: true
    fuels:
      - item_sources: ["minecraft-stick"]
        duration_seconds: 5
      - item_sources: ["minecraft-coal"]
        duration_seconds: 80
    moisture_rules:
      # input.{item_sources, matcher} decides the item put in; the item_sources at the
      # rule root is the empty container handed back, a construction field, not a match
      - input:
          item_sources: ["minecraft-water_bucket"]
        item_sources:
          - minecraft-bucket
        moisture: 120
      - input:
          item_sources: ["minecraft-potion"]
        item_sources:
          - minecraft-glass_bottle
        moisture: 40
    reset_progress_when_steam_empty: true
    steam_production_efficiency: 10
    steam_conversion_efficiency: 1
    steam_consumption_efficiency: 1
FieldTypeRequiredDefaultRangeDescription
heat_item_sourceslist<string> or objectNo[minecraft-furnace, minecraft-smoker, minecraft-blast_furnace]Item source shorthand; object form holds item_sources (or source / item), lit_item_sources, unlit_item_sourcesBlock sources below the steamer that act as heat sources. The object form can give custom blocks lit/unlit replacement sources; an omitted unlit_item_sources falls back to the sibling source
ignite_heat_sourcebooleanNotruetrue / falseWhether adding fuel lights the heat source block appearance
fuels[].item_sourcesstringNo—Item source shorthandAllowed fuel item sources. ANDed with the sibling matcher; the entry never matches only when both are omitted
fuels[].matcherobjectNoNoneGeneral matcher; item source conditions are not allowedExtra fuel conditions (component, PDC, lore). See Item Matcher
fuels[].duration_secondsintNo0≥ 0 (seconds)Burn time added by the fuel. Fuel takes the first match, so narrow entries must precede wider entries with the same source
moisture_rules[].inputobjectNoNoneHolds item_sources / matcherMatches the inserted moisture item; input.item_sources and input.matcher are ANDed and the rule never matches only when both are omitted
moisture_rules[].input_item_sources / moisture_rules[].input_matcher—No——Legacy flat form of input, read only when no input child node exists
moisture_rules[].item_sourcesstringNo—Item source shorthandEmpty container returned after adding moisture. This one is a construction field, not a matching position
moisture_rules[].moistureintNo0≥ 0Moisture value added
reset_progress_when_steam_emptybooleanNotruetrue / falseWhether to reset all progress when steam runs out
steam_production_efficiencyintNo10≥ 0Max moisture converted to steam per cycle
steam_conversion_efficiencyintNo1≥ 0Progress gained per steam consumed
steam_consumption_efficiencyintNo1≥ 0Base steam consumed per cycle
actions.fuel / actions.moisturelist<string>NoSample actions shippedCoreLib action stringsFeedback actions for adding fuel and moisture

Steamer logic: fuel provides burn time → burning converts moisture into steam → steam advances steaming progress. The three efficiency parameters control conversion rates. Both moisture and fuel must be manually replenished by the player

Oven example ​

yaml
stations:
  oven:
    block_item_sources:
      - minecraft-smoker
    interactions:
      open: shift_right_click
      fuel: shift_left_click
      inspect: shift_left_click
    drop_result: true
    heat:
      min: 20
      max: 80
      decay_per_second: 5
    fuels:
      - item_sources: ["minecraft-stick"]
        duration_seconds: 5
        heat: 10
      - item_sources: ["minecraft-coal"]
        duration_seconds: 80
        heat: 35
FieldTypeRequiredDefaultRangeDescription
heat.minintNo20≥ 0Lower heat bound; below it, baking time pauses
heat.maxintNo80≥ heat.minUpper heat bound; above it, baking time pauses. Values below the minimum are raised to it
heat.decay_per_secondintNo5≥ 0 (per second)Natural heat decay per second
fuels[].item_sourcesstringNo—Item source shorthandAllowed fuel item sources. ANDed with the sibling matcher; the entry never matches only when both are omitted
fuels[].matcherobjectNoNoneGeneral matcher; item source conditions are not allowedExtra fuel conditions. See Item Matcher
fuels[].duration_secondsintNo0≥ 0 (seconds)Burn time added by the fuel. Fuel takes the first match in list order and stops there
fuels[].heatintNo0≥ 0Heat added by the fuel
actions.fuellist<string>NoSample actions shippedCoreLib action stringsFeedback actions for adding fuel

fuel and inspect share a binding and are told apart by the held item

The default config above binds both fuel and inspect to shift_left_click. They do not clash because the held item is mutually exclusive:

  • The held item matches one of the fuels[] entries → add fuel
  • The hand is empty → show info
  • The held item is neither fuel nor empty → neither branch runs

So empty your hand before inspecting the oven

The oven runtime records current heat, remaining burn time, accumulated baking time, and baking stage. Heat that is too low or too high pauses normal baking. Recipes can use perfect heat ratio and overbake time to resolve the final result

Juicer example ​

yaml
stations:
  juicer:
    block_item_sources:
      - minecraft-cauldron
    interactions:
      open: shift_right_click
      process: shift_left_click
      inspect: right_click
      serve: shift_left_click
    drop_result: true
    only_recipe_items: true
    require_container: true
    max_fluid_ml: 1000
    default_serving_ml: 250
    container:
      item_sources:
        - minecraft-glass_bottle
FieldTypeRequiredDefaultRangeDescription
require_containerbooleanNotruetrue / falseWhether a container is required to serve
max_fluid_mlintNo1000≥ 1 (ml)Default internal fluid capacity
default_serving_mlintNo250≥ 1 (ml)Default fluid consumed per serving; a recipe's container.serving_ml overrides it
containerobjectNoNo child node written (so no item can act as a container)Holds item_sources / matcherServing-container detection; the two sibling fields are ANDed
container_item_sources / container_matcher—No——Legacy flat form of container, read only when no container child node exists
actions.press / actions.complete / actions.servelist<string>NoSample actions shippedCoreLib action stringsFeedback actions for pressing, completion, and serving

serve and process share a binding and are resolved by serving precedence

The default config above binds both serve and process to shift_left_click. The order of resolution checks whether serve takes precedence first: it does when the station holds fluid and either containers are not required or the player holds a valid serving container. When neither holds, serving is only used as a fallback if the player has no pressable ingredient either; otherwise pressing runs

So holding a container serves, holding an ingredient presses, and the shared binding never blocks itself

The juicer stores output as a fluid id plus an amount. One juicer should only contain one fluid at a time to prevent mixing different drinks. The fluid amount must reach serving_ml before a serving can be bottled

Fermentation barrel example ​

yaml
stations:
  fermentation_barrel:
    block_item_sources:
      - minecraft-barrel
    interactions:
      open: shift_right_click
      start: shift_left_click
      inspect: right_click
      serve: shift_left_click
    drop_result: true
    pause_when_open: true
    only_recipe_items: true
FieldTypeRequiredDefaultRangeDescription
pause_when_openbooleanNotruetrue / falseWhether fermentation pauses while the GUI is open
only_recipe_itemsbooleanNoInherits input_rules.only_recipe_items (default true)true / falseWhether only recipe ingredients can be inserted
actions.start / actions.collectlist<string>NoSample actions shippedCoreLib action stringsFeedback actions for starting and collecting

interactions.serve is a dead key

The fermentation barrel only dispatches open, start, and inspect; serve takes no part in the decision. The default config.yml still carries the key, but changing it has no effect

Collection is dispatched by the start binding according to the current state:

  • Completed: collect the normal completion output
  • Fermenting and still within the early stage: collect the early output
  • Otherwise: start fermenting

In other words, to change the collection key, change interactions.start

Fermentation barrels are suited for long-duration, multi-input recipes. Recipes can define early collection, normal completion, and over-fermented results

Lifecycle ​

  1. The player interacts with the station using a configured click
  2. The module checks permission, cooldown, occupancy, and held-item requirements
  3. A GUI or interaction state is opened
  4. The player inserts items, adds fuel/moisture, presses, or starts fermenting
  5. The station tracks progress such as cuts, grinding time, steam, heat, fluid amount, or fermentation stage
  6. Inputs are consumed and results are generated, or the station enters a completed-but-unclaimed state
  7. Actions run and temporary state is cleared. Remaining fluid, fuel, or progress may be kept

Safety notes ​

  • Avoid multiple players mutating the same item cache at the same time
  • If cooperation is allowed, define who receives results and who pays the inputs
  • Station state is persisted through block-entity PDC when possible; normal blocks use the data/stations/ YAML fallback
  • data/stations/index/<world>.idx records coordinates and backend so ChunkLoad restores inventories, progress, and displays by index while ChunkUnload drops runtime caches
  • If a block entity is removed or replaced directly, the index may still point to the old PDC station; use /ec inspect block to check backend/PDC state, then /ec station reindex to rebuild the index
  • For juicers, ovens, and fermentation barrels, verify fluid amount, baking stage, and fermentation progress serialization

Display entities ​

Station inputs, intermediates, and results can be shown in the world through display entities, controlled by display_entities and display_adjustments

yaml
display_entities:
  backend: auto
  view_distance_blocks: 48
  refresh_interval_ticks: 20
FieldTypeRequiredDefaultRangeDescription
display_entities.backendstringNoautoauto / packet_events / bukkitDisplay backend; invalid values fall back to auto. packet_events falls back to Bukkit when loading fails
display_entities.view_distance_blocksdoubleNo48≥ 1 (blocks)Viewer distance for the packet backend
display_entities.refresh_interval_ticksintNo20≥ 1 (ticks)Visibility refresh interval for the packet backend
display_entities.wok.layout_radiusdoubleNo0.26≥ 0 (blocks)Layout radius of wok ingredient displays

display_adjustments tunes offset, rotation, and scale: display_adjustments.defaults.item / defaults.block are the global defaults for item-style and block-style displays, and display_adjustments.station_defaults.<station> overrides them per station. When configuring a custom-block station, confirm the default display first, then fine-tune height and rotation

FieldTypeRequiredDefaultRangeDescription
display_adjustments.defaults.item.offset.x/y/zdoubleNo0.5 / 1.02 / 0.5— (not validated)Position offset of item-style displays relative to the station block
display_adjustments.defaults.item.rotation.x/y/zdouble or stringNo90.0 / 0.0 / 0.0Degrees, or a "min-max" range stringRotation of item-style displays; a range picks a random value each time
display_adjustments.defaults.item.scale.x/y/zdoubleNo0.5 / 0.5 / 0.5— (not validated)Scale of item-style displays
display_adjustments.defaults.block.offset.x/y/zdoubleNo0.5 / 1.125 / 0.5— (not validated)Position offset of block-style displays
display_adjustments.defaults.block.rotation.x/y/zdouble or stringNo0.0 / 90.0 / 0.0Degrees, or a "min-max" range stringRotation of block-style displays
display_adjustments.defaults.block.scale.x/y/zdoubleNo0.25 / 0.25 / 0.25— (not validated)Scale of block-style displays
display_adjustments.station_defaults.<station>.<item|block>.*as aboveNoInherits the matching defaultsas abovePer-station override of any subfield above; omitted subfields inherit the global default

display_entities.text controls the runtime text display entity (result / progress / next-step hints):

FieldTypeRequiredDefaultRangeDescription
text.enabledbooleanNotruetrue / falseWhether text display entities are used
text.billboardstringNocenterfixed / vertical / horizontal / centerFacing mode; invalid values fall back to center
text.line_widthintNo200≥ 1 (pixels)Maximum text line width
text.backgroundintNo0ARGB integerBackground color; 0 means fully transparent (no background box). Semi-transparent black example: 1056964608
text.shadowbooleanNotruetrue / falseWhether text shadow is rendered
text.see_throughbooleanNofalsetrue / falseWhether the text is visible through blocks
text.defaults.offset.x/y/zdoubleNo0.5 / 1.6 / 0.5— (not validated)Text offset relative to the station block; an omitted axis falls back on its own
text.defaults.scale.x/y/zdoubleNo1.0 / 1.0 / 1.0— (not validated)Text scale
text.stations.<station>.enabledbooleanNotruetrue / falsePer-station text display toggle
text.stations.<station>.billboardstringNoInherits text.billboardSame as text.billboardPer-station facing override
text.stations.<station>.offset / .scaleobjectNoInherits text.defaultsSame as text.defaultsPer-station offset and scale override

Item display adjustments ​

The item_adjustments/ directory sets per-item display parameters for specific stations. File names are not used for matching; the item source parsed from item_sources inside the file is the key, and only the last loaded file wins for a given source

yaml
item_sources:
  - "minecraft-carrot"

stations:
  chopping_board:
    offset:
      x: 0.54
      y: 1.01
      z: 0.52
    rotation:
      x: 90.0
      y: 0.0
      z: 24.0
    scale:
      x: 0.72
      y: 0.72
      z: 0.72

  wok:
    offset:
      x: 0.47
      y: 1.0
      z: 0.45
    rotation:
      x: 88.0
      y: 12.0
      z: "-28.0-18.0"
    scale:
      x: 0.56
      y: 0.56
      z: 0.56
FieldTypeRequiredDefaultRangeDescription
item_sourcesitem source shorthandYes—A single item sourceMatching item source. The parsed shorthand becomes the key for this adjustment; a missing or unparsable value skips the whole file
adjustmentobjectNoNoneHolds offset / rotation / scaleShared adjustment for all stations. When this section is omitted, offset / rotation / scale are read from the file root instead
stations.<station>objectNoNoneStation folder namePer-station override, taking precedence over adjustment
offset.x/y/zdoubleNoInherits the global default— (not validated)Position offset relative to the station block
rotation.x/y/zdouble or stringNoInherits the global defaultDegrees, or a range such as "-28.0-18.0"Rotation; a range string picks a random value, and min > max is swapped automatically
scale.x/y/zdoubleNoInherits the global default— (not validated)Scale factors

A file is skipped when it has neither a shared adjustment nor any recognizable station adjustment

Station permissions ​

The permission nodes, default holders, and descriptions for every station operation are listed once in Commands & Permissions; all of them default to true in paper-plugin.yml

Individual recipes can further restrict access through their own permission field, see Recipes

Wok tuning notes ​

The stir_animation, scald_damage, and failure fields are listed in Wok config fields above. When you run a casual wok, disable scald damage or lower scald_damage.value; for a rhythm-challenge wok, raise failure.chance and pair it with failure outputs

GUI configuration ​

The steamer, oven, juicer, and fermentation barrel have a GUI; the chopping board, grinder, and wok are direct-interaction only. Each GUI station maps to one file under gui/: gui/steamer.yml, gui/oven.yml, gui/juicer.yml, and gui/fermentation_barrel.yml

yaml
gui_type: CHEST
title: "<dark_gray>Steamer"
rows: 1
slots:
  ingredient_slots:
    slots:
      - 0
      - 1
      - 2
      - 3
      - 4
    type: "ingredient"
FieldTypeRequiredDefaultRangeDescription
gui_typestringNoCHEST in all four shipped filesContainer type nameCooking's GUI controllers do not read this key; it is declarative only and changing it has no effect
titlestringNoSteamer <dark_gray>蒸锅, oven <dark_gray>烤炉, juicer <dark_gray>榨汁机, fermentation barrel <dark_gray>发酵桶MiniMessage textInventory title
rowsintNo1 for steamer / oven / juicer, 3 for the fermentation barrelClamped to 1-6 after readingRow count
slots.<group>.slotslist<int>NoSee the fallback rule belowIndex list; indexes beyond rows × 9 are ignoredSlot indexes used by this group
slots.<group>.typestringNoEmpty value counts as ingredientOnly ingredient is implemented todaySlot group type. A group whose type is non-empty and not ingredient is skipped entirely

The group name itself takes no part in the decision and only serves readability. The shipped files also write id, item, display_name, and lore, which Cooking does not read today. If slots is empty or every group is skipped, the station falls back to the first N slots (N=5 for steamer / oven / juicer, N=7 for the fermentation barrel)

Testing checklist ​

  • Players without permission cannot open or use the station
  • Breaking a station returns, drops, or processes materials according to configuration
  • Closing a GUI leaves the state as expected
  • Full inventory, reload, death, and disconnect do not duplicate or delete items
  • Multiple players clicking the same station do not create race conditions
  • Oven results are correct for low heat, valid heat, high heat, and overbaking
  • Juicer behavior is correct for insufficient fluid, enough fluid, wrong containers, and mixed-fluid attempts
  • Fermentation behavior is correct for early collection, normal completion, over-fermentation, and GUI pause