Skip to content

工位系统

Cooking 工位承载配方交互、进度状态、材料缓存、燃料、流体、阶段数据和结果产出。一个工位可以对应方块、GUI 或交互实体;排查时先确认方块来源,再看工位状态和配方匹配。

工位类型

工位主要状态适合玩法
砧板当前输入、累计数量、切割次数切菜、分割、预处理。
研磨机当前输入、剩余时间磨粉、研磨药材、压碎矿物。
蒸锅当前输入、燃料、水分、蒸汽进度蒸鱼、蒸饭、熟制半成品。
炒锅材料列表、火候、翻炒次数、错误次数需要操作节奏和判定的料理。
烤炉输入、燃烧时间、火力、烘烤阶段需要控温和阶段判定的烘焙。
榨汁机输入、压榨次数、流体 ID、流体容量果汁、饮品、按容器分装。
发酵桶多输入、发酵进度、是否完成、阶段酒、醋、发酵半成品。

配置顺序

  1. 先在 config.yml 里确认工位方块来源和交互方式。
  2. 再到 recipes/<station>/ 写对应工位配方。
  3. 如果工位有 GUI,再调整 gui/*.yml
  4. 使用 /ec inspect hand 检查材料、工具、容器和方块来源。
  5. 使用 /ec debug 排查工位监听、展示实体和持久化状态。

通用配置字段

字段类型说明
block_item_sourceslist绑定的方块来源,推荐使用 minecraft-oak_log 这类短横线格式。不支持 matcher,见下方说明。
interactionsobject每个操作对应的点击方式。
drop_resultboolean结果是否直接掉落到世界。
only_recipe_itemsboolean是否只允许可匹配配方的物品进入输入。
disabled_worldslist该工位的禁用世界列表,默认空列表。命中后插件不接管该工位事件,保留原版方块行为。

工具与容器的通用物品匹配器

工位的工具、锅铲和容器识别写在各自的子节点下,子节点内是标准的 item_sources + matcher 两个同级字段:

子节点作用旧的扁平键(仍兼容读取)
stations.chopping_board.tool砧板工具tool_matcher / tool_item_sources
stations.wok.spatula炒锅锅铲spatula_matcher / spatula_item_sources
stations.juicer.container榨汁机容器container_matcher / container_item_sources

TIP

子节点里 item_sourcesmatcherANDitem_sources 只写允许的物品源,matcher 只写组件 / PDC / Lore 等条件。两者都省略时该角色永不命中。

matcher 内部不能写物品源条件type: item_source / item_sources / source / sources 会被拒绝并告警)。

旧的扁平前缀键仍被加载期兼容读取,不会失效,但推荐迁移到子节点写法。

yaml
stations:
  chopping_board:
    block_item_sources:
      - minecraft-oak_log
    # 既是铁斧,又附了效率:物品源写 item_sources,组件条件写 matcher
    tool:
      item_sources:
        - minecraft-iron_axe
      matcher:
        type: component
        component: enchantments
        path: efficiency
        operator: '>='
        value: 1

DANGER

block_item_sources 不支持 matcher。 它回答的是"哪个方块算这个工位",属于方块侧识别,不是物品输入匹配。在那里写 matcher 不会生效。

同理,配方产出侧(result.<branch>.outputs)也不支持。详见 只有输入匹配点支持 matcher

完整语法见 物品匹配器

世界黑名单

工位交互可以按世界禁用,分全局和按工位两层,两层都默认空列表(不禁用任何世界):

yaml
# 全局:对所有工位生效
station:
  disabled_worlds:
    - world_nether

stations:
  chopping_board:
    # 按工位:只对该工位生效
    disabled_worlds:
      - world_the_end

命中黑名单时插件不接管相关事件,方块保持原版行为,因此可以用它在资源世界或副本世界里保留原版交互。

状态存储与 IO 优化

EmakiCooking 会按实际锚点方块选择工位状态后端:如果方块状态实现 Bukkit TileState,工位状态优先写入该方块实体的 PersistentDataContainerBLOCK_PDC);如果只是普通方块,则回退到 data/stations/ 的 YAML 文件(YAML_FALLBACK)。

这对服务器 IO 进程性能有直接帮助:

  • 大量工位使用方块实体后,状态随区块/方块实体保存链路持久化,避免每个工位频繁生成和改写独立 YAML 文件。
  • data/stations/index/<world>.idx 只保存坐标、类型、来源和后端,用于按区块快速定位工位,减少重启或 ChunkLoad 时的全目录扫描。
  • 旧 YAML 状态在成功迁入方块实体 PDC 后会移到 data/stations-legacy-backup/,便于回退排查而不会继续作为热路径文件。
  • 非方块实体仍保持 YAML fallback;因此性能敏感、工位数量多的服务器,建议优先把工位锚点配置成方块实体方块。

PDC 键名

工位状态写入方块实体 PDC 时使用下列键,命名空间为插件名 emakicooking(即完整键形如 emakicooking:station_state)。用第三方 NBT 工具排查时按这些键读取:

说明
station_state序列化后的工位状态主体。
station_type工位类型。
station_source工位方块来源。
station_saved_at_ms最后一次落盘的时间戳(毫秒)。
station_state_version状态版本号,用于并发与陈旧写入判定。
station_tombstone墓碑标记,表示该位置的工位已移除。

物品侧另有一个 PDC 键 cooking_history:以逗号分隔记录该物品经过的配方 ID,蒸锅链式配方的 requires_previous_step 就是靠它判定前置步骤。

排查命令:

  • /ec inspect block:查看准星目标方块的 block_statetile_statestorage_backendpdc_stateindexedlegacy_yaml
  • /ec station reindex:重建工位坐标索引,扫描 legacy YAML 与当前已加载区块中的 PDC 工位。

Minecraft 方块实体列表(适合做工位锚点)

下面按 Paper/Bukkit TileState 可识别的常见原版方块实体整理;具体可用性仍以服务器版本和目标方块 tile_state=yes 为准。同一类的木种、颜色或变体合并展示。

类型常见方块
容器箱子、陷阱箱、木桶、潜影盒、末影箱、漏斗、发射器、投掷器、唱片机、讲台、錾制书架
处理/制作熔炉、烟熏炉、高炉、酿造台、营火、灵魂营火、合成器
展示/装饰旗帜、床、告示牌、悬挂告示牌、玩家头颅、饰纹陶罐、蜂巢、蜂箱
红石/功能比较器、日照探测器、命令方块、结构方块、拼图方块、移动活塞
世界/特殊信标、附魔台、钟、潮涌核心、刷怪笼、试炼刷怪笼、宝库、末地折跃门
幽匿/考古幽匿感测体、校频幽匿感测体、幽匿催发体、幽匿尖啸体、可疑沙子、可疑砂砾
新版本 API 暴露铜傀儡雕像、货架、测试方块、测试实例方块

砧板示例

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

砧板的输入交互会一次性接收玩家主手整叠物品,并在运行态累计数量;物品展示实体仍只显示 1 个输入物品。配方里的 input.amount 表示每轮完成切割需要并消耗的数量,累计数量不足时不能开始切割。若配方设置 cuts_required: 1,玩家可以对已放入的一批食材连续切割,无需每次重新放入单个食材。

炒锅示例

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

炒锅热度参数

字段说明
need_bowl是否要求手持碗才能出锅。
stir_delay_ms两次翻炒之间的最小间隔。
timeout_ms锅状态超时后按过火处理。
heat_levels[].item_sources命中的下方方块来源。
heat_levels[].level对应火候等级。

研磨机示例

yaml
stations:
  grinder:
    block_item_sources:
      - minecraft-grindstone
    interactions:
      start: shift_left_click
    drop_result: true
    check_delay_ticks: 20
    actions:
      start:
        - 'play_sound sound=block.grindstone.use volume=0.7 pitch=1.0'
      running:
        - 'spawn_particle particle=SMOKE count=2 offset_x=0.15 offset_y=0.15 offset_z=0.15'
      complete:
        - 'play_sound sound=entity.experience_orb.pickup volume=0.8 pitch=1.2'
字段说明
check_delay_ticks后台检查周期(tick)。研磨机放入材料后自动开始,按此间隔检查进度。
interactions.start手动启动研磨的交互方式。

研磨机是最简单的工位——放入材料后自动开始研磨,达到配方时间后产出结果。不需要燃料、水分或手动翻炒。

蒸锅示例

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 是返还的空容器,属产出侧
      - 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
字段说明
heat_item_sources蒸锅下方热源方块来源。支持对象写法指定 lit_item_sources 作为点亮替换。
ignite_heat_source加燃料后是否点亮下方热源外观。
fuels[].item_sources燃料允许的物品来源。省略表示不限来源。
fuels[].matcher燃料的通用物品匹配器,只写组件 / PDC / Lore 等非物品源条件,与同级 item_sources 取 AND。两者都省略时该条目永不命中。见 物品匹配器
fuels[].duration_seconds投入燃料后增加的燃烧时间。
moisture_rules[].input.item_sources加水输入允许的物品来源。
moisture_rules[].input.matcher加水输入的通用物品匹配器,与同级 input.item_sources 取 AND。两者都省略时该规则永不命中。旧的扁平 input_matcher / input_item_sources 仍被兼容读取。
moisture_rules[].item_sources加水后返还的容器物品来源。这是产出侧构造字段,不是判定位。
moisture_rules[].moisture加水后增加的水分值。
reset_progress_when_steam_empty蒸汽耗尽时是否重置全部进度。
steam_production_efficiency每个周期最多将多少 moisture 转成 steam。
steam_conversion_efficiency每次 steam 消耗换算成多少进度。
steam_consumption_efficiency每个周期的基础 steam 消耗量。

蒸锅的运行逻辑:燃料提供燃烧时间 → 燃烧时将 moisture 转化为 steam → steam 推进蒸制进度。三个 efficiency 参数控制转化速率。水分和燃料都需要玩家手动补充。

烤炉示例

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
字段说明
heat.min / heat.max火力处于该区间时才推进烤制计时。
heat.decay_per_second每秒自然衰减的火力。
fuels[].duration_seconds投入燃料后增加的燃烧时间。
fuels[].heat投入燃料后增加的火力。
fuels[].item_sources燃料允许的物品来源。省略表示不限来源。
fuels[].matcher燃料的通用物品匹配器,只写组件 / PDC / Lore 等非物品源条件,与同级 item_sources 取 AND。两者都省略时该条目永不命中。见 物品匹配器

fuelinspect 同绑时靠手持物区分

上面的默认配置把 fuelinspect 都绑到 shift_left_click,两者靠手持物互斥消歧,不会冲突:

  • 手持物命中某条 fuels[] 条目 → 走加燃料。
  • 手持物为空 → 走查看信息。
  • 手持物既不是燃料也不为空 → 两个分支都不进入。

所以查看烤炉信息前要先空手。

烤炉的运行状态会记录当前火力、剩余燃烧时间、累计烘烤时间和烘烤阶段。火力过低或过高都会暂停正常烘烤,配方可根据完美火力占比和过烤时间决定最终产物。

榨汁机示例

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
字段说明
require_container是否要求容器才能盛取结果。
max_fluid_ml榨汁机内部默认最大流体容量。
default_serving_ml默认每次容器盛取需要的流体量。
container.item_sources可作为容器的物品来源。
container.matcher容器的通用物品匹配器,只写非物品源条件,与同级 item_sources 取 AND。两者都省略时没有物品能当容器。旧的扁平 container_matcher 仍被兼容读取。

serveprocess 同绑时按盛取优先级判定

上面的默认配置把 serveprocess 都绑到 shift_left_click。判定顺序是先看 serve 能不能优先:工位内有流体,且满足「不要求容器」或「手持有效盛取容器」时,盛取优先;两者都不满足时,只有玩家手上也没有可压榨材料才退回盛取,否则走压榨。

因此手持容器时是盛取,手持食材时是压榨,同一个键位不会互相挡住。

榨汁机会把压榨产物保存为“流体 ID + 容量”。同一台榨汁机同一时间只应保存一种流体,避免不同饮品混入。容量达到容器所需 serving_ml 后才可盛取。

发酵桶示例

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
字段说明
pause_when_openGUI 打开时是否暂停发酵进度。
only_recipe_items是否只允许配方材料进入输入。

interactions.serve 是死键

发酵桶只分派 openstartinspect 三个操作,serve 不参与判定——默认 config.yml 里保留了这个键,但改它不产生任何效果。

收取动作由 start 绑定按当前状态分派:

  • 已完成:收取正常完成产物。
  • 正在发酵且处于提前收取阶段:收取提前产物。
  • 其他情况:开始发酵。

也就是说想改收取键位,要改的是 interactions.start

发酵桶适合多输入长周期配方。配方可以定义提前收取比例、正常完成结果和过度发酵结果。

展示实体

Cooking 支持把工位输入、半成品或结果以展示实体形式呈现在世界中。展示实体由 display_entitiesdisplay_adjustments 控制。

yaml
display_entities:
  backend: auto
  view_distance_blocks: 48
  refresh_interval_ticks: 20
字段说明
backend展示后端,通常可使用 autopacket_eventsbukkit
view_distance_blocks玩家可见距离。
refresh_interval_ticks展示刷新间隔。

display_adjustments 可按工位调整偏移、旋转和缩放:display_adjustments.defaults.item / defaults.block 是物品型与方块型展示的全局默认值,display_adjustments.station_defaults.<工位> 按工位覆盖。配置自定义方块工位时,建议先使用默认值确认展示正常,再微调高度和旋转。

display_entities.text 控制工位运行态文本展示实体(结果 / 过程 / 下一步引导):

字段说明
text.enabled是否启用文本展示实体。
text.billboard朝向模式:fixedverticalhorizontalcenter
text.line_width文本最大行宽(像素)。
text.background背景色 ARGB 整数;0 表示完全透明。
text.shadow是否渲染文字阴影。
text.see_through是否穿墙可见。
text.defaults.offset / text.defaults.scale文本相对工位方块的偏移与缩放。
text.stations.<工位>.enabled按工位开关文本展示;省略时默认启用。

物品展示调整

item_adjustments/ 目录用于给特定物品在特定工位上单独设置展示参数。文件名不参与匹配,实际以文件内 item_sources 解析出的来源为准;同一来源只保留最后加载的一份。

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
字段说明
item_sources匹配的物品来源。解析出的来源简写作为该调整的键。
adjustment可选。适用于所有工位的共享调整;省略该段时,会尝试直接从文件根读取 offset / rotation / scale
stations.<工位>按工位覆盖的调整,工位键使用文件夹名。
offset.x/y/z相对工位方块的位置偏移。
rotation.x/y/z旋转角度。支持 "-28.0-18.0" 这类范围写法表示随机取值。
scale.x/y/z缩放比例。

若文件既没有共享调整也没有任何可识别的工位调整,该文件会被跳过。

炒锅动画与烫伤

炒锅可配置翻炒动画和过热惩罚,用于强化操作节奏:

yaml
stir_animation:
  enabled: true
  duration_ticks: 20
  height: 1.0
  rotation_axis: x
  rotation_degrees: 360.0
scald_damage:
  enabled: true
  value: 2
字段说明
stir_animation.duration_ticks翻炒动画持续时间。
stir_animation.height动画抛起高度。
stir_animation.rotation_axis旋转轴。
stir_animation.rotation_degrees旋转角度。
scald_damage.enabled是否启用烫伤。
scald_damage.value烫伤伤害值。

如果炒锅用于轻休闲玩法,可以关闭烫伤或降低伤害;如果用于节奏挑战,可以提高错误惩罚并配合失败产物。

状态生命周期

  1. 玩家右键或按配置点击工位。
  2. 模块检查权限、冷却、工位是否被占用以及手持物是否满足交互要求。
  3. 打开 GUI 或进入交互状态。
  4. 玩家放入材料、投入燃料、注入水分、压榨或开始发酵。
  5. 工位记录进度,例如切割次数、研磨剩余时间、蒸汽、火候、流体容量或发酵阶段。
  6. 达成条件后消耗输入并生成结果;部分工位可先进入“完成待领取”状态。
  7. 执行动作并清理临时状态,必要时保留剩余流体、剩余燃料或剩余进度。

多人和重启处理

  • 同一工位应避免被多个玩家同时修改同一份材料缓存。
  • 如果允许协作,需要明确谁获得产物、谁承担材料消耗。
  • 工位状态优先随方块实体 PDC 持久化,普通方块使用 data/stations/ YAML fallback。
  • data/stations/index/<world>.idx 记录坐标与后端,ChunkLoad 时按索引恢复容器内容、进度和展示状态,ChunkUnload 时卸载运行态缓存。
  • 若直接删除或替换方块实体,索引可能仍指向旧 PDC 工位;用 /ec inspect block 判断 backend/PDC,再用 /ec station reindex 重建索引。
  • 对榨汁机、烤炉和发酵桶,额外确认流体容量、烘烤阶段和发酵进度能正确序列化。

工位权限

各工位的操作权限节点:

权限说明
emakicooking.station.chopping_board.use使用砧板。
emakicooking.station.chopping_board.cut执行砧板切割。
emakicooking.station.wok.use使用炒锅。
emakicooking.station.wok.stir翻炒。
emakicooking.station.wok.serve出锅。
emakicooking.station.grinder.use使用研磨机。
emakicooking.station.steamer.use使用蒸锅。
emakicooking.station.steamer.fuel向蒸锅投入燃料。
emakicooking.station.steamer.moisture向蒸锅注入水分。
emakicooking.station.oven.use使用烤炉。
emakicooking.station.oven.fuel向烤炉投入燃料。
emakicooking.station.juicer.use使用榨汁机。
emakicooking.station.juicer.press执行压榨操作。
emakicooking.station.juicer.collect盛取榨汁结果。
emakicooking.station.fermentation_barrel.use使用发酵桶。
emakicooking.station.fermentation_barrel.start开始发酵。
emakicooking.station.fermentation_barrel.collect收取发酵结果。

NOTE

以上工位权限默认全部为 true。配方还可以通过自身的 permission 字段单独限制使用者。

GUI 覆盖范围

工位是否有 GUI
蒸锅
烤炉
榨汁机
发酵桶
砧板无(直接交互)
研磨机无(直接交互)
炒锅无(直接交互)

GUI 配置结构

四个有 GUI 的工位各对应 gui/ 下的一个文件:gui/steamer.ymlgui/oven.ymlgui/juicer.ymlgui/fermentation_barrel.yml

yaml
gui_type: CHEST
title: "<dark_gray>蒸锅"
rows: 1
slots:
  ingredient_slots:
    slots:
      - 0
      - 1
      - 2
      - 3
      - 4
    type: "ingredient"
字段说明
gui_type容器类型,当前四个文件都是 CHEST
title界面标题,支持 MiniMessage。
rows界面行数,读取后截断到 1~6。默认值:蒸锅 / 烤炉 / 榨汁机为 1,发酵桶为 3
slots.<组名>.slots该组占用的槽位下标列表。超出 rows × 9 的下标被忽略。
slots.<组名>.type槽位组类型。当前只实现了 ingredient:解析器遍历 slots 下每个子节,type 非空且不等于 ingredient 的组会被整组跳过(留空视为 ingredient)。

组名本身不参与判定,只用于分组可读性。若 slots 为空或全部组都被跳过,回退为占用前 N 格(蒸锅 / 烤炉 / 榨汁机 N=5,发酵桶 N=7)。