数据加载条件(Data Load Conditions)
有时候,你可能希望在检测到其他模组(mod)存在时,禁用或启用某些功能,或者当任意模组添加了新的矿石类型时执行某些操作。针对这些需求,NeoForge 提供了数据加载条件(data load conditions)。这一机制最初被称为配方条件(recipe conditions),因为它最早是为配方系统设计的,但现在已经扩展到了其他系统。这也是为什么部分内置条件目前仅限于物品(item)的原因。
大多数 JSON 文件都可以在根节点中可选地声明一个 neoforge:conditions 块。在实际加载数据文件之前,NeoForge 会先评估这些条件。只有当所有条件都通过时,数据才会被加载,否则该数据文件会被忽略。(掉落表 是一个例外,如果条件不通过,会被替换为空的掉落表。)
{
"neoforge:conditions": [
{
// 条件 1
},
{
// 条件 2
},
// ...
],
// 数据文件的其他部分
}
如果要加载的值不是一个 map/object(映射/对象),则需要存储在 neoforge:value 字段中:
{
"neoforge:conditions": [ /* ...*/ ],
"neoforge:value": 2 // 要加载的值
}
例如,如果我们只希望在 id 为 examplemod 的模组存在时加载文件,可以这样写:
{
"neoforge:conditions": [
{
"type": "neoforge:mod_loaded",
"modid": "examplemod"
}
],
"type": "minecraft:crafting_shaped",
// ...
}
大多数原版(vanilla)文件已经通过 ConditionalCodec 包装器进行了条件判断的补丁。然而,并非所有系统(尤其是不使用 编解码器 的系统)都能用条件。要判断某个数据文件是否支持条件,请查看其底层编解码器定义。
内置条件(Built-In Conditions)
neoforge:always 和 neoforge:never
这两个条件都不需要额外数据,并且会返回预期的布尔值。
{
// "neoforge:always" 总是返回 true("neoforge:never" 则返回 false)
"type": "neoforge:always"
}
使用 neoforge:never 条件可以非常方便地禁用任意数据文件。只需在需要的位置放置如下内容的文件即可:
{"neoforge:conditions":[{"type":"neoforge:never"}]}
通过这种方式禁用文件,不会导致日志刷屏。
neoforge:not
该条件接受另一个条件,并将其结果取反。
{
// 反转所存储条件的结果
"type": "neoforge:not",
"value": {
// 另一个条件
}
}
neoforge:and 和 neoforge:or
这些条件可以接受任意数量的条件,并应用相应的逻辑操作。可被接收的条件数量没有限制。
{
// 将所有存储的条件进行 AND 运算(对于 "neoforge:or" 则为 OR 运算)
"type": "neoforge:and",
"values": [
{
// 第一个条件
},
{
// 第二个条件
}
]
}
neoforge:mod_loaded
如果指定 mod id 的 mod 已加载,则该条件返回 true,否则返回 false。
{
"type": "neoforge:mod_loaded",
// 如果 "examplemod" 已加载,则返回 true
"modid": "examplemod"
}
neoforge:registered
如果在指定注册表(Registry)中,给定注册名的对象已被注册,则该条件返回 true,否则返回 false。
{
"type": "neoforge:registered",
// 要检查的注册表(Registry)
// 默认为 `minecraft:item`
"registry": "minecraft:item",
// 如果 "examplemod:example_item" 已被注册,则返回 true
"value": "examplemod:example_item"
}
neoforge:tag_empty
如果指定注册表(Registry)中的 标签 为空,则该条件返回 true,否则返回 false。
{
"type": "neoforge:tag_empty",
// 要检查标签的注册表(Registry)
// 默认为 `minecraft:item`
"registry": "minecraft:item",
// 如果 "examplemod:example_tag" 是一个空标签,则返回 true
"tag": "examplemod:example_tag"
}
neoforge:feature_flags_enabled
如果指定的 功能标志 已启用,则该条件返回 true,否则返回 false。
{
"type": "neoforge:feature_flags_enabled",
// 如果 "examplemod:example_feature" 已启用,则返回 true
"flags": [
"examplemod:example_feature"
]
}
创建自定义条件(Creating Custom Conditions)
可以通过实现 ICondition 及其 #test(IContext) 方法,并为其创建一个 map codec,来自定义条件。#test 方法中的 IContext 参数可以访问游戏状态的部分内容。目前,这仅允许你从注册表(Registry)中查询标签(tag)。有些带有条件的对象可能会在标签加载之前就被加载,此时 context 会是 IContext.EMPTY,不包含任何标签信息。
例如,假设我们想要实现一个 xor 条件,那么我们的条件实现大致如下:
public record XorCondition(ICondition first, ICondition second) implements ICondition {
public static final MapCodec<XorCondition> CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group(
ICondition.CODEC.fieldOf("first").forGetter(XorCondition::first),
ICondition.CODEC.fieldOf("second").forGetter(XorCondition::second)
).apply(inst, XorCondition::new));
@Override
public boolean test(ICondition.IContext context) {
// 仅当 first 和 second 恰好有一个为 true 时返回 true
return this.first.test(context) ^ this.second.test(context);
}
@Override
public MapCodec<? extends ICondition> codec() {
return CODEC;
}
}
条件本质上是 codec 的注册表(Registry)。因此,我们需要像下面这样注册我们的 codec:
public static final DeferredRegister<MapCodec<? extends ICondition>> CONDITION_CODECS =
DeferredRegister.create(NeoForgeRegistries.Keys.CONDITION_CODECS, ExampleMod.MOD_ID);
public static final Supplier<MapCodec<XorCondition>> XOR =
CONDITION_CODECS.register("xor", () -> XorCondition.CODEC);
接下来,我们就可以在某个数据文件中使用我们自定义的条件(假设我们在 examplemod 命名空间下注册了该条件):
{
"neoforge:conditions": [
{
"type": "examplemod:xor",
"first": {
// 这个条件成立时
"type": "..."
},
"second": {
// 或者这个条件成立(但不能两个都成立!)
"type": "..."
}
}
],
// 数据文件的其余部分
}
数据生成(Datagen)
虽然任何数据包(datapack)中的 JSON 文件都可以使用加载条件(load condition),但只有少数 数据提供器 被修改以支持生成这些条件。包括:
RecipeProvider(通过RecipeOutput#withConditions),以及配方成就(recipe advancements)JsonCodecProvider及其子类SpriteSourceProviderDataMapProviderGlobalLootModifierProvider
对于条件本身,NeoForgeConditions 类为每种内置条件类型都提供了静态辅助方法,用于返回相应的 ICondition。