Skip to content

Station Definitions ​

Crafting stations live under plugins/EmakiStation/stations/, one file per station. Keep one rule in mind: the file name matches id

Full Example ​

yaml
id: "blacksmith"
display_name: "<gold>Blacksmith Workshop</gold>"

layout: "station_catalog"
preview_layout: "station_preview"
queue_layout: "station_queue"

permission: ""

queue:
  base_length: 3
  max_length: 16
  progress_mode: "offline"
  cancel_refund_rate: 1.0
  speed_multiplier: 1.0
  allow_purchase: false

channels:
  backpack: true
  storage: true
  default: "backpack"

output:
  default: "storage_first"
  player_switchable: true

condition:
  invalid_as_failure: true

Fields ​

FieldTypeRequiredDefaultAccepted rangeDescription
idstringYes——Station id, matching the file name. A missing id refuses the file (station.station_missing_id)
display_namestringNothe idMiniMessage textDisplay name used in window titles
layoutstringNothe ida gui/<name>.yml idRecipe catalog layout. When omitted the station id is used as the layout id, which is why the example writes station_catalog
preview_layoutstringNo"station_preview"a gui/<name>.yml idMaterial preview layout
queue_layoutstringNo"station_queue"a gui/<name>.yml idCraft queue layout
permissionstringNo""a permission nodePermission required to open this station. When empty, falls back to emakistation.access.<id>
queuesectionNoinherited from config.yml queuesee belowQueue parameters; omitted keys inherit the main config value
channelssectionNoboth channels enabledsee belowMaterial source channels
outputsectionNostorage_first, switchablesee belowOutput routing
conditionsectionNoemptysee belowCondition gate; the syntax matches other Emaki modules, see Conditions. It is parsed and stored, but no runtime path evaluates it, so it neither restricts opening nor refuses anything

All three layout files must exist. If one is missing, the startup precheck reports missing_layout

The dismantle page does not belong to a station: dismantle stations are configured separately, see Dismantling

yaml
# Example: a new station following the example layouts with its own permission node
id: "alchemy"
display_name: "<light_purple>Alchemy Bench</light_purple>"
layout: "station_catalog"
preview_layout: "station_preview"
queue_layout: "station_queue"
permission: "emakistation.access.alchemy"

Recipe Ownership ​

Station files have no recipes section. The recipe decides where it shows up: list the owning stations in station_ids inside recipes/<recipe>.yml. A recipe without station_ids is offered by every station

The queue Section ​

A station can override the same keys as the main config's queue section, plus its own allow_purchase key. tick_interval and purchase come only from the main config

FieldTypeRequiredDefaultAccepted rangeDescription
base_lengthintegerNoinherited (3)1–64, clampedThis station's base queue length
permission_tiersbooleanNoinherited (true)true, falseWhether permission tiers apply at this station
max_lengthintegerNoinherited (32)base_length–64, clampedThis station's hard queue-length ceiling
progress_modestringNoinherited ("offline")offline, onlineHow this station's head is timed
cancel_refund_ratedoubleNoinherited (1.0)0.0–1.0, clampedRefund rate for materials and paid currency on cancellation
speed_multiplierdoubleNoinherited (1.0)0 or below becomes 1.0; capped at 100.0This station's recipe duration multiplier
allow_purchasebooleanNofalsetrue, falseWhether this station sells extra queue slots. queue.purchase.enabled in config.yml must also be true

When you cancel an entry, any currency already paid is refunded at cancel_refund_rate -- the same rate as materials

channels — Material Channels ​

FieldTypeRequiredDefaultAccepted rangeDescription
backpackbooleanNotruetrue, falseWhether to take materials from the player's inventory
storagebooleanNotruetrue, falseWhether to take materials from the EmakiStorage warehouse; it also needs storage.enabled and the emakistorage:atomic_batch capability to be active
defaultstringNo"backpack"backpack, storageRetained key, no longer effective: the source reads the value but no window or debit path consumes it

Turn both off and the station is refused at load time (station.station_no_channel) -- a station that opens but can never be used is worse than a startup error

With both on, materials come from one merged pool of inventory and warehouse, spent inventory-first. You will not see a channel toggle, and you do not need one: the "owned" figure in the window is already the combined total

default is retained only so old configuration files do not report an unknown key, and it may be removed in a later version. Never treat it as usable configuration

output — Output Routing ​

FieldTypeRequiredDefaultAccepted rangeDescription
defaultstringNo"storage_first"storage_first, backpack_first, storage_only, backpack_onlyDefault output routing; an unrecognised value falls back to storage_first
player_switchablebooleanNotruetrue, falseWhether players may switch their own routing preference in the window. Once off, clicking output_toggle does nothing

Here is what each default value does:

ValueBehaviour
storage_firstWarehouse first, falling back to the inventory when full
backpack_firstInventory first, falling back to the warehouse when full
storage_onlyWarehouse only
backpack_onlyInventory only

When every target is full, the entry enters the pending-claim state, and nothing is dropped or destroyed

condition Gate ​

The condition block uses CoreLib's generic condition block; its fields are described in Conditions

The station-level condition is not evaluated by the current runtime: the section is parsed, stored and structurally validated by the precheck, but opening a station (/emakistation open or the openGui API) never checks it, and an unsatisfied condition does not block anything. The keys below are listed so you can pre-stage configuration for the intended semantics

FieldTypeRequiredDefaultAccepted rangeDescription
condition.typestringNoall_ofall_of, any_of, none_of, at_least, exactlyCombination mode; an unrecognised value falls back to all_of
condition.entrieslistNo[]string expressions, type: expression nodes, nested condition groupsCondition node list; an empty list makes the group always true
condition.required_countintegerNo0non-negative integerNumber of conditions that must hold under at_least / exactly
condition.invalid_as_failurebooleanNotruetrue, falseWhether an invalid or unevaluable condition counts as failure
condition.on_pass.actionslist<string>No[]action pipeline linesActions run when the condition passes. Not executed today
condition.on_fail.actionslist<string>No[]action pipeline linesActions run when the condition fails. Not executed today
condition.on_fail.block_outputbooleanNofalsetrue, falseWhether a failed condition blocks output. A station produces nothing, so this has no effect
condition.on_fail.messagestringNo""MiniMessage textMessage sent to the player on failure. Not sent today