Skip to content

机器与配方类型事件 ​

当前 API Minecraft 1.21.1 / MBD2 21.1.1

MBD2 的事件订阅都带目标。第一个参数是确切的机器定义 ID 或配方类型 ID;回调收到一个 KubeJS 包装对象,其中的 Java 事件在 wrapper.event 上。

js
// kubejs/server_scripts/mbd2_events.js
MBDMachineEvents.onAfterRecipeWorking('example:crusher', wrapper => {
  const event = wrapper.event
  console.info(`Recipe ${event.recipe.id} left its active run at ${event.machine.pos}`)
})

不要传方块 ID 或配方 ID。机器事件的目标是 MBDRegistries.MACHINE_DEFINITIONS 里的 ID;配方类型事件的目标是 MBDRegistries.RECIPE_TYPES 里的 ID。

蓝图覆盖同样这些事件

本页的每个事件同时也是一个 蓝图入口节点,所以同样的反应可以在编辑器里画出来而不用写脚本。整合包已经在写脚本就用 KubeJS;机器要自带行为发布就用蓝图。

服务端机器事件 ​

这些都放在 kubejs/server_scripts。wrapper.event.machine 始终存在。

Handler额外字段可取消触发时机
onLoad—否方块实体有效后的下一 tick
onRemoved—否机器正在被移除
onPlacedplayer、itemStack否被实体放置
onNeighborChangedblock、fromPos否相邻更新到达机器
onDropsentity、可改的 drops否掉落列表已组装、尚未生成
onOpenUIplayer是机器 UI 打开之前
onUseWithoutItemplayer、hit、可改的 interactionResult否空手右键
onUseCatalystcatalyst、player、hand是多方块催化剂使用
onUI可改的 ui、可改的 player否服务端构建好机器 UI
onStateChangedoldState、newState是机器状态切换
onStructureFormed / onStructureInvalid—否多方块成型与失效
onTick—是配方逻辑和所有 Trait tick 之前

drops 是活的 Java List<ItemStack>,往里加而不要替换它。取消 onTick 会同时跳过配方逻辑和每个 Trait 的 serverTick。

配方生命周期事件 ​

Handler额外字段可取消确切位置
onBeforeRecipeModify可改的 recipe是配置的修饰器与并行计算之前
onAfterRecipeModify可改的 recipe否修饰器产出最终配方之后
onBeforeRecipeWorkingrecipe是燃料已扣除之后、输入提交之前
onRecipeWorkingrecipe、progress是本 tick 的 per-tick IO 已提交、进度递增之前
onRecipeWaitingrecipe否状态变为 WAITING
onAfterRecipeWorkingrecipe否完成或中断,产出之前
onConsumeInputsAfterWorkingrecipe否完成时刚刚提交了延迟的输入
onRecipeFinishrecipe否产出已经存在之后
onFuelRecipeModify可改的 recipe是燃料候选匹配后、扣除其输入之前
onFuelBurningFinish可空的 recipe否已注册,但不会送达——见下

onAfterRecipeWorking 在产出生成之前触发,onRecipeFinish 在之后。「一次合成完成」的奖励要写在后者里,否则奖励物品会落进配方自己的产出正要用的槽位。

onConsumeInputsAfterWorking 只有在机器打开了 Consume inputs after working 时才会触发——无论它来自定义值,还是来自 recipe_logic.consume_inputs_after_working 的单机 runtime value 覆盖。

onFuelBurningFinish 从不触发

MBDMachine#onFuelBurningFinish 把事件投递到 NeoForge 总线时没有调用 postCustomEvent(),所以在 21.1.1 中 KubeJS handler 和蓝图入口节点都收不到它。Java 的 NeoForge.EVENT_BUS 监听器是有效的。要跟踪燃料耗尽,请改用 onRecipeWaiting 或 machine.recipeLogic.fuelTime。

一个没有 KubeJS handler 的事件

MachineUseItemOnEvent(手持物品右键)存在并且有蓝图入口节点,但 MBDServerEvents 没有为它注册 KubeJS 名字。请改用蓝图,或者用 Java 监听 NeoForge.EVENT_BUS。

js
MBDMachineEvents.onRecipeWorking('example:crusher', wrapper => {
  const { recipe, progress } = wrapper.event
  if (progress % 20 === 0) {
    console.debug(`${recipe.id}: ${progress}/${recipe.duration}`)
  }
})

取消 ​

对上表中标记为可取消的 handler,两种写法等价:

js
MBDMachineEvents.onOpenUI('example:crusher', wrapper => {
  wrapper.event.setCanceled(true)          // 直接设置 Java 事件
})

MBDMachineEvents.onOpenUI('example:crusher', wrapper => {
  return false                             // KubeJS 的 interrupt-false,会映射到 setCanceled
})

取消是控制流决策,不能替代配方条件——被取消的 onBeforeRecipeWorking 发生在燃料已经被扣掉之后,被取消的 onRecipeWorking 发生在该 tick 的 per-tick IO 已经提交之后。资格判断请写进 RecipeCondition。

不要在可能于模拟阶段或客户端执行的事件里搬运资源。资源结算属于 Java 的 IRecipeHandlerTrait。

客户端事件 ​

这些放在 kubejs/client_scripts。

Handler事件组字段
onClientTick(machineId, cb)MBDMachineEventsmachine
onCustomDataUpdate(machineId, cb)MBDMachineEventsoldValue、newValue;可取消
onCustomKeyframe(machineId, cb)MBDMachineEventsinstruction、controllerName、animationTick;仅 GeckoLib
onRecipeUI(recipeTypeId, cb)MBDRecipeTypeEvents可改的 recipe 与 ui;可取消
registerCustomRenderers(cb)MBDClientEvents不带目标——见脚本渲染器
js
// kubejs/client_scripts/mbd2_visuals.js
MBDMachineEvents.onCustomDataUpdate('example:crusher', wrapper => {
  const { oldValue, newValue } = wrapper.event
  console.debug(`Client machine data changed: ${oldValue} -> ${newValue}`)
})

这些只做视觉。在客户端拿到机器对象并不意味着获得了服务端权限。

代理配方转换 ​

js
// kubejs/server_scripts/mbd2_proxy.js
MBDRecipeTypeEvents.onTransferProxyRecipe('example:electric_furnace', wrapper => {
  const event = wrapper.event
  // event.recipeType       目标 MBDRecipeType
  // event.proxyTypeId      来源 vanilla/模组配方类型 ID
  // event.proxyType        来源 RecipeType 对象
  // event.proxyRecipeId    来源配方 ID
  // event.proxyRecipe      来源配方对象
  // event.mbdRecipe        可空、可改的转换结果
  if (`${event.proxyTypeId}` !== 'minecraft:smelting') {
    event.setCanceled(true)
  }
})

这个事件过滤的是配方类型已经声明的代理产生的配方,它本身不会启用代理。见代理配方类型。

tick 开销

onTick、onClientTick 和 onRecipeWorking 对每台机器每 tick 都会跑。不要在里面扫世界、解析 ID、重建集合或分配 UI 对象。

Released under the MIT License.