数据加载条件

数据加载条件

有时需要依据其他 Mod 是否存在、是否有 Mod 添加了某种矿石等情况启用或禁用特定功能。NeoForge 为此提供数据加载条件。该系统最初用于配方,因此曾称为“配方条件”,后来扩展到了其他系统。这也是部分内置条件只适用于物品的原因。

大多数 JSON 文件可以在根对象中添加可选的 neoforge:conditions 区块。条件会在实际加载数据文件前求值,只有所有条件均通过时才继续加载,否则忽略该文件。(战利品表是例外:它会替换为空战利品表。)

{
    "neoforge:conditions": [
        {
            // Condition 1
        },
        {
            // Condition 2
        },
        // ...
    ],
    // The rest of the data file
}

例如,若只想在 ID 为 examplemod 的 Mod 存在时加载文件,可以这样写:

{
    // highlight-start
    "neoforge:conditions": [
        {
            "type": "neoforge:mod_loaded",
            "modid": "examplemod"
        }
    ],
    // highlight-end
    "type": "minecraft:crafting_shaped",
    // ...
}

提示 大多数原版文件已通过 ConditionalCodec 包装器支持条件。但并非所有系统都能使用条件,尤其是那些不使用 codec 的系统。要确定某个数据文件能否使用条件,请查看其底层 codec 定义。

内置条件

neoforge:true 与 neoforge:false

这两个条件没有额外数据,分别返回相应的布尔值。

{
    // Will always return true (or false for "neoforge:false")
    "type": "neoforge:true"
}

建议 使用 neoforge:false 可以简洁地禁用任意数据文件。只需在对应位置放置以下内容的文件:

{"neoforge:conditions":[{"type":"neoforge:false"}]}

以这种方式禁用文件不会导致日志刷屏。

neoforge:not

该条件接收另一个条件,并将其结果取反。

{
    // Inverts the result of the stored condition
    "type": "neoforge:not",
    "value": {
        // Another condition
    }
}

neoforge:and 与 neoforge:or

这两个条件接收待运算的条件,并分别执行逻辑与、逻辑或运算。接收的条件数量没有限制。

{
    // ANDs the stored conditions together (or ORs for "neoforge:or")
    "type": "neoforge:and",
    "values": [
        {
            // First condition
        },
        {
            // Second condition
        }
    ]
}

neoforge:mod_loaded

给定 Mod ID 的 Mod 已加载时返回 true,否则返回 false。

{
    "type": "neoforge:mod_loaded",
    // Returns true if "examplemod" is loaded
    "modid": "examplemod"
}

neoforge:item_exists

给定注册名称的物品已注册时返回 true,否则返回 false。

{
    "type": "neoforge:item_exists",
    // Returns true if "examplemod:example_item" has been registered
    "item": "examplemod:example_item"
}

neoforge:tag_empty

给定物品标签为空时返回 true,否则返回 false。

{
    "type": "neoforge:tag_empty",
    // Returns true if "examplemod:example_tag" is an empty item tag
    "tag": "examplemod:example_tag"
}

创建自定义条件

自定义条件需实现 ICondition 及其 #test(IContext) 方法,并创建对应的 map codec。#test 的 IContext 参数可访问部分游戏状态,目前仅支持查询注册表标签。某些带条件的对象可能先于标签加载,此时上下文为 IContext.EMPTY,完全不包含标签信息。

例如,假设要重新实现 tag_empty,但检查实体类型标签而非物品标签,条件实现如下:

// This class is basically a boiled-down copy of TagEmptyCondition, adjusted for entity types instead of items.
public record EntityTagEmptyCondition(TagKey<EntityType<?>> tag) implements ICondition {
    public static final MapCodec<EntityTagEmptyCondition> CODEC = RecordCodecBuilder.mapCodec(inst -> inst.group(
            ResourceLocation.CODEC.xmap(rl -> TagKey.create(Registries.ENTITY_TYPES, rl), TagKey::location).fieldOf("tag").forGetter(EntityTagEmptyCondition::tag)
    ).apply(inst, EntityTagEmptyCondition::new));

    @Override
    public boolean test(ICondition.IContext context) {
        return context.getTag(this.tag()).isEmpty();
    }

    @Override
    public MapCodec<? extends ICondition> codec() {
        return CODEC;
    }
}

条件使用的是一个 codec 注册表,因此需要注册相应 codec:

public static final DeferredRegister<MapCodec<? extends ICondition>> CONDITION_CODECS =
        DeferredRegister.create(NeoForgeRegistries.Keys.CONDITION_CODECS, ExampleMod.MOD_ID);

public static final Supplier<MapCodec<EntityTagEmptyCondition>> ENTITY_TAG_EMPTY =
        CONDITION_CODECS.register("entity_tag_empty", () -> EntityTagEmptyCondition.CODEC);

之后就可以在数据文件中使用自定义条件(假设它注册在 examplemod 命名空间下):

{
    "neoforge:conditions": [
        {
            "type": "examplemod:entity_tag_empty",
            "tag": "minecraft:zombies"
        }
    ],
    // The rest of the data file
}

数据生成

尽管任意数据包 JSON 文件都可以使用加载条件,但只有部分数据提供器已支持生成条件,包括:

对于条件本身,IConditionBuilder 接口为每个内置条件类型提供静态辅助方法,返回对应的 ICondition。


来源: NeoForged/Documentation(1.21.1)。中文翻译依据提交 4a680cdd4d15。