Skip to content

Configuration ​

plugins/EmakiStation/config.yml is the main configuration. It controls queue defaults, capacity ceilings, the EmakiStorage channel, persistence and GUI throttling

The version key is only a configuration-structure marker: the plugin uses it to merge newly added default keys. It tracks separately from the module release version, so you never need to edit it to match the plugin version

Shipped Defaults ​

This is what the config.yml released from the Jar contains:

yaml
version: "1.1.8"
language: "zh_CN"
release_default_data: true

queue:
  base_length: 3
  permission_tiers: true
  max_length: 32
  progress_mode: "offline"
  cancel_refund_rate: 1.0
  tick_interval: 20
  speed_multiplier: 1.0
  purchase:
    enabled: true
    cost_file: "queue_costs.yml"

limits:
  max_pending_claim: 100
  warn_material_types: 50
  batch_multiplier_max: 0

storage:
  enabled: true
  batch_max_ops: 200

persistence:
  autosave_interval_seconds: 60
  save_on_submit: true

gui:
  click_throttle_ms: 200
  refresh_interval_ticks: 20

Top-Level Keys ​

FieldTypeRequiredDefaultAccepted rangeDescription
versionstringNo"1.1.8"—Configuration-structure marker, maintained by default-resource sync. The internal migration constant is 1.0.2 and is not a release coordinate
languagestringNo"zh_CN"—Language file name, resolving to lang/<language>.yml
release_default_databooleanNotruetrue, falseWhether to release example data on first start (the built-in default files under stations/, gui/, recipes/). Once false, existing files are not overwritten and missing examples are not restored

queue — Queue Defaults ​

Each station can override these same keys in its own stations/<id>.yml (purchase is configured only here; a station has its own separate queue.allow_purchase switch)

FieldTypeRequiredDefaultAccepted rangeDescription
base_lengthintegerNo31–64, clampedBase queue length. Only WAITING / RUNNING occupy length; PENDING_CLAIM does not
permission_tiersbooleanNotruetrue, falseWhether emakistation.queue.<n> tiers apply; when enabled the player's highest tier wins, and with no node under that prefix the base length is kept
max_lengthintegerNo32base_length–64, clampedHard queue-length ceiling that neither permission tiers nor purchases can exceed
progress_modestringNo"offline"offline, onlineHow the head is timed; an unrecognised value falls back to offline. offline follows real time, online only accumulates while the player is online
cancel_refund_ratedoubleNo1.00.0–1.0, clampedFraction of materials refunded when cancelling an entry; materials and any paid currency use the same rate
tick_intervalintegerNo2010–100, clampedInterval of the queue advance task, in ticks. There is exactly one server-wide timer
speed_multiplierdoubleNo1.00 or below becomes 1.0; capped at 100.0Global recipe duration multiplier applied on top of duration_seconds
purchase.enabledbooleanNotruetrue, falseServer-wide master switch for paid queue slots; the station also needs queue.allow_purchase: true to sell slots
purchase.cost_filestringNo"queue_costs.yml"—, blank falls back to the default namePrice tier file name, relative to the plugin data folder. When the file is missing or carries no usable price, purchases are refused

Leaving pending_claim out of queue length is deliberate: otherwise a player whose warehouse and inventory are both full would be blocked by their own undelivered output

cancel_refund_rate is not prorated by progress. In a serial single-line queue only the head has progress, and per-entry progress accounting for an almost non-existent case is not worth it. This is an intentional simplification

progress_mode: offline only means "the timer keeps running", not "delivery while offline". EmakiStorage refuses any write for an offline player, so entries that come due while offline are merely "due"; settlement happens at the player's next login

If the price file is missing, empty or carries no usable price, purchases are refused rather than granted for free

yaml
# Example: shorten the advance interval to 10 ticks and raise the base length to 5
queue:
  tick_interval: 10
  base_length: 5

limits — Capacity Ceilings ​

FieldTypeRequiredDefaultAccepted rangeDescription
max_pending_claimintegerNo1001–10000, clampedHow many unclaimed outputs one player may accumulate (summed across all stations). New submissions are refused at the ceiling with station.pending_claim_full
warn_material_typesintegerNo501–10000, clampedAbove this many material kinds in one recipe only a station.recipe_many_materials warning is logged; loading is not blocked
batch_multiplier_maxlongNo00 or positive; negatives clamp to 0Maximum multiplier per submission; 0 means no extra limit. The current source only parses and stores this value — the submission path performs no check against it, so the real ceiling is still set by materials and balance

The number of material kinds is not limited by GUI slots; warn_material_types is only a guard against typos

storage — Warehouse Channel ​

FieldTypeRequiredDefaultAccepted rangeDescription
enabledbooleanNotruetrue, falseMaster switch. Once off, EmakiStation never calls EmakiStorage at all
batch_max_opsintegerNo2001–10000, clampedMaximum operations per batch, matching EmakiStorage's behavior.batch_max_ops; exceeding it refuses the batch with station.storage_batch_too_large

enabled: true alone is not enough: the warehouse channel also needs EmakiStorage to provide the emakistorage:atomic_batch capability (a batch operation that either does everything or nothing). Without that capability there is no fallback to withdrawing item by item: that would make materials flash through your inventory once, creating an exploitable window instead

When materials come from both the inventory and the warehouse, the plugin prefers the emakistorage:reservation capability: place a reservation in the warehouse (without actually withdrawing), spend from the inventory, then commit the reservation. If something fails midway, only the reservation needs to be released, and releasing cannot fail on warehouse capacity. On older EmakiStorage versions lacking that capability, it degrades to "withdraw from the warehouse first, deposit back on failure", where the deposit itself may be refused for lack of capacity -- hence inferior to the reservation path

yaml
# Example: supply everything from the inventory and never touch the warehouse
storage:
  enabled: false

persistence ​

FieldTypeRequiredDefaultAccepted rangeDescription
autosave_interval_secondsintegerNo605–3600, clampedAutosave interval in seconds. The actual schedule runs every max(100 ticks, seconds × 20). The legacy key autosave_interval is still read, logs a warning at startup, and is migrated to the new key
save_on_submitbooleanNotruetrue, falseWhether to flush immediately after a successful submission instead of waiting for the next autosave

Entries in the queue file correspond to materials that have already been deducted, so this interval is shorter than the warehouse's autosave

The queue file and the warehouse file are two independent files, so a hard crash can still leave them inconsistent (materials deducted but the entry unsaved, or the entry saved but the deduction unflushed). Every entry records its full consumption list so you can reconcile manually. Closing this window entirely would need a cross-plugin two-phase commit, which costs too much

gui ​

FieldTypeRequiredDefaultAccepted rangeDescription
click_throttle_msintegerNo2000–5000, clampedMinimum interval between two clicks in one session, in milliseconds; 0 disables throttling
refresh_interval_tickslongNo205–200, clampedHow often an open window repaints its progress display, in ticks; at runtime this is treated as at least 50 milliseconds. The legacy key refresh_interval is still read, logs a warning at startup, and is migrated to the new key
yaml
# Example: loosen click throttling and repaint every 10 ticks
gui:
  click_throttle_ms: 300
  refresh_interval_ticks: 10