注册机器与配方类型
MBD2 21.1.1
对大多数模组,最安全的流程是:在 /mbd2_editor 中创作项目,导出后将产品文件打包到 assets/<modid>/...,再通过 MBDRegistryEvent 注册。只有定义必须由代码生成时才使用程序化 builder。
注册编辑器产品
public static void registerRecipeTypes(MBDRegistryEvent.MBDRecipeType event) {
event.registerFromResource(
ExampleMod.class,
"examplemod/mbd/recipe_types/heat_press.rt"
);
}
public static void registerMachines(MBDRegistryEvent.Machine event) {
event.registerFromResource(
ExampleMod.class,
"single_machine", // registry key,不是 KubeJS 的 "single" 别名
"examplemod/mbd/machines/heat_press.sm"
);
event.registerFromResource(
ExampleMod.class,
"multiblock",
"examplemod/mbd/machines/blast_furnace.mb"
);
}registerFromResource 从 /assets/<projectFile> 读取 NBT。类型或资源缺失时会记录错误并跳过定义。编辑器产品加载会把依赖 registry 的字段延迟到 MBD2 post task 中处理。
用 Java 创建配方类型
public static final ResourceLocation HEAT_PRESS_RECIPES =
ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "heat_press");
public static void registerRecipeTypes(MBDRegistryEvent.MBDRecipeType event) {
MBDRecipeType type = new MBDRecipeType(HEAT_PRESS_RECIPES);
MBDRecipe recipe = type.recipeBuilder(
ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "press_iron"))
.inputItems(Items.IRON_INGOT, 2)
.input(HeatUnitsCapability.CAP, 400)
.outputItems(Items.IRON_BLOCK)
.duration(200)
.addCondition(new MoonPhaseCondition(0))
.saveAsBuiltinRecipe();
event.register(type);
}saveAsBuiltinRecipe() 将构建结果放入该类型的内置配方表。buildRawRecipe() 只返回对象,不会注册或保存。数据生成时,请配置 onSave 并调用 MBDRecipeBuilder#save(RecipeOutput)。
用 Java 创建简单定义
public static void registerMachines(MBDRegistryEvent.Machine event) {
var energy = new ForgeEnergyCapabilityTraitDefinition();
energy.setName("power");
energy.setCapacity(100_000);
energy.setMaxReceive(2_000);
energy.setMaxExtract(2_000);
energy.setRecipeHandlerIO(IO.IN);
var definition = MBDMachineDefinition.builder()
.id(ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "heat_press"))
.rootState(MachineState.baseBuilder()
.modelRenderer(ResourceLocation.fromNamespaceAndPath(
ExampleMod.MOD_ID, "block/heat_press"))
.shape(Shapes.block())
.lightLevel(0)
.child("working")
.build())
.blockProperties(ConfigBlockProperties.builder().build())
.itemProperties(ConfigItemProperties.builder().build())
.machineSettings(() -> ConfigMachineSettings.builder()
.machineLevel(1)
.hasUI(true)
.traitDefinitions(new ArrayList<>(List.of(energy)))
.build())
.recipeLogicSettings(ConfigRecipeLogicSettings.builder()
.enable(true)
.recipeType(HEAT_PRESS_RECIPES)
.build())
.partSettings(() -> ConfigPartSettings.builder().build())
.build();
event.register(definition);
}该定义随后会注册自己的方块、物品、方块实体、渲染器和 capability。不要再把这些生成对象放入自己的 DeferredRegister。
在 Java 中使用多个配方逻辑
21.1.2 之后的版本中,一个定义可以运行多个配方逻辑:ConfigRecipeLogicSettings 有 name 和 threads,定义自身的 recipeLogicSettings().additionalRecipeLogics() 列出更多的 ConfigRecipeLogicSettings,每个都有自己的名字和配方类型。这个设置对象被禁用时,多余的线程和更多的逻辑都不存在。运行时:
| API | 得到 |
|---|---|
IMachine#getRecipeLogic() | 主逻辑,与以前相同 |
IMachine#getRecipeLogics() | 按 tick 顺序排列的所有逻辑 |
IMachine#getRecipeLogic(String address) | 某个地址上的逻辑——逻辑名或 name#thread——没有则为 null |
IMachine#getAggregatedRecipeStatus() | 机器汇总所有逻辑后显示的状态 |
IMachine#getRecipeCapabilitiesProxy(RecipeLogic) | 某个逻辑可以使用的 handler |
IMachine 的每个配方 hook——beforeWorking、onWorking、afterWorking、getModifiedRecipe、notifyRecipeStatusChanged 等——都有一个以 RecipeLogic 为首个参数的重载,配方逻辑总是调用这个重载。它的默认实现调用旧 hook,所以为单个逻辑编写的机器类照常工作;在 MBDMachine 中,旧 hook 可以通过 getContextRecipeLogic() 得知自己是为哪个逻辑运行的。想区别对待各个逻辑时重写这些重载。旧的 notifyRecipeStatusChanged(oldStatus, newStatus) 现在传递的是机器汇总后的状态,这正是机器状态应当跟随的。
自己构建 RecipeLogic 的子类重写 createRecipeLogic(Object...) 来构建主逻辑,重写 createRecipeLogic(ConfigRecipeLogicSettings, String, int) 来构建其余的每个逻辑与线程。
何时创建定义类型
只有需要不同的定义/运行时类或编辑器项目提供器时,才创建 MachineDefinitionType<T>。普通的自定义外观、Trait 集合、UI 或配方类型不需要新定义类型。内置类型为 single_machine(.sm)和 multiblock(.mb)。