条件加载数据
开发者有时希望使用另一个 Mod 的信息创建数据驱动对象,却不想将该 Mod 显式设为依赖;也可能希望在其他 Mod 的条目存在时替换某些对象。条件子系统可以实现这些需求。
原创说明图,依据 Forge 1.21.x 官方文档 绘制。
实现
目前配方和进度支持条件加载。条件配方或进度会加载条件与数据项的配对列表。如果某个数据项的条件为真,则返回该数据项;否则丢弃。
带注释和省略号的示例用于说明结构;实际 JSON 文件需移除注释并补全内容。
{
// 配方可有自定义序列化器,因此需要指定类型;进度不需要
"type": "forge:conditional",
"recipes": [ // 进度使用 'advancements'
{
// 要检查的条件;列表中的条件以 AND 组合
"conditions": [
{ /* 条件 1 */ },
{ /* 条件 2 */ }
],
"recipe": { // 进度使用 'advancement';所有条件成功时使用的配方
}
},
{ /* 前一项失败时检查的下一条件 */ }
]
}
条件数据还通过 ConditionalRecipe$Builder 和 ConditionalAdvancement$Builder 提供数据生成包装器。
条件
将 type 设置为 IConditionSerializer#getID 指定的条件名称。
True 和 False
布尔条件不含数据,返回对应的预期值,分别为 forge:true 和 forge:false。
// 某个条件:始终返回 true(forge:false 返回 false)
{ "type": "forge:true" }
Not、And 和 Or
布尔运算条件包含被操作的条件,分别为 forge:not、forge:and 和 forge:or。
// 对保存的条件结果取反
{ "type": "forge:not", "value": { /* 一个条件 */ } }
// 对保存的条件执行 AND;forge:or 则执行 OR
{
"type": "forge:and",
"values": [
{ /* 第一个条件 */ },
{ /* 第二个 AND 条件;forge:or 时为 OR 条件 */ }
]
}
Mod 已加载
当前应用中加载了指定 ID 的 Mod 时,ModLoadedCondition 返回 true,对应 forge:mod_loaded。
{
"type": "forge:mod_loaded",
"modid": "examplemod" // examplemod 加载时返回 true
}
物品存在
给定物品已在当前应用注册时,ItemExistsCondition 返回 true,对应 forge:item_exists。
{
"type": "forge:item_exists",
"item": "examplemod:example_item" // 已注册时返回 true
}
标签为空
给定物品标签没有条目时,TagEmptyCondition 返回 true,对应 forge:tag_empty。
{
"type": "forge:tag_empty",
"tag": "examplemod:example_tag" // 为空物品标签时返回 true
}
创建自定义条件
实现 ICondition 及其对应的 IConditionSerializer 即可创建自定义条件。
ICondition
条件只需实现两个方法:
| 方法 | 说明 |
|---|---|
getID |
条件注册表名称,必须与 IConditionSerializer#getID 一致,仅用于数据生成。 |
test |
条件满足时返回 true。 |
每个 #test 都可以访问表示游戏状态的 IContext;目前只能从注册表获取标签。
IConditionSerializer
序列化器需实现三个方法:
| 方法 | 说明 |
|---|---|
getID |
条件注册表名称,必须与 ICondition#getID 一致。 |
read |
从 JSON 读取条件数据。 |
write |
将给定条件数据写入 JSON。 |
与 Minecraft 的其他序列化器实现类似,条件序列化器不负责读写自身类型。
随后声明静态实例保存初始化后的序列化器,并在 RecipeSerializer 的 RegisterEvent 或 FMLCommonSetupEvent 期间使用 CraftingHelper#register 注册:
// 在某个序列化器类中
public static final ExampleConditionSerializer INSTANCE = new ExampleConditionSerializer();
// 在某个处理器类中
public void registerSerializers(RegisterEvent event) {
event.register(ForgeRegistries.Keys.RECIPE_SERIALIZERS,
helper -> CraftingHelper.register(INSTANCE)
);
}
重要:如果在
FMLCommonSetupEvent注册条件序列化器,必须通过FMLCommonSetupEvent#enqueueWork加入同步工作队列,因为CraftingHelper#register不是线程安全的。