机器事件示例
当前 API Minecraft 1.21.1 / MBD2 21.1.1
空手交互与状态切换
js
const InteractionResult = Java.loadClass('net.minecraft.world.InteractionResult')
MBDMachineEvents.onUseWithoutItem('example:crusher', wrapper => {
const { machine, player } = wrapper.event
const next = machine.machineStateName === 'idle' ? 'disabled' : 'idle'
machine.setMachineState(next)
player.sendSystemMessage(Component.literal(`Machine state: ${next}`))
wrapper.event.setInteractionResult(InteractionResult.SUCCESS)
})状态名必须已经存在于编辑器 state machine;不存在时 setMachineState 会静默忽略。
配方生命周期日志
js
MBDMachineEvents.onRecipeStatusChanged('example:crusher', wrapper => {
const { machine, oldStatus, newStatus } = wrapper.event
console.info(`${machine.pos}: ${oldStatus} -> ${newStatus}`)
})
MBDMachineEvents.onRecipeWorking('example:crusher', wrapper => {
const { recipe, progress } = wrapper.event
if (progress % 20 === 0) {
console.debug(`${recipe.id}: ${progress}/${recipe.duration}`)
}
})多方块成型/失效
js
MBDMachineEvents.onStructureFormed('example:blast_furnace', wrapper => {
wrapper.event.machine.setMachineState('formed')
})
MBDMachineEvents.onStructureInvalid('example:blast_furnace', wrapper => {
wrapper.event.machine.setMachineState('idle')
})阻止 UI 与修改掉落
js
MBDMachineEvents.onOpenUI('example:crusher', wrapper => {
const { machine, player } = wrapper.event
if (!player.hasPermissions(2) && machine.machineStateName === 'locked') {
wrapper.event.setCanceled(true)
}
})
MBDMachineEvents.onDrops('example:crusher', wrapper => {
// drops 是底层 Java List<ItemStack>。
wrapper.event.drops.add(Item.of('minecraft:iron_nugget', 3))
})放置、邻居和燃料
js
MBDMachineEvents.onPlaced('example:crusher', wrapper => {
const { machine, itemStack } = wrapper.event
const data = machine.customData.copy()
data.putString('placed_from', `${itemStack.id}`)
machine.setCustomData(data)
})
MBDMachineEvents.onNeighborChanged('example:crusher', wrapper => {
console.debug(`Neighbor ${wrapper.event.block} changed at ${wrapper.event.fromPos}`)
})
MBDMachineEvents.onFuelRecipeModify('example:crusher', wrapper => {
const fuelRecipe = wrapper.event.recipe
console.debug(`Selected fuel: ${fuelRecipe.id}`)
})客户端同步观察
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}`)
})onClientTick 与 GeckoLib 的 onCustomKeyframe 也属于客户端事件,只应用于动画和视觉状态。
高频事件 onTick、onClientTick、onRecipeWorking 中不要扫描世界、解析大量 JSON 或重建 UI。
一次合成完成之后
js
MBDMachineEvents.onRecipeFinish('example:crusher', wrapper => {
const { machine, recipe } = wrapper.event
// The outputs already exist here; onAfterRecipeWorking runs before they do.
console.info(`${recipe.id} finished at ${machine.pos}`)
})
MBDMachineEvents.onConsumeInputsAfterWorking('example:crusher', wrapper => {
// Only fires when the machine defers input consumption to completion.
console.debug(`deferred inputs taken for ${wrapper.event.recipe.id}`)
})onFuelBurningFinish 从不触发
它的 KubeJS 名字已注册,但 MBDMachine#onFuelBurningFinish 向 NeoForge 总线投递时没有调用 postCustomEvent(),所以在 21.1.1 中这个 handler 永远不会被调用。请改为观察 machine.recipeLogic.fuelTime 或 WAITING 状态。